'))
applyCampaignStyles: ->
diff --git a/app/views/teachers/ConvertToTeacherAccountView.coffee b/app/views/teachers/ConvertToTeacherAccountView.coffee
index ad3e3b7f5..79f0eb04a 100644
--- a/app/views/teachers/ConvertToTeacherAccountView.coffee
+++ b/app/views/teachers/ConvertToTeacherAccountView.coffee
@@ -7,9 +7,9 @@ errors = require 'core/errors'
User = require 'models/User'
ConfirmModal = require 'views/editor/modal/ConfirmModal'
algolia = require 'core/services/algolia'
-NCES_KEYS = ['id', 'name', 'district', 'district_id', 'district_schools', 'district_students', 'students', 'phone']
-FORM_KEY = 'request-quote-form'
+DISTRICT_NCES_KEYS = ['district', 'district_id', 'district_schools', 'district_students', 'phone']
+SCHOOL_NCES_KEYS = DISTRICT_NCES_KEYS.concat(['id', 'name', 'students'])
module.exports = class ConvertToTeacherAccountView extends RootView
id: 'convert-to-teacher-account-view'
@@ -40,13 +40,13 @@ module.exports = class ConvertToTeacherAccountView extends RootView
return 'Your account has not been updated! If you continue, your changes will be lost.'
invalidateNCES: ->
- for key in NCES_KEYS
+ for key in SCHOOL_NCES_KEYS
@$('input[name="nces_' + key + '"]').val ''
onLoaded: ->
if @trialRequests.size() and me.isTeacher()
return application.router.navigate('/teachers', { trigger: true, replace: true })
-
+
super()
afterRender: ->
@@ -75,16 +75,34 @@ module.exports = class ConvertToTeacherAccountView extends RootView
"
#{hr.name.value}
" +
"
#{hr.district.value}, " +
"#{hr.city?.value}, #{hr.state.value}
"
-
]).on 'autocomplete:selected', (event, suggestion, dataset) =>
+ @$('input[name="district"]').val suggestion.district
@$('input[name="city"]').val suggestion.city
@$('input[name="state"]').val suggestion.state
- @$('input[name="district"]').val suggestion.district
@$('input[name="country"]').val 'USA'
-
- for key in NCES_KEYS
+ for key in SCHOOL_NCES_KEYS
@$('input[name="nces_' + key + '"]').val suggestion[key]
+ @onChangeForm()
+ $("#district-control").algolia_autocomplete({hint: false}, [
+ source: (query, callback) ->
+ algolia.schoolsIndex.search(query, { hitsPerPage: 5, aroundLatLngViaIP: false }).then (answer) ->
+ callback answer.hits
+ , ->
+ callback []
+ displayKey: 'district',
+ templates:
+ suggestion: (suggestion) ->
+ hr = suggestion._highlightResult
+ "
#{hr.district.value}, " +
+ "#{hr.city?.value}, #{hr.state.value}
"
+ ]).on 'autocomplete:selected', (event, suggestion, dataset) =>
+ @$('input[name="organization"]').val '' # TODO: does not persist on tabbing: back to school, back to district
+ @$('input[name="city"]').val suggestion.city
+ @$('input[name="state"]').val suggestion.state
+ @$('input[name="country"]').val 'USA'
+ for key in DISTRICT_NCES_KEYS
+ @$('input[name="nces_' + key + '"]').val suggestion[key]
@onChangeForm()
onChangeForm: ->
@@ -97,28 +115,35 @@ module.exports = class ConvertToTeacherAccountView extends RootView
form = @$('form')
attrs = forms.formToObject(form)
-
+ trialRequestAttrs = _.cloneDeep(attrs)
+
+ # Don't save n/a district entries, but do validate required district client-side
+ trialRequestAttrs = _.omit(trialRequestAttrs, 'district') if trialRequestAttrs.district?.replace(/\s/ig, '').match(/n\/a/ig)
+
if @$('#other-education-level-checkbox').is(':checked')
val = @$('#other-education-level-input').val()
- attrs.educationLevel.push(val) if val
+ trialRequestAttrs.educationLevel.push(val) if val
forms.clearFormAlerts(form)
- result = tv4.validateMultiple(attrs, formSchema)
+ result = tv4.validateMultiple(trialRequestAttrs, formSchema)
error = false
if not result.valid
forms.applyErrorsToForm(form, result.errors)
error = true
- if not _.size(attrs.educationLevel)
- forms.setErrorToProperty(form, 'educationLevel', 'Include at least one.')
+ if not _.size(trialRequestAttrs.educationLevel)
+ forms.setErrorToProperty(form, 'educationLevel', 'include at least one')
+ error = true
+ unless attrs.district
+ forms.setErrorToProperty(form, 'district', $.i18n.t('common.required_field'))
error = true
if error
forms.scrollToFirstError()
return
- attrs['siteOrigin'] = 'convert teacher'
+ trialRequestAttrs['siteOrigin'] = 'convert teacher'
@trialRequest = new TrialRequest({
type: 'course'
- properties: attrs
+ properties: trialRequestAttrs
})
if me.get('role') is 'student' and not me.isAnonymous()
modal = new ConfirmModal({
@@ -151,15 +176,14 @@ module.exports = class ConvertToTeacherAccountView extends RootView
formSchema = {
type: 'object'
- required: [
- 'firstName', 'lastName', 'organization', 'role', 'numStudents', 'city', 'state', 'country'
- ]
+ required: ['firstName', 'lastName', 'role', 'numStudents', 'city', 'state', 'country']
properties:
firstName: { type: 'string' }
lastName: { type: 'string' }
phoneNumber: { type: 'string' }
role: { type: 'string' }
organization: { type: 'string' }
+ district: { type: 'string' }
city: { type: 'string' }
state: { type: 'string' }
country: { type: 'string' }
@@ -172,5 +196,5 @@ formSchema = {
notes: { type: 'string' }
}
-for key in NCES_KEYS
+for key in SCHOOL_NCES_KEYS
formSchema['nces_' + key] = type: 'string'
diff --git a/app/views/teachers/CreateTeacherAccountView.coffee b/app/views/teachers/CreateTeacherAccountView.coffee
index b0107e08c..8f1e103f7 100644
--- a/app/views/teachers/CreateTeacherAccountView.coffee
+++ b/app/views/teachers/CreateTeacherAccountView.coffee
@@ -7,9 +7,9 @@ errors = require 'core/errors'
User = require 'models/User'
algolia = require 'core/services/algolia'
-FORM_KEY = 'request-quote-form'
SIGNUP_REDIRECT = '/teachers/classes'
-NCES_KEYS = ['id', 'name', 'district', 'district_id', 'district_schools', 'district_students', 'students', 'phone']
+DISTRICT_NCES_KEYS = ['district', 'district_id', 'district_schools', 'district_students', 'phone']
+SCHOOL_NCES_KEYS = DISTRICT_NCES_KEYS.concat(['id', 'name', 'students'])
module.exports = class CreateTeacherAccountView extends RootView
id: 'create-teacher-account-view'
@@ -43,12 +43,12 @@ module.exports = class CreateTeacherAccountView extends RootView
super()
invalidateNCES: ->
- for key in NCES_KEYS
+ for key in SCHOOL_NCES_KEYS
@$('input[name="nces_' + key + '"]').val ''
-
+
afterRender: ->
super()
-
+
# apply existing trial request on form
properties = @trialRequest.get('properties')
if properties
@@ -58,7 +58,7 @@ module.exports = class CreateTeacherAccountView extends RootView
otherLevel = _.first(_.difference(submittedLevels, commonLevels)) or ''
@$('#other-education-level-checkbox').attr('checked', !!otherLevel)
@$('#other-education-level-input').val(otherLevel)
-
+
$("#organization-control").algolia_autocomplete({hint: false}, [
source: (query, callback) ->
algolia.schoolsIndex.search(query, { hitsPerPage: 5, aroundLatLngViaIP: false }).then (answer) ->
@@ -72,16 +72,34 @@ module.exports = class CreateTeacherAccountView extends RootView
"
#{hr.name.value}
" +
"
#{hr.district.value}, " +
"#{hr.city?.value}, #{hr.state.value}
"
-
]).on 'autocomplete:selected', (event, suggestion, dataset) =>
+ @$('input[name="district"]').val suggestion.district
@$('input[name="city"]').val suggestion.city
@$('input[name="state"]').val suggestion.state
- @$('input[name="district"]').val suggestion.district
@$('input[name="country"]').val 'USA'
-
- for key in NCES_KEYS
+ for key in SCHOOL_NCES_KEYS
@$('input[name="nces_' + key + '"]').val suggestion[key]
+ @onChangeForm()
+ $("#district-control").algolia_autocomplete({hint: false}, [
+ source: (query, callback) ->
+ algolia.schoolsIndex.search(query, { hitsPerPage: 5, aroundLatLngViaIP: false }).then (answer) ->
+ callback answer.hits
+ , ->
+ callback []
+ displayKey: 'district',
+ templates:
+ suggestion: (suggestion) ->
+ hr = suggestion._highlightResult
+ "
#{hr.district.value}, " +
+ "#{hr.city?.value}, #{hr.state.value}
"
+ ]).on 'autocomplete:selected', (event, suggestion, dataset) =>
+ @$('input[name="organization"]').val '' # TODO: does not persist on tabbing: back to school, back to district
+ @$('input[name="city"]').val suggestion.city
+ @$('input[name="state"]').val suggestion.state
+ @$('input[name="country"]').val 'USA'
+ for key in DISTRICT_NCES_KEYS
+ @$('input[name="nces_' + key + '"]').val suggestion[key]
@onChangeForm()
onClickLoginLink: ->
@@ -95,35 +113,41 @@ module.exports = class CreateTeacherAccountView extends RootView
onSubmitForm: (e) ->
e.preventDefault()
-
+
# Creating Trial Request first, validate user attributes but do not use them
form = @$('form')
allAttrs = forms.formToObject(form)
trialRequestAttrs = _.omit(allAttrs, 'name', 'password1', 'password2')
-
+
+ # Don't save n/a district entries, but do validate required district client-side
+ trialRequestAttrs = _.omit(trialRequestAttrs, 'district') if trialRequestAttrs.district?.replace(/\s/ig, '').match(/n\/a/ig)
+
if @$('#other-education-level-checkbox').is(':checked')
val = @$('#other-education-level-input').val()
trialRequestAttrs.educationLevel.push(val) if val
-
+
forms.clearFormAlerts(form)
-
+
result = tv4.validateMultiple(trialRequestAttrs, formSchema)
error = false
if not result.valid
forms.applyErrorsToForm(form, result.errors)
error = true
- if not forms.validateEmail(trialRequestAttrs.email)
- forms.setErrorToProperty(form, 'email', 'Invalid email.')
+ if not error and not forms.validateEmail(trialRequestAttrs.email)
+ forms.setErrorToProperty(form, 'email', 'invalid email')
error = true
if not _.size(trialRequestAttrs.educationLevel)
- forms.setErrorToProperty(form, 'educationLevel', 'Include at least one.')
+ forms.setErrorToProperty(form, 'educationLevel', 'include at least one')
+ error = true
+ unless allAttrs.district
+ forms.setErrorToProperty(form, 'district', $.i18n.t('common.required_field'))
error = true
unless @gplusAttrs or @facebookAttrs
if not allAttrs.password1
- forms.setErrorToProperty(form, 'password1', 'Required field')
+ forms.setErrorToProperty(form, 'password1', $.i18n.t('common.required_field'))
error = true
else if not allAttrs.password2
- forms.setErrorToProperty(form, 'password2', 'Required field')
+ forms.setErrorToProperty(form, 'password2', $.i18n.t('common.required_field'))
error = true
else if allAttrs.password1 isnt allAttrs.password2
forms.setErrorToProperty(form, 'password1', 'Password fields are not equivalent')
@@ -151,7 +175,7 @@ module.exports = class CreateTeacherAccountView extends RootView
.addClass('has-error')
.append($("
#{userExists}
#{logIn}"))
forms.scrollToFirstError()
- else
+ else
errors.showNotyNetworkError(arguments...)
onClickEmailExistsLoginLink: ->
@@ -225,7 +249,6 @@ module.exports = class CreateTeacherAccountView extends RootView
@$('input[type="password"]').attr('disabled', true)
@$('#gplus-logged-in-row, #social-network-signups').toggleClass('hide')
-
# Facebook signup
onClickFacebookSignupButton: ->
@@ -269,13 +292,9 @@ module.exports = class CreateTeacherAccountView extends RootView
@$('#facebook-logged-in-row, #social-network-signups').toggleClass('hide')
-
formSchema = {
type: 'object'
- required: [
- 'firstName', 'lastName', 'email', 'organization', 'role', 'numStudents', 'city'
- 'state', 'country'
- ]
+ required: ['firstName', 'lastName', 'email', 'role', 'numStudents', 'city', 'state', 'country']
properties:
password1: { type: 'string' }
password2: { type: 'string' }
@@ -286,6 +305,7 @@ formSchema = {
phoneNumber: { type: 'string' }
role: { type: 'string' }
organization: { type: 'string' }
+ district: { type: 'string' }
city: { type: 'string' }
state: { type: 'string' }
country: { type: 'string' }
@@ -298,5 +318,5 @@ formSchema = {
notes: { type: 'string' }
}
-for key in NCES_KEYS
+for key in SCHOOL_NCES_KEYS
formSchema['nces_' + key] = type: 'string'
diff --git a/app/views/teachers/RequestQuoteView.coffee b/app/views/teachers/RequestQuoteView.coffee
index b48a9d355..be34f5ad2 100644
--- a/app/views/teachers/RequestQuoteView.coffee
+++ b/app/views/teachers/RequestQuoteView.coffee
@@ -8,7 +8,8 @@ ConfirmModal = require 'views/editor/modal/ConfirmModal'
algolia = require 'core/services/algolia'
SIGNUP_REDIRECT = '/teachers'
-NCES_KEYS = ['id', 'name', 'district', 'district_id', 'district_schools', 'district_students', 'students', 'phone']
+DISTRICT_NCES_KEYS = ['district', 'district_id', 'district_schools', 'district_students', 'phone']
+SCHOOL_NCES_KEYS = DISTRICT_NCES_KEYS.concat(['id', 'name', 'students'])
module.exports = class RequestQuoteView extends RootView
id: 'request-quote-view'
@@ -46,7 +47,7 @@ module.exports = class RequestQuoteView extends RootView
super()
invalidateNCES: ->
- for key in NCES_KEYS
+ for key in SCHOOL_NCES_KEYS
@$('input[name="nces_' + key + '"]').val ''
afterRender: ->
@@ -75,16 +76,34 @@ module.exports = class RequestQuoteView extends RootView
"
#{hr.name.value}
" +
"
#{hr.district.value}, " +
"#{hr.city?.value}, #{hr.state.value}
"
-
]).on 'autocomplete:selected', (event, suggestion, dataset) =>
+ @$('input[name="district"]').val suggestion.district
@$('input[name="city"]').val suggestion.city
@$('input[name="state"]').val suggestion.state
- @$('input[name="district"]').val suggestion.district
@$('input[name="country"]').val 'USA'
-
- for key in NCES_KEYS
+ for key in SCHOOL_NCES_KEYS
@$('input[name="nces_' + key + '"]').val suggestion[key]
+ @onChangeRequestForm()
+ $("#district-control").algolia_autocomplete({hint: false}, [
+ source: (query, callback) ->
+ algolia.schoolsIndex.search(query, { hitsPerPage: 5, aroundLatLngViaIP: false }).then (answer) ->
+ callback answer.hits
+ , ->
+ callback []
+ displayKey: 'district',
+ templates:
+ suggestion: (suggestion) ->
+ hr = suggestion._highlightResult
+ "
#{hr.district.value}, " +
+ "#{hr.city?.value}, #{hr.state.value}
"
+ ]).on 'autocomplete:selected', (event, suggestion, dataset) =>
+ @$('input[name="organization"]').val '' # TODO: does not persist on tabbing: back to school, back to district
+ @$('input[name="city"]').val suggestion.city
+ @$('input[name="state"]').val suggestion.state
+ @$('input[name="country"]').val 'USA'
+ for key in DISTRICT_NCES_KEYS
+ @$('input[name="nces_' + key + '"]').val suggestion[key]
@onChangeRequestForm()
onChangeRequestForm: ->
@@ -96,32 +115,39 @@ module.exports = class RequestQuoteView extends RootView
e.preventDefault()
form = @$('#request-form')
attrs = forms.formToObject(form)
+ trialRequestAttrs = _.cloneDeep(attrs)
+
+ # Don't save n/a district entries, but do validate required district client-side
+ trialRequestAttrs = _.omit(trialRequestAttrs, 'district') if trialRequestAttrs.district?.replace(/\s/ig, '').match(/n\/a/ig)
# custom other input logic
if @$('#other-education-level-checkbox').is(':checked')
val = @$('#other-education-level-input').val()
- attrs.educationLevel.push(val) if val
+ trialRequestAttrs.educationLevel.push(val) if val
forms.clearFormAlerts(form)
requestFormSchema = if me.isAnonymous() then requestFormSchemaAnonymous else requestFormSchemaLoggedIn
- result = tv4.validateMultiple(attrs, requestFormSchemaAnonymous)
+ result = tv4.validateMultiple(trialRequestAttrs, requestFormSchemaAnonymous)
error = false
if not result.valid
forms.applyErrorsToForm(form, result.errors)
error = true
- if not forms.validateEmail(attrs.email)
- forms.setErrorToProperty(form, 'email', 'Invalid email.')
+ if not error and not forms.validateEmail(trialRequestAttrs.email)
+ forms.setErrorToProperty(form, 'email', 'invalid email')
error = true
- if not _.size(attrs.educationLevel)
- forms.setErrorToProperty(form, 'educationLevel', 'Include at least one.')
+ if not _.size(trialRequestAttrs.educationLevel)
+ forms.setErrorToProperty(form, 'educationLevel', 'include at least one')
+ error = true
+ unless attrs.district
+ forms.setErrorToProperty(form, 'district', $.i18n.t('common.required_field'))
error = true
if error
forms.scrollToFirstError()
return
- attrs['siteOrigin'] = 'demo request'
+ trialRequestAttrs['siteOrigin'] = 'demo request'
@trialRequest = new TrialRequest({
type: 'course'
- properties: attrs
+ properties: trialRequestAttrs
})
if me.get('role') is 'student' and not me.isAnonymous()
modal = new ConfirmModal({
@@ -262,7 +288,7 @@ module.exports = class RequestQuoteView extends RootView
requestFormSchemaAnonymous = {
type: 'object'
required: [
- 'firstName', 'lastName', 'email', 'organization', 'role', 'purchaserRole', 'numStudents',
+ 'firstName', 'lastName', 'email', 'role', 'purchaserRole', 'numStudents',
'numStudentsTotal', 'phoneNumber', 'city', 'state', 'country']
properties:
firstName: { type: 'string' }
@@ -273,6 +299,7 @@ requestFormSchemaAnonymous = {
role: { type: 'string' }
purchaserRole: { type: 'string' }
organization: { type: 'string' }
+ district: { type: 'string' }
city: { type: 'string' }
state: { type: 'string' }
country: { type: 'string' }
@@ -285,7 +312,7 @@ requestFormSchemaAnonymous = {
notes: { type: 'string' },
}
-for key in NCES_KEYS
+for key in SCHOOL_NCES_KEYS
requestFormSchemaAnonymous['nces_' + key] = type: 'string'
# same form, but add username input
diff --git a/app/views/teachers/TeachersContactModal.coffee b/app/views/teachers/TeachersContactModal.coffee
index 0d3dbb0f8..1f86a1cc9 100644
--- a/app/views/teachers/TeachersContactModal.coffee
+++ b/app/views/teachers/TeachersContactModal.coffee
@@ -34,7 +34,8 @@ module.exports = class TeachersContactModal extends ModalView
message = """
Hi CodeCombat! I want to learn more about the Classroom experience and get licenses so that my students can access Computer Science 2 and on.
- Name of School/District: #{props.organization or ''}
+ Name of School #{props.nces_name or props.organization or ''}
+ Name of District: #{props.nces_district or props.district or ''}
Role: #{props.role or ''}
Phone Number: #{props.phoneNumber or ''}
"""
diff --git a/scripts/updateCloseIoLeads.js b/scripts/updateCloseIoLeads.js
index 1fcc5209a..6a1ca5d9f 100644
--- a/scripts/updateCloseIoLeads.js
+++ b/scripts/updateCloseIoLeads.js
@@ -16,7 +16,7 @@ if (process.argv.length !== 10) {
// TODO: Cleanup country/status lookup code
// Save as custom fields instead of user-specific lead notes (also saving nces_ props)
-const commonTrialProperties = ['organization', 'city', 'state', 'country'];
+const commonTrialProperties = ['organization', 'district', 'city', 'state', 'country'];
// Old properties which are deprecated or moved
const customFieldsToRemove = [
@@ -327,7 +327,7 @@ function findCocoLeads(done) {
if (!trialRequest.properties || !trialRequest.properties.email) continue;
const email = trialRequest.properties.email.toLowerCase();
emails.push(email);
- const name = trialRequest.properties.nces_name || trialRequest.properties.organization || trialRequest.properties.school || email;
+ const name = trialRequest.properties.nces_name || trialRequest.properties.organization || trialRequest.properties.school || trialRequest.properties.district || trialRequest.properties.nces_district || email;
if (!leads[name]) leads[name] = new CocoLead(name);
leads[name].addTrialRequest(email, trialRequest);
emailLeadMap[email] = leads[name];
diff --git a/server/middleware/classrooms.coffee b/server/middleware/classrooms.coffee
index b04045fce..2a300a435 100644
--- a/server/middleware/classrooms.coffee
+++ b/server/middleware/classrooms.coffee
@@ -105,13 +105,13 @@ module.exports =
members = classroom.get('members') or []
members = members.slice(memberSkip, memberSkip + memberLimit)
dbqs = []
- select = 'state.complete level creator playtime changed dateFirstCompleted submitted'
+ select = 'state.complete level creator playtime changed created dateFirstCompleted submitted'
for member in members
dbqs.push(LevelSession.find({creator: member.toHexString()}).select(select).exec())
results = yield dbqs
sessions = _.flatten(results)
res.status(200).send(sessions)
-
+
fetchMembers: wrap (req, res, next) ->
throw new errors.Unauthorized() unless req.user
memberLimit = parse.getLimitFromReq(req, {default: 10, max: 100, param: 'memberLimit'})
diff --git a/server/middleware/prepaids.coffee b/server/middleware/prepaids.coffee
index 80192ddac..4b8b625fc 100644
--- a/server/middleware/prepaids.coffee
+++ b/server/middleware/prepaids.coffee
@@ -11,10 +11,6 @@ cutoffDate = new Date(2015,11,11)
cutoffID = mongoose.Types.ObjectId(Math.floor(cutoffDate/1000).toString(16)+'0000000000000000')
module.exports =
- logError: (user, msg) ->
- console.warn "Prepaid Error: [#{user.get('slug')} (#{user._id})] '#{msg}'"
-
-
post: wrap (req, res) ->
validTypes = ['course']
unless req.body.type in validTypes
@@ -71,7 +67,7 @@ module.exports =
update = { $push: { redeemers : { date: new Date(), userID: user._id } }}
result = yield Prepaid.update(query, update)
if result.nModified is 0
- @logError(req.user, "POST prepaid redeemer lost race on maxRedeemers")
+ console.error("Prepaid redeem error: [#{req.user.get('slug')} (#{req.user._id})] 'POST prepaid redeemer lost race on maxRedeemers'")
throw new errors.Forbidden('This prepaid is exhausted')
update = {
@@ -142,7 +138,7 @@ module.exports =
trialRequests = yield TrialRequest.find({$and: [{type: 'course'}, {applicant: {$in: userIDs}}]}, {applicant: 1, properties: 1}).lean()
schoolPrepaidsMap = {}
for trialRequest in trialRequests
- school = trialRequest.properties?.organization ? trialRequest.properties?.school
+ school = trialRequest.properties?.nces_name ? trialRequest.properties?.organization ? trialRequest.properties?.school
continue unless school
if userPrepaidsMap[trialRequest.applicant.valueOf()]?.length > 0
schoolPrepaidsMap[school] ?= []
diff --git a/test/app/factories.coffee b/test/app/factories.coffee
index e23bd0630..88c5a9dcb 100644
--- a/test/app/factories.coffee
+++ b/test/app/factories.coffee
@@ -184,6 +184,7 @@ module.exports = {
email: 'an@email.com'
phoneNumber: '555-555-5555'
organization: 'Greendale'
+ district: 'Green District'
}
}, attrs)
}
diff --git a/test/app/views/teachers/ConvertToTeacherAccountView.spec.coffee b/test/app/views/teachers/ConvertToTeacherAccountView.spec.coffee
index d853030c7..8a36b4782 100644
--- a/test/app/views/teachers/ConvertToTeacherAccountView.spec.coffee
+++ b/test/app/views/teachers/ConvertToTeacherAccountView.spec.coffee
@@ -31,6 +31,7 @@ describe 'ConvertToTeacherAccountView (/teachers/update-account)', ->
phoneNumber: '555-555-5555'
role: 'Teacher'
organization: 'School'
+ district: 'District'
city: 'Springfield'
state: 'AA'
country: 'asdf'
@@ -168,3 +169,48 @@ describe 'ConvertToTeacherAccountView (/teachers/update-account)', ->
})
expect(me.get('role')).toBe(successForm.role.toLowerCase())
+ describe 'submitting the form without school', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('form')
+ formData = _.omit(successForm, ['organization'])
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'submits a trial request, which does not include school setting', ->
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.url).toBe('/db/trial.request')
+ expect(request.method).toBe('POST')
+ attrs = JSON.parse(request.params)
+ expect(attrs.properties?.organization).toBeUndefined()
+ expect(attrs.properties?.district).toEqual('District')
+
+ describe 'submitting the form without district', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('form')
+ formData = _.omit(successForm, ['district'])
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'displays a validation error on district and not school', ->
+ expect(view.$('#organization-control').parent().hasClass('has-error')).toEqual(false)
+ expect(view.$('#district-control').parent().hasClass('has-error')).toEqual(true)
+
+ describe 'submitting the form district set to n/a', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('form')
+ formData = _.omit(successForm, ['organization'])
+ formData.district = 'N/A'
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'submits a trial request, which does not include district setting', ->
+ expect(view.$('#organization-control').parent().hasClass('has-error')).toEqual(false)
+ expect(view.$('#district-control').parent().hasClass('has-error')).toEqual(false)
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.url).toBe('/db/trial.request')
+ expect(request.method).toBe('POST')
+ attrs = JSON.parse(request.params)
+ expect(attrs.properties?.district).toBeUndefined()
diff --git a/test/app/views/teachers/CreateTeacherAccountView.spec.coffee b/test/app/views/teachers/CreateTeacherAccountView.spec.coffee
index ee8903535..20d132651 100644
--- a/test/app/views/teachers/CreateTeacherAccountView.spec.coffee
+++ b/test/app/views/teachers/CreateTeacherAccountView.spec.coffee
@@ -33,6 +33,7 @@ describe 'CreateTeacherAccountView', ->
phoneNumber: '555-555-5555'
role: 'Teacher'
organization: 'School'
+ district: 'District'
city: 'Springfield'
state: 'AA'
country: 'asdf'
@@ -219,6 +220,8 @@ describe 'CreateTeacherAccountView', ->
expect(attrs.password2).toBeUndefined()
expect(attrs.name).toBeUndefined()
expect(attrs.properties?.siteOrigin).toBe('create teacher')
+ expect(attrs.properties?.organization).toEqual('School')
+ expect(attrs.properties?.district).toEqual('District')
describe 'after saving the new trial request', ->
beforeEach ->
@@ -266,5 +269,49 @@ describe 'CreateTeacherAccountView', ->
spyOn(view, 'openModalView')
view.$('#email-form-group .login-link').click()
expect(view.openModalView).toHaveBeenCalled()
-
-
\ No newline at end of file
+
+ describe 'submitting the form without school', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('form')
+ formData = _.omit(successForm, ['organization'])
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'submits a trial request, which does not include school setting', ->
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.url).toBe('/db/trial.request')
+ expect(request.method).toBe('POST')
+ attrs = JSON.parse(request.params)
+ expect(attrs.properties?.organization).toBeUndefined()
+ expect(attrs.properties?.district).toEqual('District')
+
+ describe 'submitting the form without district', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('form')
+ formData = _.omit(successForm, ['district'])
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'displays a validation error on district and not school', ->
+ expect(view.$('#organization-control').parent().hasClass('has-error')).toEqual(false)
+ expect(view.$('#district-control').parent().hasClass('has-error')).toEqual(true)
+
+ describe 'submitting the form district set to n/a', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('form')
+ formData = _.omit(successForm, ['organization'])
+ formData.district = 'N/A'
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'submits a trial request, which does not include district setting', ->
+ expect(view.$('#organization-control').parent().hasClass('has-error')).toEqual(false)
+ expect(view.$('#district-control').parent().hasClass('has-error')).toEqual(false)
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.url).toBe('/db/trial.request')
+ expect(request.method).toBe('POST')
+ attrs = JSON.parse(request.params)
+ expect(attrs.properties?.district).toBeUndefined()
diff --git a/test/app/views/teachers/RequestQuoteView.spec.coffee b/test/app/views/teachers/RequestQuoteView.spec.coffee
index 73d2c3386..060d50375 100644
--- a/test/app/views/teachers/RequestQuoteView.spec.coffee
+++ b/test/app/views/teachers/RequestQuoteView.spec.coffee
@@ -2,16 +2,17 @@ RequestQuoteView = require 'views/teachers/RequestQuoteView'
forms = require 'core/forms'
describe 'RequestQuoteView', ->
-
+
view = null
-
- successFormValues = {
+
+ successForm = {
firstName: 'A'
lastName: 'B'
email: 'C@D.com'
phoneNumber: '555-555-5555'
role: 'Teacher'
organization: 'School'
+ district: 'District'
city: 'Springfield'
state: 'AA'
country: 'asdf'
@@ -20,10 +21,10 @@ describe 'RequestQuoteView', ->
purchaserRole: 'Approve Funds'
educationLevel: ['Middle']
}
-
+
isSubmitRequest = (r) -> _.string.startsWith(r.url, '/db/trial.request') and r.method is 'POST'
- describe 'when user is anonymous and has an existing trial request', ->
+ describe 'when an anonymous user', ->
beforeEach (done) ->
me.clear()
me.set('_id', '1234')
@@ -32,184 +33,220 @@ describe 'RequestQuoteView', ->
view = new RequestQuoteView()
view.render()
jasmine.demoEl(view.$el)
-
- request = jasmine.Ajax.requests.mostRecent()
- request.respondWith({
- status: 200
- responseText: JSON.stringify([{
- _id: '1'
- properties: {
- firstName: 'First'
- lastName: 'Last'
- }
- }])
- })
- _.defer done # Let SuperModel finish
-
- it 'shows request received', ->
- expect(view.$('#request-form').hasClass('hide')).toBe(true)
- expect(view.$('#form-submit-success').hasClass('hide')).toBe(false)
-
-
- describe 'when user is signed in and has an existing trial request', ->
- beforeEach (done) ->
- me.clear()
- me.set('_id', '1234')
- me._revertAttributes = {}
- spyOn(me, 'isAnonymous').and.returnValue(false)
- view = new RequestQuoteView()
- view.render()
- jasmine.demoEl(view.$el)
-
- request = jasmine.Ajax.requests.mostRecent()
- request.respondWith({
- status: 200
- responseText: JSON.stringify([{
- _id: '1'
- properties: {
- firstName: 'First'
- lastName: 'Last'
- }
- }])
- })
_.defer done # Let SuperModel finish
- it 'shows form with data from the most recent request', ->
- expect(view.$('input[name="firstName"]').val()).toBe('First')
-
- describe 'when a user is anonymous and does NOT have an existing trial request', ->
- beforeEach (done) ->
- me.clear()
- me.set('_id', '1234')
- me._revertAttributes = {}
- spyOn(me, 'isAnonymous').and.returnValue(true)
- view = new RequestQuoteView()
- view.render()
- jasmine.demoEl(view.$el)
-
- request = jasmine.Ajax.requests.mostRecent()
- request.respondWith({
- status: 200
- responseText: '[]'
- })
- _.defer done # Let SuperModel finish
-
- describe 'when the form is unchanged', ->
- it 'does not prevent navigating away', ->
- expect(_.result(view, 'onLeaveMessage')).toBeFalsy()
-
- describe 'when the form has changed but is not submitted', ->
- beforeEach ->
- view.$el.find('#request-form').trigger('change')
-
- it 'prevents navigating away', ->
- expect(_.result(view, 'onLeaveMessage')).toBeTruthy()
-
- describe 'on successful form submit', ->
- beforeEach ->
- view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
- forms.objectToForm(view.$el, successFormValues)
- view.$('#request-form').submit()
- @submitRequest = _.last(jasmine.Ajax.requests.filter(isSubmitRequest))
- @submitRequest.respondWith({
- status: 201
- responseText: JSON.stringify(_.extend({_id: 'a'}, successFormValues))
+ describe 'has an existing trial request', ->
+ beforeEach (done) ->
+ request = jasmine.Ajax.requests.mostRecent()
+ request.respondWith({
+ status: 200
+ responseText: JSON.stringify([{
+ _id: '1'
+ properties: {
+ firstName: 'First'
+ lastName: 'Last'
+ }
+ }])
})
+ _.defer done # Let SuperModel finish
- it 'does not prevent navigating away', ->
- expect(_.result(view, 'onLeaveMessage')).toBeFalsy()
-
- it 'creates a new trial request', ->
- expect(@submitRequest).toBeTruthy()
- expect(@submitRequest.method).toBe('POST')
- attrs = JSON.parse(@submitRequest.params)
- expect(attrs.properties?.siteOrigin).toBe('demo request')
-
- it 'sets the user\'s role to the one they chose', ->
- request = _.last(jasmine.Ajax.requests.filter((r) -> _.string.startsWith(r.url, '/db/user')))
- expect(request).toBeTruthy()
- expect(request.method).toBe('PUT')
- expect(JSON.parse(request.params).role).toBe('teacher')
-
- it 'shows a signup form', ->
- expect(view.$('#form-submit-success').hasClass('hide')).toBe(false)
+ it 'shows request received', ->
expect(view.$('#request-form').hasClass('hide')).toBe(true)
-
- describe 'signup form', ->
+ expect(view.$('#form-submit-success').hasClass('hide')).toBe(false)
+
+ describe 'does NOT have an existing trial request', ->
+ beforeEach (done) ->
+ request = jasmine.Ajax.requests.mostRecent()
+ request.respondWith({
+ status: 200
+ responseText: '[]'
+ })
+ _.defer done # Let SuperModel finish
+
+ describe 'when the form is unchanged', ->
+ it 'does not prevent navigating away', ->
+ expect(_.result(view, 'onLeaveMessage')).toBeFalsy()
+
+ describe 'when the form has changed but is not submitted', ->
beforeEach ->
- application.facebookHandler.fakeAPI()
- application.gplusHandler.fakeAPI()
-
- it 'fills the username field with the given first and last names', ->
- expect(view.$('input[name="name"]').val()).toBe('A B')
-
- it 'includes a facebook button which will sign them in immediately', ->
- view.$('#facebook-signup-btn').click()
- request = jasmine.Ajax.requests.mostRecent()
- expect(request.method).toBe('PUT')
- expect(request.url).toBe('/db/user?facebookID=abcd&facebookAccessToken=1234')
-
- it 'includes a gplus button which will sign them in immediately', ->
- view.$('#gplus-signup-btn').click()
- request = jasmine.Ajax.requests.mostRecent()
- expect(request.method).toBe('PUT')
- expect(request.url).toBe('/db/user?gplusID=abcd&gplusAccessToken=1234')
-
- it 'can sign them up with username and password', ->
- form = view.$('#signup-form')
- forms.objectToForm(form, {
- password1: 'asdf'
- password2: 'asdf'
- name: 'some name'
+ view.$el.find('#request-form').trigger('change')
+
+ it 'prevents navigating away', ->
+ expect(_.result(view, 'onLeaveMessage')).toBeTruthy()
+
+ describe 'on successful form submit', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ forms.objectToForm(view.$el, successForm)
+ view.$('#request-form').submit()
+ @submitRequest = _.last(jasmine.Ajax.requests.filter(isSubmitRequest))
+ @submitRequest.respondWith({
+ status: 201
+ responseText: JSON.stringify(_.extend({_id: 'a'}, successForm))
})
- form.submit()
- request = jasmine.Ajax.requests.mostRecent()
+
+ it 'does not prevent navigating away', ->
+ expect(_.result(view, 'onLeaveMessage')).toBeFalsy()
+
+ it 'creates a new trial request', ->
+ expect(@submitRequest).toBeTruthy()
+ expect(@submitRequest.method).toBe('POST')
+ attrs = JSON.parse(@submitRequest.params)
+ expect(attrs.properties?.siteOrigin).toBe('demo request')
+
+ it 'sets the user\'s role to the one they chose', ->
+ request = _.last(jasmine.Ajax.requests.filter((r) -> _.string.startsWith(r.url, '/db/user')))
+ expect(request).toBeTruthy()
expect(request.method).toBe('PUT')
- expect(request.url).toBe('/db/user/1234')
-
- describe 'when an anonymous user tries to submit a request with an existing user\'s email', ->
-
+ expect(JSON.parse(request.params).role).toBe('teacher')
+
+ it 'shows a signup form', ->
+ expect(view.$('#form-submit-success').hasClass('hide')).toBe(false)
+ expect(view.$('#request-form').hasClass('hide')).toBe(true)
+
+ describe 'signup form', ->
+ beforeEach ->
+ application.facebookHandler.fakeAPI()
+ application.gplusHandler.fakeAPI()
+
+ it 'fills the username field with the given first and last names', ->
+ expect(view.$('input[name="name"]').val()).toBe('A B')
+
+ it 'includes a facebook button which will sign them in immediately', ->
+ view.$('#facebook-signup-btn').click()
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.method).toBe('PUT')
+ expect(request.url).toBe('/db/user?facebookID=abcd&facebookAccessToken=1234')
+
+ it 'includes a gplus button which will sign them in immediately', ->
+ view.$('#gplus-signup-btn').click()
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.method).toBe('PUT')
+ expect(request.url).toBe('/db/user?gplusID=abcd&gplusAccessToken=1234')
+
+ it 'can sign them up with username and password', ->
+ form = view.$('#signup-form')
+ forms.objectToForm(form, {
+ password1: 'asdf'
+ password2: 'asdf'
+ name: 'some name'
+ })
+ form.submit()
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.method).toBe('PUT')
+ expect(request.url).toBe('/db/user/1234')
+
+ describe 'tries to submit a request with an existing user\'s email', ->
beforeEach ->
- forms.objectToForm(view.$el, successFormValues)
+ forms.objectToForm(view.$el, successForm)
view.$('#request-form').submit()
@submitRequest = _.last(jasmine.Ajax.requests.filter(isSubmitRequest))
@submitRequest.respondWith({
status: 409
responseText: '{}'
})
-
+
it 'shows an error that the email already exists', ->
expect(view.$('#email-form-group').hasClass('has-error')).toBe(true)
expect(view.$('#email-form-group .error-help-block').length).toBe(1)
-
- describe 'when user is signed in and has role "student"', ->
+
+ describe 'submits the form without school', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('#request-form')
+ formData = _.omit(successForm, ['organization'])
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'submits a trial request, which does not include school setting', ->
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.url).toBe('/db/trial.request')
+ expect(request.method).toBe('POST')
+ attrs = JSON.parse(request.params)
+ expect(attrs.properties?.organization).toBeUndefined()
+ expect(attrs.properties?.district).toEqual('District')
+
+ describe 'submits the form without district', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('#request-form')
+ formData = _.omit(successForm, ['district'])
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'displays a validation error on district and not school', ->
+ expect(view.$('#organization-control').parent().hasClass('has-error')).toEqual(false)
+ expect(view.$('#district-control').parent().hasClass('has-error')).toEqual(true)
+
+ describe 'submits form with district set to n/a', ->
+ beforeEach ->
+ view.$el.find('#request-form').trigger('change') # to confirm navigating away isn't prevented
+ form = view.$('#request-form')
+ formData = _.omit(successForm, ['organization'])
+ formData.district = 'N/A'
+ forms.objectToForm(form, formData)
+ form.submit()
+
+ it 'submits a trial request, which does not include district setting', ->
+ expect(view.$('#organization-control').parent().hasClass('has-error')).toEqual(false)
+ expect(view.$('#district-control').parent().hasClass('has-error')).toEqual(false)
+ request = jasmine.Ajax.requests.mostRecent()
+ expect(request.url).toBe('/db/trial.request')
+ expect(request.method).toBe('POST')
+ attrs = JSON.parse(request.params)
+ expect(attrs.properties?.district).toBeUndefined()
+
+ describe 'when a signed in user', ->
beforeEach (done) ->
- me.set('role', 'student')
- me.set('name', 'Some User')
+ me.clear()
+ me.set('_id', '1234')
+ me._revertAttributes = {}
spyOn(me, 'isAnonymous').and.returnValue(false)
view = new RequestQuoteView()
view.render()
jasmine.demoEl(view.$el)
-
- request = jasmine.Ajax.requests.mostRecent()
- request.respondWith({ status: 200, responseText: '[]'})
_.defer done # Let SuperModel finish
-
- it 'shows a conversion warning', ->
- expect(view.$('#conversion-warning').length).toBe(1)
-
- it 'requires confirmation to submit the form', ->
- form = view.$('#request-form')
- forms.objectToForm(form, successFormValues)
- spyOn(view, 'openModalView')
- form.submit()
- expect(view.openModalView).toHaveBeenCalled()
-
- submitRequest = _.last(jasmine.Ajax.requests.filter(isSubmitRequest))
- expect(submitRequest).toBeFalsy()
- confirmModal = view.openModalView.calls.argsFor(0)[0]
- confirmModal.trigger 'confirm'
- submitRequest = _.last(jasmine.Ajax.requests.filter(isSubmitRequest))
- expect(submitRequest).toBeTruthy()
-
-
\ No newline at end of file
+
+ describe 'has an existing trial request', ->
+ beforeEach (done) ->
+ request = jasmine.Ajax.requests.mostRecent()
+ request.respondWith({
+ status: 200
+ responseText: JSON.stringify([{
+ _id: '1'
+ properties: {
+ firstName: 'First'
+ lastName: 'Last'
+ }
+ }])
+ })
+ _.defer done # Let SuperModel finish
+
+ it 'shows form with data from the most recent request', ->
+ expect(view.$('input[name="firstName"]').val()).toBe('First')
+
+ describe 'has role "student"', ->
+ beforeEach (done) ->
+ me.clear()
+ me.set('role', 'student')
+ me.set('name', 'Some User')
+ request = jasmine.Ajax.requests.mostRecent()
+ request.respondWith({ status: 200, responseText: '[]'})
+ _.defer done # Let SuperModel finish
+
+ it 'shows a conversion warning', ->
+ expect(view.$('#conversion-warning').length).toBe(1)
+
+ it 'requires confirmation to submit the form', ->
+ form = view.$('#request-form')
+ forms.objectToForm(form, successForm)
+ spyOn(view, 'openModalView')
+ form.submit()
+ expect(view.openModalView).toHaveBeenCalled()
+
+ submitRequest = _.last(jasmine.Ajax.requests.filter(isSubmitRequest))
+ expect(submitRequest).toBeFalsy()
+ confirmModal = view.openModalView.calls.argsFor(0)[0]
+ confirmModal.trigger 'confirm'
+ submitRequest = _.last(jasmine.Ajax.requests.filter(isSubmitRequest))
+ expect(submitRequest).toBeTruthy()