diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 29528035a..3bf4586f5 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -815,6 +815,7 @@ more_info_1: "Our" more_info_2: "teachers forum" more_info_3: "is a good place to connect with fellow educators who are using CodeCombat." + licenses_needed: "Licenses needed" teachers_quote: name: "Demo Form" diff --git a/app/templates/courses/enrollments-view.jade b/app/templates/courses/enrollments-view.jade index babd88a79..0ec9f35fb 100644 --- a/app/templates/courses/enrollments-view.jade +++ b/app/templates/courses/enrollments-view.jade @@ -101,9 +101,6 @@ mixin addCredits button#request-sent-btn.btn-lg.btn.btn-forest(disabled=true, data-i18n="teacher.request_sent") else p(data-i18n="teacher.num_enrollments_needed") - div.m-t-2 - input#students-input.enrollment-count.text-center(value=view.state.get('numberOfStudents') type='number') - strong(data-i18n="teacher.credits") p.m-y-2(data-i18n="teacher.get_enrollments_blurb") button#contact-us-btn.btn-lg.btn.btn-forest(data-i18n="contribute.contact_us_url") diff --git a/app/templates/teachers/teachers-contact-modal.jade b/app/templates/teachers/teachers-contact-modal.jade index de3826063..a795d9792 100644 --- a/app/templates/teachers/teachers-contact-modal.jade +++ b/app/templates/teachers/teachers-contact-modal.jade @@ -1,5 +1,7 @@ extends /templates/core/modal-base-flat +//- TODO: i18n + block modal-header-content .text-center h3 Contact Our Classroom Team @@ -11,26 +13,36 @@ block modal-body-content - var sent = view.state.get('sendingState') === 'sent'; - var values = view.state.get('formValues'); - var errors = view.state.get('formErrors'); - + + .form-group(class=errors.name ? 'has-error' : '') + label.control-label(for="name" data-i18n="general.name") + +formErrors(errors.name) + input.form-control(name="name", type="text", value=values.name || '', tabindex=1, disabled=sending || sent) + .form-group(class=errors.email ? 'has-error' : '') label.control-label(for="email" data-i18n="general.email") +formErrors(errors.email) input.form-control(name="email", type="email", value=values.email || '', tabindex=1, disabled=sending || sent) - + + .form-group(class=errors.licensesNeeded ? 'has-error' : '') + label.control-label(for="licensesNeeded" data-i18n="teachers.licenses_needed") + +formErrors(errors.licensesNeeded) + input.form-control(name="licensesNeeded", type="text", value=values.licensesNeeded || '', tabindex=1, disabled=sending || sent) + .form-group(class=errors.message ? 'has-error' : '') label.control-label(for="message" data-i18n="general.message") +formErrors(errors.message) textarea.form-control(name="message", tabindex=1 disabled=sending || sent)= values.message - + if view.state.get('sendingState') === 'error' .alert.alert-danger Could not send message. - + if sent .alert.alert-success Message sent! - + .text-right button#submit-btn.btn.btn-navy.btn-lg(type='submit' disabled=sending || sent) Submit - + block modal-footer mixin formErrors(errors) diff --git a/app/views/courses/EnrollmentsView.coffee b/app/views/courses/EnrollmentsView.coffee index bcc3b3596..4e91ae1a3 100644 --- a/app/views/courses/EnrollmentsView.coffee +++ b/app/views/courses/EnrollmentsView.coffee @@ -14,7 +14,6 @@ module.exports = class EnrollmentsView extends RootView template: template events: - 'input #students-input': 'onInputStudentsInput' 'click #enroll-students-btn': 'onClickEnrollStudentsButton' 'click #how-to-enroll-link': 'onClickHowToEnrollLink' 'click #contact-us-btn': 'onClickContactUsButton' @@ -96,17 +95,8 @@ module.exports = class EnrollmentsView extends RootView @openModalView(new HowToEnrollModal()) onClickContactUsButton: -> - window.tracker?.trackEvent 'Classes Licenses Contact Us', category: 'Teachers', enrollmentsNeeded: @state.get('numberOfStudents'), ['Mixpanel'] - @openModalView(new TeachersContactModal({ enrollmentsNeeded: @state.get('numberOfStudents') })) - - onInputStudentsInput: -> - input = @$('#students-input').val() - if input isnt "" and (parseFloat(input) isnt parseInt(input) or _.isNaN parseInt(input)) - @$('#students-input').val(@state.get('numberOfStudents')) - else - @state.set({'numberOfStudents': Math.max(parseInt(@$('#students-input').val()) or 0, 0)}, {silent: true}) # do not re-render - - numberOfStudentsIsValid: -> 0 < @get('numberOfStudents') < 100000 + window.tracker?.trackEvent 'Classes Licenses Contact Us', category: 'Teachers', ['Mixpanel'] + @openModalView(new TeachersContactModal()) onClickEnrollStudentsButton: -> window.tracker?.trackEvent 'Classes Licenses Enroll Students', category: 'Teachers', ['Mixpanel'] diff --git a/app/views/teachers/TeachersContactModal.coffee b/app/views/teachers/TeachersContactModal.coffee index ec19bd824..ab8fbf06b 100644 --- a/app/views/teachers/TeachersContactModal.coffee +++ b/app/views/teachers/TeachersContactModal.coffee @@ -7,20 +7,22 @@ contact = require 'core/contact' module.exports = class TeachersContactModal extends ModalView id: 'teachers-contact-modal' template: require 'templates/teachers/teachers-contact-modal' - + defaultLicenses: 15 + events: 'submit form': 'onSubmitForm' - + initialize: (options={}) -> @state = new State({ formValues: { + name: '' email: '' + licensesNeeded: @defaultLicenses message: '' } formErrors: {} sendingState: 'standby' # 'sending', 'sent', 'error' }) - @enrollmentsNeeded = options.enrollmentsNeeded or '-' @trialRequests = new TrialRequests() @supermodel.trackRequest @trialRequests.fetchOwn() @state.on 'change', @render, @ @@ -28,41 +30,46 @@ module.exports = class TeachersContactModal extends ModalView onLoaded: -> trialRequest = @trialRequests.first() props = trialRequest?.get('properties') or {} - message = """ - Name of School/District: #{props.organization or ''} - Your Name: #{props.name || ''} - Enrollments Needed: #{@enrollmentsNeeded} - - 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 = if props.firstName and props.lastName then "#{props.firstName} #{props.lastName}" else me.get('name') ? '' email = props.email or me.get('email') or '' - @state.set('formValues', { email, message }) + 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 ''} + Role: #{props.role or ''} + Phone Number: #{props.phoneNumber or ''} + """ + @state.set('formValues', { name, email, licensesNeeded: @defaultLicenses, message }) super() onSubmitForm: (e) -> e.preventDefault() return if @state.get('sendingState') is 'sending' - + formValues = forms.formToObject @$el @state.set('formValues', formValues) - + formErrors = {} - if not forms.validateEmail(formValues.email) + unless formValues.name + formErrors.name = 'Name required.' + unless forms.validateEmail(formValues.email) formErrors.email = 'Invalid email.' - if not formValues.message + unless parseInt(formValues.licensesNeeded) > 0 + formErrors.licensesNeeded = 'Licenses needed is required.' + unless formValues.message formErrors.message = 'Message required.' @state.set({ formErrors, formValues, sendingState: 'standby' }) return unless _.isEmpty(formErrors) - + @state.set('sendingState', 'sending') - data = _.extend({ country: me.get('country'), recipientID: 'schools@codecombat.com', enrollmentsNeeded: @enrollmentsNeeded }, formValues) + data = _.extend({ country: me.get('country'), recipientID: 'schools@codecombat.com' }, formValues) contact.send({ data context: @ success: -> @state.set({ sendingState: 'sent' }) me.set('enrollmentRequestSent', true) - setTimeout(=> + setTimeout(=> @hide?() , 3000) error: -> @state.set({ sendingState: 'error' }) diff --git a/server/routes/contact.coffee b/server/routes/contact.coffee index 651639bcb..f391a9050 100644 --- a/server/routes/contact.coffee +++ b/server/routes/contact.coffee @@ -25,11 +25,11 @@ module.exports.setup = (app) -> createMailContent = (req, fromAddress, done) -> country = req.body.country - enrollmentsNeeded = req.body.enrollmentsNeeded + licensesNeeded = req.body.licensesNeeded message = req.body.message user = req.user subject = switch - when enrollmentsNeeded then "#{enrollmentsNeeded} Licenses needed for #{fromAddress}" + when licensesNeeded then "#{licensesNeeded} Licenses needed for #{fromAddress}" when req.body.subject then req.body.subject else "Contact Us Form: #{fromAddress}" level = if user?.get('points') > 0 then Math.floor(5 * Math.log((1 / 100) * (user.get('points') + 100))) + 1 else 0 diff --git a/test/app/views/courses/EnrollmentsView.spec.coffee b/test/app/views/courses/EnrollmentsView.spec.coffee index 75ba21deb..52c91a6e1 100644 --- a/test/app/views/courses/EnrollmentsView.spec.coffee +++ b/test/app/views/courses/EnrollmentsView.spec.coffee @@ -66,16 +66,6 @@ describe 'EnrollmentsView', -> fail('There should be an #action-col, other tests depend on it.') describe '"Get Licenses" area', -> - - describe '"Contact Us" button', -> - it 'opens a TeachersContactModal, passing in the number of licenses', -> - spyOn(@view, 'openModalView') - @view.state.set('numberOfStudents', 20) - @view.$('#contact-us-btn').click() - expect(view.openModalView).toHaveBeenCalled() - args = view.openModalView.calls.argsFor(0) - expect(args[0] instanceof TeachersContactModal).toBe(true) - expect(args[0].enrollmentsNeeded).toBe(20) describe 'when the teacher has made contact', -> beforeEach -> diff --git a/test/app/views/courses/TeachersContactModal.spec.coffee b/test/app/views/courses/TeachersContactModal.spec.coffee index 69552323e..0750b74f9 100644 --- a/test/app/views/courses/TeachersContactModal.spec.coffee +++ b/test/app/views/courses/TeachersContactModal.spec.coffee @@ -4,18 +4,28 @@ factories = require 'test/app/factories' describe 'TeachersContactModal', -> beforeEach (done) -> - @modal = new TeachersContactModal({ enrollmentsNeeded: 10 }) + @modal = new TeachersContactModal() @modal.render() trialRequests = new TrialRequests([factories.makeTrialRequest()]) @modal.trialRequests.fakeRequests[0].respondWith({ status: 200, responseText: trialRequests.stringify() }) @modal.supermodel.once('loaded-all', done) jasmine.demoModal(@modal) + it 'shows an error when the name is empty and the form is submitted', -> + @modal.$('input[name="name"]').val('') + @modal.$('form').submit() + expect(@modal.$('input[name="name"]').closest('.form-group').hasClass('has-error')).toBe(true) + it 'shows an error when the email is invalid and the form is submitted', -> @modal.$('input[name="email"]').val('not an email') @modal.$('form').submit() expect(@modal.$('input[name="email"]').closest('.form-group').hasClass('has-error')).toBe(true) + it 'shows an error when licensesNeeded is not > 0 and the form is submitted', -> + @modal.$('input[name="licensesNeeded"]').val('') + @modal.$('form').submit() + expect(@modal.$('input[name="licensesNeeded"]').closest('.form-group').hasClass('has-error')).toBe(true) + it 'shows an error when the message is empty and the form is submitted', -> @modal.$('textarea[name="message"]').val('') @modal.$('form').submit()