555 lines
31 KiB
PHP
555 lines
31 KiB
PHP
@extends('layouts.account', ['title' => __('addresses.page_title')])
|
|
|
|
@section('content')
|
|
<!-- Addresses content -->
|
|
<div class="col-lg-9">
|
|
<div class="ps-lg-3 ps-xl-0">
|
|
|
|
<!-- Page title -->
|
|
<h1 class="h2 mb-1 mb-sm-2">{{ __('addresses.page_title') }}</h1>
|
|
|
|
@foreach ($addresses as $address)
|
|
<div class="border-bottom py-4">
|
|
<div class="nav flex-nowrap align-items-center justify-content-between pb-1 mb-3">
|
|
<div class="d-flex align-items-center gap-3 me-4">
|
|
<h2 class="h6 mb-0">{{ $address->label }}</h2>
|
|
@if ($address->is_primary)
|
|
<span class="badge text-bg-info rounded-pill">{{ __('addresses.primary') }}</span>
|
|
@endif
|
|
</div>
|
|
<a class="nav-link hiding-collapse-toggle text-decoration-underline p-0 collapsed primaryAddressEditButton"
|
|
data-address-id="{{ $address->id }}" href=".primary-address-{{ $address->id }}"
|
|
data-bs-toggle="collapse" aria-expanded="false"
|
|
aria-controls="primaryAddressPreview{{ $address->id }} primaryAddressEdit{{ $address->id }}">{{ __('addresses.edit') }}</a>
|
|
</div>
|
|
<div class="collapse primary-address-{{ $address->id }} show"
|
|
id="primaryAddressPreview{{ $address->id }}">
|
|
<ul class="list-unstyled fs-sm m-0">
|
|
<li>{{ $address->location }}</li>
|
|
<li>{{ $address->address }}</li>
|
|
</ul>
|
|
</div>
|
|
<div class="collapse primary-address-{{ $address->id }}" id="primaryAddressEdit{{ $address->id }}">
|
|
<form class="row g-3 g-sm-4 needs-validation" novalidate>
|
|
|
|
<div class="col-sm-6">
|
|
<div class="position-relative">
|
|
<label class="form-label">{{ __('addresses.province') }}</label>
|
|
<select class="form-select province-select" data-select='{"searchEnabled": true}'
|
|
aria-label="Select city" required data-address-id="{{ $address->id }}">
|
|
<option value="">{{ __('addresses.select_province') }}</option>
|
|
</select>
|
|
<div class="invalid-feedback">{{ __('addresses.please_select_province') }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-sm-6">
|
|
<div class="position-relative">
|
|
<label class="form-label">{{ __('addresses.city') }}</label>
|
|
<select class="form-select city-select" data-select='{"searchEnabled": true}'
|
|
aria-label="Select city" required data-address-id="{{ $address->id }}">
|
|
<option value="">{{ __('addresses.select_city') }}</option>
|
|
</select>
|
|
<div class="invalid-feedback">{{ __('addresses.please_select_city') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<div class="position-relative">
|
|
<label class="form-label">{{ __('addresses.district') }}</label>
|
|
<select class="form-select district-select" data-select='{"searchEnabled": true}'
|
|
aria-label="Select district" required data-address-id="{{ $address->id }}">
|
|
<option value="">{{ __('addresses.select_district') }}</option>
|
|
</select>
|
|
<div class="invalid-feedback">{{ __('addresses.please_select_district') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<div class="position-relative">
|
|
<label class="form-label">{{ __('addresses.village') }}</label>
|
|
<select class="form-select village-select" data-select='{"searchEnabled": true}'
|
|
aria-label="Select village" required data-address-id="{{ $address->id }}">
|
|
<option value="">{{ __('addresses.select_village') }}</option>
|
|
</select>
|
|
<div class="invalid-feedback">{{ __('addresses.please_select_village') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-4">
|
|
<div class="position-relative">
|
|
<label for="psa-zip-{{ $address->id }}"
|
|
class="form-label">{{ __('addresses.zip_code') }}</label>
|
|
<input type="text" class="form-control" id="psa-zip-{{ $address->id }}"
|
|
value="{{ $address->postal_code }}" required>
|
|
<div class="invalid-feedback">{{ __('addresses.please_enter_zip_code') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-8">
|
|
<div class="position-relative">
|
|
<label for="psa-address-{{ $address->id }}"
|
|
class="form-label">{{ __('addresses.address') }}</label>
|
|
<input type="text" class="form-control" id="psa-address-{{ $address->id }}"
|
|
value="{{ $address->address }}" required>
|
|
<div class="invalid-feedback">{{ __('addresses.please_enter_address') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="form-check mb-0">
|
|
<input type="checkbox" class="form-check-input" id="set-primary-{{ $address->id }}"
|
|
{{ $address->is_primary ? 'checked' : '' }}>
|
|
<label for="set-primary-{{ $address->id }}"
|
|
class="form-check-label">{{ __('addresses.set_as_primary_address') }}</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="d-flex gap-3 pt-2 pt-sm-0">
|
|
<button type="submit"
|
|
class="btn btn-primary">{{ __('addresses.save_changes') }}</button>
|
|
<button type="button" class="btn btn-secondary" data-bs-toggle="collapse"
|
|
data-bs-target=".primary-address-{{ $address->id }}" aria-expanded="true"
|
|
aria-controls="primaryAddressPreview{{ $address->id }} primaryAddressEdit{{ $address->id }}">{{ __('addresses.close') }}</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
|
|
|
|
|
|
<!-- Add address button -->
|
|
<div class="nav pt-4">
|
|
<a class="nav-link animate-underline fs-base px-0" href="#newAddressModal" data-bs-toggle="modal">
|
|
<i class="ci-plus fs-lg ms-n1 me-2"></i>
|
|
<span class="animate-target">{{ __('addresses.add_address') }}</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- New Address Modal -->
|
|
<div class="modal fade" id="newAddressModal" tabindex="-1" aria-labelledby="newAddressModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="newAddressModalLabel">{{ __('addresses.add_address') }}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form class="row g-3 g-sm-4 needs-validation" novalidate>
|
|
<div class="col-sm-6">
|
|
<div class="position-relative">
|
|
<label class="form-label">{{ __('addresses.country') }}</label>
|
|
<select class="form-select" data-select='{"searchEnabled": true}'
|
|
aria-label="Select country" required>
|
|
<option value="">{{ __('addresses.select_country') }}</option>
|
|
<optgroup label="{{ __('addresses.regions.africa') }}">
|
|
<option value="Nigeria">Nigeria</option>
|
|
<option value="South Africa">South Africa</option>
|
|
<option value="Kenya">Kenya</option>
|
|
<option value="Egypt">Egypt</option>
|
|
<option value="Ethiopia">Ethiopia</option>
|
|
</optgroup>
|
|
<optgroup label="{{ __('addresses.regions.asia') }}">
|
|
<option value="China">China</option>
|
|
<option value="India">India</option>
|
|
<option value="Japan">Japan</option>
|
|
<option value="South Korea">South Korea</option>
|
|
<option value="Saudi Arabia">Saudi Arabia</option>
|
|
</optgroup>
|
|
<optgroup label="{{ __('addresses.regions.europe') }}">
|
|
<option value="Germany">Germany</option>
|
|
<option value="France">France</option>
|
|
<option value="United Kingdom">United Kingdom</option>
|
|
<option value="Italy">Italy</option>
|
|
<option value="Spain">Spain</option>
|
|
</optgroup>
|
|
<optgroup label="{{ __('addresses.regions.north_america') }}">
|
|
<option value="United States">United States</option>
|
|
<option value="Canada">Canada</option>
|
|
<option value="Mexico">Mexico</option>
|
|
<option value="Jamaica">Jamaica</option>
|
|
<option value="Costa Rica">Costa Rica</option>
|
|
</optgroup>
|
|
<optgroup label="{{ __('addresses.regions.south_america') }}">
|
|
<option value="Brazil">Brazil</option>
|
|
<option value="Argentina">Argentina</option>
|
|
<option value="Colombia">Colombia</option>
|
|
<option value="Chile">Chile</option>
|
|
<option value="Peru">Peru</option>
|
|
</optgroup>
|
|
<optgroup label="{{ __('addresses.regions.oceania') }}">
|
|
<option value="Australia">Australia</option>
|
|
<option value="New Zealand">New Zealand</option>
|
|
<option value="Papua New Guinea">Papua New Guinea</option>
|
|
<option value="Fiji">Fiji</option>
|
|
<option value="Solomon Islands">Solomon Islands</option>
|
|
</optgroup>
|
|
</select>
|
|
<div class="invalid-feedback">{{ __('addresses.please_select_country') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<div class="position-relative">
|
|
<label class="form-label">{{ __('addresses.city') }}</label>
|
|
<select class="form-select" data-select='{"searchEnabled": true}'
|
|
aria-label="Select city" required>
|
|
<option value="">{{ __('addresses.select_city') }}</option>
|
|
<option value="Austin">Austin</option>
|
|
<option value="Charlotte">Charlotte</option>
|
|
<option value="Chicago">Chicago</option>
|
|
<option value="Columbus">Columbus</option>
|
|
<option value="Dallas">Dallas</option>
|
|
<option value="Houston">Houston</option>
|
|
<option value="Jacksonville">Jacksonville</option>
|
|
<option value="Los Angeles">Los Angeles</option>
|
|
<option value="New York">New York</option>
|
|
<option value="Orlando">Orlando</option>
|
|
<option value="Philadelphia">Philadelphia</option>
|
|
<option value="Phoenix">Phoenix</option>
|
|
<option value="San Antonio">San Antonio</option>
|
|
<option value="San Diego">San Diego</option>
|
|
<option value="San Jose">San Jose</option>
|
|
</select>
|
|
<div class="invalid-feedback">{{ __('addresses.please_select_city') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-4">
|
|
<div class="position-relative">
|
|
<label for="new-zip" class="form-label">{{ __('addresses.zip_code') }}</label>
|
|
<input type="text" class="form-control" id="new-zip" required>
|
|
<div class="invalid-feedback">{{ __('addresses.please_enter_zip_code') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-8">
|
|
<div class="position-relative">
|
|
<label for="new-address" class="form-label">{{ __('addresses.address') }}</label>
|
|
<input type="text" class="form-control" id="new-address" required>
|
|
<div class="invalid-feedback">{{ __('addresses.please_enter_address') }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="form-check mb-0">
|
|
<input type="checkbox" class="form-check-input" id="set-primary-new">
|
|
<label for="set-primary-new"
|
|
class="form-check-label">{{ __('addresses.set_as_primary_address') }}</label>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary"
|
|
data-bs-dismiss="modal">{{ __('addresses.close') }}</button>
|
|
<button type="submit" class="btn btn-primary">{{ __('addresses.save_changes') }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Add click event listener to edit buttons
|
|
document.addEventListener('click', function(e) {
|
|
// Check if clicked element is an edit button
|
|
if (e.target.closest('.primaryAddressEditButton')) {
|
|
// Find the button element to get its data attribute
|
|
const button = e.target.closest('.primaryAddressEditButton');
|
|
console.log('Button clicked:', button);
|
|
|
|
// Get address ID from data attribute
|
|
const addressId = button.getAttribute('data-address-id');
|
|
console.log('Address ID:', addressId);
|
|
|
|
if (addressId) {
|
|
loadProvincesForAddress(addressId);
|
|
}
|
|
}
|
|
});
|
|
|
|
function loadProvincesForAddress(addressId) {
|
|
console.log('Loading provinces for address ID:', addressId);
|
|
const provinceSelect = document.querySelector(`.province-select[data-address-id="${addressId}"]`);
|
|
if (!provinceSelect) {
|
|
console.log('Province select not found for address ID:', addressId);
|
|
return;
|
|
}
|
|
|
|
const currentProvinceId = '{{ $address->province_id }}';
|
|
const currentCityId = '{{ $address->city_id }}';
|
|
const currentDistrictId = '{{ $address->district_id }}';
|
|
const currentVillageId = '{{ $address->subdistrict_id }}';
|
|
|
|
// Load provinces via AJAX
|
|
fetch('/addresses/provinces')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (window.Choices) {
|
|
// Destroy existing instance if any
|
|
if (provinceSelect.choices) {
|
|
provinceSelect.choices.destroy();
|
|
}
|
|
}
|
|
// Clear and set options
|
|
provinceSelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_province') }}</option>';
|
|
|
|
data.data.forEach(province => {
|
|
const option = document.createElement('option');
|
|
option.value = province.id;
|
|
option.textContent = province.name;
|
|
|
|
// Select current province if it matches
|
|
if (province.id == currentProvinceId) {
|
|
option.selected = true;
|
|
}
|
|
|
|
provinceSelect.appendChild(option);
|
|
});
|
|
|
|
console.log(provinceSelect);
|
|
|
|
// Initialize Choices.js
|
|
if (window.Choices) {
|
|
// Destroy existing instance if any
|
|
if (provinceSelect.choices) {
|
|
provinceSelect.choices.destroy();
|
|
}
|
|
// Initialize new Choices instance
|
|
provinceSelect.choices = new window.Choices(provinceSelect, {
|
|
searchEnabled: true,
|
|
itemSelectText: 'Select an option',
|
|
noResultsText: 'No results found',
|
|
shouldSort: false
|
|
});
|
|
}
|
|
|
|
// Load cities if province is selected
|
|
if (currentProvinceId) {
|
|
loadCitiesForAddress(addressId, currentProvinceId, currentCityId, currentDistrictId,
|
|
currentVillageId);
|
|
}
|
|
})
|
|
.catch(error => console.log('Error loading provinces:', error));
|
|
}
|
|
|
|
// Add change event listener to province selects
|
|
document.addEventListener('change', function(e) {
|
|
if (e.target.classList.contains('province-select')) {
|
|
const addressId = e.target.dataset.addressId;
|
|
const provinceId = e.target.value;
|
|
|
|
// Clear district and village selects
|
|
const citySelect = document.querySelector(
|
|
`.city-select[data-address-id="${addressId}"]`);
|
|
const districtSelect = document.querySelector(
|
|
`.district-select[data-address-id="${addressId}"]`);
|
|
const villageSelect = document.querySelector(
|
|
`.village-select[data-address-id="${addressId}"]`);
|
|
|
|
if (citySelect) {
|
|
citySelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_city') }}</option>';
|
|
}
|
|
if (districtSelect) {
|
|
districtSelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_district') }}</option>';
|
|
}
|
|
if (villageSelect) {
|
|
villageSelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_village') }}</option>';
|
|
}
|
|
|
|
// Load cities if province is selected
|
|
if (provinceId) {
|
|
loadCitiesForAddress(addressId, provinceId);
|
|
}
|
|
}
|
|
|
|
if (e.target.classList.contains('city-select')) {
|
|
const addressId = e.target.dataset.addressId;
|
|
const cityId = e.target.value;
|
|
|
|
// Clear district and village selects
|
|
const districtSelect = document.querySelector(
|
|
`.district-select[data-address-id="${addressId}"]`);
|
|
const villageSelect = document.querySelector(
|
|
`.village-select[data-address-id="${addressId}"]`);
|
|
|
|
if (districtSelect) {
|
|
districtSelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_district') }}</option>';
|
|
}
|
|
if (villageSelect) {
|
|
villageSelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_village') }}</option>';
|
|
}
|
|
|
|
// Load districts if city is selected
|
|
if (cityId) {
|
|
loadDistrictsForAddress(addressId, cityId);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Add change event listener to district selects
|
|
document.addEventListener('change', function(e) {
|
|
if (e.target.classList.contains('district-select')) {
|
|
const addressId = e.target.dataset.addressId;
|
|
const districtId = e.target.value;
|
|
|
|
// Clear village select
|
|
const villageSelect = document.querySelector(
|
|
`.village-select[data-address-id="${addressId}"]`);
|
|
if (villageSelect) {
|
|
villageSelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_village') }}</option>';
|
|
}
|
|
|
|
// Load villages if district is selected
|
|
if (districtId) {
|
|
loadVillages(addressId, districtId);
|
|
}
|
|
}
|
|
});
|
|
|
|
function loadCitiesForAddress(addressId, provinceId, currentCityId = null, currentDistrictId = null,
|
|
currentVillageId = null) {
|
|
fetch(`/addresses/cities/${provinceId}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const citySelect = document.querySelector(
|
|
`.city-select[data-address-id="${addressId}"]`);
|
|
if (citySelect) {
|
|
// Clear and set options
|
|
citySelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_city') }}</option>';
|
|
|
|
data.data.forEach(city => {
|
|
const option = document.createElement('option');
|
|
option.value = city.id;
|
|
option.textContent = city.name;
|
|
|
|
if (currentCityId && city.id == currentCityId) {
|
|
option.selected = true;
|
|
}
|
|
|
|
citySelect.appendChild(option);
|
|
});
|
|
|
|
// Initialize Choices.js
|
|
if (window.Choices) {
|
|
// Destroy existing instance if any
|
|
if (citySelect.choices) {
|
|
citySelect.choices.destroy();
|
|
}
|
|
// Initialize new Choices instance
|
|
citySelect.choices = new window.Choices(citySelect, {
|
|
searchEnabled: true,
|
|
itemSelectText: 'Select an option',
|
|
noResultsText: 'No results found',
|
|
shouldSort: false
|
|
});
|
|
}
|
|
|
|
// Load districts if city is selected
|
|
if (currentCityId) {
|
|
loadDistrictsForAddress(addressId, currentCityId, currentDistrictId,
|
|
currentVillageId);
|
|
}
|
|
}
|
|
})
|
|
.catch(error => console.log('Error loading cities:', error));
|
|
}
|
|
|
|
function loadDistrictsForAddress(addressId, cityId, currentDistrictId = null, currentVillageId = null) {
|
|
fetch(`/addresses/districts/${cityId}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const districtSelect = document.querySelector(
|
|
`.district-select[data-address-id="${addressId}"]`);
|
|
if (districtSelect) {
|
|
// Clear and set options
|
|
districtSelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_district') }}</option>';
|
|
|
|
data.data.forEach(district => {
|
|
const option = document.createElement('option');
|
|
option.value = district.id;
|
|
option.textContent = district.name;
|
|
|
|
if (currentDistrictId && district.id == currentDistrictId) {
|
|
option.selected = true;
|
|
}
|
|
|
|
districtSelect.appendChild(option);
|
|
});
|
|
|
|
// Initialize Choices.js
|
|
if (window.Choices) {
|
|
// Destroy existing instance if any
|
|
if (districtSelect.choices) {
|
|
districtSelect.choices.destroy();
|
|
}
|
|
// Initialize new Choices instance
|
|
districtSelect.choices = new window.Choices(districtSelect, {
|
|
searchEnabled: true,
|
|
itemSelectText: 'Select an option',
|
|
noResultsText: 'No results found',
|
|
shouldSort: false
|
|
});
|
|
}
|
|
|
|
// Load villages if district is selected
|
|
if (currentDistrictId) {
|
|
loadVillages(addressId, currentDistrictId, currentVillageId);
|
|
}
|
|
}
|
|
})
|
|
.catch(error => console.log('Error loading districts:', error));
|
|
}
|
|
|
|
function loadVillages(addressId, districtId, currentVillageId = null) {
|
|
fetch(`/addresses/villages/${districtId}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const villageSelect = document.querySelector(
|
|
`.village-select[data-address-id="${addressId}"]`);
|
|
if (villageSelect) {
|
|
// Clear and set options
|
|
villageSelect.innerHTML =
|
|
'<option value="">{{ __('addresses.select_village') }}</option>';
|
|
|
|
data.data.forEach(village => {
|
|
const option = document.createElement('option');
|
|
option.value = village.id;
|
|
option.textContent = village.name;
|
|
|
|
if (currentVillageId && village.id == currentVillageId) {
|
|
option.selected = true;
|
|
}
|
|
|
|
villageSelect.appendChild(option);
|
|
});
|
|
|
|
// Initialize Choices.js
|
|
if (window.Choices) {
|
|
// Destroy existing instance if any
|
|
if (villageSelect.choices) {
|
|
villageSelect.choices.destroy();
|
|
}
|
|
// Initialize new Choices instance
|
|
villageSelect.choices = new window.Choices(villageSelect, {
|
|
searchEnabled: true,
|
|
itemSelectText: 'Select an option',
|
|
noResultsText: 'No results found',
|
|
shouldSort: false
|
|
});
|
|
}
|
|
}
|
|
})
|
|
.catch(error => console.log('Error loading villages:', error));
|
|
}
|
|
});
|
|
</script>
|
|
@endsection
|