diff --git a/app/core/forms.coffee b/app/core/forms.coffee
index b6c115ed4..c632e4beb 100644
--- a/app/core/forms.coffee
+++ b/app/core/forms.coffee
@@ -45,7 +45,7 @@ module.exports.applyErrorsToForm = (el, errors, warning=false) ->
for error in errors
if error.code is tv4.errorCodes.OBJECT_REQUIRED
prop = _.last(_.string.words(error.message)) # hack
- message = 'Required field'
+ message = $.i18n.t('common.required_field')
else if error.dataPath
prop = error.dataPath[1..]
diff --git a/app/locale/en.coffee b/app/locale/en.coffee
index 09b17cf3e..2d856e6d8 100644
--- a/app/locale/en.coffee
+++ b/app/locale/en.coffee
@@ -356,7 +356,7 @@
submit_patch: "Submit Patch"
submit_changes: "Submit Changes"
save_changes: "Save Changes"
- required_field: "Required field"
+ required_field: "required" # {change}
general:
and: "and"
@@ -885,7 +885,9 @@
evaluate_recommend: "Evaluate/Recommend"
approve_funds: "Approve Funds"
no_purchaser_role: "No role in purchase decisions"
- organization_label: "Name of School/District"
+ district_label: "District"
+ district_na: "Enter N/A if not applicable"
+ organization_label: "School" # {change}
city: "City"
state: "State"
country: "Country"
diff --git a/app/styles/teachers/request-quote-view.sass b/app/styles/teachers/request-quote-view.sass
deleted file mode 100644
index f4c61da92..000000000
--- a/app/styles/teachers/request-quote-view.sass
+++ /dev/null
@@ -1,96 +0,0 @@
-@import "app/styles/mixins"
-@import "app/styles/bootstrap/variables"
-
-#request-quote-view
- #site-content-area
- margin: 50px 0 100px
- .row
- margin: 20px 0
-
- #conversion-warning
- margin-top: 20px
-
- .form-group
- label
- margin-bottom: 0
-
- label.checkbox
- font-weight: normal
-
- .help-block
- margin: -4px 0 2px
-
- p
- margin: 0 0 20px
-
- .checkbox, .checkbox-inline
- input
- margin-top: 8px
-
- #other-education-level-input
- label
- display: inline-block
- display: inline-block
- width: 200px
- margin-left: 5px
-
- #submit-request-btn
- margin-left: 10px
-
- // After submit (anonymous)
-
- h5
- margin-top: 50px
-
- #social-network-signups
- margin: 20px 0
- button
- margin-left: 10px
-
- .text-h1
- margin: 40px 0 30px
-
-
-.algolia-autocomplete
- width: 100%;
-
- .aa-input
- width: 100%
-
- .aa-hint
- color: #999
- width: 100%
-
- .aa-dropdown-menu
- background-color: #fff
- border: 1px solid #999
- border-top: none
- width: 100%
-
- .aa-suggestion
- cursor: pointer
- padding: 5px 4px
- border-top: 1px solid #ccc
-
- .school
- font-family: Open Sans
- font-size: 14px
- line-height: 20px
- font-weight: bold
-
- .district
- font-family: Open Sans
- font-size: 14px
- line-height: 20px
-
- span
- white-space: nowrap
-
-
- .aa-suggestion.aa-cursor
- background-color: #B2D7FF
-
- em
- font-weight: bold
- font-style: normal
-
diff --git a/app/styles/teachers/teacher-trial-requests.sass b/app/styles/teachers/teacher-trial-requests.sass
new file mode 100644
index 000000000..b933f00e9
--- /dev/null
+++ b/app/styles/teachers/teacher-trial-requests.sass
@@ -0,0 +1,81 @@
+#create-teacher-account-view, #convert-to-teacher-account-view, #request-quote-view
+ .algolia-autocomplete
+ width: 100%;
+
+ .aa-input
+ width: 100%
+
+ .aa-hint
+ color: #999
+ width: 100%
+
+ .aa-dropdown-menu
+ background-color: #fff
+ border: 1px solid #999
+ border-top: none
+ width: 100%
+
+ .aa-suggestion
+ cursor: pointer
+ padding: 5px 4px
+ border-top: 1px solid #ccc
+
+ .school
+ font-family: Open Sans
+ font-size: 14px
+ line-height: 20px
+ font-weight: bold
+
+ .district
+ font-family: Open Sans
+ font-size: 14px
+ line-height: 20px
+
+ span
+ white-space: nowrap
+
+
+ .aa-suggestion.aa-cursor
+ background-color: #B2D7FF
+
+ em
+ font-weight: bold
+ font-style: normal
+
+ // TODO: update form validation instead of overwriting these styles
+
+ .control-label
+ font-weight: bold
+ width: 100%
+
+ .error-help-block
+ margin-top: inherit
+ margin-bottom: 0px
+ float: right
+ font-size: 13px
+ font-style: italic
+ font-weight: normal
+
+ .text-muted
+ float: right
+ font-size: 13px
+ font-style: italic
+ font-weight: normal
+
+ .nullify-form-control
+ display: inherit
+ width: inherit
+ height: inherit
+ padding: inherit
+ font-size: inherit
+ line-height: inherit
+ color: inherit
+ vertical-align: inherit
+ background-color: inherit
+ background-image: inherit
+ border: inherit
+ border-radius: inherit
+ -webkit-box-shadow: inherit
+ box-shadow: inherit
+ -webkit-transition: inherit
+ transition: inherit
diff --git a/app/templates/admin/demo-requests.jade b/app/templates/admin/demo-requests.jade
index d072b64e6..ad4d251fa 100644
--- a/app/templates/admin/demo-requests.jade
+++ b/app/templates/admin/demo-requests.jade
@@ -30,8 +30,8 @@ block content
thead
tr
th Created
- th NCES District
th School Name
+ th School District
th.number NCES District Schools
th.number NCES District Students
th.number NCES School Students
@@ -44,8 +44,8 @@ block content
- continue;
tr
td.created= trialRequest.get('created').substring(0, 10)
- td= trialRequest.get('properties').nces_district || ''
- td= trialRequest.get('properties').organization || ''
+ td= trialRequest.get('properties').nces_name || trialRequest.get('properties').organization || ''
+ td= trialRequest.get('properties').nces_district || trialRequest.get('properties').district || ''
td= trialRequest.get('properties').nces_district_schools || ''
td= trialRequest.get('properties').nces_district_students || ''
td= trialRequest.get('properties').nces_students || ''
diff --git a/app/templates/teachers/convert-to-teacher-account-view.jade b/app/templates/teachers/convert-to-teacher-account-view.jade
index 3feab53ac..ec754d4c8 100644
--- a/app/templates/teachers/convert-to-teacher-account-view.jade
+++ b/app/templates/teachers/convert-to-teacher-account-view.jade
@@ -28,40 +28,36 @@ block content
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.username")
+ span.control-label(data-i18n="general.username")
input.form-control(disabled=true value=me.get('name'))
.col-md-4.col-sm-6
#email-form-group.form-group
- label.control-label(data-i18n="general.email")
+ span.control-label(data-i18n="general.email")
input.form-control(name='email' disabled=true value=me.get('email'))
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.first_name")
+ span.control-label(data-i18n="general.first_name")
input.form-control(name="firstName" value=me.get('firstName') || '')
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.last_name")
+ span.control-label(data-i18n="general.last_name")
input.form-control(name="lastName" value=me.get('lastName') || '')
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label
+ span.control-label
span(data-i18n="teachers_quote.phone_number")
span.spl.text-muted(data-i18n="signup.optional")
- .help-block.small
- em.text-info(data-i18n="teachers_quote.phone_number_help")
- input.form-control(name="phoneNumber")
+ input.form-control(name="phoneNumber", data-i18n="[placeholder]teachers_quote.phone_number_help")
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.primary_role_label")
- .help-block.small
- em.text-info(data-i18n="teachers_quote.role_help")
+ span.control-label(data-i18n="teachers_quote.primary_role_label")
select.form-control(name="role")
option(data-i18n="teachers_quote.role_default", , value='')
option(data-i18n="courses.teacher", value="Teacher")
@@ -75,30 +71,40 @@ block content
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.organization_label")
+ span.control-label
+ span(data-i18n="teachers_quote.organization_label")
+ span.spl.text-muted(data-i18n="signup.optional")
input.form-control#organization-control(name="organization")
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.city")
- input.form-control(name="city")
+ //- TODO: algolia and form errors both change form-control
+ //- TODO: District not red on validation error
+ span.control-label.form-control.nullify-form-control(data-i18n="teachers_quote.district_label")
+ input.form-control#district-control(name="district", data-i18n="[placeholder]teachers_quote.district_na")
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.state")
- input.form-control(name="state")
+ span.control-label(data-i18n="teachers_quote.city")
+ input.form-control(name="city")
.col-md-4.col-sm-6
.form-group
- label.control-labellabel.control-label(data-i18n="teachers_quote.country")
+ span.control-label(data-i18n="teachers_quote.state")
+ input.form-control(name="state")
+
+ .row.m-y-2
+ .col-md-offset-2.col-md-4.col-sm-6
+ .form-group
+ span.control-labelspan.control-label(data-i18n="teachers_quote.country")
input.form-control(name="country")
#form-students-info
.row.m-y-2
.col-md-offset-2.col-md-4
.form-group
- label.control-label(data-i18n="courses.number_programming_students")
+ span.control-label(data-i18n="courses.number_programming_students")
.help-block.small
em.text-info(data-i18n="teachers_quote.num_students_help")
select.form-control(name="numStudents")
@@ -113,7 +119,7 @@ block content
.col-md-4.col-sm-6
.form-group
- label.control-label
+ span.control-label
span(data-i18n="courses.number_total_students")
span.spl.text-muted(data-i18n="signup.optional")
select.form-control(name="numStudentsTotal")
@@ -126,11 +132,10 @@ block content
.form-group
.row.m-y-2
- .col-md-offset-2.col-md-10
- label.control-label(data-i18n="teachers_quote.education_level_label")
+ .col-md-offset-2.col-md-4
+ span.control-label(data-i18n="teachers_quote.education_level_label")
.help-block.small
em.text-info(data-i18n="teachers_quote.education_level_help")
- .col-md-offset-2.col-md-5
.checkbox
label
input(type="checkbox" name="educationLevel" value="Elementary")
@@ -156,7 +161,7 @@ block content
#anything-else-row.row.m-y-2
.col-md-offset-2.col-md-8
- label.control-label
+ span.control-label
span(data-i18n="teachers_quote.anything_else")
span.spl.text-muted(data-i18n="signup.optional")
textarea.form-control(rows=8, name="notes")
diff --git a/app/templates/teachers/create-teacher-account-view.jade b/app/templates/teachers/create-teacher-account-view.jade
index e7a4e940e..742b509cd 100644
--- a/app/templates/teachers/create-teacher-account-view.jade
+++ b/app/templates/teachers/create-teacher-account-view.jade
@@ -34,49 +34,47 @@ block content
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.username")
+ span.control-label(data-i18n="general.username")
input.form-control(name="name")
.col-md-4.col-sm-6
#email-form-group.form-group
- label.control-label(data-i18n="general.email")
+ span.control-label(data-i18n="general.email")
input.form-control(name="email")
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.first_name")
+ span.control-label(data-i18n="general.first_name")
input.form-control(name="firstName")
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.last_name")
+ span.control-label(data-i18n="general.last_name")
input.form-control(name="lastName")
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.password")
+ span.control-label(data-i18n="general.password")
input.form-control(name="password1", type="password")
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.confirm_password")
+ span.control-label(data-i18n="general.confirm_password")
input.form-control(name="password2", type="password")
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label
+ span.control-label
span(data-i18n="teachers_quote.phone_number")
span.spl.text-muted(data-i18n="signup.optional")
- .help-block.small
- em.text-info(data-i18n="teachers_quote.phone_number_help")
- input.form-control(name="phoneNumber")
+ input.form-control(name="phoneNumber", data-i18n="[placeholder]teachers_quote.phone_number_help")
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.primary_role_label")
+ span.control-label(data-i18n="teachers_quote.primary_role_label")
select.form-control(name="role")
option(data-i18n="teachers_quote.role_default", , value='')
option(data-i18n="courses.teacher", value="Teacher")
@@ -90,30 +88,40 @@ block content
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.organization_label")
+ span.control-label
+ span(data-i18n="teachers_quote.organization_label")
+ span.spl.text-muted(data-i18n="signup.optional")
input.form-control#organization-control(name="organization")
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.city")
- input.form-control(name="city")
+ //- TODO: algolia and form errors both change form-control
+ //- TODO: District not red on validation error
+ span.control-label.form-control.nullify-form-control(data-i18n="teachers_quote.district_label")
+ input.form-control#district-control(name="district", data-i18n="[placeholder]teachers_quote.district_na")
.row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.state")
- input.form-control(name="state")
+ span.control-label(data-i18n="teachers_quote.city")
+ input.form-control(name="city")
.col-md-4.col-sm-6
.form-group
- label.control-labellabel.control-label(data-i18n="teachers_quote.country")
+ span.control-label(data-i18n="teachers_quote.state")
+ input.form-control(name="state")
+
+ .row.m-y-2
+ .col-md-offset-2.col-md-4.col-sm-6
+ .form-group
+ span.control-label(data-i18n="teachers_quote.country")
input.form-control(name="country")
#form-students-info
.row.m-y-2
.col-md-offset-2.col-md-4
.form-group
- label.control-label(data-i18n="courses.number_programming_students")
+ span.control-label(data-i18n="courses.number_programming_students")
.help-block.small
em.text-info(data-i18n="teachers_quote.num_students_help")
select.form-control(name="numStudents")
@@ -128,7 +136,7 @@ block content
.col-md-4.col-sm-6
.form-group
- label.control-label
+ span.control-label
span(data-i18n="courses.number_total_students")
span.spl.text-muted(data-i18n="signup.optional")
select.form-control(name="numStudentsTotal")
@@ -140,14 +148,11 @@ block content
option 10,000+
.form-group
-
.row.m-y-2
- .col-md-offset-2.col-md-10
- label.control-label(data-i18n="teachers_quote.education_level_label")
- .help-block.small
- em.text-info(data-i18n="teachers_quote.education_level_help")
-
- .col-md-offset-2.col-md-5
+ .col-md-offset-2.col-md-4
+ span.control-label(data-i18n="teachers_quote.education_level_label")
+ .help-block.small
+ em.text-info(data-i18n="teachers_quote.education_level_help")
.checkbox
label
input(type="checkbox" name="educationLevel" value="Elementary")
@@ -173,7 +178,7 @@ block content
#anything-else-row.row.m-y-2
.col-md-offset-2.col-md-8
- label.control-label
+ span.control-label
span(data-i18n="teachers_quote.anything_else")
span.spl.text-muted(data-i18n="signup.optional")
diff --git a/app/templates/teachers/request-quote-view.jade b/app/templates/teachers/request-quote-view.jade
index f92a53fa3..0dffd6446 100644
--- a/app/templates/teachers/request-quote-view.jade
+++ b/app/templates/teachers/request-quote-view.jade
@@ -36,7 +36,7 @@ block content
.row
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label
+ span.control-label
span(data-i18n="general.username")
span.spl.text-muted(data-i18n="signup.optional")
- var name = me.get('name') || '';
@@ -44,20 +44,20 @@ block content
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="share_progress_modal.form_label")
+ span.control-label(data-i18n="share_progress_modal.form_label")
- var email = me.get('email') || '';
input.form-control(name="email" value=email, disabled=!!email)
.row
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.first_name")
+ span.control-label(data-i18n="general.first_name")
- var firstName = me.get('firstName') || '';
input.form-control(name="firstName" value=firstName, disabled=!!firstName)
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="general.last_name")
+ span.control-label(data-i18n="general.last_name")
- var lastName = me.get('lastName') || '';
input.form-control(name="lastName" value=lastName, disabled=!!lastName)
@@ -65,33 +65,30 @@ block content
.row
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label
- span(data-i18n="teachers_quote.phone_number")
- .help-block.small
- em.text-info(data-i18n="teachers_quote.phone_number_help")
- input.form-control(name="phoneNumber")
-
+ span.control-label(data-i18n="teachers_quote.phone_number")
+ input.form-control(name="phoneNumber", data-i18n="[placeholder]teachers_quote.phone_number_help")
+
if me.isAnonymous()
.row
.col-md-offset-2.col-md-4.col-sm-6
#email-form-group.form-group
- label.control-label(data-i18n="general.email")
+ span.control-label(data-i18n="general.email")
- var email = me.get('email') || '';
input.form-control(name="email" type="email", value=email, disabled=!!email)
.col-md-4.col-sm-6
.form-group
- label.control-label
+ span.control-label
span(data-i18n="teachers_quote.phone_number")
.help-block.small
em.text-info(data-i18n="teachers_quote.phone_number_help")
- input.form-control(name="phoneNumber")
+ input.form-control(name="phoneNumber")
+
-
.row
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.primary_role_label")
+ span.control-label(data-i18n="teachers_quote.primary_role_label")
select.form-control(name="role")
option(data-i18n="teachers_quote.primary_role_default", , value='')
option(data-i18n="courses.teacher", value="Teacher")
@@ -100,45 +97,55 @@ block content
option(data-i18n="teachers_quote.principal", value="Principal")
option(data-i18n="teachers_quote.superintendent", value="Superintendent")
option(data-i18n="teachers_quote.parent", value="Parent")
-
- .col-md-4.col-sm-6
+
+ .col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.purchaser_role_label")
+ span.control-label(data-i18n="teachers_quote.purchaser_role_label")
select.form-control(name="purchaserRole")
option(data-i18n="teachers_quote.purchaser_role_default", , value='')
option(data-i18n="teachers_quote.influence_advocate", value="Influence/Advocate")
option(data-i18n="teachers_quote.evaluate_recommend", value="Evaluate/Recommend")
option(data-i18n="teachers_quote.approve_funds", value="Approve Funds")
option(data-i18n="teachers_quote.no_purchaser_role", value="No role in purchase decisions")
-
+
#form-school-info
- .row
+ .row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.organization_label")
+ span.control-label
+ span(data-i18n="teachers_quote.organization_label")
+ span.spl.text-muted(data-i18n="signup.optional")
input.form-control#organization-control(name="organization")
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.city")
- input.form-control(name="city")
+ //- TODO: algolia and form errors both change form-control
+ //- TODO: District not red on validation error
+ span.control-label.form-control.nullify-form-control(data-i18n="teachers_quote.district_label")
+ input.form-control#district-control(name="district", data-i18n="[placeholder]teachers_quote.district_na")
- .row
+ .row.m-y-2
.col-md-offset-2.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="teachers_quote.state")
- input.form-control(name="state")
+ span.control-label(data-i18n="teachers_quote.city")
+ input.form-control(name="city")
.col-md-4.col-sm-6
.form-group
- label.control-labellabel.control-label(data-i18n="teachers_quote.country")
+ span.control-label(data-i18n="teachers_quote.state")
+ input.form-control(name="state")
+
+ .row.m-y-2
+ .col-md-offset-2.col-md-4.col-sm-6
+ .form-group
+ span.control-labelspan.control-label(data-i18n="teachers_quote.country")
input.form-control(name="country")
#form-students-info
.row
.col-md-offset-2.col-md-4
.form-group
- label.control-label(data-i18n="courses.number_programming_students")
+ span.control-label(data-i18n="courses.number_programming_students")
.help-block.small
em.text-info(data-i18n="teachers_quote.num_students_help")
select.form-control(name="numStudents")
@@ -150,10 +157,10 @@ block content
option 201-500
option 501-1000
option 1000+
-
+
.col-md-4.col-sm-6
.form-group
- label.control-label(data-i18n="courses.number_total_students")
+ span.control-label(data-i18n="courses.number_total_students")
select.form-control(name="numStudentsTotal")
option(data-i18n="teachers_quote.num_students_default", value='')
option 1-500
@@ -163,14 +170,11 @@ block content
option 10,000+
.form-group
-
- .row
- .col-md-offset-2.col-md-10
- label.control-label(data-i18n="teachers_quote.education_level_label")
- .help-block.small
- em.text-info(data-i18n="teachers_quote.education_level_help")
-
- .col-md-offset-2.col-md-5
+ .row.m-y-2
+ .col-md-offset-2.col-md-4
+ span.control-label(data-i18n="teachers_quote.education_level_label")
+ .help-block.small
+ em.text-info(data-i18n="teachers_quote.education_level_help")
.checkbox
label
input(type="checkbox" name="educationLevel" value="Elementary")
@@ -196,7 +200,7 @@ block content
#anything-else-row.row
.col-md-offset-2.col-md-8
- label.control-label
+ span.control-label
span(data-i18n="teachers_quote.anything_else")
span.spl.text-muted(data-i18n="signup.optional")
@@ -210,7 +214,7 @@ block content
input(type="hidden" name="nces_students")
input(type="hidden" name="nces_phone")
- #buttons-row.row.text-center
+ #buttons-row.row.m-y-2.text-center
input#submit-request-btn.btn.btn-lg.btn-primary(type="submit" data-i18n="[value]teachers_quote.title")
#form-submit-success.text-center(class=showDone ? '' : 'hide')
@@ -219,7 +223,7 @@ block content
p
span.spr(data-i18n="teachers_quote.thanks_p")
a.spl(href="mailto:team@codecombat.com") team@codecombat.com
-
+
unless me.isAnonymous()
a.btn.btn-lg.btn-navy(href="/teachers/classes")
span(data-i18n='teachers_quote.back_to_classes')
@@ -244,17 +248,17 @@ block content
.row
.col-md-offset-2.col-md-4
.form-group
- label.control-label(data-i18n="general.username")
+ span.control-label(data-i18n="general.username")
input.form-control(name="name")
.row
.col-md-offset-2.col-md-4
.form-group
- label.control-label(data-i18n="general.password")
+ span.control-label(data-i18n="general.password")
input.form-control(name="password1", type="password")
.col-md-4
.form-group
- label.control-label(data-i18n="general.confirm_password")
+ span.control-label(data-i18n="general.confirm_password")
input.form-control(name="password2", type="password")
.text-center
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
"
#{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/prepaids.coffee b/server/middleware/prepaids.coffee
index 11fc9bde2..4b8b625fc 100644
--- a/server/middleware/prepaids.coffee
+++ b/server/middleware/prepaids.coffee
@@ -138,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()