Merge branch 'main' into dev
This commit is contained in:
commit
7991a9b662
@ -1302,6 +1302,7 @@
|
||||
"Remote dispense failed for slot :slot": "Remote dispense failed for slot :slot",
|
||||
"Remote dispense successful for slot :slot": "Remote dispense successful for slot :slot",
|
||||
"Removal": "Removal",
|
||||
"Remove Assignment Confirmation": "Remove Assignment Confirmation",
|
||||
"Repair": "Repair",
|
||||
"Replenish": "Replenish",
|
||||
"Replenishment": "Replenishment",
|
||||
|
||||
@ -1302,6 +1302,7 @@
|
||||
"Remote dispense failed for slot :slot": "スロット :slot の遠隔出庫に失敗しました",
|
||||
"Remote dispense successful for slot :slot": "スロット :slot の遠隔出庫に成功しました",
|
||||
"Removal": "撤去",
|
||||
"Remove Assignment Confirmation": "割り当て解除の確認",
|
||||
"Repair": "修理",
|
||||
"Replenish": "補充",
|
||||
"Replenishment": "補充",
|
||||
|
||||
@ -1321,6 +1321,7 @@
|
||||
"Remote dispense failed for slot :slot": "貨道 :slot 遠端出貨失敗",
|
||||
"Remote dispense successful for slot :slot": "貨道 :slot 遠端出貨成功",
|
||||
"Removal": "撤機",
|
||||
"Remove Assignment Confirmation": "確認解除綁定",
|
||||
"Repair": "維修",
|
||||
"Replenish": "補貨",
|
||||
"Replenishment": "補貨",
|
||||
|
||||
@ -760,6 +760,17 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
|
||||
<x-status-confirm-modal :title="__('Disable Advertisement Confirmation')" :message="__('Are you sure you want to disable this advertisement?')" />
|
||||
|
||||
<x-confirm-modal
|
||||
alpineVar="isAssignmentDeleteOpen"
|
||||
confirmAction="submitRemoveAssignment()"
|
||||
iconType="danger"
|
||||
confirmColor="rose"
|
||||
:title="__('Remove Assignment Confirmation')"
|
||||
:message="__('Are you sure you want to remove this assignment?')"
|
||||
:confirmText="__('Delete Permanently')"
|
||||
isSubmittingVar="isSubmitting"
|
||||
/>
|
||||
|
||||
<form x-ref="statusToggleForm" :action="toggleFormAction" method="POST" class="hidden">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
@ -790,6 +801,10 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
isDeleteConfirmOpen: false,
|
||||
deleteFormAction: '',
|
||||
|
||||
// Assignment Delete Modal
|
||||
isAssignmentDeleteOpen: false,
|
||||
assignmentIdToDelete: null,
|
||||
|
||||
// Status Toggle
|
||||
isStatusConfirmOpen: false,
|
||||
toggleFormAction: '',
|
||||
@ -1218,6 +1233,11 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
},
|
||||
|
||||
async submitAssignment() {
|
||||
if (this.isSubmitting) return;
|
||||
this.isSubmitting = true;
|
||||
|
||||
const bar = document.getElementById('top-loading-bar');
|
||||
if (bar) bar.classList.add('loading');
|
||||
try {
|
||||
const response = await fetch(this.urls.assign, {
|
||||
method: 'POST',
|
||||
@ -1232,7 +1252,7 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
const result = await response.json();
|
||||
if (response.ok && result.success) {
|
||||
this.isAssignModalOpen = false;
|
||||
this.fetchMachineAds();
|
||||
await this.fetchMachineAds();
|
||||
window.showToast?.(result.message, 'success');
|
||||
} else {
|
||||
let msg = result.message || 'Error';
|
||||
@ -1244,6 +1264,9 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
} catch (e) {
|
||||
console.error('Failed to assign ad', e);
|
||||
window.showToast?.('{{ __("System Error") }}', 'error');
|
||||
} finally {
|
||||
this.isSubmitting = false;
|
||||
if (bar) bar.classList.remove('loading');
|
||||
}
|
||||
},
|
||||
|
||||
@ -1280,6 +1303,7 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
|
||||
async fetchMachineAds() {
|
||||
const url = this.urls.getMachineAds.replace(':id', this.selectedMachineId);
|
||||
this.isLoading = true;
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const result = await response.json();
|
||||
@ -1292,6 +1316,8 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch machine ads', e);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1406,8 +1432,20 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
});
|
||||
},
|
||||
|
||||
async removeAssignment(id) {
|
||||
if (!confirm("{{ __('Are you sure you want to remove this assignment?') }}")) return;
|
||||
removeAssignment(id) {
|
||||
this.assignmentIdToDelete = id;
|
||||
this.isAssignmentDeleteOpen = true;
|
||||
},
|
||||
|
||||
async submitRemoveAssignment() {
|
||||
const id = this.assignmentIdToDelete;
|
||||
if (!id) return;
|
||||
|
||||
if (this.isSubmitting) return;
|
||||
this.isSubmitting = true;
|
||||
|
||||
const bar = document.getElementById('top-loading-bar');
|
||||
if (bar) bar.classList.add('loading');
|
||||
|
||||
const url = this.urls.removeAssignment.replace(':id', id);
|
||||
try {
|
||||
@ -1420,13 +1458,19 @@ $baseRoute = 'admin.data-config.advertisements';
|
||||
});
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
this.fetchMachineAds();
|
||||
this.isAssignmentDeleteOpen = false;
|
||||
await this.fetchMachineAds();
|
||||
window.showToast?.(result.message, 'success');
|
||||
} else {
|
||||
window.showToast?.(result.message || 'Error', 'error');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to remove assignment', e);
|
||||
} finally {
|
||||
this.assignmentIdToDelete = null;
|
||||
this.isAssignmentDeleteOpen = false;
|
||||
this.isSubmitting = false;
|
||||
if (bar) bar.classList.remove('loading');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0">
|
||||
|
||||
<div class="fixed inset-0 bg-slate-900/60 backdrop-blur-sm" @click="isAssignModalOpen = false"></div>
|
||||
<div class="fixed inset-0 bg-slate-900/60 backdrop-blur-sm" @click="!isSubmitting && (isAssignModalOpen = false)"></div>
|
||||
|
||||
<div class="flex items-center justify-center min-h-screen p-4 sm:p-0">
|
||||
<div class="relative inline-block px-8 py-10 text-left align-bottom transition-all transform luxury-card rounded-3xl dark:bg-slate-900 border-slate-200/50 dark:border-slate-700/50 shadow-2xl sm:my-8 sm:align-middle sm:max-w-lg sm:w-full overflow-visible animate-luxury-in">
|
||||
@ -19,7 +19,7 @@
|
||||
<h3 class="text-2xl font-black text-slate-800 dark:text-white font-display tracking-tight">{{ __('Assign Advertisement') }}</h3>
|
||||
<p class="text-[10px] font-bold text-slate-400 uppercase tracking-widest mt-1">{{ __('Select a material to play on this machine') }}</p>
|
||||
</div>
|
||||
<button @click="isAssignModalOpen = false" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors">
|
||||
<button @click="!isSubmitting && (isAssignModalOpen = false)" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors" :disabled="isSubmitting">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M6 18L18 6M6 6l12 12" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
@ -44,11 +44,15 @@
|
||||
|
||||
<!-- Action Footer -->
|
||||
<div class="flex items-center justify-end gap-3 pt-6">
|
||||
<button type="button" @click="isAssignModalOpen = false" class="px-6 py-3 text-sm font-black text-slate-500 hover:text-slate-700 dark:hover:text-slate-300 transition-colors uppercase tracking-widest">
|
||||
<button type="button" @click="isAssignModalOpen = false" :disabled="isSubmitting" class="px-6 py-3 text-sm font-black text-slate-500 hover:text-slate-700 dark:hover:text-slate-300 transition-colors uppercase tracking-widest disabled:opacity-60 disabled:cursor-not-allowed">
|
||||
{{ __('Cancel') }}
|
||||
</button>
|
||||
<button type="submit" class="btn-luxury-primary px-10 py-3">
|
||||
{{ __('Confirm Assignment') }}
|
||||
<button type="submit" :disabled="isSubmitting" class="btn-luxury-primary px-10 py-3 flex items-center justify-center gap-2 disabled:opacity-60 disabled:cursor-not-allowed">
|
||||
<svg x-show="isSubmitting" x-cloak class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<span>{{ __('Confirm Assignment') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
'confirmText' => __('Confirm'),
|
||||
'cancelText' => __('Cancel'),
|
||||
'confirmColor' => 'sky', // sky, rose, amber, emerald
|
||||
'isSubmittingVar' => null, // Optional Alpine variable for submitting state
|
||||
])
|
||||
|
||||
@php
|
||||
@ -77,11 +78,19 @@
|
||||
</div>
|
||||
<div class="mt-8 sm:mt-10 sm:flex sm:flex-row-reverse gap-3">
|
||||
<button type="button" @click="{{ $confirmAction }}"
|
||||
class="inline-flex justify-center w-full px-6 py-3 text-sm font-black text-white transition-all rounded-xl shadow-lg dark:shadow-none hover:scale-[1.02] active:scale-[0.98] sm:w-auto uppercase tracking-widest font-display {{ $btnClasses }}">
|
||||
{{ $confirmText }}
|
||||
@if($isSubmittingVar) :disabled="{{ $isSubmittingVar }}" @endif
|
||||
class="inline-flex items-center justify-center gap-2 w-full px-6 py-3 text-sm font-black text-white transition-all rounded-xl shadow-lg dark:shadow-none hover:scale-[1.02] active:scale-[0.98] sm:w-auto uppercase tracking-widest font-display {{ $btnClasses }} disabled:opacity-60 disabled:cursor-not-allowed">
|
||||
@if($isSubmittingVar)
|
||||
<svg x-show="{{ $isSubmittingVar }}" x-cloak class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
@endif
|
||||
<span>{{ $confirmText }}</span>
|
||||
</button>
|
||||
<button type="button" @click="{{ $alpineVar }} = false"
|
||||
class="inline-flex justify-center w-full px-6 py-3 mt-3 text-sm font-black text-slate-700 dark:text-slate-200 transition-all bg-slate-100 dark:bg-slate-800 rounded-xl hover:bg-slate-200 dark:hover:bg-slate-700 sm:mt-0 sm:w-auto uppercase tracking-widest font-display">
|
||||
@if($isSubmittingVar) :disabled="{{ $isSubmittingVar }}" @endif
|
||||
class="inline-flex justify-center w-full px-6 py-3 mt-3 text-sm font-black text-slate-700 dark:text-slate-200 transition-all bg-slate-100 dark:bg-slate-800 rounded-xl hover:bg-slate-200 dark:hover:bg-slate-700 sm:mt-0 sm:w-auto uppercase tracking-widest font-display disabled:opacity-60 disabled:cursor-not-allowed">
|
||||
{{ $cancelText }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user