Commit 8eb484c1 by AlasdairSwan Committed by Will Daly

ECOM-811 design and layout changes

parent 7d8a9779
......@@ -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):
......
......@@ -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)
......
......@@ -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',
......
......@@ -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',
......
......@@ -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() {
......
......@@ -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,
{
......
......@@ -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();
......
......@@ -21,7 +21,8 @@ var edx = edx || {};
return {
courseName: '',
courseStartDate: '',
coursewareUrl: ''
coursewareUrl: '',
platformName: ''
};
}
});
......
......@@ -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' ),
......
......@@ -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' ),
......
......@@ -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 );
}
......
......@@ -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 ) {
$("<input>").attr({
type: "hidden",
$('<input>').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;
},
......
/**
* 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();
}
});
......
......@@ -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.
*/
......
/**
* 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 );
/**
* 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 );
......@@ -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' ) );
}
......
......@@ -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 );
......
......@@ -47,6 +47,7 @@
// base - specific views
@import 'views/login-register';
@import 'views/verification';
@import 'views/decoupled-verification';
@import 'views/shoppingcart';
// applications
......
// 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);
}
}
}
<div class="wrapper-content-main enrollment-confirmation-step">
<article class="content-main">
<h3 class="title"><%- gettext( "Congratulations! You are now enrolled in the verified track." ) %></h3>
<h3 class="title"><%- _.sprintf( gettext( "Congratulations! You are now verified on %(platformName)s!" ), { platformName: platformName } ) %></h3>
<div class="instruction">
<p><%- gettext( "You are now enrolled as a verified student! Your enrollment details are below.") %></p>
<p><%- gettext( "You are now enrolled as an ID verified student for:" ) %></p>
</div>
<ul class="list-info">
<li class="info-item course-info">
<h4 class="title">
<%- gettext( "You are enrolled in " ) %> :
</h4>
<div class="wrapper-report">
<table class="report report-course">
<caption class="sr"><%- gettext( "A list of courses you have just enrolled in as a verified student" ) %></caption>
......@@ -17,7 +14,6 @@
<tr>
<th scope="col" ><%- gettext( "Course" ) %></th>
<th scope="col" ><%- gettext( "Status" ) %></th>
<th scope="col" ><span class="sr"><%- gettext( "Options" ) %></span></th>
</tr>
</thead>
......@@ -27,17 +23,18 @@
<td>
<%- _.sprintf( gettext( "Starts: %(start)s" ), { start: courseStartDate } ) %>
</td>
<td class="options">
<% if ( coursewareUrl ) { %>
<a class="action action-course" href="<%- coursewareUrl %>"><%- gettext( "Go to Course" ) %></a>
<% } %>
</td>
</tr>
</tbody>
<tfoot>
<tr class="course-actions">
<td colspan="3">
<a class="action action-dashboard" href="/dashboard"><%- gettext("Go to your dashboard") %></a>
<td>
<% if ( coursewareUrl ) { %>
<a class="action action-course" href="<%- coursewareUrl %>"><%- gettext( "Explore your course!" ) %></a>
<% } %>
</td>
<td>
<a class="action action-primary" href="/dashboard"><%- gettext("Go to your dashboard") %></a>
</td>
</tr>
</tfoot>
......@@ -46,5 +43,11 @@
</li>
</ul>
<div class="enrollment-status-footer">
<h4 class="title"><%- gettext( "Verified Status" ) %></h4>
<p class="verify-pending-msg">
<%- gettext( "Thank you for submitting your identification photos, we will review them soon. If there is a problem with any of the items, we will contact you to resubmit. You can now enroll in any of the verified certificate courses for one year without having to re-verify." ) %></p>
</div>
</article>
</div>
......@@ -16,21 +16,27 @@
<ul class="list-help">
<li class="help-item"><%- gettext( "Make sure your face is well-lit" ) %></li>
<li class="help-item"><%- gettext( "Be sure your entire face is inside the frame" ) %></li>
<li class="help-item">
<%= _.sprintf( gettext( "Once in position, use the camera button %(icon)s to capture your face" ), { icon: '<span class="example">(<i class="icon-camera"></i>)</span>' } ) %>
</li>
<li class="help-item"><%- gettext( "Can we match the photo you took with the one on your ID?" ) %></li>
<li class="help-item"><%- gettext( "Once in position, use the camera button" ) %> <span class="example">(<i class="icon-camera"></i>)</span> <%- gettext( "to capture your picture" ) %></li>
<li class="help-item"><%- gettext( "Use the retake photo button if you are not pleased with your photo" ) %></li>
</ul>
</div>
</div>
<div class="help help-faq facefaq">
<h4 class="sr title"><%- gettext( "Common Questions" ) %></h4>
<div class="copy">
<dl class="list-faq">
<dt class="faq-question"><%- gettext( "Why do you need my photo?" ) %></dt>
<dd class="faq-answer"><%- gettext( "As part of the verification process, we need your photo to confirm that you are you." ) %></dd>
<dt class="faq-question"><%- gettext( "What do you do with this picture?" ) %></dt>
<dd class="faq-answer"><%- gettext( "We only use it to verify your identity. It is not displayed anywhere." ) %></dd>
<dt class="faq-question">
<%- _.sprintf( gettext( "Why does %(platformName)s need my photo?" ), { platformName: platformName } ) %>
</dt>
<dd class="faq-answer"><%- gettext( "As part of the verification process, we need your photo to confirm your identity." ) %></dd>
<dt class="faq-question">
<%- _.sprintf( gettext( "What does %(platformName)s do with this picture?" ), { platformName: platformName } ) %>
</dt>
<dd class="faq-answer"><%- gettext( "We encrypt it and send it to our secure authorization service for review. We use the highest levels of security and do not save the photo or information anywhere once the match has been completed." ) %></dd>
</dl>
</div>
</div>
......@@ -39,18 +45,11 @@
<% if ( nextStepTitle ) { %>
<nav class="nav-wizard" id="face_next_button_nav">
<span class="help help-inline">
<%- _.sprintf( gettext( "Once you verify your photo looks good, you can move on to step %s." ), nextStepNum ) %>
</span>
<ol class="wizard-steps">
<li class="wizard-step">
<a id="next_step_button" class="next action-primary is-disabled" aria-hidden="true" title="Next">
<%- _.sprintf( gettext( "Go to Step %s" ), nextStepNum ) %>: <%- nextStepTitle %>
</a>
</li>
</ol>
<a id="next_step_button" class="next action-primary is-disabled right" aria-hidden="true" title="Next">
<%- nextStepTitle %>
</a>
</nav>
<% } %>
</div>
......
<div id="wrapper-idphoto" class="wrapper-view block-photo id-photo-step">
<div class="idphoto view">
<h3 class="title"><%- gettext( "Show Us Your ID" ) %></h3>
<h3 class="title"><%- gettext( "Take a Photo of Your ID" ) %></h3>
<div class="instruction">
<p><%- gettext("Use your webcam to take a picture of your ID so we can match it with your photo and the name on your account.") %></p>
</div>
......@@ -9,7 +9,7 @@
<div id="idcam" class="task cam"></div>
<div class="wrapper-help">
<div class="help help-task photo-tips idtips">
<div class="help help-task photo-tips idtips">
<h4 class="title"><%- gettext( "Tips on taking a successful photo" ) %></h4>
<div class="copy">
......@@ -18,8 +18,10 @@
<li class="help-item"><%- gettext( "Check that there isn't any glare" ) %></li>
<li class="help-item"><%- gettext( "Ensure that you can see your photo and read your name" ) %></li>
<li class="help-item"><%- gettext( "Try to keep your fingers at the edge to avoid covering important information" ) %></li>
<li class="help-item"><%- gettext( "Acceptable IDs include drivers licenses, passports, or other goverment-issued IDs that include your name and photo" ) %></li>
<li class="help-item"><%- gettext( "Once in position, use the camera button ") %> <span class="example">(<i class="icon-camera"></i>)</span> <%- gettext( "to capture your ID" ) %></li>
<li class="help-item"><%- gettext( "Acceptable IDs include driver's licenses, passports, or other government-issued IDs that include your name and photo" ) %></li>
<li class="help-item">
<%= _.sprintf( gettext( "Once in position, use the camera button %(icon)s to capture your ID" ), { icon: '<span class="example">(<i class="icon-camera"></i>)</span>' } ) %>
</li>
</ul>
</div>
</div>
......@@ -42,17 +44,9 @@
<% if ( nextStepTitle ) { %>
<nav class="nav-wizard" id="face_next_button_nav">
<span class="help help-inline">
<%- _.sprintf( gettext( "Once you verify your photo looks good, you can move on to step %s." ), nextStepNum ) %>
</span>
<ol class="wizard-steps">
<li class="wizard-step">
<a id="next_step_button" class="next action-primary is-disabled" aria-hidden="true" title="Next">
<%- _.sprintf( gettext( "Go to Step %s" ), nextStepNum ) %>: <%- nextStepTitle %>
</a>
</li>
</ol>
<a id="next_step_button" class="next action-primary is-disabled right" aria-hidden="true" title="Next">
<%- nextStepTitle %>
</a>
</nav>
<% } %>
</div>
......
<div class="wrapper-content-main intro-step">
<article class="content-main">
<h3 class="title"><%- introTitle %></h3>
<div class="instruction"><p><%- introMsg %></p></div>
<% if ( introMsg ) { %>
<div class="instruction"><p><%- introMsg %></p></div>
<% } %>
<div class="requirements-container">
<ul class="list-reqs <% if ( requirements['account-activation-required'] ) { %>account-not-activated<% } %>">
<% if ( requirements['account-activation-required'] ) { %>
<li class="req req-0 req-activate">
<h4 class="title"><%- gettext( "Activate Your Account" ) %></h4>
<div class="placeholder-art">
<i class="icon-envelope-alt"></i>
</div>
<div class="copy">
<p>
<span class="copy-super"><%- gettext( "Check your email" ) %></span>
<span class="copy-sub"><%-
gettext( "You need to activate your account before you can register for courses. Check your inbox for an activation email." )
%>
</span>
</p>
</div>
</li>
<% } %>
<% if ( requirements['photo-id-required'] ) { %>
<li class="req req-1 req-id">
<h4 class="title"><%- gettext( "Photo ID" ) %></h4>
<div class="placeholder-art">
<i class="icon-list-alt icon-under"></i>
<i class="icon-user icon-over"></i>
</div>
<div class="requirements-container"></div>
<div class="copy">
<p>
<span class="copy-sub"><%- gettext( "A driver's license, passport, or government-issued ID with your name and picture" ) %></span>
</p>
</div>
</li>
<% } %>
<% if ( requirements['webcam-required'] ) { %>
<li class="req req-2 req-webcam">
<h4 class="title"><%- gettext( "Webcam" ) %></h4>
<div class="placeholder-art">
<i class="icon-facetime-video"></i>
</div>
<div class="copy"></div>
</li>
<% } %>
</ul>
</div>
<% if ( nextStepTitle ) { %>
<nav class="nav-wizard is-ready">
......@@ -13,7 +63,7 @@
<% if ( !isActive ) { %>
<%- gettext( "Activate Your Account" ) %>
<% } else { %>
<%- _.sprintf( gettext( "Go to Step %(stepNumber)s" ), { stepNumber: nextStepNum } ) %>: <%- nextStepTitle %>
<%- nextStepTitle %>
<% } %>
</a>
</li>
......
<div id="wrapper-review" class="wrapper-view make-payment-step">
<div class="review view">
<h3 class="title"><%- gettext( "Make Payment" ) %></h3>
<div class="instruction">
<p><%- gettext( "Make payment. TODO: actual copy here." ) %></p>
</div>
<div class="requirements-container"></div>
<h3 class="title <% if ( !upgrade ) { %>center-col<% } %>">
<%- gettext( "You are enrolling in: " ) %>
<span class="course-title"><%= courseName %></span>
</h3>
<% if ( isActive ) { %>
<div class="wrapper-task">
<div class="wrapper-task hidden" aria-hidden="true">
<ol class="review-tasks">
<% if ( suggestedPrices.length > 0 ) { %>
<li class="review-task review-task-contribution">
......@@ -60,7 +58,7 @@
<li class="review-task review-task-contribution">
<h4 class="title"><%- gettext( "Your Course Total" ) %></h4>
<div class="copy">
<p><%- gettext( "To complete your registration, you will need to pay:" ) %></p>
<p><%- gettext( "To complete your enrollment, you will need to pay:" ) %></p>
</div>
<ul class="list-fields contribution-options">
<li class="field contribution-option">
......@@ -74,12 +72,71 @@
</ol>
</div>
</div>
<% } %>
<% } %>
<div class="instruction <% if ( !upgrade ) { %>center-col<% } %>">
<% if ( _.some( requirements, function( isVisible ) { return isVisible; } ) ) { %>
<p>
<% if ( verificationDeadline ) { %>
<%- _.sprintf(
gettext( "You can pay now even if you don't have the following items available, but you will need to have these by %(date)s to qualify to earn a Verified Certificate." ),
{ date: verificationDeadline }
) %>
<% } else { %>
<%- gettext( "You can pay now even if you don't have the following items available, but you will need to have these to qualify to earn a Verified Certificate." ) %>
<% } %>
</p>
<% } %>
</div>
<div class="requirements-container">
<ul class="list-reqs <% if ( requirements['account-activation-required'] ) { %>account-not-activated<% } %>">
<% if ( requirements['account-activation-required'] ) { %>
<li class="req req-0 req-activate">
<h4 class="title"><%- gettext( "Activate Your Account" ) %></h4>
<div class="placeholder-art">
<i class="icon-envelope-alt"></i>
</div>
<div class="copy">
<p>
<span class="copy-super"><%- gettext( "Check your email" ) %></span>
<span class="copy-sub"><%-
gettext( "You need to activate your account before you can enroll in courses. Check your inbox for an activation email." )
%>
</span>
</p>
</div>
</li>
<% } %>
<% if ( requirements['photo-id-required'] ) { %>
<li class="req req-1 req-id">
<h4 class="title"><%- gettext( "Government-Issued Photo ID" ) %></h4>
<div class="placeholder-art">
<i class="icon-list-alt icon-under"></i>
<i class="icon-user icon-over"></i>
</div>
<div class="copy"></div>
</li>
<% } %>
<% if ( requirements['webcam-required'] ) { %>
<li class="req req-2 req-webcam">
<h4 class="title"><%- gettext( "Webcam" ) %></h4>
<div class="placeholder-art">
<i class="icon-facetime-video"></i>
</div>
<div class="copy"></div>
</li>
<% } %>
</ul>
</div>
<nav class="nav-wizard is-ready">
<ol class="wizard-steps">
<li class="wizard-step">
<% if ( isActive ) { %>
<nav class="nav-wizard is-ready center">
<% if ( isActive ) { %>
<a class="next action-primary is-disabled" id="pay_button">
<%- gettext( "Go to payment" ) %>
</a>
......@@ -88,10 +145,7 @@
<%- gettext( "Activate Your Account" ) %>
</a>
<% } %>
</li>
</ol>
</nav>
<form id="payment-processor-form"></form>
</div>
......@@ -11,7 +11,7 @@ from verify_student.views import PayAndVerifyView
<%block name="header_extras">
<%
template_names = (
["progress", "requirements", "webcam_photo", "error"] +
["webcam_photo", "error"] +
[step['templateName'] for step in display_steps]
)
%>
......@@ -26,6 +26,7 @@ from verify_student.views import PayAndVerifyView
<script src="${static.url('js/vendor/underscore-min.js')}"></script>
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
<script src="${static.url('js/vendor/backbone-min.js')}"></script>
<script src="${static.url('js/src/tooltip_manager.js')}"></script>
<%static:js group='verify_student'/>
</%block>
......@@ -36,24 +37,12 @@ from verify_student.views import PayAndVerifyView
<div class="container">
<section class="wrapper carousel">
## Verification status header
<header class="page-header">
<h2 class="title">
<span class="wrapper-sts">
<span class="sts-label">${messages.top_level_msg}</span>
</span>
<span class="sts-track ${"professional-ed" if course_mode.slug == "professional" else ""}">
<span class="sts-track-value"><span class="context">${messages.status_msg}</span>: ${course_mode.name}<span>
</span>
</h2>
</header>
## Payment / Verification flow
## Most of these data attributes are used to dynamically render
## the steps, but some are just useful for A/B test setup.
<div
id="pay-and-verify-container"
class="pay-and-verify"
data-full-name='${user_full_name}'
data-platform-name='${platform_name}'
data-course-key='${course_key}'
......@@ -67,6 +56,7 @@ from verify_student.views import PayAndVerifyView
data-course-mode-currency='${course_mode.currency}'
data-contribution-amount='${contribution_amount}'
data-purchase-endpoint='${purchase_endpoint}'
data-verification-deadline='${verification_deadline}'
data-display-steps='${json.dumps(display_steps)}'
data-current-step='${current_step}'
data-requirements='${json.dumps(requirements)}'
......
<div class="wrapper-content-main payment-confirmation-step">
<article class="content-main">
<h3 class="title"><%- gettext( "Congratulations! You are now enrolled in the verified track." ) %></h3>
<div class="instruction">
<p><%- gettext( "You are now enrolled as a verified student! Your enrollment details are below.") %></p>
</div>
<h3 class="title">
<%- _.sprintf( gettext( "Thank you! We have received your payment for %(courseName)s" ), { courseName: courseName } ) %>
</h3>
<% if ( receipt ) { %>
<ul class="list-info">
<li class="info-item payment-info">
<h4 class="title"><%- gettext( "Payment Details" ) %></h4>
<div class="copy">
<p><%- gettext( "Please print this page for your records; it serves as your receipt. You will also receive an email with the same information." ) %></p>
</div>
......@@ -77,23 +74,73 @@
</li>
</ul>
<% } else { %>
<p><%- gettext( "No receipt available." ) %></p>
<p class="no-content"><%- gettext( "No receipt available." ) %></p>
<% } %>
<% if ( nextStepTitle ) { %>
<nav class="nav-wizard is-ready">
<ol class="wizard-steps">
<li class="wizard-step">
<a class="next action-primary" id="verify_now_button" href="?skip-first-step=1">
<%- gettext( "Verify Now" ) %>
</a>
<h3 class="title"><%- gettext( "Next Step: Confirm Your Identity" ) %></h3>
<div class="requirements-container">
<ul class="list-reqs <% if ( requirements['account-activation-required'] ) { %>account-not-activated<% } %>">
<% if ( requirements['account-activation-required'] ) { %>
<li class="req req-0 req-activate">
<h4 class="title"><%- gettext( "Activate Your Account" ) %></h4>
<div class="placeholder-art">
<i class="icon-envelope-alt"></i>
</div>
<div class="copy">
<p>
<span class="copy-super"><%- gettext( "Check your email." ) %></span>
<span class="copy-sub"><%-
gettext( "You need to activate your account before you can enroll in courses. Check your inbox for an activation email." )
%>
</span>
</p>
</div>
</li>
<li class="wizard-step">
<a class="next action-secondary" id="verify_later_button" href="/dashboard">
<%- gettext( "Verify Later" ) %>
</a>
<% } %>
<% if ( requirements['photo-id-required'] ) { %>
<li class="req req-1 req-id">
<h4 class="title"><%- gettext( "Photo ID" ) %></h4>
<div class="placeholder-art">
<i class="icon-list-alt icon-under"></i>
<i class="icon-user icon-over"></i>
</div>
<div class="copy">
<p>
<span class="copy-sub"><%- gettext( "A driver's license, passport, or government-issued ID with your name and picture." ) %></span>
</p>
</div>
</li>
<% } %>
<% if ( requirements['webcam-required'] ) { %>
<li class="req req-2 req-webcam">
<h4 class="title"><%- gettext( "Webcam" ) %></h4>
<div class="placeholder-art">
<i class="icon-facetime-video"></i>
</div>
<div class="copy"></div>
</li>
</ol>
<% } %>
</ul>
</div>
<nav class="nav-wizard is-ready">
<a id="verify_now_button"
class="next action-primary right"
href="<%- _.sprintf( '/verify_student/verify-now/%(courseKey)s', { courseKey: courseKey } ) %>"
>
<%- nextStepTitle %>
</a>
<a id="verify_later_button" class="next action-secondary verify-later nav-link" href="/dashboard" data-tooltip="<%- _.sprintf( gettext( "If you don't confirm your identity now, you can go to the dashboard to explore your course and %(platformName)s will remind you later." ), { platformName: platformName } ) %>">
<%- gettext( "Want to confirm your identity later?" ) %>
</a>
</nav>
<% } %>
</article>
......
<div class="wrapper-progress progress">
<section class="progress">
<h3 class="sr title"><%- gettext("Your Progress") %></h3>
<ol class="progress-steps">
<% for ( var stepNum = 0; stepNum < steps.length; stepNum++ ) { %>
<li
class="progress-step
<% if ( steps[stepNum].isCurrent ) { %> is-current <% } %>
<% if ( steps[stepNum].isComplete ) { %> is-completed <% } %>"
id="progress-step-<%- stepNum + 1 %>"
>
<span class="wrapper-step-number"><span class="step-number"><%- stepNum + 1 %></span></span>
<span class="step-name"><span class="sr"><%- gettext("Current Step") %>: </span><%- steps[stepNum].title %></span>
</li>
<% } %>
<span class="progress-sts">
<span class="progress-sts-value"></span>
</span>
</section>
</div>
<ul class="list-reqs <% if ( requirements['account-activation-required'] ) { %>account-not-activated<% } %>">
<% if ( requirements['account-activation-required'] ) { %>
<li class="req req-0 req-activate">
<h4 class="title"><%- gettext( "Activate Your Account" ) %></h4>
<div class="placeholder-art">
<i class="icon-envelope-alt"></i>
</div>
<div class="copy">
<p>
<span class="copy-super"><%- gettext( "Check your email." ) %></span>
<span class="copy-sub"><%-
gettext( "You need to activate your account before you can register for courses. Check your inbox for an activation email." )
%>
</span>
</p>
</div>
</li>
<% } %>
<% if ( requirements['photo-id-required'] ) { %>
<li class="req req-1 req-id">
<h4 class="title"><%- gettext( "Identification" ) %></h4>
<div class="placeholder-art">
<i class="icon-list-alt icon-under"></i>
<i class="icon-user icon-over"></i>
</div>
<div class="copy">
<p>
<span class="copy-super"><%- gettext( "A photo identification document" ) %></span>
<span class="copy-sub"><%- gettext( "A driver's license, passport, or other government or school-issued ID with your name and picture on it." ) %></span>
</p>
</div>
</li>
<% } %>
<% if ( requirements['webcam-required'] ) { %>
<li class="req req-2 req-webcam">
<h4 class="title"><%- gettext( "Webcam" ) %></h4>
<div class="placeholder-art">
<i class="icon-facetime-video"></i>
</div>
<div class="copy">
<p>
<span class="copy-super"><%- gettext( "A webcam and a modern browser" ) %></span>
<span class="copy-sub"><strong>
<a rel="external" href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a>,
<a rel="external" href="https://www.google.com/intl/en/chrome/browser/">Chrome</a>,
<a rel="external" href="http://www.apple.com/safari/">Safari</a>,
<a rel="external" href="http://windows.microsoft.com/en-us/internet-explorer/download-ie"><%- gettext("Internet Explorer 9 or later" ) %></a></strong>.
<%- gettext( "Please make sure your browser is updated to the most recent version possible." ) %>
</span>
</p>
</div>
</li>
<% } %>
<% if ( requirements['credit-card-required'] ) { %>
<li class="req req-3 req-payment">
<h4 class="title"><%- gettext( "Credit or Debit Card" ) %></h4>
<div class="placeholder-art">
<i class="icon-credit-card"></i>
</div>
<div class="copy">
<p>
<span class="copy-super"><%- gettext( "A major credit or debit card" ) %></span>
<span class="copy-sub"><%- gettext( "Visa, MasterCard, American Express, Discover, Diners Club, or JCB with the Discover logo." ) %></span>
</p>
</div>
</li>
<% } %>
</ul>
<div id="wrapper-review" class="wrapper-view review-photos-step">
<div class="review view">
<h3 class="title"><%- gettext( "Verify Your Submission" ) %></h3>
<h3 class="title"><%- gettext( "Review Your Photos" ) %></h3>
<div class="instruction">
<p><%- gettext( "Make sure we can verify your identity with the photos and information below." ) %></p>
<p><%- gettext( "Make sure we can verify your identity from the photos below." ) %></p>
</div>
<div class="wrapper-task">
<ol class="review-tasks">
<li class="review-task review-task-photos">
<h4 class="title"><%- gettext( "Review the Photos You've Taken" ) %></h4>
<div class="copy">
<p><%- gettext( "Please review the photos and verify that they meet the requirements listed below." ) %></p>
<div class="review-task review-task-photos">
<div class="wrapper-photos">
<div class="wrapper-photo">
<div class="placeholder-photo">
<img id="face_image" src=""/>
</div>
</div>
<ol class="wrapper-photos">
<li class="wrapper-photo">
<div class="placeholder-photo">
<img id="face_image" src=""/>
</div>
<div class="help-tips">
<h5 class="title"><%- gettext( "The photo above needs to meet the following requirements:" ) %></h5>
<ul class="list-help list-tips copy">
<li class="tip"><%- gettext( "Be well lit" ) %></li>
<li class="tip"><%- gettext( "Show your whole face" ) %></li>
<li class="tip"><%- gettext( "The photo on your ID must match the photo of your face" ) %></li>
</ul>
</div>
</li>
<li class="wrapper-photo">
<div class="placeholder-photo">
<img id="photo_id_image" src=""/>
</div>
<div class="help-tips">
<h5 class="title"><%- gettext( "The photo above needs to meet the following requirements:" ) %></h5>
<ul class="list-help list-tips copy">
<li class="tip"><%- gettext( "Be readable (not too far away, no glare)" ) %></li>
<li class="tip"><%- gettext( "The photo on your ID must match the photo of your face" ) %></li>
<li class="tip"><%- gettext( "The name on your ID must match the name on your account below" ) %></li>
</ul>
</div>
</li>
</ol>
<div class="msg msg-retake msg-followup">
<div class="copy">
<p><%- gettext( "Photos don't meet the requirements?" ) %></p>
<div class="wrapper-photo">
<div class="placeholder-photo">
<img id="photo_id_image" src=""/>
</div>
<ul class="list-actions">
<li class="action action-retakephotos">
<a id="retake_photos_button" class="retake-photos">
<%- gettext( "Retake Your Photos" ) %>
</a>
</div>
</div>
<div class="wrapper-photos">
<div class="help-tips">
<h5 class="title"><%- gettext( "Photo requirements:" ) %></h5>
<ul class="list-help list-tips copy">
<li class="tip"><%- gettext( "Does the photo of you show your whole face?" ) %></li>
<li class="tip"><%- gettext( "Does the photo of you match your ID photo?" ) %></li>
<li class="tip"><%- gettext( "Is your name on your ID readable?" ) %></li>
<li class="tip"><%- _.sprintf( gettext( "Does the name on your ID match your account name: %(fullName)s?" ), { fullName: fullName } ) %>
<div class="help-tip is-expandable">
<a href="#" class="title title-expand" aria-expanded="false" role="link">
<%- gettext( "Edit Your Name" ) %>
</a>
<div class="copy expandable-area">
<p><%- gettext( "You should change the name on your account to match your ID." ) %></p>
<input type="text" name="new-name" id="new-name" placeholder=<%= fullName %>>
</div>
</div>
</li>
</ul>
</div>
</li>
<li class="review-task review-task-name">
<h4 class="title"><%- gettext( "Check Your Name" ) %></h4>
</div>
<div class="msg msg-retake msg-followup">
<div class="copy">
<p><%- _.sprintf( gettext( "Make sure the full name on your %(platformName)s account (%(fullName)s) matches your ID. We will use this as the name on your certificate." ), { platformName: platformName, fullName: fullName } ) %></p>
</div>
<div class="msg msg-followup">
<div class="help-tip is-expandable">
<h5 class="title title-expand" aria-expanded="false" role="link">
<i class="icon-caret-down expandable-icon"></i>
<%- gettext( "What if the name on my account doesn't match the name on my ID?" ) %>
</h5>
<div class="copy expandable-area">
<p><%- gettext( "You should change the name on your account to match." ) %></p>
<input type="text" name="new-name" id="new-name" placeholder=<%= fullName %>>
</div>
</div>
<p>
<%- gettext( "Photos don't meet the requirements?" ) %>
<a id="retake_photos_button" class="retake-photos">
<%- gettext( "Retake Your Photos" ) %>
</a>
</p>
</div>
</div>
</ol>
</div>
</div>
<nav class="nav-wizard">
<div class="prompt-verify">
<h3 class="title"><%- gettext( "Before proceeding, please confirm that your details match" ) %></h3>
<p class="copy">
<%- _.sprintf( gettext( "Once you verify your details match the requirements, you can move on to step %(stepNum)s, %(stepTitle)s." ), { stepNum: nextStepNum, stepTitle: nextStepTitle } ) %>
</p>
<ul class="list-actions">
<li class="action action-verify">
<input type="checkbox" name="match" id="confirm_pics_good" />
<label for="confirm_pics_good"><%- gettext( "Yes! My details all match." ) %></label>
</li>
</ul>
<h3 class="title"><%- gettext( "Before proceeding, please confirm that your photos match." ) %></h3>
</div>
<ol class="wizard-steps">
<li class="wizard-step step-proceed">
<a id="next_step_button" class="next action-primary is-disabled" aria-hidden="true" title="Next">
<%- _.sprintf( gettext( "Go to Step %s" ), nextStepNum ) %>: <%- nextStepTitle %>
<a id="next_step_button" class="next action-primary right" aria-hidden="true" title="Confirmation">
<%- gettext( "Confirmation" ) %>
</a>
</li>
</ol>
......
......@@ -10,11 +10,8 @@
<div class="controls photo-controls">
<ul class="list-controls">
<li class="control control-retake is-hidden" id="webcam_reset_button">
<a class="action action-redo">
<i class="icon-undo"></i> <span class="sr"><%- gettext( "Retake" ) %></span>
</a>
<a class="action action-redo"><%- gettext( "Retake Photo" ) %></a>
</li>
<li class="control control-do is-hidden" id="webcam_capture_button">
<a class="action action-do">
<i class="icon-camera"></i> <span class="sr"><%- gettext( "Take photo" ) %></span>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment