'use strict'; var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var LoginForm = (function (_React$Component) { _inherits(LoginForm, _React$Component); function LoginForm(props) { _classCallCheck(this, LoginForm); _get(Object.getPrototypeOf(LoginForm.prototype), 'constructor', this).call(this, props); var timezoneToCountryCode = {}; Object.keys(BFHTimezonesList).forEach(function (countryCode) { Object.keys(BFHTimezonesList[countryCode]).forEach(function (timezone) { timezoneToCountryCode[timezone] = countryCode; }); }); var timezone = jstz.determine().name(); var country = timezoneToCountryCode[timezone]; this.state = { tab: null, form: null, defaults: { timezone: timezone, country: country, phoneCountrySelected: country } }; } _createClass(LoginForm, [{ key: 'componentDidMount', value: function componentDidMount() { var _this = this; this.initializeInfo(); // NB: the LoginModal is _always_ mounted after the page loads // It is just hidden - this code runs only once per page load. if (this.props.referralCode) { CAMBLY.get('/verifyReferralCode', { referralCode: this.props.referralCode }).done(function (resp) { var newState = { referralCode: { valid: resp.valid, minutes: resp.minutes } }; if (!resp.valid) { newState['error'] = "Your invite is not valid."; } _this.setState(newState); }).fail(function () { return _this.setState({ referralCode: { valid: false } }); }); } if (window.location.hash) { var deviceTypeModal; var _ret = (function () { // Handle the cases when we're navigating from another page or link to login/passwordReset form var forms = ['login', 'signup', 'forgotPassword', 'resetPassword', 'referral', 'download']; var tab = window.location.hash.slice(1); deviceTypeModal = new UAParser().getDevice().type; // referral is a mobile only form, it just prompts the user to download the app. if (tab != 'referral' || deviceTypeModal == 'mobile') { if (forms.indexOf(tab) >= 0) { _this.setState(function (prevState) { return { tab: tab }; }); if (tab == 'referral') { if (new UAParser().getDevice().type != 'mobile') { return { v: undefined }; // for referrals, we'll only modal on mobile } } else if (tab == 'download') { _this.setState({ success: "You're subscribed!" }); } } } })(); if (typeof _ret === 'object') return _ret.v; } } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps() { this.initializeInfo(); } }, { key: 'initializeInfo', value: function initializeInfo() { // TODO: Add the login form tab to the redux state this.setTab(this.props.tab); var defaults = Object.assign({}, this.state.defaults); if (this.props.username) { defaults['username'] = this.props.username; this.setState({ defaults: defaults }); } } }, { key: 'setTab', value: function setTab(name) { this.setState({ tab: name, form: this.formTemplate(name), error: null, success: null }); } }, { key: 'formTemplate', value: function formTemplate(formName) { var _this2 = this; // Generates a template form for the tab. // This is called only when the tab is changed. var field = function field(type, name, placeholder) { return { type: type, name: name, placeholder: placeholder, value: _this2.props[name] || _this2.state.defaults[name] || '' }; }; var username = field('text', 'username', "Username"); var tutorUsername = Object.assign({}, username, { help: React.createElement("div", { className: "alert alert-info text-center" }, "Your username should be a first name and last name or initial.", React.createElement("br", null), " For your privacy, it can be different from your real name.", React.createElement("br", null), "Example: John D or John Doe") }); var email = field('text', 'email', 'Email Address'); var paypalEmail = field('text', 'paypalEmail', 'Paypal Email Address'); var usernameOrEmail = Object.assign({}, email, { placeholder: "Username or Email" }); var firstName = field('text', 'firstName', "First Name"); var lastName = field('text', 'lastName', "Last Name"); var dob = field('text', 'dob', 'Date of Birth (mm/dd/yyyy)'); var gender = Object.assign({}, field('select', 'gender', 'Gender'), { options: [{ value: 'm', text: "Male" }, { value: 'f', text: "Female" }, { value: 'other', text: "Not specified" }] }); var password = field('password', 'password', 'Password'); var confirmPassword = field('password', 'confirm', 'Confirm Password'); var phoneNumber = Object.assign({}, field('tel', 'phoneNumber'), { reference: function reference(r) { // Initialize phone number input $(r).intlTelInput({ utilsScript: "/static/intl-tel-input/js/utils.js?_=417a97bd596c60d54550392c18aae026", initialCountry: _this2.state.defaults.phoneCountrySelected, preferredCountries: [_this2.state.defaults.country || 'US'] }); $(r).on("countrychange", function (e, countryData) { _this2.setState({ defaults: Object.assign(_this2.state.defaults, { "phoneCountrySelected": countryData.iso2 }) }); }); } }); var referralCode = field(this.props.referralCode ? 'hidden' : 'text', 'referralCode', 'Referral Code'); var referralChannel = field('select', 'referralChannel'); var signIn = { type: 'submit', text: 'Sign In' }; var createAccount = { type: 'submit', text: 'Create Account' }; if (formName == 'login') { return [usernameOrEmail, password, Object.assign(signIn, { enabled: function enabled(f) { return f['email'] && f['password']; } })]; } else if (formName == 'signup') { // Country & Timezone always get passed as part of device registration // and as part of user creation so that we can validate phone numbers // These are computed when the component mounts. var country = field('hidden', 'country'); var timezone = field('hidden', 'timezone'); var fields = [country, timezone]; // common to all forms if (this.props.accountType == 'tutor') { var referringTutor = field('text', 'referringTutor', "Tutor that referred you (optional)"); var heardFrom = Object.assign(field('select', 'heardFrom', 'Where did you hear about Cambly?'), { options: window.HEARD_FROM_OPTIONS }); var heardFromOther = Object.assign(field('text', 'heardFromOther', 'Where did you hear about Cambly?'), { hidden: function hidden(f) { return f['heardFrom'] != 'Other'; } }); var nativeSpeaker = { type: 'checkbox', name: 'nativeSpeaker', label: 'I am a native English speaker' }; // We support adding accounts for all types; but, it's pretty // undiscoverable for students/tutors, and they'll likely // just create a new account. If we make it more discoverable, // it'll work out of the box. // TODO(gar): we could just check which fields are present in the // user, and ask them for missing fields if (cambly.AUTHENTICATED) { // Add Tutor Account fields = fields.concat([dob, referringTutor, heardFrom, heardFromOther, Object.assign(createAccount, { enabled: function enabled(f) { return f['dob'] && f['heardFrom']; } })]); } else { // Create Tutor Account fields = fields.concat([tutorUsername, email, phoneNumber, password, dob, referringTutor, heardFrom, heardFromOther, nativeSpeaker, Object.assign(createAccount, { enabled: function enabled(f) { return f['username'] && f['email'] && f['password'] && f['dob'] && f['heardFrom'] && f['nativeSpeaker']; }, agreementClause: this.userAgreement() })]); } } else if (this.props.accountType == 'marketing') { var marketerCode = field('text', 'marketerCode', 'Referral Code (e.g. ShakespeareEnglish'); if (cambly.AUTHENTICATED) { // Add Ambassador Account fields = fields.concat([firstName, lastName, paypalEmail, marketerCode, Object.assign(createAccount, { enabled: function enabled(f) { return f['firstName'] && f['lastName'] && f['paypalEmail']; } })]); } else { // Create Ambassador Account fields = fields.concat([username, firstName, lastName, email, paypalEmail, phoneNumber, password, marketerCode, Object.assign(createAccount, { enabled: function enabled(f) { return f['username'] && f['firstName'] && f['lastName'] && f['email'] && f['paypalEmail'] && f['password'] && f['phoneNumber']; } })]); } } else { // this.props.accountType == 'student' var studentSource = field('hidden', 'studentSource'); if (cambly.AUTHENTICATED) { // Add Student Account fields = fields.concat([referralCode, studentSource, Object.assign(createAccount, { enabled: function enabled(f) { return true; } })]); } else { // Create Student Account fields = fields.concat([username, email, password, gender, phoneNumber, referralCode, studentSource, Object.assign(createAccount, { enabled: function enabled(f) { return f['username'] && f['email'] && f['password'] && f['gender']; }, agreementClause: this.userAgreement() })]); } } return fields; } else if (formName == 'forgotPassword') { return [usernameOrEmail, { type: 'submit', text: 'Reset Password', enabled: function enabled(f) { return f['email']; } }]; } else if (formName == 'resetPassword') { var code = field('hidden', 'code'); return [Object.assign({}, usernameOrEmail, { readonly: true }), password, confirmPassword, code, Object.assign(signIn, { enabled: function enabled(f) { return f['password'] && f['password'].length >= 4; } })]; } else if (formName == 'referral') { return [email, referralCode, { type: 'submit', text: 'Claim', enabled: function enabled(f) { return f['email'] && f['email'].indexOf('@') > 0; } }]; } else if (formName == 'download') { return []; } else { console.error('Unknown Login Modal Form: ' + formName); } } }, { key: 'tabs', value: function tabs() { var _this3 = this; if (this.state.tab == null) { return null; } if (this.state.tab == 'login' || this.state.tab == 'signup') { var signupTitle = this.props.accountType == 'tutor' ? "Become a Tutor" : this.props.accountType == 'marketing' ? "Become an Ambassador" : "Sign Up"; var tabs = [React.createElement(LoginModalNav, { tab: "signup", key: "signup", active: this.state.tab == 'signup', title: signupTitle, onClick: function onClick() { return _this3.setTab('signup'); } })]; if (this.props.accountType != 'marketing' || !cambly.USER_ID) { tabs.push(React.createElement(LoginModalNav, { tab: "login", key: "login", active: this.state.tab == 'login', title: "Log In", onClick: function onClick() { return _this3.setTab('login'); } })); } return tabs; } else if (this.state.tab == 'forgotPassword') { return React.createElement(LoginModalNav, { tab: "forgotPassword", active: true, title: "Forgot Password?" }); } else if (this.state.tab == 'resetPassword') { return React.createElement(LoginModalNav, { tab: "resetPassword", active: true, title: "Reset Password" }); } else if (this.state.tab == 'referral') { var title = undefined; if (this.props.accountType == 'tutor') { if (this.props.language == 'es') { // Not sure if that translation is right title = "Enseñar español en Cambly."; } else { title = "Teach English on Cambly."; } } else { if (this.props.language == 'es') { title = "Practice Spanish with native speakers on Cambly."; } else { title = "Practice English with native speakers on Cambly."; } } if (this.props.referralCode && (this.state.referralCode || {}).valid) { var subtitle = "Claim Your Free {minutes} Minutes".replace('{minutes}', this.state.referralCode.minutes); title = React.createElement("div", null, title, React.createElement("br", null), subtitle); } return React.createElement(LoginModalNav, { tab: "referral", active: true }, title); } else if (this.state.tab == 'download') { return React.createElement(LoginModalNav, { tab: "download", active: true, title: "Practice English with native speakers on Cambly." }); } else { console.error('Unknown Login Modal Tab: ' + this.state.tab); } } }, { key: 'form', value: function form() { var _this4 = this; if (this.state.tab == null) { return null; } var data = this.getFormData(); return React.createElement("form", { className: "form-horizontal" }, (this.state.error || this.props.error) && React.createElement("div", { className: "alert alert-danger text-center" }, this.state.error || this.props.error), (this.state.success || this.props.success) && React.createElement("div", { className: "alert alert-success text-center" }, this.state.success || this.props.success), this.state.form.map(function (field, idx) { var onChange = function onChange(e) { var value = field.formatter ? field.formatter(e.target.value) : e.target.value; if (field.type == 'checkbox') { value = !(_this4.state.form[idx].value || false); } _this4.setState({ form: [].concat(_toConsumableArray(_this4.state.form.slice(0, idx))).concat(Object.assign({}, _this4.state.form[idx], { value: value })).concat([].concat(_toConsumableArray(_this4.state.form.slice(idx + 1)))) }); }; if (field.type == 'hidden') { return React.createElement("input", { id: field.name, key: field.name, type: "hidden", className: "form-control", name: field.name, value: field.value }); } else { var input = undefined; if (field.type == 'textarea') { input = React.createElement("textarea", { id: field.name, key: field.name, rows: "3", className: "form-control", name: field.name, placeholder: field.placeholder, value: field.value, onChange: onChange }); } else if (field.type == 'select') { input = React.createElement("select", { id: field.name, key: 'submit', className: "form-control", name: field.name, value: field.value, onChange: onChange }, React.createElement("option", { key: "", value: "", disabled: true }, field.placeholder), field.options.map(function (o) { return React.createElement("option", { key: o.value, value: o.value }, o.text || o.value); })); } else if (field.type == 'submit') { input = React.createElement("span", null, React.createElement("p", null, field.agreementClause), React.createElement("button", { type: "submit", key: 'submit', className: "btn btn-accent", disabled: !field.enabled(data) || _this4.state.submitting, onClick: function onClick(e) { return _this4.submit(e); } }, _this4.state.submitting ? React.createElement("i", { className: "fa fa-spinner fa-pulse fa-2x fa-fw" }) : field.text)); } else if (field.type == 'checkbox') { input = React.createElement("div", { className: "checkbox form-control text-left", style: { background: 'rgba(0, 0, 0, 0)', border: 'none', paddingLeft: 8 } }, React.createElement("label", null, React.createElement("input", { type: "checkbox", id: field.name, key: field.name, name: field.name, placeholder: field.placeholder, readOnly: field.readonly, checked: field.value || false, onChange: onChange, ref: field.reference }), field.label)); } else { input = React.createElement("input", { type: field.type, id: field.name, key: field.name, className: "form-control", name: field.name, placeholder: field.placeholder, readOnly: field.readonly, value: field.value, onChange: onChange, ref: field.reference }); } return React.createElement("div", { key: field.name || field.type, className: classNames("form-group", { 'has-error': (field.errors || []).length }), style: field.hidden && field.hidden(data) ? { display: 'none' } : {} }, React.createElement("label", { htmlFor: field.name, className: "control-label sr-only" }, field.placeholder), React.createElement("div", { className: "col-xs-12 col-sm-10 col-sm-offset-1" }, field.help, input, (field.errors || []).map(function (e, i) { return React.createElement("span", { key: i, className: "help-block text-center" }, e); }))); } })); } }, { key: 'body', value: function body() { var _this5 = this; var sections = []; if (['login', 'signup', 'referral'].indexOf(this.state.tab) >= 0) { // We dont show FB login button when becoming ambassadors - we could someday, though var hideFbLogin = this.state.tab == 'signup' && this.props.accountType == 'marketing' || !this.state.fbLoaded; return React.createElement("div", { className: this.props.pageType, style: { padding: this.props.pageStyle } }, React.createElement("div", { className: "row", style: hideFbLogin ? { display: 'none' } : {} }, React.createElement("div", { className: "col-xs-10 col-xs-offset-1" }, this.state.fbError ? React.createElement("div", { className: "alert alert-danger text-center" }, this.state.fbError) : null), React.createElement("div", { className: "col-xs-12 col-sm-8 col-sm-offset-2" }, React.createElement(FacebookButton, { onClick: function onClick(resp) { return _this5.fbSubmit(resp); }, onLoad: function onLoad(isLoaded) { return _this5.setState({ fbLoaded: isLoaded }); }, title: this.state.tab == 'login' ? 'Log in with Facebook' : this.state.tab == 'signup' ? 'Sign up with Facebook' : 'Claim with Facebook' })), React.createElement("div", { className: "col-xs-10 col-xs-offset-1" }, React.createElement("hr", null)), React.createElement("div", { className: "col-xs-2 col-xs-offset-5", style: { marginTop: '-36px' } }, React.createElement("h5", { className: "bg-white" }, React.createElement("strong", null, "or")))), this.form(), this.state.tab == 'login' ? React.createElement("div", { style: { marginTop: '30px' }, key: "forgotPassword" }, React.createElement("a", { href: "#", onClick: function onClick() { return _this5.setTab('forgotPassword'); } }, "Forgot your password?")) : null); } else { return React.createElement("div", { className: this.props.pageType }, this.form(), this.state.tab == 'download' ? React.createElement("div", null, React.createElement("div", null, this.downloadLink()), React.createElement("div", null, this.learnMore())) : null); } } }, { key: 'userAgreement', value: function userAgreement() { if (this.props.accountType == 'marketing') { return React.createElement("small", null, "By creating an account, you agree to our ", React.createElement("a", { href: "/static/legal/aa_en.pdf" }, "Ambassador Program Agreement"), "."); } else { return React.createElement("small", null, "By creating an account, you agree to our ", React.createElement("a", { href: "/static/legal/ua.html", target: "_blank" }, "User Agreement"), " and that you have read our ", React.createElement("a", { href: "/static/legal/pp.html", target: "_blank" }, "Privacy Policy"), "."); } } }, { key: 'render', value: function render() { return React.createElement("div", null, React.createElement("ul", { className: "nav-transparent nav-tabs-square nav-justified nav-single-line", role: "tablist" }, this.tabs()), this.body()); } }, { key: 'logClick', value: function logClick(trackingTag, e) { CAMBLY.logUIEvent('postReferralRedirect', { trackingTag: trackingTag }); } }, { key: 'downloadLink', value: function downloadLink() { var _this6 = this; var android = React.createElement("a", { target: "_blank", href: "https://play.google.com/store/apps/details?id=com.cambly.cambly&referrer=utm_source%3Du%26utm_medium%3Du%26utm_campaign%3Dinvite" }, React.createElement("img", { src: "/static/en/images/play_store_badge.png" })); var ios = React.createElement("a", { target: "_blank", href: "https://itunes.apple.com/app/cambly-english-teacher/id564024107?mt=8" }, React.createElement("img", { src: "/static/en/images/app_store_badge.jpg" })); return React.createElement("div", { className: "row text-center" }, React.createElement("div", { className: "col-xs-12 col-sm-10 col-sm-offset-1" }, React.createElement("h4", null, "Download the Cambly App to use your free minutes.")), React.createElement("div", { className: "col-xs-12", style: { padding: '20px' } }, React.createElement("span", { onClick: function onClick() { return _this6.logClick('downloadApp'); } }, new UAParser().getOS().name == 'Android' ? android : ios))); } }, { key: 'learnMore', value: function learnMore() { var _this7 = this; return React.createElement("div", { style: { paddingBottom: '20px' }, key: "learnMore" }, React.createElement("a", { href: "/index", style: { textDecoration: 'underline' }, onClick: function onClick() { return _this7.logClick('learnMore'); } }, "Learn More")); } }, { key: 'getAccountTypes', value: function getAccountTypes() { if (['tutor', 'student'].indexOf(this.props.accountType) >= 0) { return [this.props.accountType + '-' + this.props.language]; } else { return [this.props.accountType]; } } }, { key: 'getFormData', value: function getFormData() { // Transform the form to key/value pairs return this.state.form.reduce(function (d, f) { if (f['value'] != undefined && f['value'] != null && f['value'] != '') { d[f['name']] = f['value']; } return d; }, {}); } }, { key: 'submit', value: function submit(e) { var _this8 = this; // TODO(gar): spinner of sorts during submission e.preventDefault(); // Clear any form errors this.setState({ error: null, form: this.state.form.map(function (f) { var copy = Object.assign({}, f); delete copy['errors']; return copy; }), submitting: true }); var data = this.getFormData(); if (this.state.tab == 'login') { this.completeLogin(data).always(function () { return _this8.setState({}); }).fail(function (resp) { _this8.setState({ error: "Login failed. Check your e-mail and password.", submitting: false }); }); } else if (this.state.tab == 'signup') { if (!data['referralCode'] && this.props.referralCode) { data['referralCode'] = this.props.referralCode; } if (data['phoneNumber']) { data['phoneCountry'] = this.state.defaults.phoneCountrySelected; } data['accountTypes'] = this.getAccountTypes(); var createAccount = undefined; if (cambly.AUTHENTICATED) { // They're logged in, we'll add the new account type createAccount = CAMBLY.post('/model/users/' + cambly.USER_ID, data); } else { createAccount = CAMBLY.post('/model/users', data); } createAccount.done(function () { if (cambly.AUTHENTICATED) { return _this8.forwardToNext(); } else { return _this8.completeLogin(data); } }).fail(function (resp) { var update = { submitting: false }; if (resp.status == 422) { (function () { var errors = resp.responseJSON; if (errors.fields) { // If we have field level errors, display those update['form'] = _this8.state.form.map(function (f) { return errors.fields[f['name']] ? Object.assign({}, f, { 'errors': errors.fields[f['name']]['errors'] }) : f; }); } else { update['error'] = resp.responseJSON.customMessage; } })(); } else { update['error'] = "An error occurred"; } _this8.setState(update); }); } else if (this.state.tab == 'forgotPassword') { CAMBLY.post('/forgotPassword', data).always(function () { return _this8.setState({ submitting: false }); }).done(function (resp) { _this8.setState({ success: resp.success }); }).fail(function (resp) { if (resp.responseJSON && resp.responseJSON.error_text) { _this8.setState({ error: resp.responseJSON.error_text }); } else { _this8.setState({ error: "An error occurred" }); } }); } else if (this.state.tab == 'resetPassword') { if (data['password'] != data['confirm']) { this.setState({ error: "Confirmation does not match Password", submitting: false }); } else { CAMBLY.post('/resetPassword', data).done(function (resp) { _this8.setState({ success: 'Success!' }); return _this8.completeLogin(data); }).fail(function (resp) { if (resp.responseJSON && resp.responseJSON.error_text) { _this8.setState({ error: resp.responseJSON.error_text, submitting: false }); } else { _this8.setState({ error: "An error occurred", submitting: false }); } }); } } else if (this.state.tab == 'referral') { var email = this.state.form.filter(function (f) { return f.name == 'email'; })[0]; if (email.value.indexOf('@') < 0) { this.setState({ error: "Invalid Email Address" }); return; } CAMBLY.post('/redeemReferralCode', data).always(function () { return _this8.setState({ submitting: false }); }).done(function (resp) { var msg = "You just earned {minutes} free minutes!".replace('{minutes}', _this8.state.referralCode.minutes); if (new UAParser().getDevice().type == 'mobile') { _this8.setTab('download'); _this8.setState({ success: msg }); } else { // TODO(gar): I don't think this ever happens anymore, right? if (resp.minutes) { // This user already has an account _this8.setTab('login'); _this8.setState({ defaults: Object.assign({}, _this8.state.defaults, { 'username': data['email'] }), success: msg }); } else { _this8.setTab('signup'); _this8.setState({ defaults: Object.assign({}, _this8.state.defaults, { 'email': data['email'], 'username': data['email'].split('@')[0] }), success: msg }); } } }).fail(function (resp) { if ((data.responseJSON || {}).error == 'invalidReferralCode') { _this8.setState({ error: "Your invite is not valid." }); } else { _this8.setState({ error: 'An error occurred' }); } }); } else { console.info("Unkown form submission: " + this.state.tab); } return false; } }, { key: 'fbSubmit', value: function fbSubmit(loginResponse) { var _this9 = this; var data = { fbToken: loginResponse.authResponse.accessToken, // We don't try to add account types on login accountTypes: this.state.tab == 'login' ? [] : this.getAccountTypes(), referralCode: this.props.referralCode }; // TODO(gar): signupProfile var onFail = function onFail(resp) { console.error('FB Connect Failed'); _this9.setState({ fbError: "An error occurred" }); return resp; }; var checkEmail = undefined; if (this.state.tab == 'signup') { checkEmail = $.Deferred(); FB.api('/me', { fields: 'email' }, function (resp) { // TODO(gar): we should probably not require email for signup // if (!resp.email) { var email = prompt("Please enter your e-mail, so we can contact you."); if (!email || email.indexOf('@') < 0) { return checkEmail.reject(); } else { data['email'] = email; } } return checkEmail.resolve(); }); } else { checkEmail = $.when(); } return checkEmail.done(function () { return CAMBLY.post('/model/facebook_users', data).done(function (resp) { if (_this9.state.tab == 'login' || _this9.state.tab == 'signup') { return _this9.completeLogin(data).fail(onFail); } else { // implicitly referral tab - i.e. Claim with Facebook if (new UAParser().getDevice().type == 'mobile') { _this9.setTab('download'); var msg = "You just earned {minutes} free minutes!".replace('{minutes}', _this9.state.referralCode.minutes); _this9.setState({ success: msg }); } else { // TOOD(gar): I don't htink this happens anymore? _this9.setState({ success: React.createElement("span", null, "msg", React.createElement("br", null), "_('Logging in to Cambly...')") }); return _this9.completeLogin(data).fail(onFail); } } }).fail(onFail); }).fail(function () { return _this9.setState({ fbError: "Please enter your e-mail, so we can contact you." }); }); } }, { key: 'forwardToNext', value: function forwardToNext() { // TODO(gar): not sure this works for ambassadors? var redirectURL = this.state.next || this.props.next; if (redirectURL) { // Only allow redirects to this host. var l = document.createElement("a"); l.href = redirectURL; if (l.host == window.location.host) { window.location.href = redirectURL; return; } } if (this.props.accountType == 'marketing') { redirectURL = '/referrals'; } else if (this.props.accountType == 'tutor' && this.state.tab == 'signup') { redirectURL = '/' + this.props.language + '/tutor/warmup?speedtest=true&onboarding=true'; } else { redirectURL = '/' + this.props.language + '/' + this.props.accountType; } window.location.href = redirectURL; } }, { key: 'completeLogin', value: function completeLogin(credentials) { var _this10 = this; // Called after the user is created; // This creates a session, registers the device, // and then forwards to the next page return CAMBLY.post('/api/sessions', credentials).done(function () { return _this10.registerDevice().then(function () { return _this10.forwardToNext(); }); }).fail(function () { return _this10.setState({ submitting: false }); }); } }, { key: 'getPushSub', value: function getPushSub() { if ('serviceWorker' in navigator) { var _ret3 = (function () { var pushSubscription = $.Deferred(); navigator.serviceWorker.register('/static/service-worker/sw.js').then(function (reg) { return reg.pushManager.getSubscription().then(function (sub) { if (sub) { // They're subscribed to Push Notifs, make sure to link // it to this device. pushSubscription.resolve({ webPushSub: sub }); } else { // They aren't subscribed; We're going to prompt // them once they're logged in to enable Push Notifs. pushSubscription.resolve({}); } })['catch'](function (error) { return pushSubscription.resolve({}); }); })['catch'](function (error) { return pushSubscription.resolve({}); }); return { v: pushSubscription }; })(); if (typeof _ret3 === 'object') return _ret3.v; } else { return $.when({}); } } }, { key: 'getDeviceId', value: function getDeviceId() { var guid = undefined; if (localStorage !== 'undefined') { guid = localStorage.getItem('browser-guid'); } if (!guid) { var S4 = function S4() { return ((1 + Math.random()) * 0x10000 | 0).toString(16).substring(1); }; guid = S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); if (localStorage !== 'undefined') { try { localStorage.setItem('browser-guid', guid); } catch (e) { // Mobile Safari (and maybe others?) don't allow local storage. } } } var deviceIdData = { deviceId: guid, deviceIdType: 'guid', guid: guid }; if (typeof Fingerprint2 !== 'undefined') { var _ret4 = (function () { var deviceId = $.Deferred(); new Fingerprint2().get(function (fp, components) { deviceIdData['browserFingerprint'] = fp; deviceIdData['browserFingerprintComponents'] = components; deviceId.resolve(deviceIdData); }); return { v: deviceId }; })(); if (typeof _ret4 === 'object') return _ret4.v; } else { return $.when(deviceIdData); } } }, { key: 'registerDevice', value: function registerDevice() { var _this11 = this; return $.when(this.getDeviceId(), this.getPushSub()).then(function (deviceId, webPushSub) { var device = Object.assign({}, deviceId, webPushSub, { 'deviceType': 'browser', 'userAgent': navigator.userAgent, 'language': navigator.languages && navigator.languages[0] || navigator.language || navigator.userLanguage, 'timezone': _this11.state.defaults.timezone, 'country': _this11.state.defaults.country }); return CAMBLY.post('/api/devices', device); }); } }]); return LoginForm; })(React.Component); var LoginModalNav = (function (_React$Component2) { _inherits(LoginModalNav, _React$Component2); function LoginModalNav() { _classCallCheck(this, LoginModalNav); _get(Object.getPrototypeOf(LoginModalNav.prototype), 'constructor', this).apply(this, arguments); } _createClass(LoginModalNav, [{ key: 'render', value: function render() { return React.createElement("li", { role: "presentation", className: this.props.active ? "active" : "", onClick: this.props.onClick, style: { textAlign: 'center' } }, React.createElement("a", { 'aria-controls': this.props.tab, role: "tab", style: { cursor: 'pointer' } }, this.props.title), this.props.children); } }]); return LoginModalNav; })(React.Component); var FacebookButton = ReactRedux.connect(function (state) { return { me: state.users.me, fb: state.fb }; })((function (_React$Component3) { _inherits(FacebookButton, _React$Component3); function FacebookButton(props) { _classCallCheck(this, FacebookButton); _get(Object.getPrototypeOf(FacebookButton.prototype), 'constructor', this).call(this, props); this.state = {}; } _createClass(FacebookButton, [{ key: 'componentWillMount', value: function componentWillMount() { var _this12 = this; loadFbStatus().done(function () { return _this12.props.onLoad(true); }); } }, { key: 'render', value: function render() { var _this13 = this; return React.createElement("button", { className: "btn btn-social btn-facebook", onClick: function onClick(e) { return _this13.submit(e); }, disabled: this.props.fb.status == null || this.state.disabled }, React.createElement("i", { className: "fa fa-facebook" }), " ", this.props.title || "Facebook"); } }, { key: 'submit', value: function submit(e) { var _this14 = this; this.setState({ disabled: true }); var fbLogin = function fbLogin() { return FB.login(function (resp) { return onFbLogin(resp, false); }, { scope: 'public_profile,email,user_likes,user_friends' }); }; var onFbLogin = function onFbLogin(loginResponse, retry) { // The user is now logged into facebook and the Cambly FB App // Send the fbToken to the server to validate their account, and then validate the referral code if (loginResponse.status === 'connected') { // We expect onClick triggers async activities, // so it should return a Deferred that we can wait on. _this14.props.onClick(loginResponse).fail(function () { return _this14.setState({ disabled: false }); }); } else { _this14.setState({ disabled: false }); } }; // Calling FB.login when they are already logged in doesn't do anything // So, we want to fork between prompting the user to log in vs just executing // the post login logic. But, it's important that we know this _before_ the user // clicks the link because executing FB.login() inside of an async method will // trigger pop-up blockers (browser's don't like it when non-user initiated actions // open pop-ups). So, we're always polling for the user's FB status if the buttonn // is mounted. if (this.props.fb.connected == 'connected') { onFbLogin(this.props.fb.resp); } else { fbLogin(); } } }]); return FacebookButton; })(React.Component));