jam-cloud/web/app/assets/javascripts/accounts_profile.js

613 lines
23 KiB
JavaScript

(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.AccountProfileScreen = function(app) {
var $document = $(document);
var logger = context.JK.logger;
var EVENTS = context.JK.EVENTS;
var api = context.JK.Rest();
var userId;
var user = {};
var recentUserDetail = null;
var loadingCitiesData = false;
var loadingRegionsData = false;
var loadingCountriesData = false;
var nilOptionStr = '<option value=""></option>';
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,
photoUrl: context.JK.resolveAvatarUrl(userDetail.photo_url),
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)
})
}
context.JK.dropdown($('select', content_root));
}
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) {
// countries has the format ["US", ...]
var foundCountry = false;
var countrySelect = getCountryElement();
countrySelect.children().remove();
var nilOption = $(nilOptionStr);
nilOption.text(nilOptionText);
countrySelect.append(nilOption);
$.each(countries, function(index, country) {
if(!country) return;
var option = $(nilOptionStr);
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 = $(nilOptionStr);
option.text(userCountry);
option.attr("value", userCountry);
countrySelect.append(option);
}
countrySelect.val(userCountry);
countrySelect.attr("disabled", null)
context.JK.dropdown(countrySelect);
}
function populateCountriesx(countriesx, userCountry) {
// countriesx has the format [{countrycode: "US", countryname: "United States"}, ...]
var foundCountry = false;
var countrySelect = getCountryElement();
countrySelect.children().remove();
var nilOption = $(nilOptionStr);
nilOption.text(nilOptionText);
countrySelect.append(nilOption);
$.each(countriesx, function(index, countryx) {
if(!countryx.countrycode) return;
var option = $(nilOptionStr);
option.text(countryx.countryname);
option.attr("value", countryx.countrycode);
if(countryx.countrycode == 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 = $(nilOptionStr);
option.text(userCountry);
option.attr("value", userCountry);
countrySelect.append(option);
}
countrySelect.val(userCountry);
countrySelect.attr("disabled", null)
context.JK.dropdown(countrySelect);
}
function populateRegions(regions, userRegion) {
var regionSelect = getRegionElement()
regionSelect.children().remove()
var nilOption = $(nilOptionStr);
nilOption.text(nilOptionText);
regionSelect.append(nilOption);
$.each(regions, function(index, region) {
if(!region) return;
var option = $(nilOptionStr)
option.text(region['name'])
option.attr("value", region['region'])
regionSelect.append(option)
})
regionSelect.val(userRegion)
regionSelect.attr("disabled", null)
context.JK.dropdown(regionSelect);
}
function populateCities(cities, userCity) {
var citySelect = getCityElement();
citySelect.children().remove();
var nilOption = $(nilOptionStr);
nilOption.text(nilOptionText);
citySelect.append(nilOption);
$.each(cities, function(index, city) {
if(!city) return;
var option = $(nilOptionStr)
option.text(city)
option.attr("value", city)
citySelect.append(option)
})
citySelect.val(userCity)
citySelect.attr("disabled", null)
context.JK.dropdown(citySelect);
}
/****************** 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) {
logger.debug("no regions found for country: " + recentUserDetail.country);
}
else {
app.ajaxError(arguments);
}
}
function cityListFailure(jqXHR, textStatus, errorThrown) {
if(jqXHR.status == 422) {
logger.debug("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(countriesx) { populateCountriesx(countriesx["countriesx"], 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;})
}
}
})
context.JK.dropdown($('select'));
}
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."
},
null,
true);
$document.triggerHandler(EVENTS.USER_UPDATED, response);
}
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());
updateCityList(selectedCountry, null, cityElement);
}
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($(nilOptionStr).text('loading...'))
api.getRegions({ country: selectedCountry })
.done(getRegionsDone)
.error(function(err) {
regionElement.children().remove()
regionElement.append($(nilOptionStr).text(nilOptionText))
})
.always(function () {
loadingRegionsData = false;
})
}
else {
regionElement.children().remove()
regionElement.append($(nilOptionStr).text(nilOptionText))
}
}
function updateCityList(selectedCountry, selectedRegion, cityElement) {
logger.debug("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($(nilOptionStr).text('loading...'))
api.getCities({ country: selectedCountry, region: selectedRegion })
.done(getCitiesDone)
.error(function(err) {
cityElement.children().remove()
cityElement.append($(nilOptionStr).text(nilOptionText))
})
.always(function () {
loadingCitiesData = false;
})
}
else {
cityElement.children().remove();
cityElement.append($(nilOptionStr).text(nilOptionText));
context.JK.dropdown(cityElement);
}
}
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);