diff --git a/app/assets/main.html b/app/assets/main.html index 717b8985b..bda9da542 100644 --- a/app/assets/main.html +++ b/app/assets/main.html @@ -38,15 +38,6 @@ ga('create', 'UA-39724129-1', 'auto'); </script> - <!-- Errorception --> - <script> - (function(_,e,rr,s){_errs=[s];var c=_.onerror;_.onerror=function(){var a=arguments;_errs.push(a); - c&&c.apply(this,a)};var b=function(){var c=e.createElement(rr),b=e.getElementsByTagName(rr)[0]; - c.src="//beacon.errorception.com/"+s+".js";c.async=!0;b.parentNode.insertBefore(c,b)}; - _.addEventListener?_.addEventListener("load",b,!1):_.attachEvent("onload",b)}) - (window,document,"script","51a79585ee207206390002a2"); - </script> - <!-- Mixpanel --> <script type="text/javascript"> (function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]); diff --git a/app/core/services/algolia.coffee b/app/core/services/algolia.coffee new file mode 100644 index 000000000..10cbd50c5 --- /dev/null +++ b/app/core/services/algolia.coffee @@ -0,0 +1,5 @@ +client = algoliasearch("JJM5H2CHJR", "50382fc2f7fa69c67e8233ace7cd7c4c") + +module.exports = + client: client + schoolsIndex: client.initIndex('schools') diff --git a/app/styles/teachers/request-quote-view.sass b/app/styles/teachers/request-quote-view.sass index f00405168..f4c61da92 100644 --- a/app/styles/teachers/request-quote-view.sass +++ b/app/styles/teachers/request-quote-view.sass @@ -49,3 +49,48 @@ .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/templates/teachers/request-quote-view.jade b/app/templates/teachers/request-quote-view.jade index 8852838af..645771c77 100644 --- a/app/templates/teachers/request-quote-view.jade +++ b/app/templates/teachers/request-quote-view.jade @@ -96,7 +96,7 @@ block content .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") + input.form-control#organization-control(name="organization") .col-md-4.col-sm-6 .form-group @@ -170,6 +170,14 @@ block content span.spl.text-muted(data-i18n="signup.optional") textarea.form-control(rows=8, name="notes") + input(type="hidden" name="nces_id") + input(type="hidden" name="nces_name") + input(type="hidden" name="nces_district") + input(type="hidden" name="nces_district_id") + input(type="hidden" name="nces_district_schools") + input(type="hidden" name="nces_district_students") + input(type="hidden" name="nces_students") + input(type="hidden" name="phone") #buttons-row.row.text-center input#submit-request-btn.btn.btn-lg.btn-primary(type="submit" data-i18n="[value]teachers_quote.title") diff --git a/app/views/teachers/RequestQuoteView.coffee b/app/views/teachers/RequestQuoteView.coffee index 3316d5c6a..14065b9f7 100644 --- a/app/views/teachers/RequestQuoteView.coffee +++ b/app/views/teachers/RequestQuoteView.coffee @@ -6,9 +6,11 @@ AuthModal = require 'views/core/AuthModal' storage = require 'core/storage' errors = require 'core/errors' ConfirmModal = require 'views/editor/modal/ConfirmModal' +algolia = require 'core/services/algolia' FORM_KEY = 'request-quote-form' SIGNUP_REDIRECT = '/teachers' +NCES_KEYS = ['id', 'name', 'district', 'district_id', 'district_schools', 'district_students', 'students', 'phone'] module.exports = class RequestQuoteView extends RootView id: 'request-quote-view' @@ -18,6 +20,10 @@ module.exports = class RequestQuoteView extends RootView events: 'change #request-form': 'onChangeRequestForm' 'submit #request-form': 'onSubmitRequestForm' + 'change input[name="city"]': 'invalidateNCES' + 'change input[name="state"]': 'invalidateNCES' + 'change input[name="district"]': 'invalidateNCES' + 'change input[name="country"]': 'invalidateNCES' 'click #email-exists-login-link': 'onClickEmailExistsLoginLink' 'submit #signup-form': 'onSubmitSignupForm' 'click #logout-link': -> me.logout() @@ -36,10 +42,14 @@ module.exports = class RequestQuoteView extends RootView 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() - + + invalidateNCES: -> + for key in NCES_KEYS + @$('input[name="nces_' + key + '"]').val '' + afterRender: -> super() - + # apply existing trial request on form properties = @trialRequest.get('properties') if properties @@ -49,7 +59,7 @@ module.exports = class RequestQuoteView extends RootView 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 @@ -57,6 +67,31 @@ module.exports = class RequestQuoteView extends RootView @$('#other-education-level-input').val(obj.otherInput) forms.objectToForm(@$('#request-form'), obj, { overwriteExisting: true }) + $("#organization-control").autocomplete({hint: false}, [ + source: (query, callback) -> + algolia.schoolsIndex.search(query, { hitsPerPage: 5, aroundLatLngViaIP: false }).then (answer) -> + callback answer.hits + , -> + callback [] + displayKey: 'name', + templates: + suggestion: (suggestion) -> + hr = suggestion._highlightResult + "<div class='school'> #{hr.name.value} </div>" + + "<div class='district'>#{hr.district.value}, " + + "<span>#{hr.city?.value}, #{hr.state.value}</span></div>" + + ]).on 'autocomplete:selected', (event, suggestion, dataset) => + @$('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 + @$('input[name="nces_' + key + '"]').val suggestion[key] + + @onChangeRequestForm() + onChangeRequestForm: -> # save changes to local storage obj = forms.formToObject(@$('form')) @@ -68,12 +103,12 @@ module.exports = class RequestQuoteView extends RootView e.preventDefault() form = @$('#request-form') attrs = forms.formToObject(form) - + # custom other input logic (also used in form local storage save/restore) if @$('#other-education-level-checkbox').is(':checked') val = @$('#other-education-level-input').val() attrs.educationLevel.push(val) if val - + forms.clearFormAlerts(form) requestFormSchema = if me.isAnonymous() then requestFormSchemaAnonymous else requestFormSchemaLoggedIn result = tv4.validateMultiple(attrs, requestFormSchemaAnonymous) @@ -106,7 +141,7 @@ module.exports = class RequestQuoteView extends RootView modal.once 'confirm', @saveTrialRequest, @ else @saveTrialRequest() - + saveTrialRequest: -> @trialRequest.notyErrors = false @$('#submit-request-btn').text('Sending').attr('disabled', true) @@ -123,7 +158,7 @@ module.exports = class RequestQuoteView extends RootView .addClass('has-error') .append($("<div class='help-block error-help-block'>#{userExists} <a id='email-exists-login-link'>#{logIn}</a>")) forms.scrollToFirstError() - else + else errors.showNotyNetworkError(arguments...) onClickEmailExistsLoginLink: -> @@ -167,7 +202,7 @@ module.exports = class RequestQuoteView extends RootView }) }) }) - + onClickFacebookSignupButton: -> btn = @$('#facebook-signup-btn') btn.attr('disabled', true) @@ -212,7 +247,7 @@ module.exports = class RequestQuoteView extends RootView forms.setErrorToProperty(form, 'password1', 'Passwords do not match') error = true return if error - + me.set({ password: attrs.password1 name: attrs.name @@ -246,9 +281,12 @@ requestFormSchemaAnonymous = { type: 'array' items: { type: 'string' } } - notes: { type: 'string' } + notes: { type: 'string' }, } +for key in NCES_KEYS + requestFormSchemaAnonymous['nces_' + key] = type: 'string' + # same form, but add username input requestFormSchemaLoggedIn = _.cloneDeep(requestFormSchemaAnonymous) requestFormSchemaLoggedIn.required.push('name') diff --git a/bower.json b/bower.json index b75664929..46ec14996 100644 --- a/bower.json +++ b/bower.json @@ -49,9 +49,14 @@ "fastclick": "~1.0.3", "three.js": "~0.71.0", "lscache": "~1.0.5", - "esper.js": "http://files.codecombat.com/esper.tar.gz" + "esper.js": "http://files.codecombat.com/esper.tar.gz", + "algoliasearch": "^3.13.1", + "algolia-autocomplete.js": "^1.17.0" }, "overrides": { + "algolia-autocomplete.js": { + "main": "dist/autocomplete.jquery.js" + }, "backbone": { "main": "backbone.js" },