Commit 56ba7850 by alasdairswan Committed by AlasdairSwan

Integrated JS with Peter's Django wrapper

Rendering form. Updated form field template to accept instructions for all input types
Added setExtraData function to FormView to allow non-form attributes to be added to the model before saving
parent e9a32340
......@@ -522,15 +522,15 @@ class ViewsTestCase(ModuleStoreTestCase):
effort = "I'm done, okay? You just give me my money, and you and I, we're done."
data = {
'username': username,
'course_id': course,
'legal_name': legal_name,
'course': course,
'name': legal_name,
'email': self.user.email,
'country': country,
'income': income,
'reason_for_applying': reason_for_applying,
'goals': goals,
'effort': effort,
'marketing_permission': False,
'mktg-permission': False,
}
response = self._submit_financial_assistance_form(data)
self.assertEqual(response.status_code, 204)
......@@ -560,15 +560,15 @@ class ViewsTestCase(ModuleStoreTestCase):
def test_zendesk_submission_failed(self, _mock_record_feedback):
response = self._submit_financial_assistance_form({
'username': self.user.username,
'course_id': '',
'legal_name': '',
'course': '',
'name': '',
'email': '',
'country': '',
'income': '',
'reason_for_applying': '',
'goals': '',
'effort': '',
'marketing_permission': False,
'mktg-permission': False,
})
self.assertEqual(response.status_code, 500)
......
......@@ -1460,15 +1460,15 @@ def financial_assistance_request(request):
if request.user.username != username:
return HttpResponseForbidden()
course_id = data['course_id']
legal_name = data['legal_name']
course_id = data['course']
legal_name = data['name']
email = data['email']
country = data['country']
income = data['income']
reason_for_applying = data['reason_for_applying']
goals = data['goals']
effort = data['effort']
marketing_permission = data['marketing_permission']
marketing_permission = data['mktg-permission']
ip_address = get_ip(request)
except ValueError:
# Thrown if JSON parsing fails
......
;(function (define) {
'use strict';
define([
'js/financial-assistance/views/financial_assistance_form_view'
],
function (FinancialAssistanceFormView) {
return function (options) {
var formView = new FinancialAssistanceFormView({
el: '.financial-assistance-wrapper',
context: options
});
return formView;
};
});
}).call(this, define || RequireJS.define);
/**
* Model for Financial Assistance.
*/
(function (define) {
'use strict';
define(['backbone'], function (Backbone) {
var FinancialAssistance = Backbone.Model.extend({
initialize: function(options) {
this.url = options.url;
}
});
return FinancialAssistance;
});
}).call(this, define || RequireJS.define);
<h1><%- gettext('Financial Assistance Application') %></h1>
<div class="intro">
<% _.each(header_text, function(copy) { %>
<p class="copy"><%- copy %></p>
<% }); %>
</div>
<form class="financial-assistance-form">
<div class="status submission-error hidden" aria-live="polite">
<h4 class="message-title"><%- gettext('Application not submitted') %></h4>
<ul class="message-copy"></ul>
</div>
<div class="user-info">
<h2><%- gettext('About You') %></h2>
<p><%- interpolate_text(
gettext('The following information is already a part of your {platform} profile. We\'ve included it here for your application.'),
{platform: platform_name}
) %></p>
<div class="info-column">
<div class="title"><%- gettext('Username') %></div>
<div class="data"><%- username %></div>
</div>
<div class="info-column">
<div class="title"><%- gettext('Email address') %></div>
<div class="data"><%- email %></div>
</div>
<div class="info-column">
<div class="title"><%- gettext('Legal name') %></div>
<div class="data"><%- name %></div>
</div>
<div class="info-column">
<div class="title"><%- gettext('Country of residence') %></div>
<div class="data"><%- country %></div>
</div>
</div>
<%= fields %>
<div class="cta-wrapper clearfix">
<a href="<%- student_faq_url %>" class="nav-link"><%- interpolate_text(
gettext('Back to {platform} FAQs'),
{platform: platform_name}
) %></a>
<button type="submit" class="action action-primary action-update js-submit-form submit-form"><%- gettext("Submit Application") %></button>
</div>
</form>
<h1><%- gettext('Financial Assistance Application') %></h1>
<p class="js-success-message success-message" tabindex="-1"><%- interpolate_text(
gettext('Thank you for submitting your financial assistance application for {course_name}! You can expect a response in 2-4 business days.'), {course_name: course}
) %>
</p>
<div class="cta-wrapper clearfix">
<a href="<%- dashboard_url %>" class="btn btn-blue btn-dashboard"><%- gettext('Go to Dashboard') %></a>
</div>
;(function (define) {
'use strict';
define(['backbone',
'jquery',
'underscore',
'gettext',
'js/financial-assistance/models/financial_assistance_model',
'text!js/financial-assistance/templates/financial_assessment_form.underscore',
'text!js/financial-assistance/templates/financial_assessment_submitted.underscore',
'js/student_account/views/FormView',
'text!templates/student_account/form_field.underscore'
],
function(Backbone, $, _, gettext, FinancialAssistanceModel, formViewTpl, successTpl, FormView, formFieldTpl) {
return FormView.extend({
el: '.financial-assistance-wrapper',
events: {
'click .js-submit-form': 'submitForm'
},
tpl: formViewTpl,
fieldTpl: formFieldTpl,
formType: 'financial-assistance',
requiredStr: '',
submitButton: '.js-submit-form',
initialize: function(data) {
var context = data.context,
fields = context.fields;
// Add default option to array
if ( fields[0].options.length > 1 ) {
fields[0].options.unshift({
name: '- ' + gettext('Choose one') + ' -',
value: '',
default: true
});
}
// Set non-form data needed to render the View
this.context = {
dashboard_url: context.dashboard_url,
header_text: context.header_text,
platform_name: context.platform_name,
student_faq_url: context.student_faq_url
};
// Make the value accessible to this View
this.user_details = context.user_details;
// Initialize the model and set user details
this.model = new FinancialAssistanceModel({
url: context.submit_url
});
this.model.set( context.user_details );
this.listenTo( this.model, 'error', this.saveError );
this.model.on('sync', this.renderSuccess, this);
// Build the form
this.buildForm( fields );
},
render: function(html) {
var data = _.extend( this.model.toJSON(), this.context, {
fields: html || '',
});
this.$el.html(_.template(this.tpl, data));
this.postRender();
return this;
},
renderSuccess: function() {
this.$el.html(_.template(successTpl, {
course: this.model.get('course'),
dashboard_url: this.context.dashboard_url
}));
$('.js-success-message').focus();
},
saveError: function(error) {
/*jslint maxlen: 500 */
var txt = [
'An error has occurred. Wait a few minutes and then try to submit the application again.',
'If you continue to have issues please contact support.'
],
msg = gettext(txt.join(' '));
if (error.status === 0) {
msg = gettext('An error has occurred. Check your Internet connection and try again.');
}
this.errors = ['<li>' + msg + '</li>'];
this.setErrors();
this.element.hide( this.$resetSuccess );
this.toggleDisableButton(false);
},
setExtraData: function(data) {
return _.extend(data, this.user_details);
}
});
}
);
}).call(this, define || RequireJS.define);
define([
'backbone',
'jquery',
'js/financial-assistance/views/financial_assistance_form_view'
], function (Backbone, $, FinancialAssistanceFormView) {
'use strict';
describe('Financial Assistance View', function () {
var view = null,
context = {
fields: [{
defaultValue: '',
form: 'financial-assistance',
instructions: 'select a course',
label: 'Course',
name: 'course',
options: [
{'name': 'Verified with Audit', 'value': 'course-v1:HCFA+VA101+2015'},
{'name': 'Something Else', 'value': 'course-v1:SomethingX+SE101+215'},
{'name': 'Test Course', 'value': 'course-v1:TestX+T101+2015'}
],
placeholder: '',
required: true,
requiredStr: '',
type: 'select'
}],
user_details: {
country: 'UK',
email: 'xsy@edx.org',
name: 'xsy',
username: 'xsy4ever'
},
header_text: ['Line one.', 'Line two.'],
student_faq_url: '/faqs',
dashboard_url: '/dashboard',
platform_name: 'edx',
submit_url: '/api/financial/v1/assistance'
};
beforeEach(function() {
setFixtures('<div class="financial-assistance-wrapper"></div>');
view = new FinancialAssistanceFormView({
el: '.financial-assistance-wrapper',
context: context
});
});
afterEach(function() {
view.undelegateEvents();
view.remove();
});
it('should exist', function() {
expect(view).toBeDefined();
});
});
}
);
......@@ -213,6 +213,13 @@
this.focusFirstError();
},
/* Allows extended views to add non-form attributes
* to the data before saving it to model
*/
setExtraData: function( data ) {
return data;
},
submitForm: function( event ) {
var data = this.getFormData();
......@@ -223,6 +230,7 @@
this.toggleDisableButton(true);
if ( !_.compact(this.errors).length ) {
data = this.setExtraData( data );
this.model.set( data );
this.model.save();
this.toggleErrorMsg( false );
......
%fa-copy {
@extend %t-copy-base;
padding: ($baseline/2) 0;
margin: 0;
color: $m-gray-d2;
};
.financial-assistance-wrapper {
margin: auto;
padding: $baseline 0;
padding: $baseline ($baseline/2);
max-width: 1180px;
.financial-assistance {
h1 {
@extend %t-title4;
@include text-align(left);
margin: 0;
padding: ($baseline/2) 0;
border-bottom: 4px solid $gray-l5;
color: $m-gray-d3;
}
h1 {
@extend %t-title4;
@include text-align(left);
margin: 0;
padding: ($baseline/2) 0;
border-bottom: 4px solid $gray-l5;
color: $m-gray-d3;
}
h2 {
@extend %t-title6;
@extend %t-strong;
margin-top: ($baseline/2);
text-transform: none;
}
h2 {
@extend %t-title6;
@extend %t-strong;
margin-top: ($baseline/2);
text-transform: none;
}
p {
@extend %fa-copy;
font-size: 0.875em;
}
p {
@extend %t-copy-base;
padding: ($baseline/2) 0;
margin: 0;
color: $m-gray-d2;
}
.financial-assistance {
padding-bottom: ($baseline/2);
border-bottom: 4px solid $gray-l5;
.apply-form-list {
padding: 0;
......@@ -73,4 +79,165 @@
border-radius: 2px;
}
}
// Application form View
.intro {
border-bottom: 4px solid $gray-l5;
p {
margin: 10px 0;
}
}
.success-message {
p {
margin: 10px 0;
}
}
.btn-dashboard {
@include float(right);
color: $white;
&:hover,
&:active,
&:focus {
color: $white;
}
}
.user-info {
@include clearfix();
border-bottom: 2px solid $gray-l5;
padding: 20px 0;
margin-bottom: 20px;
.info-column {
@include float(left);
width: 100%;
margin: 10px 0;
}
.title {
@extend %fa-copy;
padding: 0;
}
.data {
@extend %fa-copy;
padding: 0;
color: $black;
font-size: 1.125em;
}
}
.financial-assistance-form {
@extend .login-register;
.action-primary {
@include float(left);
width: auto;
margin-top: 0;
}
.nav-link {
margin: 15px 0;
display: block;
}
form {
border: none;
}
.form-field {
select,
input {
width: 320px;
}
input {
border: {
top: none;
right: none;
bottom: 3px solid $gray-l1;
left: none;
};
box-shadow: none;
}
textarea {
height: 125px;
}
.checkbox {
height: auto;
position: absolute;
top: 5px;
& + label {
@include margin-left(30px);
display: inline-block;
}
}
}
}
.cta-wrapper {
border-top: 4px solid $gray-l5;
padding: 20px 0;
}
@include media($bp-medium) {
.user-info {
.info-column {
width: 50%;
}
}
.financial-assistance-form {
.action-primary {
@include float(right);
}
.nav-link {
display: inline-block;
}
}
}
@include media($bp-large) {
.user-info {
.info-column {
width: 25%;
}
}
.financial-assistance-form {
.action-primary {
@include float(right);
}
.nav-link {
display: inline-block;
}
}
}
@include media($bp-huge) {
.user-info {
.info-column {
width: 25%;
}
}
.financial-assistance-form {
.action-primary {
@include float(right);
}
.nav-link {
display: inline-block;
}
}
}
}
......@@ -21,6 +21,7 @@
<option value="<%= el.value%>"<% if ( el.default ) { %> data-isdefault="true"<% } %>><%= el.name %></option>
<% }); %>
</select>
<% if ( instructions ) { %> <span class="tip tip-input" id="<%= form %>-<%= name %>-desc"><%= instructions %></span><% } %>
<% } else if ( type === 'textarea' ) { %>
<textarea id="<%= form %>-<%= name %>"
type="<%= type %>"
......@@ -35,6 +36,7 @@
<% });
} %>
<% if ( required ) { %> aria-required="true" required<% } %> ></textarea>
<% if ( instructions ) { %> <span class="tip tip-input" id="<%= form %>-<%= name %>-desc"><%= instructions %></span><% } %>
<% } else { %>
<input id="<%= form %>-<%= name %>"
type="<%= type %>"
......@@ -52,16 +54,15 @@
<% if ( placeholder ) { %> placeholder="<%= placeholder %>"<% } %>
value="<%- defaultValue %>"
/>
<% if ( type === 'checkbox' ) { %>
<label for="<%= form %>-<%= name %>">
<%= label %>
<% if ( required && requiredStr ) { %> <%= requiredStr %><% } %>
</label>
<% } %>
<% if ( instructions ) { %> <span class="tip tip-input" id="<%= form %>-<%= name %>-desc"><%= instructions %></span><% } %>
<% } %>
<% if ( type === 'checkbox' ) { %>
<label for="<%= form %>-<%= name %>">
<%= label %>
<% if ( required && requiredStr ) { %> <%= requiredStr %><% } %>
</label>
<% } %>
<% if( form === 'login' && name === 'password' ) { %>
<a href="#" class="forgot-password field-link"><%- gettext("Forgot password?") %></a>
<% } %>
......
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