interim fix for drop downs
This commit is contained in:
@@ -18,11 +18,11 @@ class CompanyController extends Controller
|
||||
{
|
||||
return view('company::index', [
|
||||
'companies' => Company::query()
|
||||
->with(['address.country', 'country'])
|
||||
->with(['address.country'])
|
||||
->withCount(['users', 'warehouses', 'licenseKeys', 'divisions'])
|
||||
->latest('id')
|
||||
->paginate(20),
|
||||
'countries' => $this->countries(),
|
||||
'countries' => $this->countriesForSelect(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class CompanyController extends Controller
|
||||
'status' => 'active',
|
||||
'timezone' => 'Europe/London',
|
||||
]),
|
||||
'countries' => $this->countries(),
|
||||
'countries' => $this->countriesForSelect(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,10 @@ class CompanyController extends Controller
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$company = Company::create($this->validated($request));
|
||||
$validated = $this->validated($request);
|
||||
|
||||
$company = Company::create($validated['company']);
|
||||
$this->syncAddressCountry($company, $validated['country_id']);
|
||||
|
||||
return redirect()
|
||||
->route('platform.companies.index')
|
||||
@@ -73,7 +76,7 @@ class CompanyController extends Controller
|
||||
'recentUsers' => $company->users()->latest('id')->limit(5)->get(),
|
||||
'recentWarehouses' => $company->warehouses()->latest('id')->limit(5)->get(),
|
||||
'recentLicenseKeys' => $company->licenseKeys()->latest('id')->limit(5)->get(),
|
||||
'countries' => Country::query()->active()->orderBy('sort_order')->orderBy('name')->get(['id', 'alpha2', 'name', 'display_name', 'common_name']),
|
||||
'countries' => $this->countriesForSelect(),
|
||||
'companyUsers' => $company->users()->orderBy('name')->get(['id', 'name', 'email', 'company_id']),
|
||||
'unassignedWarehouses' => $company->warehouses()->whereNull('division_id')->orderBy('name')->get(),
|
||||
]);
|
||||
@@ -85,8 +88,8 @@ class CompanyController extends Controller
|
||||
public function edit(Company $company)
|
||||
{
|
||||
return view('company::edit', [
|
||||
'company' => $company->loadMissing(['address.country', 'country']),
|
||||
'countries' => $this->countries(),
|
||||
'company' => $company->loadMissing('address.country'),
|
||||
'countries' => $this->countriesForSelect(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -95,7 +98,10 @@ class CompanyController extends Controller
|
||||
*/
|
||||
public function update(Request $request, Company $company)
|
||||
{
|
||||
$company->update($this->validated($request, $company));
|
||||
$validated = $this->validated($request, $company);
|
||||
|
||||
$company->update($validated['company']);
|
||||
$this->syncAddressCountry($company, $validated['country_id']);
|
||||
|
||||
return redirect()
|
||||
->route('platform.companies.show', $company)
|
||||
@@ -122,20 +128,44 @@ class CompanyController extends Controller
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'billing_email' => ['nullable', 'email', 'max:255'],
|
||||
'status' => ['required', Rule::in(['active', 'suspended', 'inactive'])],
|
||||
'country_id' => ['nullable', Rule::exists('countries', 'id')->where('is_active', true)],
|
||||
'country_id' => ['nullable', 'integer', Rule::exists('countries', 'id')],
|
||||
]);
|
||||
|
||||
$data['slug'] = Str::slug($data['name']);
|
||||
$data['timezone'] = $company?->timezone ?: 'Europe/London';
|
||||
|
||||
return $data;
|
||||
return [
|
||||
'company' => [
|
||||
'name' => $data['name'],
|
||||
'billing_email' => $data['billing_email'] ?? null,
|
||||
'status' => $data['status'],
|
||||
'slug' => Str::slug($data['name']),
|
||||
'timezone' => $company?->timezone ?: 'Europe/London',
|
||||
],
|
||||
'country_id' => $data['country_id'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
private function countries()
|
||||
private function countriesForSelect()
|
||||
{
|
||||
return Country::query()
|
||||
->active()
|
||||
->ordered()
|
||||
->get(['id', 'alpha2', 'name', 'display_name', 'common_name', 'sort_order']);
|
||||
->orderByRaw("LOWER(COALESCE(NULLIF(display_name, ''), NULLIF(common_name, ''), name)) ASC")
|
||||
->get(['id', 'alpha2', 'name', 'display_name', 'common_name']);
|
||||
}
|
||||
|
||||
private function syncAddressCountry(Company $company, ?int $countryId): void
|
||||
{
|
||||
if ($countryId === null) {
|
||||
$company->address()?->delete();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$company->address()->updateOrCreate(
|
||||
[],
|
||||
[
|
||||
'country_id' => $countryId,
|
||||
'label' => 'Registered address',
|
||||
'is_primary' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
@csrf
|
||||
|
||||
<div class="grid gap-6 md:grid-cols-2">
|
||||
<div class="grid gap-6 lg:grid-cols-2">
|
||||
<div>
|
||||
<label for="name" class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200">Company name</label>
|
||||
<input
|
||||
id="name"
|
||||
name="name"
|
||||
value="{{ old('name', $company->name) }}"
|
||||
class="mt-2 w-full rounded-xl border-zinc-300 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
class="mt-2 h-12 w-full rounded-xl border-zinc-300 bg-white px-4 text-sm text-zinc-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
required
|
||||
>
|
||||
@error('name')
|
||||
@@ -23,7 +23,7 @@
|
||||
name="billing_email"
|
||||
value="{{ old('billing_email', $company->billing_email) }}"
|
||||
placeholder="billing@example.com"
|
||||
class="mt-2 w-full rounded-xl border-zinc-300 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
class="mt-2 h-12 w-full rounded-xl border-zinc-300 bg-white px-4 text-sm text-zinc-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
>
|
||||
@error('billing_email')
|
||||
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@@ -35,7 +35,7 @@
|
||||
<select
|
||||
id="status"
|
||||
name="status"
|
||||
class="mt-2 w-full rounded-xl border-zinc-300 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
class="mt-2 h-12 w-full rounded-xl border-zinc-300 bg-white px-4 text-sm text-zinc-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
required
|
||||
>
|
||||
<option value="active" @selected(old('status', $company->status) === 'active')>Active</option>
|
||||
@@ -47,25 +47,26 @@
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="wms-form-field wms-select2-field">
|
||||
<div>
|
||||
<label for="country_id" class="block text-sm font-semibold text-zinc-700 dark:text-zinc-200">Country</label>
|
||||
<div class="mt-2">
|
||||
<select
|
||||
id="country_id"
|
||||
name="country_id"
|
||||
data-wms-select2
|
||||
data-placeholder="Search and select country"
|
||||
class="wms-country-select w-full"
|
||||
>
|
||||
<option value="">Search and select country</option>
|
||||
@foreach ($countries as $country)
|
||||
<option value="{{ $country->id }}" @selected((int) old('country_id', $company->country_id ?? $company->address?->country_id) === $country->id)>
|
||||
{{ $country->effective_name ?? $country->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<p class="mt-2 text-xs font-medium text-zinc-500 dark:text-zinc-400">Start typing to filter the country list.</p>
|
||||
<select
|
||||
id="country_id"
|
||||
name="country_id"
|
||||
data-company-country-select2
|
||||
data-placeholder="Search and select country"
|
||||
class="wms-country-select mt-2 w-full"
|
||||
>
|
||||
<option value=""></option>
|
||||
@foreach($countries as $country)
|
||||
<option
|
||||
value="{{ $country->id }}"
|
||||
data-code="{{ $country->alpha2 }}"
|
||||
@selected(old('country_id', $company->address?->country_id) == $country->id)
|
||||
>
|
||||
{{ $country->display_name ?? $country->common_name ?? $country->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('country_id')
|
||||
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@enderror
|
||||
@@ -73,14 +74,188 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-8 flex flex-wrap items-center gap-3 border-t border-zinc-200 pt-6 dark:border-zinc-800">
|
||||
<button class="inline-flex items-center justify-center rounded-xl bg-green-600 px-5 py-2.5 text-sm font-bold text-white shadow-sm shadow-green-600/20 transition hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 dark:bg-green-500 dark:text-white dark:hover:bg-green-400 dark:focus:ring-offset-zinc-900">
|
||||
<button class="rounded-xl bg-green-600 px-5 py-2.5 text-sm font-semibold text-white shadow-sm shadow-green-950/20 transition hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/40">
|
||||
Save company
|
||||
</button>
|
||||
|
||||
<a
|
||||
href="{{ $company->exists ? route('platform.companies.show', $company) : route('platform.companies.index') }}"
|
||||
class="rounded-xl border border-zinc-300 px-4 py-2 text-sm font-semibold text-zinc-700 hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-800"
|
||||
class="rounded-xl border border-zinc-300 px-5 py-2.5 text-sm font-semibold text-zinc-700 transition hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-200 dark:hover:bg-zinc-800"
|
||||
>
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
@once
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css">
|
||||
|
||||
<style>
|
||||
.wms-country-select.select2-hidden-accessible {
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
padding: 0 !important;
|
||||
margin: -1px !important;
|
||||
overflow: hidden !important;
|
||||
clip: rect(0, 0, 0, 0) !important;
|
||||
white-space: nowrap !important;
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
margin-top: 0.5rem !important;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single {
|
||||
height: 3rem !important;
|
||||
min-height: 3rem !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
border-radius: 0.75rem !important;
|
||||
border: 1px solid rgb(63 63 70) !important;
|
||||
background: rgb(9 9 11) !important;
|
||||
box-shadow: none !important;
|
||||
transition: border-color 150ms ease, box-shadow 150ms ease, background-color 150ms ease !important;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__rendered {
|
||||
width: 100% !important;
|
||||
height: 3rem !important;
|
||||
line-height: 3rem !important;
|
||||
padding-left: 1rem !important;
|
||||
padding-right: 2.75rem !important;
|
||||
color: rgb(244 244 245) !important;
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__placeholder {
|
||||
color: rgb(161 161 170) !important;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__arrow {
|
||||
height: 3rem !important;
|
||||
right: 0.75rem !important;
|
||||
top: 0 !important;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: rgb(161 161 170) transparent transparent transparent !important;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__clear {
|
||||
margin-right: 0.5rem !important;
|
||||
color: rgb(161 161 170) !important;
|
||||
font-size: 1rem !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container.select2-container--focus .select2-selection--single,
|
||||
.wms-country-select + .select2-container.select2-container--open .select2-selection--single {
|
||||
border-color: rgb(59 130 246) !important;
|
||||
box-shadow: 0 0 0 3px rgb(59 130 246 / 0.28) !important;
|
||||
}
|
||||
|
||||
.select2-container--open .select2-dropdown.wms-country-select2-dropdown,
|
||||
.wms-country-select2-dropdown {
|
||||
border: 1px solid rgb(63 63 70) !important;
|
||||
border-radius: 0.875rem !important;
|
||||
overflow: hidden !important;
|
||||
background: rgb(24 24 27) !important;
|
||||
box-shadow: 0 20px 35px -15px rgb(0 0 0 / 0.7) !important;
|
||||
}
|
||||
|
||||
.wms-country-select2-dropdown .select2-search--dropdown {
|
||||
padding: 0.75rem !important;
|
||||
border-bottom: 1px solid rgb(63 63 70) !important;
|
||||
background: rgb(24 24 27) !important;
|
||||
}
|
||||
|
||||
.wms-country-select2-dropdown .select2-search__field {
|
||||
min-height: 2.5rem !important;
|
||||
border-radius: 0.75rem !important;
|
||||
border: 1px solid rgb(63 63 70) !important;
|
||||
background: rgb(9 9 11) !important;
|
||||
padding: 0.5rem 0.75rem !important;
|
||||
color: rgb(244 244 245) !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.wms-country-select2-dropdown .select2-results__option {
|
||||
padding: 0.7rem 0.9rem !important;
|
||||
color: rgb(228 228 231) !important;
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
|
||||
.wms-country-select2-dropdown .select2-results__option--highlighted.select2-results__option--selectable {
|
||||
background: rgb(37 99 235) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.wms-country-select2-dropdown .select2-results__option--selected {
|
||||
background: rgb(22 101 52) !important;
|
||||
color: white !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
function loadScript(src, callback) {
|
||||
var existing = document.querySelector('script[src="' + src + '"]');
|
||||
if (existing) {
|
||||
existing.addEventListener('load', callback, { once: true });
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var script = document.createElement('script');
|
||||
script.src = src;
|
||||
script.defer = true;
|
||||
script.onload = callback;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
function initCompanyCountrySelect2() {
|
||||
if (!window.jQuery || !window.jQuery.fn || !window.jQuery.fn.select2) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.jQuery('[data-company-country-select2]').each(function () {
|
||||
var select = window.jQuery(this);
|
||||
|
||||
if (select.hasClass('select2-hidden-accessible')) {
|
||||
return;
|
||||
}
|
||||
|
||||
select.select2({
|
||||
width: '100%',
|
||||
placeholder: select.data('placeholder') || 'Search and select country',
|
||||
allowClear: true,
|
||||
dropdownAutoWidth: false,
|
||||
dropdownCssClass: 'wms-country-select2-dropdown',
|
||||
selectionCssClass: 'wms-country-select2-selection'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
window.initialiseCompanyCountrySelect2 = initCompanyCountrySelect2;
|
||||
|
||||
function bootCompanyCountrySelect2() {
|
||||
if (window.jQuery && window.jQuery.fn && window.jQuery.fn.select2) {
|
||||
initCompanyCountrySelect2();
|
||||
return;
|
||||
}
|
||||
|
||||
loadScript('https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js', function () {
|
||||
loadScript('https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js', initCompanyCountrySelect2);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', bootCompanyCountrySelect2);
|
||||
document.addEventListener('livewire:navigated', bootCompanyCountrySelect2);
|
||||
bootCompanyCountrySelect2();
|
||||
})();
|
||||
</script>
|
||||
@endonce
|
||||
|
||||
@@ -30,57 +30,86 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('platform.companies.store') }}" class="mt-6 grid gap-5 lg:grid-cols-12 lg:items-end">
|
||||
<form method="POST" action="{{ route('platform.companies.store') }}" class="mt-6">
|
||||
@csrf
|
||||
|
||||
<div class="lg:col-span-3">
|
||||
<label for="quick_company_name" class="mb-2 block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Company</label>
|
||||
<input
|
||||
id="quick_company_name"
|
||||
name="name"
|
||||
value="{{ old('name') }}"
|
||||
placeholder="Company name"
|
||||
class="h-11 w-full rounded-xl border-zinc-300 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
required
|
||||
>
|
||||
</div>
|
||||
<div class="grid gap-5 xl:grid-cols-[minmax(0,1.15fr)_minmax(0,1.15fr)_minmax(12rem,.75fr)_minmax(18rem,1.15fr)_auto] xl:items-end">
|
||||
<div>
|
||||
<label for="quick_company_name" class="block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Company</label>
|
||||
<input
|
||||
id="quick_company_name"
|
||||
name="name"
|
||||
value="{{ old('name') }}"
|
||||
placeholder="Company name"
|
||||
class="mt-2 h-12 w-full rounded-xl border-zinc-300 bg-white px-4 text-sm text-zinc-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
required
|
||||
>
|
||||
@error('name')
|
||||
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="lg:col-span-3">
|
||||
<label for="quick_billing_email" class="mb-2 block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Billing email</label>
|
||||
<input
|
||||
id="quick_billing_email"
|
||||
name="billing_email"
|
||||
value="{{ old('billing_email') }}"
|
||||
placeholder="billing@example.com"
|
||||
type="email"
|
||||
class="h-11 w-full rounded-xl border-zinc-300 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<label for="quick_billing_email" class="block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Billing email</label>
|
||||
<input
|
||||
id="quick_billing_email"
|
||||
name="billing_email"
|
||||
value="{{ old('billing_email') }}"
|
||||
placeholder="billing@example.com"
|
||||
type="email"
|
||||
class="mt-2 h-12 w-full rounded-xl border-zinc-300 bg-white px-4 text-sm text-zinc-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
>
|
||||
@error('billing_email')
|
||||
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="lg:col-span-2">
|
||||
<label for="quick_status" class="mb-2 block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Status</label>
|
||||
<select id="quick_status" name="status" class="h-11 w-full rounded-xl border-zinc-300 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white" required>
|
||||
<option value="active" @selected(old('status', 'active') === 'active')>Active</option>
|
||||
<option value="suspended" @selected(old('status') === 'suspended')>Suspended</option>
|
||||
<option value="inactive" @selected(old('status') === 'inactive')>Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="quick_status" class="block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Status</label>
|
||||
<select
|
||||
id="quick_status"
|
||||
name="status"
|
||||
class="mt-2 h-12 w-full rounded-xl border-zinc-300 bg-white px-4 text-sm text-zinc-900 shadow-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/30 dark:border-zinc-700 dark:bg-zinc-950 dark:text-white"
|
||||
required
|
||||
>
|
||||
<option value="active" @selected(old('status', 'active') === 'active')>Active</option>
|
||||
<option value="suspended" @selected(old('status') === 'suspended')>Suspended</option>
|
||||
<option value="inactive" @selected(old('status') === 'inactive')>Inactive</option>
|
||||
</select>
|
||||
@error('status')
|
||||
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="wms-select2-field lg:col-span-3">
|
||||
<label for="quick_country_id" class="mb-2 block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Country</label>
|
||||
<select id="quick_country_id" name="country_id" data-wms-select2 data-placeholder="Search country" class="wms-country-select w-full">
|
||||
<option value="">Search country</option>
|
||||
@foreach ($countries as $country)
|
||||
<option value="{{ $country->id }}" @selected((int) old('country_id') === $country->id)>
|
||||
{{ $country->effective_name ?? $country->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="quick_country_id" class="block text-xs font-bold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">Country</label>
|
||||
<select
|
||||
id="quick_country_id"
|
||||
name="country_id"
|
||||
data-company-country-select2
|
||||
data-placeholder="Search and select country"
|
||||
class="wms-country-select mt-2 w-full"
|
||||
>
|
||||
<option value=""></option>
|
||||
@foreach($countries as $country)
|
||||
<option
|
||||
value="{{ $country->id }}"
|
||||
data-code="{{ $country->alpha2 }}"
|
||||
@selected(old('country_id') == $country->id)
|
||||
>
|
||||
{{ $country->display_name ?? $country->common_name ?? $country->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('country_id')
|
||||
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button class="inline-flex h-11 items-center justify-center rounded-xl bg-green-600 px-5 text-sm font-bold text-white shadow-sm shadow-green-600/20 transition hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 dark:bg-green-500 dark:hover:bg-green-400 dark:focus:ring-offset-zinc-900 lg:col-span-1">
|
||||
Create
|
||||
</button>
|
||||
<button class="h-12 rounded-xl bg-green-600 px-6 text-sm font-bold text-white shadow-sm shadow-green-950/20 transition hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-green-500/40">
|
||||
Create
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="overflow-x-auto rounded-2xl bg-white shadow-sm ring-1 ring-zinc-200 dark:bg-zinc-900 dark:ring-zinc-800">
|
||||
@@ -183,4 +212,30 @@
|
||||
|
||||
{{ $companies->links() }}
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
|
||||
<script>
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
$('[data-company-country-select2]').select2({
|
||||
|
||||
width: '100%',
|
||||
|
||||
placeholder: 'Search and select country',
|
||||
|
||||
allowClear: true,
|
||||
|
||||
dropdownAutoWidth: false,
|
||||
|
||||
sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)),
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@endpush
|
||||
</x-layouts::app>
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
latest: 1.2.0
|
||||
latest: 1.2.1
|
||||
|
||||
versions:
|
||||
- version: 1.2.1
|
||||
date: 2026-07-07
|
||||
changes:
|
||||
- Replaced company country inputs with a shared Select2-enhanced dropdown populated by the Countries module.
|
||||
- Aligned the company create forms and changed the primary create/save action to green.
|
||||
- Stored the selected country on the company address relationship during create and update.
|
||||
- version: 1.2.0
|
||||
date: 2026-07-02
|
||||
changes:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Company",
|
||||
"alias": "company",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.1",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"priority": 0,
|
||||
|
||||
@@ -13,10 +13,7 @@ use Modules\Countries\Support\CountryUsageReport;
|
||||
|
||||
class CountriesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display ISO 3166 country records.
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
public function __invoke(Request $request): View
|
||||
{
|
||||
$search = trim((string) $request->query('search', ''));
|
||||
$status = (string) $request->query('status', 'all');
|
||||
@@ -40,80 +37,78 @@ class CountriesController extends Controller
|
||||
->when($status === 'active', fn ($query) => $query->where('is_active', true))
|
||||
->when($status === 'inactive', fn ($query) => $query->where('is_active', false))
|
||||
->when($region !== 'all' && $region !== '', fn ($query) => $query->where('region', $region))
|
||||
->ordered()
|
||||
->orderByRaw('LOWER(COALESCE(display_name, common_name, name)) ASC')
|
||||
->paginate(50)
|
||||
->withQueryString();
|
||||
|
||||
$activeCount = Country::query()->where('is_active', true)->count();
|
||||
$inactiveCount = Country::query()->where('is_active', false)->count();
|
||||
$totalCount = Country::query()->count();
|
||||
$regions = Country::query()->whereNotNull('region')->distinct()->orderBy('region')->pluck('region');
|
||||
|
||||
return view('countries::index', compact('countries', 'activeCount', 'inactiveCount', 'totalCount', 'search', 'status', 'region', 'regions'));
|
||||
$regions = Country::query()
|
||||
->whereNotNull('region')
|
||||
->distinct()
|
||||
->orderBy('region')
|
||||
->pluck('region');
|
||||
|
||||
return view('countries::index', compact(
|
||||
'countries',
|
||||
'activeCount',
|
||||
'inactiveCount',
|
||||
'totalCount',
|
||||
'search',
|
||||
'status',
|
||||
'region',
|
||||
'regions'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the country creation form.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('countries::create', ['country' => new Country]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new ISO country record.
|
||||
*/
|
||||
public function store(StoreCountryRequest $request): RedirectResponse
|
||||
{
|
||||
$country = Country::query()->create($this->payload($request));
|
||||
|
||||
return redirect()->route('countries.show', $country)->with('success', 'Country created.');
|
||||
return redirect()
|
||||
->route('countries.show', $country)
|
||||
->with('success', 'Country created.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a country record.
|
||||
*/
|
||||
public function show(Country $country, CountryUsageReport $usageReport): View
|
||||
{
|
||||
$country->load(['subdivisions' => fn ($query) => $query->ordered()->limit(250)]);
|
||||
|
||||
$usageRows = $usageReport->forCountry($country);
|
||||
|
||||
return view('countries::show', compact('country', 'usageRows'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the edit form.
|
||||
*/
|
||||
public function edit(Country $country): View
|
||||
{
|
||||
return view('countries::edit', compact('country'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all editable ISO/support fields.
|
||||
*/
|
||||
public function update(UpdateCountryRequest $request, Country $country): RedirectResponse
|
||||
{
|
||||
$country->update($this->payload($request));
|
||||
|
||||
return redirect()->route('countries.show', $country)->with('success', 'Country updated.');
|
||||
return redirect()
|
||||
->route('countries.show', $country)
|
||||
->with('success', 'Country updated.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft-delete a custom/retired country record.
|
||||
*/
|
||||
public function destroy(Country $country): RedirectResponse
|
||||
{
|
||||
$country->delete();
|
||||
|
||||
return redirect()->route('countries.index')->with('success', 'Country archived.');
|
||||
return redirect()
|
||||
->route('countries.index')
|
||||
->with('success', 'Country archived.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the database payload from validated request data.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function payload(StoreCountryRequest|UpdateCountryRequest $request): array
|
||||
{
|
||||
$data = $request->validated();
|
||||
@@ -130,7 +125,10 @@ class CountriesController extends Controller
|
||||
|
||||
foreach (['languages', 'timezones', 'metadata'] as $jsonField) {
|
||||
$value = $data[$jsonField] ?? null;
|
||||
$data[$jsonField] = blank($value) ? null : json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
$data[$jsonField] = blank($value)
|
||||
? null
|
||||
: json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
foreach (['is_active', 'independent', 'un_member'] as $booleanField) {
|
||||
|
||||
@@ -6,7 +6,7 @@ use Modules\Countries\Http\Controllers\CountrySyncController;
|
||||
use Modules\Countries\Http\Controllers\ReferenceDataController;
|
||||
|
||||
Route::prefix('countries')->name('countries.')->middleware(['web', 'auth'])->group(function (): void {
|
||||
Route::get('/', [CountriesController::class, 'index'])->name('index');
|
||||
Route::get('/', CountriesController::class)->name('index');
|
||||
Route::get('/create', [CountriesController::class, 'create'])->name('create');
|
||||
Route::post('/', [CountriesController::class, 'store'])->name('store');
|
||||
Route::post('/sync', CountrySyncController::class)->name('sync');
|
||||
|
||||
+126
-195
@@ -1410,199 +1410,130 @@ html[data-wms-sidebar="collapsed"] .wms-sidebar {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@layer components {
|
||||
.wms-select2-field .select2-container {
|
||||
width: 100% !important;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default .select2-selection--single {
|
||||
position: relative;
|
||||
min-height: 2.75rem;
|
||||
border: 1px solid rgb(212 212 216);
|
||||
border-radius: 0.85rem;
|
||||
background: linear-gradient(180deg, rgb(255 255 255), rgb(250 250 250));
|
||||
box-shadow: 0 1px 2px rgb(15 23 42 / 0.05);
|
||||
transition: border-color 140ms ease, box-shadow 140ms ease, background 140ms ease;
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
min-height: 2.75rem;
|
||||
padding-left: 0.95rem;
|
||||
padding-right: 3rem;
|
||||
color: rgb(24 24 27);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 650;
|
||||
line-height: 2.75rem;
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default .select2-selection--single .select2-selection__placeholder {
|
||||
color: rgb(113 113 122);
|
||||
font-weight: 550;
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default .select2-selection--single .select2-selection__clear {
|
||||
position: absolute;
|
||||
right: 2.6rem;
|
||||
top: 0.62rem;
|
||||
z-index: 2;
|
||||
width: 1.35rem;
|
||||
height: 1.35rem;
|
||||
border-radius: 999px;
|
||||
color: rgb(113 113 122);
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default .select2-selection--single .select2-selection__clear:hover {
|
||||
background: rgb(244 244 245);
|
||||
color: rgb(39 39 42);
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
top: 0.45rem;
|
||||
right: 0.55rem;
|
||||
width: 1.85rem;
|
||||
height: 1.85rem;
|
||||
border-radius: 0.65rem;
|
||||
background: rgb(244 244 245);
|
||||
border: 1px solid rgb(228 228 231);
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: rgb(82 82 91) transparent transparent transparent;
|
||||
border-width: 5px 4px 0 4px;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent rgb(82 82 91) transparent;
|
||||
border-width: 0 4px 5px 4px;
|
||||
}
|
||||
|
||||
.wms-select2-field .select2-container--default.select2-container--focus .select2-selection--single,
|
||||
.wms-select2-field .select2-container--default.select2-container--open .select2-selection--single {
|
||||
border-color: rgb(22 163 74);
|
||||
background: white;
|
||||
box-shadow: 0 0 0 4px rgb(34 197 94 / 0.14), 0 10px 24px rgb(15 23 42 / 0.08);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-dropdown {
|
||||
overflow: hidden;
|
||||
margin-top: 0.35rem;
|
||||
border: 1px solid rgb(212 212 216);
|
||||
border-radius: 1rem;
|
||||
background: white;
|
||||
box-shadow: 0 24px 60px rgb(15 23 42 / 0.18);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-search--dropdown {
|
||||
padding: 0.75rem;
|
||||
border-bottom: 1px solid rgb(244 244 245);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
min-height: 2.5rem;
|
||||
border: 1px solid rgb(212 212 216);
|
||||
border-radius: 0.75rem;
|
||||
padding: 0.55rem 0.8rem;
|
||||
background: rgb(250 250 250);
|
||||
color: rgb(24 24 27);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-search--dropdown .select2-search__field:focus {
|
||||
border-color: rgb(22 163 74);
|
||||
background: white;
|
||||
box-shadow: 0 0 0 4px rgb(34 197 94 / 0.14);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-results > .select2-results__options {
|
||||
max-height: 16rem;
|
||||
padding: 0.35rem;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-results__option {
|
||||
margin: 0.1rem 0;
|
||||
border-radius: 0.65rem;
|
||||
padding: 0.65rem 0.8rem;
|
||||
color: rgb(39 39 42);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
|
||||
background: rgb(22 163 74);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-results__option--selected {
|
||||
background: rgb(240 253 244);
|
||||
color: rgb(21 128 61);
|
||||
}
|
||||
|
||||
.dark .wms-select2-field .select2-container--default .select2-selection--single {
|
||||
border-color: rgb(63 63 70);
|
||||
background: linear-gradient(180deg, rgb(24 24 27), rgb(9 9 11));
|
||||
}
|
||||
|
||||
.dark .wms-select2-field .select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.dark .wms-select2-field .select2-container--default .select2-selection--single .select2-selection__placeholder {
|
||||
color: rgb(161 161 170);
|
||||
}
|
||||
|
||||
.dark .wms-select2-field .select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
border-color: rgb(63 63 70);
|
||||
background: rgb(39 39 42);
|
||||
}
|
||||
|
||||
.dark .wms-select2-field .select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: rgb(212 212 216) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.dark .wms-select2-field .select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent rgb(212 212 216) transparent;
|
||||
}
|
||||
|
||||
.dark .wms-select2-field .select2-container--default.select2-container--focus .select2-selection--single,
|
||||
.dark .wms-select2-field .select2-container--default.select2-container--open .select2-selection--single {
|
||||
border-color: rgb(34 197 94);
|
||||
background: rgb(9 9 11);
|
||||
box-shadow: 0 0 0 4px rgb(34 197 94 / 0.16);
|
||||
}
|
||||
|
||||
.dark .select2-container--default .select2-dropdown {
|
||||
border-color: rgb(63 63 70);
|
||||
background: rgb(24 24 27);
|
||||
color: rgb(244 244 245);
|
||||
box-shadow: 0 24px 60px rgb(0 0 0 / 0.35);
|
||||
}
|
||||
|
||||
.dark .select2-container--default .select2-search--dropdown {
|
||||
border-bottom-color: rgb(39 39 42);
|
||||
}
|
||||
|
||||
.dark .select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
border-color: rgb(63 63 70);
|
||||
background: rgb(9 9 11);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.dark .select2-container--default .select2-results__option {
|
||||
color: rgb(244 244 245);
|
||||
}
|
||||
|
||||
.dark .select2-container--default .select2-results__option--selected {
|
||||
background: rgb(20 83 45);
|
||||
color: rgb(220 252 231);
|
||||
}
|
||||
/* Company country Select2 */
|
||||
.wms-country-select + .select2-container {
|
||||
display: block;
|
||||
width: 100% !important;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single {
|
||||
height: 3rem;
|
||||
min-height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid rgb(212 212 216);
|
||||
background: rgb(255 255 255);
|
||||
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
transition: border-color 150ms ease, box-shadow 150ms ease, background-color 150ms ease;
|
||||
}
|
||||
|
||||
.dark .wms-country-select + .select2-container .select2-selection--single {
|
||||
border-color: rgb(63 63 70);
|
||||
background: rgb(9 9 11);
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__rendered {
|
||||
line-height: 3rem;
|
||||
width: 100%;
|
||||
padding-left: 1rem;
|
||||
padding-right: 2.75rem;
|
||||
color: rgb(24 24 27);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.dark .wms-country-select + .select2-container .select2-selection--single .select2-selection__rendered {
|
||||
color: rgb(244 244 245);
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__placeholder {
|
||||
color: rgb(113 113 122);
|
||||
}
|
||||
|
||||
.dark .wms-country-select + .select2-container .select2-selection--single .select2-selection__placeholder {
|
||||
color: rgb(161 161 170);
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__arrow {
|
||||
height: 3rem;
|
||||
right: 0.75rem;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: rgb(113 113 122) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container .select2-selection--single .select2-selection__clear {
|
||||
order: 2;
|
||||
margin-right: 0.5rem;
|
||||
color: rgb(113 113 122);
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.wms-country-select + .select2-container.select2-container--focus .select2-selection--single,
|
||||
.wms-country-select + .select2-container.select2-container--open .select2-selection--single {
|
||||
border-color: rgb(59 130 246);
|
||||
box-shadow: 0 0 0 3px rgb(59 130 246 / 0.28);
|
||||
}
|
||||
|
||||
.select2-container--open .select2-dropdown {
|
||||
border: 1px solid rgb(63 63 70);
|
||||
border-radius: 0.875rem;
|
||||
overflow: hidden;
|
||||
background: rgb(255 255 255);
|
||||
box-shadow: 0 20px 35px -15px rgb(0 0 0 / 0.45);
|
||||
}
|
||||
|
||||
.dark .select2-container--open .select2-dropdown {
|
||||
background: rgb(24 24 27);
|
||||
border-color: rgb(63 63 70);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-search--dropdown {
|
||||
padding: 0.75rem;
|
||||
border-bottom: 1px solid rgb(228 228 231);
|
||||
}
|
||||
|
||||
.dark .select2-container--default .select2-search--dropdown {
|
||||
border-bottom-color: rgb(63 63 70);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
min-height: 2.5rem;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid rgb(212 212 216);
|
||||
padding: 0.5rem 0.75rem;
|
||||
color: rgb(24 24 27);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.dark .select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
border-color: rgb(63 63 70);
|
||||
background: rgb(9 9 11);
|
||||
color: rgb(244 244 245);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-results__option {
|
||||
padding: 0.7rem 0.9rem;
|
||||
font-size: 0.875rem;
|
||||
color: rgb(39 39 42);
|
||||
}
|
||||
|
||||
.dark .select2-container--default .select2-results__option {
|
||||
color: rgb(228 228 231);
|
||||
}
|
||||
|
||||
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
||||
background: rgb(37 99 235);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-results__option--selected,
|
||||
.select2-container--default .select2-results__option[aria-selected="true"] {
|
||||
background: rgb(22 101 52);
|
||||
color: white;
|
||||
}
|
||||
|
||||
+8
-6
@@ -167,7 +167,7 @@ function initialiseSelect2() {
|
||||
return;
|
||||
}
|
||||
|
||||
$('[data-helpdesk-select2], [data-wms-select2]').each(function () {
|
||||
$('[data-helpdesk-select2], [data-company-country-select2]').each(function () {
|
||||
const $select = $(this);
|
||||
|
||||
if ($select.hasClass('select2-hidden-accessible')) {
|
||||
@@ -176,15 +176,17 @@ function initialiseSelect2() {
|
||||
|
||||
const isMultiple = $select.prop('multiple');
|
||||
|
||||
const placeholder =
|
||||
$select.data('placeholder') ||
|
||||
$select.find('option[value=""]').first().text() ||
|
||||
(isMultiple ? 'Select options' : 'Select option');
|
||||
|
||||
$select.select2({
|
||||
width: '100%',
|
||||
allowClear: !isMultiple,
|
||||
closeOnSelect: !isMultiple,
|
||||
dropdownAutoWidth: true,
|
||||
placeholder:
|
||||
$select.data('placeholder') ||
|
||||
$select.find('option[value=""]').first().text() ||
|
||||
(isMultiple ? 'Select options' : 'Select option'),
|
||||
dropdownAutoWidth: false,
|
||||
placeholder,
|
||||
});
|
||||
|
||||
$select.off('change.select2-livewire');
|
||||
|
||||
Reference in New Issue
Block a user