(function(context,$) { "use strict"; context.JK = context.JK || {}; context.JK.AccountProfileScreen = function(app) { var logger = context.JK.logger; var api = context.JK.Rest(); var userId; var user = {}; var recentUserDetail = null; var loadingCitiesData = false; var loadingRegionsData = false; var loadingCountriesData = false; var nilOptionText = 'n/a'; function beforeShow(data) { userId = data.id; } function afterShow(data) { resetForm(); renderAccountProfile(); } function resetForm() { // remove all display errors $('#account-profile-content-scroller form .error-text').remove() $('#account-profile-content-scroller form .error').removeClass("error") } function populateAccountProfile(userDetail, instruments) { var template = context.JK.fillTemplate($('#template-account-profile').html(), { country: userDetail.country, region: userDetail.state, city: userDetail.city, first_name: userDetail.first_name, last_name: userDetail.last_name, user_instruments: userDetail.instruments, birth_date : userDetail.birth_date, gender: userDetail.gender, subscribe_email: userDetail.subscribe_email ? "checked=checked" : "" }); var content_root = $('#account-profile-content-scroller') content_root.html(template); // now use javascript to fix up values too hard to do with templating // set gender $('select[name=gender]', content_root).val(userDetail.gender) // set birth_date if(userDetail.birth_date) { var birthDateFields = userDetail.birth_date.split('-') var birthDateYear = birthDateFields[0]; var birthDateMonth = birthDateFields[1]; var birthDateDay = birthDateFields[2]; $('select#user_birth_date_1i', content_root).val(parseInt(birthDateYear)); $('select#user_birth_date_2i', content_root).val(parseInt(birthDateMonth)); $('select#user_birth_date_3i', content_root).val(parseInt(birthDateDay)); } // update instruments $.each(instruments, function(index, instrument) { var template = context.JK.fillTemplate($('#account-profile-instrument').html(), { checked : isUserInstrument(instrument, userDetail.instruments) ? "checked=\"checked\"" :"", description : instrument.description, id : instrument.id }) $('.instrument_selector', content_root).append(template) }) // and fill in the proficiency for the instruments that the user can play if(userDetail.instruments) { $.each(userDetail.instruments, function(index, userInstrument) { $('tr[data-instrument-id="' + userInstrument.instrument_id + '"] select.proficiency_selector', content_root).val(userInstrument.proficiency_level) }) } } function isUserInstrument(instrument, userInstruments) { var isUserInstrument = false; if(!userInstruments) return false; $.each(userInstruments, function(index, userInstrument) { if(instrument.id == userInstrument.instrument_id) { isUserInstrument = true; return false; } }) return isUserInstrument; } function populateAccountProfileLocation(userDetail, regions, cities) { populateRegions(regions, userDetail.state); populateCities(cities, userDetail.city); } function populateCountries(countries, userCountry) { var foundCountry = false; var countrySelect = getCountryElement() countrySelect.children().remove() var nilOption = $(''); nilOption.text(nilOptionText); countrySelect.append(nilOption); $.each(countries, function(index, country) { if(!country) return; var option = $(''); option.text(country); option.attr("value", country); if(country == userCountry) { foundCountry = true; } countrySelect.append(option) }); if(!foundCountry) { // in this case, the user has a country that is not in the database // this can happen in a development/test scenario, but let's assume it can // happen in production too. var option = $(''); option.text(userCountry); option.attr("value", userCountry); countrySelect.append(option); } countrySelect.val(userCountry); countrySelect.attr("disabled", null) } function populateRegions(regions, userRegion) { var regionSelect = getRegionElement() regionSelect.children().remove() var nilOption = $(''); nilOption.text(nilOptionText); regionSelect.append(nilOption); $.each(regions, function(index, region) { if(!region) return; var option = $('') option.text(region) option.attr("value", region) regionSelect.append(option) }) regionSelect.val(userRegion) regionSelect.attr("disabled", null) } function populateCities(cities, userCity) { var citySelect = getCityElement(); citySelect.children().remove(); var nilOption = $(''); nilOption.text(nilOptionText); citySelect.append(nilOption); $.each(cities, function(index, city) { if(!city) return; var option = $('') option.text(city) option.attr("value", city) citySelect.append(option) }) citySelect.val(userCity) citySelect.attr("disabled", null) } /****************** MAIN PORTION OF SCREEN *****************/ // events for main screen function events() { $('#account-profile-content-scroller').on('click', '#account-edit-profile-cancel', function(evt) { evt.stopPropagation(); navToAccount(); return false; } ); $('#account-profile-content-scroller').on('click', '#account-edit-profile-submit', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } ); $('#account-profile-content-scroller').on('submit', '#account-edit-email-form', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } ); $('#account-profile-content-scroller').on('change', 'select[name=country]', function(evt) { evt.stopPropagation(); handleCountryChanged(); return false; } ); $('#account-profile-content-scroller').on('change', 'select[name=region]', function(evt) { evt.stopPropagation(); handleRegionChanged(); return false; } ); $('#account-profile-content-scroller').on('click', '#account-change-avatar', function(evt) { evt.stopPropagation(); navToAvatar(); return false; } ); } function regionListFailure(jqXHR, textStatus, errorThrown) { if(jqXHR.status == 422) { console.log("no regions found for country: " + recentUserDetail.country); } else { app.ajaxError(arguments); } } function cityListFailure(jqXHR, textStatus, errorThrown) { if(jqXHR.status == 422) { console.log("no cities found for country/region: " + recentUserDetail.country + "/" + recentUserDetail.state); } else { app.ajaxError(arguments); } } function renderAccountProfile() { $.when( api.getUserDetail(), api.getInstruments()) .done(function(userDetailResponse, instrumentsResponse) { var userDetail = userDetailResponse[0]; recentUserDetail = userDetail // store userDetail for later var instruments = instrumentsResponse[0]; // show page; which can be done quickly at this point populateAccountProfile(userDetail, instruments); var country = userDetail.country; if(!country) { // this case shouldn't happen because sign up makes you pick a location. This is just 'in case', so that the UI is more error-resilient country = 'US'; } loadingCountriesData = true; loadingRegionsData = true; loadingCitiesData = true; // make the 3 slower requests, which only matter if the user wants to affect their ISP or location api.getCountries() .done(function(countries) { populateCountries(countries["countries"], userDetail.country); } ) .fail(app.ajaxError) .always(function() { loadingCountriesData = false; }) var country = userDetail.country; var state = userDetail.state; if(country) { api.getRegions( { country: country } ) .done(function(regions) { populateRegions(regions["regions"], userDetail.state); } ) .fail(regionListFailure) .always(function() { loadingRegionsData = false; }) if(state) { api.getCities( { country: country, region: state }) .done(function(cities) { populateCities(cities["cities"], userDetail.city) }) .fail(cityListFailure) .always(function() { loadingCitiesData = false;}) } } }) } function navToAccount() { resetForm(); window.location = '/client#/account'; } function navToAvatar() { resetForm(); window.location = '/client#/account/profile/avatar'; } function handleUpdateProfile() { resetForm(); var country = getCountryElement().val(); var region = getRegionElement().val(); var city = getCityElement().val(); var firstName = getFirstNameElement().val(); var lastName = getLastNameElement().val(); var gender = getGenderElement().val(); var subscribeEmail = getSubscribeEmail().is(':checked'); var birthDate = getBirthDate(); var instruments = getInstrumentsValue(); api.updateUser({ country: country, state: region, city: city, first_name: firstName, last_name: lastName, gender: gender, birth_date: birthDate, instruments: instruments, subscribe_email: subscribeEmail }) .done(postUpdateProfileSuccess) .fail(postUpdateProfileFailure) } function postUpdateProfileSuccess(response) { app.notify( { title: "Profile Changed", text: "You have updated your profile successfully." }, { no_cancel: true }); } function postUpdateProfileFailure(xhr, textStatus, errorMessage) { var errors = JSON.parse(xhr.responseText) if(xhr.status == 422) { var first_name = context.JK.format_errors("first_name", errors); var last_name = context.JK.format_errors("last_name", errors); var country = context.JK.format_errors("country", errors); var state = context.JK.format_errors("state", errors); var city = context.JK.format_errors("city", errors); var birth_date = context.JK.format_errors("birth_date", errors); var gender = context.JK.format_errors("birth_date", errors); var subscribeEmail = context.JK.format_errors("subscribe_email", errors); var instruments = context.JK.format_errors("musician_instruments", errors) if(first_name != null) { getFirstNameElement().closest('div.field').addClass('error').end().after(first_name); } if(last_name != null) { getLastNameElement().closest('div.field').addClass('error').end().after(last_name); } if(country != null) { getCountryElement().closest('div.field').addClass('error').end().after(country); } if(state != null) { getRegionElement().closest('div.field').addClass('error').end().after(state); } if(city != null) { getCityElement().closest('div.field').addClass('error').end().after(city); } if(birth_date != null) { getYearElement().closest('div.field').addClass('error').end().after(birth_date); } if(subscribeEmail != null) { getSubscribeEmail().closest('div.field').addClass('error').end().after(subscribeEmail); } if(gender != null) { getGenderElement().closest('div.field').addClass('error').end().after(gender); } if(instruments != null) { getInstrumentsElement().closest('div.field').addClass('error').append(instruments); } } else { app.ajaxError(xhr, textStatus, errorMessage) } } function handleCountryChanged() { var selectedCountry = getCountryElement().val() var selectedRegion = getRegionElement().val() var cityElement = getCityElement(); updateRegionList(selectedCountry, getRegionElement()); } function updateRegionList(selectedCountry, regionElement) { // only update region if (selectedCountry) { // set city disabled while updating regionElement.attr('disabled', true); loadingRegionsData = true; regionElement.children().remove() regionElement.append($('').text('loading...')) api.getRegions({ country: selectedCountry }) .done(getRegionsDone) .fail(app.ajaxError) .always(function () { loadingRegionsData = false; }) } else { regionElement.children().remove() regionElement.append($('').text(nilOptionText)) } } function updateCityList(selectedCountry, selectedRegion, cityElement) { console.log("updating city list: selectedCountry %o, selectedRegion %o", selectedCountry, selectedRegion); // only update cities if (selectedCountry && selectedRegion) { // set city disabled while updating cityElement.attr('disabled', true); loadingCitiesData = true; cityElement.children().remove() cityElement.append($('').text('loading...')) api.getCities({ country: selectedCountry, region: selectedRegion }) .done(getCitiesDone) .fail(app.ajaxError) .always(function () { loadingCitiesData = false; }) } else { cityElement.children().remove() cityElement.append($('').text(nilOptionText)) } } function handleRegionChanged() { var selectedCountry = getCountryElement().val() var selectedRegion = getRegionElement().val() var cityElement = getCityElement(); updateCityList(selectedCountry, selectedRegion, cityElement); } function getCitiesDone(data) { populateCities(data['cities'], recentUserDetail.city); } function getRegionsDone(data) { populateRegions(data['regions'], recentUserDetail.state); updateCityList(getCountryElement().val(), getRegionElement().val(), getCityElement()); } function getCountryElement() { return $('#account-profile-content-scroller select[name=country]'); } function getRegionElement() { return $('#account-profile-content-scroller select[name=region]'); } function getCityElement() { return $('#account-profile-content-scroller select[name=city]'); } function getFirstNameElement() { return $('#account-profile-content-scroller input[name=first_name]'); } function getLastNameElement() { return $('#account-profile-content-scroller input[name=last_name]'); } function getGenderElement() { return $('#account-profile-content-scroller select[name=gender]'); } function getMonthElement() { return $('#account-profile-content-scroller select#user_birth_date_2i'); } function getDayElement() { return $('#account-profile-content-scroller select#user_birth_date_3i'); } function getYearElement() { return $('#account-profile-content-scroller select#user_birth_date_1i'); } function getSubscribeEmail() { return $('#account-profile-content-scroller input[name=subscribe_email]'); } function getInstrumentsElement() { return $('#account-profile-content-scroller .instrument_selector'); } function getBirthDate() { var month = getMonthElement().val() var day = getDayElement().val() var year = getYearElement().val() if(month != null && month.length > 0 && day != null && day.length > 0 && year != null && year.length > 0) { return month + "-" + day + "-" + year; } else { return null; } } // looks in instrument_selector parent element, and gathers up all // selected elements, and the proficiency level declared function getInstrumentsValue() { var instrumentsParentElement = getInstrumentsElement(); var instruments = [] $('input[type=checkbox]:checked', instrumentsParentElement).each(function(i) { var instrumentElement = $(this).closest('tr'); // traverse up to common parent of this instrument, and pick out proficiency selector var proficiency = $('select.proficiency_selector', instrumentElement).val() instruments.push({ instrument_id: instrumentElement.attr('data-instrument-id'), proficiency_level: proficiency, priority : i }) }); return instruments; } function initialize() { var screenBindings = { 'beforeShow': beforeShow, 'afterShow': afterShow }; app.bindScreen('account/profile', screenBindings); events(); } this.initialize = initialize; this.beforeShow = beforeShow; this.afterShow = afterShow; return this; }; })(window,jQuery);