CrestRoad/laravel/public/assets/js/register-location-dropdowns.js

221 lines
6.9 KiB
JavaScript

/**
* Dependent country → state → city dropdowns for registration forms.
*/
(function () {
'use strict';
var CITIES_URL =
(typeof window !== 'undefined' && window.REGISTER_LOCATION_CITIES_URL) ||
'/geo/cities';
var countriesData = null;
function isValidCountriesMap(data) {
return (
data &&
typeof data === 'object' &&
!Array.isArray(data) &&
Object.keys(data).length > 0
);
}
function loadCountriesData() {
if (isValidCountriesMap(countriesData)) {
return Promise.resolve(countriesData);
}
if (isValidCountriesMap(window.REGISTER_LOCATION_COUNTRIES)) {
countriesData = window.REGISTER_LOCATION_COUNTRIES;
return Promise.resolve(countriesData);
}
return fetch('/geo/countries', { credentials: 'same-origin' })
.then(function (res) {
if (!res.ok) {
throw new Error('Failed to load countries data');
}
var ct = res.headers.get('content-type') || '';
if (ct.indexOf('json') === -1) {
throw new Error('Countries data returned non-JSON response');
}
return res.json();
})
.then(function (data) {
if (!isValidCountriesMap(data)) {
throw new Error('Countries data is empty or invalid');
}
countriesData = data;
return data;
});
}
function loadCities(country, state) {
var url =
CITIES_URL +
'?country=' +
encodeURIComponent(country) +
'&state=' +
encodeURIComponent(state);
function fetchCitiesFrom(endpoint) {
return fetch(endpoint, { credentials: 'same-origin' }).then(function (res) {
if (!res.ok) {
throw new Error('Failed to load cities');
}
var ct = res.headers.get('content-type') || '';
if (ct.indexOf('json') === -1) {
throw new Error('Cities endpoint returned non-JSON response');
}
return res.json();
});
}
return fetchCitiesFrom(url).catch(function () {
if (url.indexOf('/api/geo/cities') === -1) {
return fetchCitiesFrom('/api/geo/cities' + url.substring(url.indexOf('?')));
}
throw new Error('Failed to load cities');
}).then(function (data) {
return Array.isArray(data) ? data : [];
});
}
function fillSelect(select, options, placeholder) {
select.innerHTML = '';
var empty = document.createElement('option');
empty.value = '';
empty.textContent = placeholder;
select.appendChild(empty);
options.forEach(function (opt) {
var el = document.createElement('option');
el.value = opt;
el.textContent = opt;
select.appendChild(el);
});
}
function setCityMode(selectEl, inputEl, cityFieldName, mode, cities) {
cities = cities || [];
if (mode === 'select' && cities.length > 0) {
selectEl.style.display = '';
inputEl.style.display = 'none';
inputEl.removeAttribute('name');
inputEl.disabled = true;
inputEl.required = false;
selectEl.setAttribute('name', cityFieldName);
selectEl.disabled = false;
selectEl.required = true;
fillSelect(selectEl, cities, '-- Select City --');
} else {
selectEl.style.display = 'none';
inputEl.style.display = '';
selectEl.removeAttribute('name');
selectEl.disabled = true;
selectEl.required = false;
selectEl.value = '';
inputEl.setAttribute('name', cityFieldName);
inputEl.disabled = false;
inputEl.required = true;
inputEl.placeholder =
mode === 'select'
? 'Enter city (no list available for this state)'
: 'Enter city';
if (mode !== 'select') {
inputEl.value = '';
}
}
}
function initRegisterLocationDropdowns() {
var wrapper = document.querySelector('.register-location-fields');
var countrySelect = document.getElementById('country');
var stateSelect = document.getElementById('state');
var citySelect = document.getElementById('city');
var cityInput = document.querySelector('.register-location-city-input');
if (!wrapper || !countrySelect || !stateSelect || !citySelect || !cityInput) {
return Promise.resolve();
}
var cityFieldName = wrapper.getAttribute('data-city-field') || 'city';
return loadCountriesData().then(function (data) {
var countries = Object.keys(data).sort(function (a, b) {
return a.localeCompare(b);
});
fillSelect(countrySelect, countries, '-- Select Country --');
var defaultCountry = wrapper.getAttribute('data-default-country') || 'India';
if (defaultCountry && data[defaultCountry]) {
countrySelect.value = defaultCountry;
fillSelect(stateSelect, data[defaultCountry], '-- Select State --');
stateSelect.disabled = false;
}
countrySelect.addEventListener('change', function () {
var country = countrySelect.value;
stateSelect.value = '';
citySelect.value = '';
cityInput.value = '';
setCityMode(citySelect, cityInput, cityFieldName, 'input');
citySelect.disabled = true;
cityInput.disabled = true;
if (!country || !data[country]) {
fillSelect(stateSelect, [], '-- Select State --');
stateSelect.disabled = true;
return;
}
fillSelect(stateSelect, data[country], '-- Select State --');
stateSelect.disabled = false;
});
stateSelect.addEventListener('change', function () {
var country = countrySelect.value;
var state = stateSelect.value;
citySelect.value = '';
cityInput.value = '';
if (!country || !state) {
setCityMode(citySelect, cityInput, cityFieldName, 'input');
citySelect.disabled = true;
cityInput.disabled = true;
return;
}
cityInput.disabled = true;
citySelect.disabled = true;
loadCities(country, state)
.then(function (cities) {
if (cities.length > 0) {
setCityMode(citySelect, cityInput, cityFieldName, 'select', cities);
} else {
setCityMode(citySelect, cityInput, cityFieldName, 'input');
cityInput.disabled = false;
}
})
.catch(function (err) {
console.warn('City list unavailable, using text input', err);
setCityMode(citySelect, cityInput, cityFieldName, 'input');
cityInput.disabled = false;
});
});
if (countrySelect.value && data[countrySelect.value]) {
stateSelect.dispatchEvent(new Event('change'));
}
});
}
function bootRegisterLocationDropdowns() {
initRegisterLocationDropdowns().catch(function (err) {
console.error('Register location dropdowns failed to initialize', err);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bootRegisterLocationDropdowns);
} else {
bootRegisterLocationDropdowns();
}
})();