diff --git a/lms/djangoapps/verify_student/tests/test_views.py b/lms/djangoapps/verify_student/tests/test_views.py index 62e339b56f..3fb52a2a6e 100644 --- a/lms/djangoapps/verify_student/tests/test_views.py +++ b/lms/djangoapps/verify_student/tests/test_views.py @@ -992,7 +992,6 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): self._assert_requirements_displayed(response, [ PayAndVerifyView.PHOTO_ID_REQ, PayAndVerifyView.WEBCAM_REQ, - PayAndVerifyView.CREDIT_CARD_REQ, ]) @ddt.data("expired", "denied") @@ -1033,9 +1032,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): PayAndVerifyView.MAKE_PAYMENT_STEP ) self._assert_messaging(response, PayAndVerifyView.FIRST_TIME_VERIFY_MSG) - self._assert_requirements_displayed(response, [ - PayAndVerifyView.CREDIT_CARD_REQ, - ]) + self._assert_requirements_displayed(response, []) @ddt.data("verified", "professional") def test_start_flow_already_paid(self, course_mode): @@ -1068,9 +1065,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): PayAndVerifyView.PAYMENT_STEPS, PayAndVerifyView.MAKE_PAYMENT_STEP ) - self._assert_requirements_displayed(response, [ - PayAndVerifyView.CREDIT_CARD_REQ, - ]) + self._assert_requirements_displayed(response, []) def test_start_flow_unenrolled(self): course = self._create_course("verified") @@ -1086,9 +1081,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): PayAndVerifyView.PAYMENT_STEPS, PayAndVerifyView.MAKE_PAYMENT_STEP ) - self._assert_requirements_displayed(response, [ - PayAndVerifyView.CREDIT_CARD_REQ, - ]) + self._assert_requirements_displayed(response, []) @ddt.data( ("verified", "submitted"), @@ -1128,7 +1121,6 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): self._assert_requirements_displayed(response, [ PayAndVerifyView.PHOTO_ID_REQ, PayAndVerifyView.WEBCAM_REQ, - PayAndVerifyView.CREDIT_CARD_REQ, ]) def test_verify_now_already_verified(self): @@ -1237,28 +1229,8 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): self._assert_requirements_displayed(response, [ PayAndVerifyView.PHOTO_ID_REQ, PayAndVerifyView.WEBCAM_REQ, - PayAndVerifyView.CREDIT_CARD_REQ, ]) - def test_payment_confirmation_skip_first_step(self): - course = self._create_course("verified") - self._enroll(course.id, "verified") - response = self._get_page( - 'verify_student_payment_confirmation', - course.id, - skip_first_step=True - ) - - self._assert_messaging(response, PayAndVerifyView.PAYMENT_CONFIRMATION_MSG) - - # Expect that *all* steps are displayed, - # but we start on the first verify step - self._assert_steps_displayed( - response, - PayAndVerifyView.PAYMENT_STEPS + PayAndVerifyView.VERIFICATION_STEPS, - PayAndVerifyView.FACE_PHOTO_STEP, - ) - def test_payment_cannot_skip(self): """ Simple test to verify that certain steps cannot be skipped. This test sets up @@ -1358,7 +1330,6 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): self._assert_requirements_displayed(response, [ PayAndVerifyView.PHOTO_ID_REQ, PayAndVerifyView.WEBCAM_REQ, - PayAndVerifyView.CREDIT_CARD_REQ, ]) def test_upgrade_already_verified(self): @@ -1373,9 +1344,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): PayAndVerifyView.MAKE_PAYMENT_STEP ) self._assert_messaging(response, PayAndVerifyView.UPGRADE_MSG) - self._assert_requirements_displayed(response, [ - PayAndVerifyView.CREDIT_CARD_REQ, - ]) + self._assert_requirements_displayed(response, []) def test_upgrade_already_paid(self): course = self._create_course("verified") @@ -1486,7 +1455,6 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): ) self._assert_requirements_displayed(response, [ PayAndVerifyView.ACCOUNT_ACTIVATION_REQ, - PayAndVerifyView.CREDIT_CARD_REQ, PayAndVerifyView.PHOTO_ID_REQ, PayAndVerifyView.WEBCAM_REQ, ]) @@ -1516,6 +1484,22 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): response = self._get_page("verify_student_start_flow", course.id) self._assert_contribution_amount(response, "12.34") + def test_verification_deadline(self): + # Set a deadline on the course mode + course = self._create_course("verified") + mode = CourseMode.objects.get( + course_id=course.id, + mode_slug="verified" + ) + expiration = datetime(2999, 1, 2, tzinfo=pytz.UTC) + mode.expiration_datetime = expiration + mode.save() + + # Expect that the expiration date is set + response = self._get_page("verify_student_start_flow", course.id) + data = self._get_page_data(response) + self.assertEqual(data['verification_deadline'], "Jan 02, 2999 at 00:00 UTC") + def _create_course(self, *course_modes, **kwargs): """Create a new course with the specified course modes. """ course = CourseFactory.create() @@ -1648,7 +1632,8 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): 'current_step': pay_and_verify_div['data-current-step'], 'requirements': json.loads(pay_and_verify_div['data-requirements']), 'message_key': pay_and_verify_div['data-msg-key'], - 'contribution_amount': pay_and_verify_div['data-contribution-amount'] + 'contribution_amount': pay_and_verify_div['data-contribution-amount'], + 'verification_deadline': pay_and_verify_div['data-verification-deadline'] } def _assert_redirects_to_dashboard(self, response): diff --git a/lms/djangoapps/verify_student/views.py b/lms/djangoapps/verify_student/views.py index 9d5999861d..5e1fec7ed7 100644 --- a/lms/djangoapps/verify_student/views.py +++ b/lms/djangoapps/verify_student/views.py @@ -47,6 +47,7 @@ from xmodule.modulestore.django import modulestore from microsite_configuration import microsite from util.json_request import JsonResponse +from util.date_utils import get_default_time_display log = logging.getLogger(__name__) @@ -259,10 +260,9 @@ class PayAndVerifyView(View): ENROLLMENT_CONFIRMATION_STEP ] - # These are steps that can be skipped, since there are no barring requirements. + # These steps can be skipped using the ?skip-first-step GET param SKIP_STEPS = [ INTRO_STEP, - PAYMENT_CONFIRMATION_STEP ] Step = namedtuple( @@ -287,15 +287,15 @@ class PayAndVerifyView(View): template_name="payment_confirmation_step" ), FACE_PHOTO_STEP: Step( - title=ugettext_lazy("Take Face Photo"), + title=ugettext_lazy("Take Photo"), template_name="face_photo_step" ), ID_PHOTO_STEP: Step( - title=ugettext_lazy("ID Photo"), + title=ugettext_lazy("Take a Photo of Your ID"), template_name="id_photo_step" ), REVIEW_PHOTOS_STEP: Step( - title=ugettext_lazy("Review Photos"), + title=ugettext_lazy("Review Your Info"), template_name="review_photos_step" ), ENROLLMENT_CONFIRMATION_STEP: Step( @@ -380,12 +380,10 @@ class PayAndVerifyView(View): ACCOUNT_ACTIVATION_REQ = "account-activation-required" PHOTO_ID_REQ = "photo-id-required" WEBCAM_REQ = "webcam-required" - CREDIT_CARD_REQ = "credit-card-required" STEP_REQUIREMENTS = { ID_PHOTO_STEP: [PHOTO_ID_REQ, WEBCAM_REQ], FACE_PHOTO_STEP: [WEBCAM_REQ], - MAKE_PAYMENT_STEP: [CREDIT_CARD_REQ], } @method_decorator(login_required) @@ -507,6 +505,10 @@ class PayAndVerifyView(View): 'course': course, 'course_key': unicode(course_key), 'course_mode': course_mode, + 'verification_deadline': ( + get_default_time_display(course_mode.expiration_datetime) + if course_mode.expiration_datetime else "" + ), 'courseware_url': courseware_url, 'current_step': current_step, 'disable_courseware_js': True, @@ -660,7 +662,6 @@ class PayAndVerifyView(View): self.ACCOUNT_ACTIVATION_REQ: not is_active, self.PHOTO_ID_REQ: False, self.WEBCAM_REQ: False, - self.CREDIT_CARD_REQ: False } display_steps = set(step['name'] for step in display_steps) diff --git a/lms/envs/common.py b/lms/envs/common.py index 5d3f1fe9a4..0003cd09a3 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1083,8 +1083,6 @@ verify_student_js = [ 'js/verify_student/models/verification_model.js', 'js/verify_student/views/error_view.js', 'js/verify_student/views/webcam_photo_view.js', - 'js/verify_student/views/progress_view.js', - 'js/verify_student/views/requirements_view.js', 'js/verify_student/views/step_view.js', 'js/verify_student/views/intro_step_view.js', 'js/verify_student/views/make_payment_step_view.js', diff --git a/lms/static/js/spec/main.js b/lms/static/js/spec/main.js index 3350a19bbf..4db456cc9c 100644 --- a/lms/static/js/spec/main.js +++ b/lms/static/js/spec/main.js @@ -397,14 +397,6 @@ exports: 'edx.verify_student.WebcamPhotoView', deps: [ 'jquery', 'underscore', 'backbone', 'gettext' ] }, - 'js/verify_student/views/progress_view': { - exports: 'edx.verify_student.ProgressView', - deps: [ 'jquery', 'underscore', 'backbone', 'gettext' ] - }, - 'js/verify_student/views/requirements_view': { - exports: 'edx.verify_student.RequirementsView', - deps: [ 'jquery', 'backbone', 'underscore', 'gettext' ] - }, 'js/verify_student/views/step_view': { exports: 'edx.verify_student.StepView', deps: [ 'jquery', 'underscore', 'underscore.string', 'backbone', 'gettext' ] @@ -414,7 +406,6 @@ deps: [ 'jquery', 'js/verify_student/views/step_view', - 'js/verify_student/views/requirements_view' ] }, 'js/verify_student/views/make_payment_step_view': { @@ -426,7 +417,6 @@ 'jquery.cookie', 'jquery.url', 'js/verify_student/views/step_view', - 'js/verify_student/views/requirements_view' ] }, 'js/verify_student/views/payment_confirmation_step_view': { @@ -436,7 +426,6 @@ 'underscore', 'gettext', 'js/verify_student/views/step_view', - 'js/verify_student/views/requirements_view' ] }, 'js/verify_student/views/face_photo_step_view': { @@ -484,7 +473,6 @@ 'backbone', 'gettext', 'js/verify_student/models/verification_model', - 'js/verify_student/views/progress_view', 'js/verify_student/views/intro_step_view', 'js/verify_student/views/make_payment_step_view', 'js/verify_student/views/payment_confirmation_step_view', diff --git a/lms/static/js/spec/verify_student/pay_and_verify_view_spec.js b/lms/static/js/spec/verify_student/pay_and_verify_view_spec.js index ddd15b7720..baf3edbdf3 100644 --- a/lms/static/js/spec/verify_student/pay_and_verify_view_spec.js +++ b/lms/static/js/spec/verify_student/pay_and_verify_view_spec.js @@ -69,27 +69,8 @@ define(['jquery', 'js/common_helpers/template_helpers', 'js/verify_student/views }; var expectStepRendered = function( stepName, stepNum, numSteps ) { - var i, j, sel; - // Expect that the step container div rendered expect( $( '.' + stepName ).length > 0 ).toBe( true ); - - // Expect that the progress indicator shows the correct step - expect( $( '#progress-step-' + stepNum ).hasClass( 'is-current' ) ).toBe( true ); - - // Expect that all steps before this step are completed - for ( i = 1; i < stepNum; i++ ) { - sel = $( '#progress-step-' + i ); - expect( sel.hasClass('is-completed') ).toBe( true ); - expect( sel.hasClass('is-current') ).toBe( false ); - } - - // Expect that all steps after this step are neither completed nor current - for ( j = stepNum + 1; j <= numSteps; j++ ) { - sel = $( '#progress-step-' + j ); - expect( sel.hasClass('is-completed') ).toBe( false ); - expect( sel.hasClass('is-current') ).toBe( false ); - } }; beforeEach(function() { diff --git a/lms/static/js/spec/verify_student/review_photos_step_view_spec.js b/lms/static/js/spec/verify_student/review_photos_step_view_spec.js index 65e86ef098..1206d825c4 100644 --- a/lms/static/js/spec/verify_student/review_photos_step_view_spec.js +++ b/lms/static/js/spec/verify_student/review_photos_step_view_spec.js @@ -31,10 +31,6 @@ define([ }).render(); }; - var confirmPhotos = function( isConfirmed ) { - $('#confirm_pics_good').trigger( 'click' ); - }; - var submitPhotos = function( requests, expectedParams, succeeds ) { // Submit the photos $( '#next_step_button' ).click(); @@ -69,27 +65,11 @@ define([ TemplateHelpers.installTemplate( 'templates/verify_student/review_photos_step' ); }); - it( 'requires the user to confirm before submitting photos', function() { - createView(); - - // Initially disabled - expectSubmitEnabled( false ); - - // Confirm the photos, enabling submission - confirmPhotos( true ); - expectSubmitEnabled( true ); - - // Unconfirm the photos, disabling submission - confirmPhotos( false ); - expectSubmitEnabled( false ); - }); - it( 'allows the user to change her full name', function() { var requests = AjaxHelpers.requests( this ); createView(); setFullName( FULL_NAME ); - confirmPhotos( true ); submitPhotos( requests, { @@ -105,7 +85,6 @@ define([ var requests = AjaxHelpers.requests( this ); createView(); - confirmPhotos( true ); submitPhotos( requests, { @@ -124,7 +103,6 @@ define([ var view = createView(), requests = AjaxHelpers.requests( this ); - confirmPhotos( true ); submitPhotos( requests, { diff --git a/lms/static/js/verify_student/pay_and_verify.js b/lms/static/js/verify_student/pay_and_verify.js index e2a9cdf4a1..8430c0749f 100644 --- a/lms/static/js/verify_student/pay_and_verify.js +++ b/lms/static/js/verify_student/pay_and_verify.js @@ -46,6 +46,8 @@ var edx = edx || {}; isActive: el.data('is-active'), requirements: el.data('requirements'), courseKey: el.data('course-key'), + courseName: el.data('course-name'), + upgrade: el.data('data-msg-key') === 'upgrade', minPrice: el.data('course-mode-min-price'), contributionAmount: el.data('contribution-amount'), suggestedPrices: _.filter( @@ -53,12 +55,16 @@ var edx = edx || {}; function( price ) { return Boolean( price ); } ), currency: el.data('course-mode-currency'), - purchaseEndpoint: el.data('purchase-endpoint') + purchaseEndpoint: el.data('purchase-endpoint'), + verificationDeadline: el.data('verification-deadline') }, 'payment-confirmation-step': { + courseKey: el.data('course-key'), courseName: el.data('course-name'), courseStartDate: el.data('course-start-date'), - coursewareUrl: el.data('courseware-url') + coursewareUrl: el.data('courseware-url'), + platformName: el.data('platform-name'), + requirements: el.data('requirements') }, 'review-photos-step': { fullName: el.data('full-name'), @@ -67,7 +73,14 @@ var edx = edx || {}; 'enrollment-confirmation-step': { courseName: el.data('course-name'), courseStartDate: el.data('course-start-date'), - coursewareUrl: el.data('courseware-url') + coursewareUrl: el.data('courseware-url'), + platformName: el.data('platform-name') + }, + 'face-photo-step': { + platformName: el.data('platform-name') + }, + 'id-photo-step': { + platformName: el.data('platform-name') } } }).render(); diff --git a/lms/static/js/verify_student/views/enrollment_confirmation_step_view.js b/lms/static/js/verify_student/views/enrollment_confirmation_step_view.js index 06feb79527..6529402f91 100644 --- a/lms/static/js/verify_student/views/enrollment_confirmation_step_view.js +++ b/lms/static/js/verify_student/views/enrollment_confirmation_step_view.js @@ -21,7 +21,8 @@ var edx = edx || {}; return { courseName: '', courseStartDate: '', - coursewareUrl: '' + coursewareUrl: '', + platformName: '' }; } }); 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 8008565a13..f1d573cf53 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 @@ -10,6 +10,12 @@ var edx = edx || {}; edx.verify_student.FacePhotoStepView = edx.verify_student.StepView.extend({ + defaultContext: function() { + return { + platformName: '' + }; + }, + postRender: function() { var webcam = new edx.verify_student.WebcamPhotoView({ el: $( '#facecam' ), 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 35ed9e7b5d..60a02e4c7b 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 @@ -10,6 +10,12 @@ var edx = edx || {}; edx.verify_student.IDPhotoStepView = edx.verify_student.StepView.extend({ + defaultContext: function() { + return { + platformName: '' + }; + }, + postRender: function() { var webcam = new edx.verify_student.WebcamPhotoView({ el: $( '#idcam' ), diff --git a/lms/static/js/verify_student/views/intro_step_view.js b/lms/static/js/verify_student/views/intro_step_view.js index 0eead8f279..f9f6eac3c7 100644 --- a/lms/static/js/verify_student/views/intro_step_view.js +++ b/lms/static/js/verify_student/views/intro_step_view.js @@ -14,7 +14,9 @@ var edx = edx || {}; return { introTitle: '', introMsg: '', - isActive: false + isActive: false, + platformName: '', + requirements: {} }; }, @@ -25,11 +27,6 @@ var edx = edx || {}; // and if they reload the page we want them to stay on the // second step. postRender: function() { - new edx.verify_student.RequirementsView({ - el: $( '.requirements-container', this.el ), - requirements: this.stepData.requirements - }).render(); - // Track a virtual pageview, for easy funnel reconstruction. window.analytics.page( 'verification', this.templateName ); } 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 3b24b625e2..3066c57957 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 @@ -15,41 +15,62 @@ var edx = edx || {}; isActive: true, suggestedPrices: [], minPrice: 0, - currency: "usd" + currency: 'usd', + upgrade: false, + verificationDeadline: '', + courseName: '', + requirements: {}, + platformName: '' }; }, postRender: function() { - // Render requirements - new edx.verify_student.RequirementsView({ - el: $( '.requirements-container', this.el ), - requirements: this.stepData.requirements - }).render(); + var templateContext = this.templateContext(), + hasVisibleReqs = _.some( + templateContext.requirements, + function( isVisible ) { return isVisible; } + ); // Track a virtual pageview, for easy funnel reconstruction. window.analytics.page( 'payment', this.templateName ); // Update the contribution amount with the amount the user // selected in a previous screen. - if ( this.stepData.contributionAmount ) { - this.selectPaymentAmount( this.stepData.contributionAmount ); + if ( templateContext.contributionAmount ) { + this.selectPaymentAmount( templateContext.contributionAmount ); } - if ( this.templateContext().suggestedPrices.length > 0 ) { + // The contribution section is hidden by default + // Display it if the user hasn't already selected an amount + // or is upgrading. + // In the short-term, we're also displaying this if there + // are no requirements (e.g. the user already verified). + // Otherwise, there's absolutely nothing to do on this page. + // In the future, we'll likely skip directly to payment + // from the track selection page if this happens. + if ( templateContext.upgrade || !templateContext.contributionAmount || !hasVisibleReqs ) { + $( '.wrapper-task' ).removeClass( 'hidden' ).removeAttr( 'aria-hidden' ); + } + + if ( templateContext.suggestedPrices.length > 0 ) { // Enable the payment button once an amount is chosen - $( "input[name='contribution']" ).on( 'click', _.bind( this.enablePaymentButton, this ) ); + $( 'input[name="contribution"]' ).on( 'click', _.bind( this.setPaymentEnabled, this ) ); } else { // If there is only one payment option, then the user isn't shown // radio buttons, so we need to enable the radio button. - this.enablePaymentButton(); + this.setPaymentEnabled( true ); } // Handle payment submission - $( "#pay_button" ).on( 'click', _.bind( this.createOrder, this ) ); + $( '#pay_button' ).on( 'click', _.bind( this.createOrder, this ) ); }, - enablePaymentButton: function() { - $("#pay_button").removeClass("is-disabled"); + setPaymentEnabled: function( isEnabled ) { + if ( _.isUndefined( isEnabled ) ) { + isEnabled = true; + } + + $( '#pay_button' ).toggleClass( 'is-disabled', !isEnabled ); }, createOrder: function() { @@ -60,7 +81,7 @@ var edx = edx || {}; }; // Disable the payment button to prevent multiple submissions - $("#pay_button").addClass("is-disabled"); + this.setPaymentEnabled( false ); // Create the order for the amount $.ajax({ @@ -84,16 +105,16 @@ var edx = edx || {}; // these parameters, then submit it to the payment processor. // This will send the user to a hosted order page, // where she can enter credit card information. - var form = $( "#payment-processor-form" ); + var form = $( '#payment-processor-form' ); - $( "input", form ).remove(); + $( 'input', form ).remove(); - form.attr( "action", this.stepData.purchaseEndpoint ); - form.attr( "method", "POST" ); + form.attr( 'action', this.stepData.purchaseEndpoint ); + form.attr( 'method', 'POST' ); _.each( paymentParams, function( value, key ) { - $("").attr({ - type: "hidden", + $('').attr({ + type: 'hidden', name: key, value: value }).appendTo(form); @@ -121,15 +142,15 @@ var edx = edx || {}; }); // Re-enable the button so the user can re-try - $( "#pay_button" ).removeClass("is-disabled"); + $( '#pay_button' ).removeClass( 'is-disabled' ); }, getPaymentAmount: function() { - var contributionInput = $("input[name='contribution']:checked", this.el), + var contributionInput = $( 'input[name="contribution"]:checked' , this.el), amount = null; if ( contributionInput.attr('id') === 'contribution-other' ) { - amount = $( "input[name='contribution-other-amt']", this.el ).val(); + amount = $( 'input[name="contribution-other-amt"]' , this.el ).val(); } else { amount = contributionInput.val(); } @@ -167,7 +188,7 @@ var edx = edx || {}; } // In either case, enable the payment button - this.enablePaymentButton(); + this.setPaymentEnabled(); return amount; }, diff --git a/lms/static/js/verify_student/views/pay_and_verify_view.js b/lms/static/js/verify_student/views/pay_and_verify_view.js index 343ef98139..ee410ebacc 100644 --- a/lms/static/js/verify_student/views/pay_and_verify_view.js +++ b/lms/static/js/verify_student/views/pay_and_verify_view.js @@ -1,8 +1,8 @@ /** * Base view for the payment/verification flow. * - * This view is responsible for the "progress steps" - * at the top of the page, but it delegates + * This view is responsible for keeping track of the + * current step, but it delegates to * to subviews to render individual steps. * */ @@ -27,21 +27,11 @@ var edx = edx || {}; initialize: function( obj ) { this.errorModel = obj.errorModel || null; this.displaySteps = obj.displaySteps || []; - - this.progressView = new edx.verify_student.ProgressView({ - el: this.el, - displaySteps: this.displaySteps, - - // Determine which step we're starting on - // Depending on how the user enters the flow, - // this could be anywhere in the sequence of steps. - currentStepIndex: _.indexOf( - _.pluck( this.displaySteps, 'name' ), - obj.currentStep - ) - }); - this.initializeStepViews( obj.stepInfo || {} ); + this.currentStepIndex = _.indexOf( + _.pluck( this.displaySteps, 'name' ), + obj.currentStep + ); }, initializeStepViews: function( stepInfo ) { @@ -94,7 +84,6 @@ var edx = edx || {}; subviewConfig = { errorModel: this.errorModel, templateName: this.displaySteps[i].templateName, - nextStepNum: (i + 2), // Next index, starting from 1 nextStepTitle: nextStepTitle, stepData: stepData }; @@ -118,7 +107,6 @@ var edx = edx || {}; }, render: function() { - this.progressView.render(); this.renderCurrentStep(); return this; }, @@ -137,19 +125,30 @@ var edx = edx || {}; // underscore template. // When the view is rendered, it will overwrite the existing // step in the DOM. - stepName = this.displaySteps[ this.progressView.currentStepIndex ].name; + stepName = this.displaySteps[ this.currentStepIndex ].name; stepView = this.subviews[ stepName ]; stepView.el = stepEl; stepView.render(); }, nextStep: function() { - this.progressView.nextStep(); + this.currentStepIndex = Math.min( + this.currentStepIndex + 1, + this.displaySteps.length - 1 + ); this.render(); }, goToStep: function( stepName ) { - this.progressView.goToStep( stepName ); + var stepIndex = _.indexOf( + _.pluck( this.displaySteps, 'name' ), + stepName + ); + + if ( stepIndex >= 0 ) { + this.currentStepIndex = stepIndex; + } + this.render(); } }); 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 47f8443d1a..ab662aa8f9 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,6 +9,18 @@ var edx = edx || {}; edx.verify_student = edx.verify_student || {}; edx.verify_student.PaymentConfirmationStepView = edx.verify_student.StepView.extend({ + + defaultContext: function() { + return { + courseKey: '', + courseName: '', + courseStartDate: '', + coursewareUrl: '', + platformName: '', + requirements: [] + }; + }, + /** * Retrieve receipt information from the shopping cart. * @@ -64,9 +76,7 @@ var edx = edx || {}; /** * The "Verify Later" button goes directly to the dashboard, - * 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. + * The "Verify Now" button sends the user to the verification flow. * For this reason, we don't need any custom click handlers here, except for * those used to track business intelligence events. */ diff --git a/lms/static/js/verify_student/views/progress_view.js b/lms/static/js/verify_student/views/progress_view.js deleted file mode 100644 index 8ebe6bf61a..0000000000 --- a/lms/static/js/verify_student/views/progress_view.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Show progress steps in the payment/verification flow. - */ - - var edx = edx || {}; - - (function( $, _, Backbone, gettext ) { - 'use strict'; - - edx.verify_student = edx.verify_student || {}; - - edx.verify_student.ProgressView = Backbone.View.extend({ - - template: '#progress-tpl', - - initialize: function( obj ) { - this.displaySteps = obj.displaySteps || {}; - this.currentStepIndex = obj.currentStepIndex || 0; - }, - - nextStep: function() { - this.currentStepIndex = Math.min( - this.currentStepIndex + 1, - this.displaySteps.length - 1 - ); - }, - - goToStep: function( stepName ) { - var stepIndex = _.indexOf( - _.pluck( this.displaySteps, 'name' ), - stepName - ); - - if ( stepIndex >= 0 ) { - this.currentStepIndex = stepIndex; - } - }, - - render: function() { - var renderedHtml, context; - - context = { - steps: this.steps() - }; - - renderedHtml = _.template( $(this.template).html(), context ); - $(this.el).html(renderedHtml); - }, - - steps: function() { - var i, - stepDescription, - steps = []; - - for ( i = 0; i < this.displaySteps.length; i++ ) { - stepDescription = { - title: this.displaySteps[i].title, - isCurrent: (i === this.currentStepIndex ), - isComplete: (i < this.currentStepIndex ) - }; - steps.push(stepDescription); - } - - return steps; - } - }); - })( $, _, Backbone, gettext ); diff --git a/lms/static/js/verify_student/views/requirements_view.js b/lms/static/js/verify_student/views/requirements_view.js deleted file mode 100644 index ec0430e1f3..0000000000 --- a/lms/static/js/verify_student/views/requirements_view.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * View for the requirements (webcam, credit card, etc.) - */ -var edx = edx || {}; - -(function( $, Backbone, _, gettext ) { - 'use strict'; - - edx.verify_student = edx.verify_student || {}; - - edx.verify_student.RequirementsView = Backbone.View.extend({ - - template: "#requirements-tpl", - - initialize: function( obj ) { - this.requirements = obj.requirements || {}; - }, - - render: function() { - var renderedHtml = _.template( - $( this.template ).html(), - { requirements: this.requirements } - ); - $( this.el ).html( renderedHtml ); - } - - }); - -})( jQuery, Backbone, _, gettext ); 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 822fc3aec3..5e72c76df5 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 @@ -12,8 +12,8 @@ var edx = edx || {}; defaultContext: function() { return { - platformName: "", - fullName: "", + platformName: '', + fullName: '', }; }, @@ -27,9 +27,6 @@ var edx = edx || {}; $( '.is-expandable' ).addClass('is-ready'); $( '.is-expandable .title-expand' ).on( 'click', this.expandCallback ); - // Disable the submit button until user confirmation - $( '#confirm_pics_good' ).on( 'click', this.toggleSubmitEnabled ); - // Go back to the first photo step if we need to retake photos $( '#retake_photos_button' ).on( 'click', _.bind( this.retakePhotos, this ) ); @@ -40,10 +37,6 @@ var edx = edx || {}; window.analytics.page( 'verification', this.templateName ); }, - toggleSubmitEnabled: function() { - $( '#next_step_button' ).toggleClass( 'is-disabled' ); - }, - retakePhotos: function() { // Track the user's intent to retake their photos window.analytics.track( 'edx.bi.user.images.retaken', { @@ -73,11 +66,10 @@ var edx = edx || {}; }, handleSubmissionError: function( xhr ) { - var isConfirmChecked = $( "#confirm_pics_good" ).prop('checked'), - errorMsg = gettext( 'An unexpected error occurred. Please try again later.' ); + var errorMsg = gettext( 'An unexpected error occurred. Please try again later.' ); // Re-enable the submit button to allow the user to retry - $( '#next_step_button' ).toggleClass( 'is-disabled', !isConfirmChecked ); + $( '#next_step_button' ).removeClass( 'is-disabled' ); if ( xhr.status === 400 ) { errorMsg = xhr.responseText; @@ -91,11 +83,12 @@ var edx = edx || {}; }, expandCallback: function( event ) { + var title; + event.preventDefault(); $(this).next('.expandable-area' ).slideToggle(); - - var title = $( this ).parent(); + title = $( this ).parent(); title.toggleClass( 'is-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 5b3afa31cb..794726a672 100644 --- a/lms/static/js/verify_student/views/step_view.js +++ b/lms/static/js/verify_student/views/step_view.js @@ -43,19 +43,6 @@ return this; }, - handleResponse: function( data ) { - var context = { - nextStepNum: this.nextStepNum, - nextStepTitle: this.nextStepTitle - }; - - // Include step-specific information - _.extend( context, this.stepData ); - - // Track a virtual pageview, for easy funnel reconstruction. - window.analytics.page( 'verification', this.templateName ); - }, - handleError: function( errorTitle, errorMsg ) { this.errorModel.set({ errorTitle: errorTitle || gettext( "Error" ), @@ -66,7 +53,6 @@ templateContext: function() { var context = { - nextStepNum: this.nextStepNum, nextStepTitle: this.nextStepTitle }; return _.extend( context, this.defaultContext(), this.stepData ); diff --git a/lms/static/sass/application-extend2.scss.mako b/lms/static/sass/application-extend2.scss.mako index 83c7664286..b1ff2a6a21 100644 --- a/lms/static/sass/application-extend2.scss.mako +++ b/lms/static/sass/application-extend2.scss.mako @@ -47,6 +47,7 @@ // base - specific views @import 'views/login-register'; @import 'views/verification'; +@import 'views/decoupled-verification'; @import 'views/shoppingcart'; // applications diff --git a/lms/static/sass/views/_decoupled-verification.scss b/lms/static/sass/views/_decoupled-verification.scss new file mode 100644 index 0000000000..47b5f52422 --- /dev/null +++ b/lms/static/sass/views/_decoupled-verification.scss @@ -0,0 +1,157 @@ +// Updates for decoupled verification A/B test +.verification-process { + .pay-and-verify { + .review { + .title.center-col { + padding: 0 calc( ( 100% - 750px ) / 2 ) 10px; + } + } + + .instruction { + &.center-col { + width: 750px; + margin-left: auto; + margin-right: auto; + } + } + + .requirements-container { + + .list-reqs { + width: 645px; + margin: 50px auto; + + .req { + width: 300px; + height: 250px; + min-height: 250px; + margin-right: 45px; + + &:last-of-type { + margin-right: 0; + } + } + + &.account-not-activated { + width: 990px; + + .req { + height: 290px; + min-height: 290px; + } + } + } + } + + .no-content { + margin-bottom: 50px; + } + + .nav-wizard { + &.center { + text-align: center; + } + + .right { + float: right; + padding: 15px 50px; + } + + .nav-link { + line-height: 45px; + } + + .prompt-verify .title { + width: 600px; + position: relative; + display: inline; + float: left; + line-height: 45px; + } + + .wizard-steps { + width: auto; + } + } + + .retake-photos { + color: $blue; + + &:hover { + cursor: pointer; + } + } + + .tip { + .is-expandable { + .title-expand { + color: $blue !important; + } + } + + .expandable-area { + margin-top: 5px; + } + } + + .help-tips { + margin-left: 0 !important; + } + + .wrapper-task { + .msg-retake { + margin-top: 0; + } + + .wrapper-photos { + margin-bottom: 0 !important; + } + } + + .report-course { + .course-actions { + td:last-of-type { + width: 300px; + } + } + } + .enrollment-status-footer { + margin: 50px 0; + + h4 { + font-weight: 600; + } + + .verify-pending-msg { + margin: 20px 0; + } + } + } + + .tooltip { + @include transition(opacity $tmg-f3 ease-out 0s); + @include font-size(12); + position: absolute; + width: 350px; + top: 0; + left: 0; + padding: 10px 20px; + border-radius: 3px; + background: rgba(0, 0, 0, 0.85); + line-height: 26px; + color: $white; + pointer-events: none; + opacity: 0.0; + + &:after { + @include font-size(20); + content: '▾'; + display: block; + position: absolute; + bottom: -14px; + left: 50%; + margin-left: -7px; + color: rgba(0, 0, 0, 0.85); + } + } +} diff --git a/lms/templates/verify_student/enrollment_confirmation_step.underscore b/lms/templates/verify_student/enrollment_confirmation_step.underscore index 7226556271..be9075b097 100644 --- a/lms/templates/verify_student/enrollment_confirmation_step.underscore +++ b/lms/templates/verify_student/enrollment_confirmation_step.underscore @@ -1,15 +1,12 @@
-

<%- gettext( "Congratulations! You are now enrolled in the verified track." ) %>

+

<%- _.sprintf( gettext( "Congratulations! You are now verified on %(platformName)s!" ), { platformName: platformName } ) %>

-

<%- gettext( "You are now enrolled as a verified student! Your enrollment details are below.") %>

+

<%- gettext( "You are now enrolled as an ID verified student for:" ) %>