diff --git a/app/core/Router.coffee b/app/core/Router.coffee index 11a6ce09d..624cdc67f 100644 --- a/app/core/Router.coffee +++ b/app/core/Router.coffee @@ -123,9 +123,15 @@ module.exports = class CocoRouter extends Backbone.Router 'schools': go('NewHomeView') 'teachers': go('NewHomeView') - 'teachers/freetrial': go('RequestQuoteView') - 'teachers/quote': go('RequestQuoteView') - 'teachers/demo': go('RequestQuoteView') + 'teachers/demo': go('teachers/RequestQuoteView') + 'teachers/freetrial': go('teachers/RequestQuoteView') + 'teachers/quote': go('teachers/RequestQuoteView') + 'teachers/signup': -> + return @routeDirectly('teachers/CreateTeacherAccountView', []) if me.isAnonymous() + @navigate('/teachers/convert', {trigger: true, replace: true}) + 'teachers/convert': -> + return @navigate('/teachers/signup', {trigger: true, replace: true}) if me.isAnonymous() + @routeDirectly('teachers/ConvertToTeacherAccountView', []) 'test(/*subpath)': go('TestView') @@ -228,3 +234,6 @@ module.exports = class CocoRouter extends Backbone.Router navigate: (fragment, options) -> super fragment, options Backbone.Mediator.publish 'router:navigated', route: fragment + + reload: -> + document.location.reload() \ No newline at end of file diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 1d9e86963..bce888537 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -295,6 +295,7 @@ subject: "Subject" email: "Email" password: "Password" + confirm_password: "Confirm Password" message: "Message" code: "Code" ladder: "Ladder" @@ -313,6 +314,9 @@ warrior: "Warrior" ranger: "Ranger" wizard: "Wizard" + first_name: "First Name" + last_name: "Last Name" + username: "Username" units: second: "second" @@ -766,6 +770,7 @@ phone_number_help: "Where can we reach you during the workday?" role_label: "Your role" role_help: "Select your primary role." + role_default: "Select Role" tech_coordinator: "Technology coordinator" advisor: "Advisor" principal: "Principal" @@ -776,6 +781,7 @@ state: "State" country: "Country" num_students_help: "How many do you anticipate enrolling in CodeCombat?" + num_students_default: "Select Range" education_level_label: "Education Level of Students" education_level_help: "Choose as many as apply." elementary_school: "Elementary School" @@ -784,10 +790,18 @@ middle_school: "Middle School" college_plus: "College or higher" anything_else: "Anything else we should know?" - thanks_header: "Thanks for requesting a demo!" - thanks_p: "We'll be in touch soon. Questions? Email us:" - thanks_anon: "Log in or create an account to set up a class, add your students, and monitor their progress as they learn computer science." - thanks_logged_in: "Set up a class, add your students, and monitor their progress as they learn computer science." + thanks_header: "Request Received!" # {change} + thanks_sub_header: "Thanks for expressing interest in CodeCombat for your school." + thanks_p: "We'll be in touch soon! If you need to get in contact, you can reach us at:" # {change} + finish_signup: "Finish creating your teacher account:" + finish_signup_p: "Create an account to set up a class, add your students, and monitor their progress as they learn computer science." + signup_with: "Sign up with:" + conversion_warning: "WARNING: Your current account is a Student Account. Once you submit this form, your account will be converted into a Teacher Account." + learn_more_modal: "Teacher accounts on CodeCombat have the ability to monitor student progress, assign enrollments and manage classrooms. Teacher accounts cannot be a part of a classroom - if you are currently enrolled in a class using this account, you will no longer be able to access it once you convert to a Teacher Account." + create_account: "Create a Teacher Account" + create_account_subtitle: "Get access to teacher-only tools for using CodeCombat in the classroom. Set up a class, add your students, and monitor their progress!" + convert_account_title: "Convert to Teacher Account" + not: "Not" setup_a_class: "Set Up a Class" versions: @@ -1674,4 +1688,4 @@ one_month_coupon: "coupon: choose either Rails or HTML" one_month_discount: "discount, 30% off: choose either Rails or HTML" license: "license" - oreilly: "ebook of your choice" + oreilly: "ebook of your choice" \ No newline at end of file diff --git a/app/models/User.coffee b/app/models/User.coffee index 9514092c2..dfcbd89e3 100644 --- a/app/models/User.coffee +++ b/app/models/User.coffee @@ -59,8 +59,10 @@ module.exports = class User extends CocoModel isEmailSubscriptionEnabled: (name) -> (@get('emails') or {})[name]?.enabled + isStudent: -> @get('role') is 'student' + isTeacher: -> - return @get('role') in ['teacher', 'technology coordinator', 'advisor', 'principal', 'superintendent'] + return @get('role') in ['teacher', 'technology coordinator', 'advisor', 'principal', 'superintendent', 'parent'] setRole: (role, force=false) -> return if me.isAdmin() diff --git a/app/styles/style-flat.sass b/app/styles/style-flat.sass index 3bf3c5955..b1fbe47ea 100644 --- a/app/styles/style-flat.sass +++ b/app/styles/style-flat.sass @@ -215,6 +215,18 @@ $forest: #20572B .btn-lg font-size: 18px + .btn-gplus + color: white + background-color: #DD4B39 + img + height: 22px + + .btn-facebook + color: white + background-color: #3B5998 + img + height: 22px + // Classes .text-navy diff --git a/app/styles/request-quote-view.sass b/app/styles/teachers/request-quote-view.sass similarity index 56% rename from app/styles/request-quote-view.sass rename to app/styles/teachers/request-quote-view.sass index 9749a4752..f00405168 100644 --- a/app/styles/request-quote-view.sass +++ b/app/styles/teachers/request-quote-view.sass @@ -1,12 +1,15 @@ +@import "app/styles/mixins" +@import "app/styles/bootstrap/variables" + #request-quote-view #site-content-area - //TODO: Maybe this should go in style-flat - margin: 50px 10px 100px + margin: 50px 0 100px + .row + margin: 20px 0 + + #conversion-warning + margin-top: 20px - .section - margin-top: 80px - margin-bottom: 50px - .form-group label margin-bottom: 0 @@ -34,5 +37,15 @@ #submit-request-btn margin-left: 10px - #login-btn - margin-right: 10px \ No newline at end of file + // After submit (anonymous) + + h5 + margin-top: 50px + + #social-network-signups + margin: 20px 0 + button + margin-left: 10px + + .text-h1 + margin: 40px 0 30px diff --git a/app/templates/base-flat.jade b/app/templates/base-flat.jade index 1ca69b21b..cc5519bae 100644 --- a/app/templates/base-flat.jade +++ b/app/templates/base-flat.jade @@ -58,12 +58,15 @@ a(href="/user/#{me.getSlugOrID()}", data-i18n="nav.profile") li a(href="/account/settings", data-i18n="play.settings") - li - a(href="/account/payments", data-i18n="account.payments") - li - a(href="/account/subscription", data-i18n="account.subscription") - li - a(href="/account/prepaid", data-i18n="account.prepaid_codes") + unless me.isStudent() + li + a(href="/account/payments", data-i18n="account.payments") + unless me.isTeacher() || me.isStudent() + li + a(href="/account/subscription", data-i18n="account.subscription") + unless me.isStudent() + li + a(href="/account/prepaid", data-i18n="account.prepaid_codes") li a#logout-button(data-i18n="login.log_out") diff --git a/app/templates/base.jade b/app/templates/base.jade index fc1c31127..cd4780d7f 100644 --- a/app/templates/base.jade +++ b/app/templates/base.jade @@ -29,15 +29,18 @@ block header div.img-circle(style="background-image: url(#{me.getPhotoURL()})") h3=me.displayName() li - a(href="/user/#{me.getSlugOrID()}" data-i18n="nav.profile") + a(href="/user/#{me.getSlugOrID()}", data-i18n="nav.profile") li a(href="/account/settings", data-i18n="play.settings") - li - a(href="/account/payments", data-i18n="account.payments") - li - a(href="/account/subscription", data-i18n="account.subscription") - li - a(href="/account/prepaid", data-i18n="account.prepaid_codes") + unless me.isStudent() + li + a(href="/account/payments", data-i18n="account.payments") + unless me.isTeacher() || me.isStudent() + li + a(href="/account/subscription", data-i18n="account.subscription") + unless me.isStudent() + li + a(href="/account/prepaid", data-i18n="account.prepaid_codes") li a#logout-button(data-i18n="login.log_out") diff --git a/app/templates/courses/courses-view.jade b/app/templates/courses/courses-view.jade index aeff6c8bb..f564a5ac5 100644 --- a/app/templates/courses/courses-view.jade +++ b/app/templates/courses/courses-view.jade @@ -3,7 +3,7 @@ extends /templates/base block content h3.text-right if me.isAnonymous() - a(href="/teachers") + a(href="/teachers/signup") span(data-i18n="courses.teachers_click") span ! else diff --git a/app/templates/courses/purchase-courses-view.jade b/app/templates/courses/purchase-courses-view.jade index 1ee184029..214f9846e 100644 --- a/app/templates/courses/purchase-courses-view.jade +++ b/app/templates/courses/purchase-courses-view.jade @@ -88,4 +88,11 @@ block content strong Invalid number of students p.text-center - button#purchase-btn.btn.btn-lg.btn-success.uppercase(data-i18n="courses.purchase_now") + button#purchase-btn.btn.btn-lg.btn-success.uppercase(data-i18n="courses.purchase_now" disabled=me.isAnonymous()) + + if me.isAnonymous() + // DNT. Temporary redirect until teacher-dashboard is finished + .alert.alert-danger.text-center + h2 You must be signed up to purchase enrollments. + p + a.btn.btn-primary.btn-lg(href="/teachers/signup") Create a teacher account diff --git a/app/templates/editor/modal/confirm-modal.jade b/app/templates/editor/modal/confirm-modal.jade index 58f016311..c397a87c2 100644 --- a/app/templates/editor/modal/confirm-modal.jade +++ b/app/templates/editor/modal/confirm-modal.jade @@ -1,10 +1,10 @@ -extends /templates/core/modal-base +extends /templates/core/modal-base-flat block modal-header-content h3= view.title block modal-body-content - p= view.body + p!= view.body block modal-footer-content button.btn.btn-secondary#decline-button(type="button", data-dismiss="modal")= view.decline diff --git a/app/templates/new-home-view.jade b/app/templates/new-home-view.jade index 0f5706230..ca333e175 100644 --- a/app/templates/new-home-view.jade +++ b/app/templates/new-home-view.jade @@ -83,7 +83,7 @@ mixin box a.btn.btn-primary.btn-lg.btn-block(href="https://sites.google.com/a/codecombat.com/teacher-guides/course-guides", data-i18n="new_home.educator_wiki") else h6(data-i18n="new_home.want_coco") - button.teacher-btn.btn.btn-primary.btn-lg.btn-block(data-i18n="new_home.get_started") + a.btn.btn-primary.btn-lg.btn-block(href="/teachers/convert", data-i18n="new_home.get_started") else if view.justPlaysCourses() div diff --git a/app/templates/request-quote-view.jade b/app/templates/request-quote-view.jade deleted file mode 100644 index 10761b4c0..000000000 --- a/app/templates/request-quote-view.jade +++ /dev/null @@ -1,154 +0,0 @@ -extends /templates/base-flat - -block content - .container - form.form(class=view.trialRequest.isNew() ? '' : 'hide') - h3.text-center(data-i18n="teachers_quote.title") - h4.text-center(data-i18n="[html]teachers_quote.subtitle") - - #form-teacher-info.section - .row - .col-sm-offset-2.col-sm-4 - .form-group - label.control-label(data-i18n="general.name") - - var name = me.get('name') || ''; - input.form-control(name="name" value=name, disabled=!!name) - - .col-sm-4 - #email-form-group.form-group - label.control-label(data-i18n="general.email") - - var email = me.get('email') || ''; - input.form-control(name="email" type="email", value=email, disabled=!!email) - - - .row - .col-sm-offset-2.col-sm-4 - .form-group - label.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") - - .col-sm-4 - .form-group - label.control-label(data-i18n="teachers_quote.role_label") - .help-block.small - em.text-info(data-i18n="teachers_quote.role_help") - select.form-control(name="role") - option - option(data-i18n="courses.teacher", value="Teacher") - option(data-i18n="teachers_quote.tech_coordinator", value="Technology coordinator") - option(data-i18n="teachers_quote.advisor", value="Advisor") - option(data-i18n="teachers_quote.principal", value="Principal") - option(data-i18n="teachers_quote.superintendent", value="Superintendent") - option(data-i18n="teachers_quote.parent", value="Parent") - - #form-school-info.section - .row - .col-sm-offset-2.col-sm-4 - .form-group - label.control-label(data-i18n="teachers_quote.organization_label") - input.form-control(name="organization") - - .col-sm-4 - .form-group - label.control-label(data-i18n="teachers_quote.city") - input.form-control(name="city") - - .row - .col-sm-offset-2.col-sm-4 - .form-group - label.control-label(data-i18n="teachers_quote.state") - input.form-control(name="state") - - .col-sm-4 - .form-group - label.control-labellabel.control-label(data-i18n="teachers_quote.country") - input.form-control(name="country") - - #form-students-info.section - .row - .col-sm-offset-2.col-sm-5 - .form-group - label.control-label(data-i18n="courses.number_students") - .help-block.small - em.text-info(data-i18n="teachers_quote.num_students_help") - select.form-control(name="numStudents") - option - option 1-10 - option 11-50 - option 51-100 - option 101-200 - option 201-500 - option 501-1000 - option 1000+ - - .form-group - - .row - .col-sm-offset-2.col-sm-4 - label.control-label(data-i18n="teachers_quote.education_level_label") - .help-block.small - em.text-info(data-i18n="teachers_quote.education_level_help") - - .row - .col-sm-offset-2.col-sm-2 - label.control-label.checkbox - input(type="checkbox" name="educationLevel" value="Elementary") - span(data-i18n="teachers_quote.elementary_school") - .col-sm-2 - label.control-label.checkbox - input(type="checkbox" name="educationLevel" value="High") - span(data-i18n="teachers_quote.high_school") - .col-sm-2 - label.control-label.checkbox - input(type="checkbox" name="educationLevel" value="Middle") - span(data-i18n="teachers_quote.middle_school") - .col-sm-2 - label.control-label.checkbox - input(type="checkbox" name="educationLevel" value="College+") - span(data-i18n="teachers_quote.college_plus") - - .row - .col-sm-offset-2.col-sm-6 - // Other field uses custom logic, so no name field is included in either input. - // That way the forms library ignores it. - .form-group - label.control-label.checkbox - input#other-education-level-checkbox(type="checkbox") - span(data-i18n="nav.other") - | - span(data-i18n="teachers_quote.please_explain") - input#other-education-level-input.form-control - - #anything-else-row.section - .row - .col-sm-offset-2.col-sm-8 - label.control-label - span(data-i18n="teachers_quote.anything_else") - span.spl.text-muted(data-i18n="signup.optional") - - textarea.form-control(rows=8, name="notes") - - #buttons-row.row.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=view.trialRequest.isNew() ? 'hide' : '') - h3.text-center(data-i18n="teachers_quote.thanks_header") - p.text-center - span.spr(data-i18n="teachers_quote.thanks_p") - a.spl(href="mailto:team@codecombat.com") team@codecombat.com - - if me.isAnonymous() - p.text-center(data-i18n="teachers_quote.thanks_anon") - - p.text-center - button#login-btn.btn.btn-info(data-i18n="login.log_in") - button#signup-btn.btn.btn-info(data-i18n="login.sign_up") - else - p.text-center(data-i18n="teachers_quote.thanks_logged_in") - div - a.btn.btn-primary.btn-lg(href="/courses/teachers", data-i18n="teachers_quote.setup_a_class") diff --git a/app/templates/teachers/convert-to-teacher-account-view.jade b/app/templates/teachers/convert-to-teacher-account-view.jade new file mode 100644 index 000000000..1a24be1ea --- /dev/null +++ b/app/templates/teachers/convert-to-teacher-account-view.jade @@ -0,0 +1,152 @@ +extends /templates/base-flat +block content + + #learn-more-modal.modal.fade + .modal-dialog.modal-sm + .modal-content.style-flat + .modal-header + .button.close(type="button", data-dismiss="modal", aria-hidden="true") × + .modal-body(data-i18n="teachers_quote.learn_more_modal") + + .container + form + .row.text-center + .col-md-offset-2.col-md-8 + h3.m-t-3(data-i18n="teachers_quote.convert_account_title") + h4(data-i18n="[html]teachers_quote.create_account_subtitle") + .alert.alert-info.m-y-2 + div + span.spr(data-i18n="teachers_quote.not") + strong= me.broadName() + | ? + a.spl#logout-link(data-i18n="login.log_out") + if me.get('role') === 'student' + div#conversion-warning.m-t-2 + span.spr(data-i18n="[html]teachers_quote.conversion_warning") + a(data-i18n="new_home.learn_more" data-toggle="modal" data-target="#learn-more-modal") + + .row.m-y-2 + .col-md-offset-2.col-md-4.col-sm-6 + .form-group + label.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") + input.form-control(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") + 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") + 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(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") + + .col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="teachers_quote.role_label") + .help-block.small + em.text-info(data-i18n="teachers_quote.role_help") + select.form-control(name="role") + option(data-i18n="teachers_quote.role_default", , value='') + option(data-i18n="courses.teacher", value="Teacher") + option(data-i18n="teachers_quote.tech_coordinator", value="Technology coordinator") + option(data-i18n="teachers_quote.advisor", value="Advisor") + option(data-i18n="teachers_quote.principal", value="Principal") + option(data-i18n="teachers_quote.superintendent", value="Superintendent") + option(data-i18n="teachers_quote.parent", value="Parent") + + #form-school-info + .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") + input.form-control(name="organization") + + .col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="teachers_quote.city") + input.form-control(name="city") + + .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") + + .col-md-4.col-sm-6 + .form-group + label.control-labellabel.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_students") + .help-block.small + em.text-info(data-i18n="teachers_quote.num_students_help") + select.form-control(name="numStudents") + option(data-i18n="teachers_quote.num_students_default", value='') + option 1-10 + option 11-50 + option 51-100 + option 101-200 + option 201-500 + option 501-1000 + option 1000+ + + .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 + .checkbox + label + input(type="checkbox" name="educationLevel" value="Elementary") + span(data-i18n="teachers_quote.elementary_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="High") + span(data-i18n="teachers_quote.high_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="Middle") + span(data-i18n="teachers_quote.middle_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="College+") + span(data-i18n="teachers_quote.college_plus") + .checkbox + label + input#other-education-level-checkbox(type="checkbox") + span(data-i18n="nav.other").spr + span(data-i18n="teachers_quote.please_explain") + input#other-education-level-input.form-control + + #anything-else-row.row.m-y-2 + .col-md-offset-2.col-md-8 + label.control-label + span(data-i18n="teachers_quote.anything_else") + span.spl.text-muted(data-i18n="signup.optional") + textarea.form-control(rows=8, name="notes") + #buttons-row.row.m-y-2.text-center + input#create-account-btn.btn.btn-lg.btn-primary(type="submit" data-i18n="[value]teachers_quote.convert_account_title") + diff --git a/app/templates/teachers/create-teacher-account-view.jade b/app/templates/teachers/create-teacher-account-view.jade new file mode 100644 index 000000000..6bc0e7b28 --- /dev/null +++ b/app/templates/teachers/create-teacher-account-view.jade @@ -0,0 +1,172 @@ +extends /templates/base-flat + +block content + .container + form + .row.text-center + .col-md-offset-2.col-md-8 + h3.m-t-3(data-i18n="teachers_quote.create_account") + h4(data-i18n="[html]teachers_quote.create_account_subtitle") + .alert.alert-info.m-y-2 + span.spr(data-i18n="signup.login_switch") + a.login-link(data-i18n="login.log_in") + #social-network-signups.m-y-2 + button#facebook-signup-btn.btn.btn-facebook.btn-lg.m-x-1 + span.spr(data-i18n="teachers_quote.signup_with") + | Facebook + img.m-l-1(src='/images/pages/community/logo_facebook.png') + + button#gplus-signup-btn.btn.btn-gplus.btn-lg.spr + span.spr(data-i18n="teachers_quote.signup_with") + | G+ + img.m-l-1(src='/images/pages/community/logo_g+.png') + + #gplus-logged-in-row.row.text-center.hide + .col-md-offset-2.col-md-8 + h2(data-i18n="signup.connected_gplus_header") + p(data-i18n="signup.connected_gplus_p") + #facebook-logged-in-row.row.text-center.hide + .col-md-offset-2.col-md-8 + h2(data-i18n="signup.connected_facebook_header") + p(data-i18n="signup.connected_facebook_p") + + + .row.m-y-2 + .col-md-offset-2.col-md-4.col-sm-6 + .form-group + label.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") + 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") + input.form-control(name="firstName") + + .col-md-4.col-sm-6 + .form-group + label.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") + input.form-control(name="password1", type="password") + + .col-md-4.col-sm-6 + .form-group + label.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(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") + + .col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="teachers_quote.role_label") + .help-block.small + em.text-info(data-i18n="teachers_quote.role_help") + select.form-control(name="role") + option(data-i18n="teachers_quote.role_default", , value='') + option(data-i18n="courses.teacher", value="Teacher") + option(data-i18n="teachers_quote.tech_coordinator", value="Technology coordinator") + option(data-i18n="teachers_quote.advisor", value="Advisor") + option(data-i18n="teachers_quote.principal", value="Principal") + option(data-i18n="teachers_quote.superintendent", value="Superintendent") + option(data-i18n="teachers_quote.parent", value="Parent") + + #form-school-info + .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") + input.form-control(name="organization") + + .col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="teachers_quote.city") + input.form-control(name="city") + + .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") + + .col-md-4.col-sm-6 + .form-group + label.control-labellabel.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_students") + .help-block.small + em.text-info(data-i18n="teachers_quote.num_students_help") + select.form-control(name="numStudents") + option(data-i18n="teachers_quote.num_students_default", value='') + option 1-10 + option 11-50 + option 51-100 + option 101-200 + option 201-500 + option 501-1000 + option 1000+ + + .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 + .checkbox + label + input(type="checkbox" name="educationLevel" value="Elementary") + span(data-i18n="teachers_quote.elementary_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="High") + span(data-i18n="teachers_quote.high_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="Middle") + span(data-i18n="teachers_quote.middle_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="College+") + span(data-i18n="teachers_quote.college_plus") + .checkbox + label + input#other-education-level-checkbox(type="checkbox") + span(data-i18n="nav.other").spr + span(data-i18n="teachers_quote.please_explain") + input#other-education-level-input.form-control + + #anything-else-row.row.m-y-2 + .col-md-offset-2.col-md-8 + label.control-label + span(data-i18n="teachers_quote.anything_else") + span.spl.text-muted(data-i18n="signup.optional") + + textarea.form-control(rows=8, name="notes") + + #buttons-row.row.m-y-2.text-center + input#create-account-btn.btn.btn-lg.btn-primary(type="submit" data-i18n="[value]teachers_quote.create_account") diff --git a/app/templates/teachers/request-quote-view.jade b/app/templates/teachers/request-quote-view.jade new file mode 100644 index 000000000..5385fa24a --- /dev/null +++ b/app/templates/teachers/request-quote-view.jade @@ -0,0 +1,219 @@ +extends /templates/base-flat + +block content + - var showDone = !view.trialRequest.isNew() && me.isAnonymous(); + + #learn-more-modal.modal.fade + .modal-dialog.modal-sm + .modal-content.style-flat + .modal-header + .button.close(type="button", data-dismiss="modal", aria-hidden="true") × + .modal-body(data-i18n="teachers_quote.learn_more_modal") + + .container + form#request-form(class=showDone ? 'hide' : '') + .row + .col-md-offset-2.col-md-8 + h3.text-center(data-i18n="teachers_quote.title") + h4.text-center(data-i18n="[html]teachers_quote.subtitle") + + if !me.isAnonymous() + .row + .col-md-offset-2.col-md-8 + .alert.alert-info.text-center + div + span.spr(data-i18n="teachers_quote.not") + strong= me.broadName() + | ? + a.spl#logout-link(data-i18n="login.log_out") + if me.get('role') === 'student' + div#conversion-warning + span.spr(data-i18n="[html]teachers_quote.conversion_warning") + a(data-i18n="new_home.learn_more" data-toggle="modal" data-target="#learn-more-modal") + + #form-teacher-info + if !me.isAnonymous() + .row + .col-md-offset-2.col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="general.username") + - var name = me.get('name') || ''; + input.form-control(name="name" value=name, disabled=!!name) + + .col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="general.email") + - 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") + - 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") + - var lastName = me.get('lastName') || ''; + input.form-control(name="lastName" value=lastName, disabled=!!lastName) + + 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") + - var email = me.get('email') || ''; + input.form-control(name="email" type="email", value=email, disabled=!!email) + + .row + .col-md-offset-2.col-md-4.col-sm-6 + .form-group + label.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") + + .col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="teachers_quote.role_label") + .help-block.small + em.text-info(data-i18n="teachers_quote.role_help") + select.form-control(name="role") + option(data-i18n="teachers_quote.role_default", , value='') + option(data-i18n="courses.teacher", value="Teacher") + option(data-i18n="teachers_quote.tech_coordinator", value="Technology coordinator") + option(data-i18n="teachers_quote.advisor", value="Advisor") + option(data-i18n="teachers_quote.principal", value="Principal") + option(data-i18n="teachers_quote.superintendent", value="Superintendent") + option(data-i18n="teachers_quote.parent", value="Parent") + + #form-school-info + .row + .col-md-offset-2.col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="teachers_quote.organization_label") + input.form-control(name="organization") + + .col-md-4.col-sm-6 + .form-group + label.control-label(data-i18n="teachers_quote.city") + input.form-control(name="city") + + .row + .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") + + .col-md-4.col-sm-6 + .form-group + label.control-labellabel.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_students") + .help-block.small + em.text-info(data-i18n="teachers_quote.num_students_help") + select.form-control(name="numStudents") + option(data-i18n="teachers_quote.num_students_default", value='') + option 1-10 + option 11-50 + option 51-100 + option 101-200 + option 201-500 + option 501-1000 + option 1000+ + + .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 + .checkbox + label + input(type="checkbox" name="educationLevel" value="Elementary") + span(data-i18n="teachers_quote.elementary_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="High") + span(data-i18n="teachers_quote.high_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="Middle") + span(data-i18n="teachers_quote.middle_school") + .checkbox + label + input(type="checkbox" name="educationLevel" value="College+") + span(data-i18n="teachers_quote.college_plus") + .checkbox + label + input#other-education-level-checkbox(type="checkbox") + span(data-i18n="nav.other").spr + span(data-i18n="teachers_quote.please_explain") + input#other-education-level-input.form-control + + #anything-else-row.row + .col-md-offset-2.col-md-8 + label.control-label + span(data-i18n="teachers_quote.anything_else") + span.spl.text-muted(data-i18n="signup.optional") + + textarea.form-control(rows=8, name="notes") + + #buttons-row.row.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') + h3(data-i18n="teachers_quote.thanks_header") + h4(data-i18n="teachers_quote.thanks_sub_header") + p + span.spr(data-i18n="teachers_quote.thanks_p") + a.spl(href="mailto:team@codecombat.com") team@codecombat.com + + if me.isAnonymous() + h5(data-i18n="teachers_quote.finish_signup") + p(data-i18n="teachers_quote.finish_signup_p") + + #social-network-signups + span(data-i18n="teachers_quote.signup_with") + button#facebook-signup-btn.btn.btn-facebook.btn-lg.m-x-1 + span.spr(data-i18n="teachers_quote.signup_with") + | Facebook + img.m-l-1(src='/images/pages/community/logo_facebook.png') + button#gplus-signup-btn.btn.btn-gplus.btn-lg.spr + span.spr(data-i18n="teachers_quote.signup_with") + | G+ + img.m-l-1(src='/images/pages/community/logo_g+.png') + + .text-h1.text-uppercase(data-i18n="general.or") + + form#signup-form.text-left + .row + .col-md-offset-2.col-md-4 + .form-group + label.control-label(data-i18n="general.name") + input.form-control(name="name") + + .row + .col-md-offset-2.col-md-4 + .form-group + label.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") + input.form-control(name="password2", type="password") + + .text-center + button.btn.btn-lg.btn-navy(data-i18n="login.sign_up") diff --git a/app/views/RequestQuoteView.coffee b/app/views/RequestQuoteView.coffee deleted file mode 100644 index 9542277fd..000000000 --- a/app/views/RequestQuoteView.coffee +++ /dev/null @@ -1,135 +0,0 @@ -RootView = require 'views/core/RootView' -forms = require 'core/forms' -TrialRequest = require 'models/TrialRequest' -TrialRequests = require 'collections/TrialRequests' -AuthModal = require 'views/core/AuthModal' -CreateAccountModal = require 'views/core/CreateAccountModal' -storage = require 'core/storage' - -formSchema = { - type: 'object' - required: ['name', 'email', 'organization', 'role', 'numStudents'] - properties: - name: { type: 'string', minLength: 1 } - email: { type: 'string', format: 'email' } - phoneNumber: { type: 'string' } - role: { type: 'string' } - organization: { type: 'string' } - city: { type: 'string' } - state: { type: 'string' } - country: { type: 'string' } - numStudents: { type: 'string' } - educationLevel: { - type: 'array' - items: { type: 'string' } - } - notes: { type: 'string' } -} - -module.exports = class RequestQuoteView extends RootView - id: 'request-quote-view' - template: require 'templates/request-quote-view' - - events: - 'change form': 'onChangeForm' - 'submit form': 'onSubmitForm' - 'click #login-btn': 'onClickLoginButton' - 'click #signup-btn': 'onClickSignupButton' - 'click #email-exists-login-link': 'onClickEmailExistsLoginLink' - - initialize: -> - @trialRequest = new TrialRequest() - @trialRequests = new TrialRequests() - @trialRequests.fetchOwn() - @supermodel.loadCollection(@trialRequests) - - onLoaded: -> - if @trialRequests.size() - @trialRequest = @trialRequests.first() - if @trialRequest and @trialRequest.get('status') isnt 'submitted' and @trialRequest.get('status') isnt 'approved' - window.tracker?.trackEvent 'View Trial Request', category: 'Teachers', label: 'View Trial Request', ['Mixpanel'] - super() - - afterRender: -> - super() - obj = storage.load('request-quote-form') - if obj - @$('#other-education-level-checkbox').attr('checked', obj.otherChecked) - @$('#other-education-level-input').val(obj.otherInput) - forms.objectToForm(@$('form'), obj) - - onChangeForm: -> - obj = forms.formToObject(@$('form')) - obj.otherChecked = @$('#other-education-level-checkbox').is(':checked') - obj.otherInput = @$('#other-education-level-input').val() - storage.save('request-quote-form', obj, 10) - - onSubmitForm: (e) -> - e.preventDefault() - form = @$('form') - attrs = forms.formToObject(form) - - # custom other input logic (also used in form local storage save/restore) - if @$('#other-education-level-checkbox').is(':checked') - attrs.educationLevel.push(@$('#other-education-level-input').val()) - - forms.clearFormAlerts(form) - result = tv4.validateMultiple(attrs, formSchema) - error = true - if not result.valid - forms.applyErrorsToForm(form, result.errors) - else if not /^.+@.+\..+$/.test(attrs.email) - forms.setErrorToProperty(form, 'email', 'Invalid email.') - else if not _.size(attrs.educationLevel) - return forms.setErrorToProperty(form, 'educationLevel', 'Check at least one.') - else - error = false - if error - forms.scrollToFirstError() - return - @trialRequest = new TrialRequest({ - type: 'course' - properties: attrs - }) - @trialRequest.notyErrors = false - @$('#submit-request-btn').text('Sending').attr('disabled', true) - @trialRequest.save() - @trialRequest.on 'sync', @onTrialRequestSubmit, @ - @trialRequest.on 'error', @onTrialRequestError, @ - me.setRole attrs.role.toLowerCase(), true - - onTrialRequestError: (model, jqxhr) -> - if jqxhr.status is 409 - userExists = $.i18n.t('teachers_quote.email_exists') - logIn = $.i18n.t('login.log_in') - @$('#email-form-group') - .addClass('has-error') - .append($("
#{$.i18n.t('teachers_quote.conversion_warning')}
#{$.i18n.t('teachers_quote.learn_more_modal')}
" + confirm: $.i18n.t('common.continue') + decline: $.i18n.t('common.cancel') + }) + @openModalView(modal) + modal.once 'confirm', @saveTrialRequest, @ + else + @saveTrialRequest() + + saveTrialRequest: -> + @trialRequest.notyErrors = false + @$('#create-account-btn').text('Sending').attr('disabled', true) + @trialRequest.save() + @trialRequest.on 'sync', @onTrialRequestSubmit, @ + @trialRequest.on 'error', @onTrialRequestError, @ + + onTrialRequestError: (model, jqxhr) -> + @$('#submit-request-btn').text('Submit').attr('disabled', false) + errors.showNotyNetworkError(arguments...) + + onTrialRequestSubmit: -> + me.setRole @trialRequest.get('properties').role.toLowerCase(), true + storage.remove(FORM_KEY) + application.router.navigate('/courses/teachers', {trigger: true}) + +formSchema = { + type: 'object' + required: ['firstName', 'lastName', 'organization', 'role', 'numStudents'] + properties: + firstName: { type: 'string' } + lastName: { type: 'string' } + phoneNumber: { type: 'string' } + role: { type: 'string' } + organization: { type: 'string' } + city: { type: 'string' } + state: { type: 'string' } + country: { type: 'string' } + numStudents: { type: 'string' } + educationLevel: { + type: 'array' + items: { type: 'string' } + } + notes: { type: 'string' } +} diff --git a/app/views/teachers/CreateTeacherAccountView.coffee b/app/views/teachers/CreateTeacherAccountView.coffee new file mode 100644 index 000000000..cee2b24aa --- /dev/null +++ b/app/views/teachers/CreateTeacherAccountView.coffee @@ -0,0 +1,264 @@ +RootView = require 'views/core/RootView' +forms = require 'core/forms' +TrialRequest = require 'models/TrialRequest' +TrialRequests = require 'collections/TrialRequests' +AuthModal = require 'views/core/AuthModal' +storage = require 'core/storage' +errors = require 'core/errors' +User = require 'models/User' + +FORM_KEY = 'request-quote-form' +SIGNUP_REDIRECT = '/courses/teachers' + +module.exports = class CreateTeacherAccountView extends RootView + id: 'create-teacher-account-view' + template: require 'templates/teachers/create-teacher-account-view' + + events: + 'click .login-link': 'onClickLoginLink' + 'change form': 'onChangeForm' + 'submit form': 'onSubmitForm' + 'click #gplus-signup-btn': 'onClickGPlusSignupButton' + 'click #facebook-signup-btn': 'onClickFacebookSignupButton' + + initialize: -> + @trialRequest = new TrialRequest() + @trialRequests = new TrialRequests() + @trialRequests.fetchOwn() + @supermodel.trackCollection(@trialRequests) + + onLoaded: -> + if @trialRequests.size() + @trialRequest = @trialRequests.first() + if @trialRequest and @trialRequest.get('status') isnt 'submitted' and @trialRequest.get('status') isnt 'approved' + window.tracker?.trackEvent 'View Trial Request', category: 'Teachers', label: 'View Trial Request', ['Mixpanel'] + super() + + afterRender: -> + super() + + # apply existing trial request on form + properties = @trialRequest.get('properties') + if properties + forms.objectToForm(@$('form'), properties) + commonLevels = _.map @$('[name="educationLevel"]'), (el) -> $(el).val() + submittedLevels = properties.educationLevel or [] + otherLevel = _.first(_.difference(submittedLevels, commonLevels)) or '' + @$('#other-education-level-checkbox').attr('checked', !!otherLevel) + @$('#other-education-level-input').val(otherLevel) + + # apply changes from local storage + obj = storage.load(FORM_KEY) + if obj + @$('#other-education-level-checkbox').attr('checked', obj.otherChecked) + @$('#other-education-level-input').val(obj.otherInput) + forms.objectToForm(@$('form'), obj, { overwriteExisting: true }) + + onClickLoginLink: -> + modal = new AuthModal({ initialValues: { email: @trialRequest.get('properties')?.email } }) + @openModalView(modal) + + onChangeRequestForm: -> + # Local storage is being used to store the contents of the form whenever it changes, + # and filling in the stored values if the page is reloaded or navigated away from and returned to. + # save changes to local storage + obj = forms.formToObject(@$('form')) + obj.otherChecked = @$('#other-education-level-checkbox').is(':checked') + obj.otherInput = @$('#other-education-level-input').val() + storage.save(FORM_KEY, obj, 10) + + 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') + + 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.') + error = true + if not _.size(trialRequestAttrs.educationLevel) + forms.setErrorToProperty(form, 'educationLevel', 'Include at least one.') + error = true + unless @gplusAttrs or @facebookAttrs + if not allAttrs.password1 + forms.setErrorToProperty(form, 'password1', 'Required field') + error = true + else if not allAttrs.password2 + forms.setErrorToProperty(form, 'password2', 'Required field') + error = true + else if allAttrs.password1 isnt allAttrs.password2 + forms.setErrorToProperty(form, 'password1', 'Password fields are not equivalent') + error = true + if error + forms.scrollToFirstError() + return + @trialRequest = new TrialRequest({ + type: 'course' + properties: trialRequestAttrs + }) + @trialRequest.notyErrors = false + @$('#create-account-btn').text('Sending').attr('disabled', true) + @trialRequest.save() + @trialRequest.on 'sync', @onTrialRequestSubmit, @ + @trialRequest.on 'error', @onTrialRequestError, @ + + onTrialRequestError: (model, jqxhr) -> + @$('#create-account-btn').text('Submit').attr('disabled', false) + if jqxhr.status is 409 + userExists = $.i18n.t('teachers_quote.email_exists') + logIn = $.i18n.t('login.log_in') + @$('#email-form-group') + .addClass('has-error') + .append($("#{$.i18n.t('teachers_quote.conversion_warning')}
#{$.i18n.t('teachers_quote.learn_more_modal')}
" + confirm: $.i18n.t('common.continue') + decline: $.i18n.t('common.cancel') + }) + @openModalView(modal) + modal.once 'confirm', @saveTrialRequest, @ + else + @saveTrialRequest() + + saveTrialRequest: -> + @trialRequest.notyErrors = false + @$('#submit-request-btn').text('Sending').attr('disabled', true) + @trialRequest.save() + @trialRequest.on 'sync', @onTrialRequestSubmit, @ + @trialRequest.on 'error', @onTrialRequestError, @ + + onTrialRequestError: (model, jqxhr) -> + @$('#submit-request-btn').text('Submit').attr('disabled', false) + if jqxhr.status is 409 + userExists = $.i18n.t('teachers_quote.email_exists') + logIn = $.i18n.t('login.log_in') + @$('#email-form-group') + .addClass('has-error') + .append($("