All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 1m2s
195 lines
11 KiB
PHP
195 lines
11 KiB
PHP
<div x-show="isAdModalOpen"
|
|
class="fixed inset-0 z-[100] overflow-y-auto"
|
|
x-cloak
|
|
x-transition:enter="transition ease-out duration-300"
|
|
x-transition:enter-start="opacity-0"
|
|
x-transition:enter-end="opacity-100"
|
|
x-transition:leave="transition ease-in duration-200"
|
|
x-transition:leave-start="opacity-100"
|
|
x-transition:leave-end="opacity-0">
|
|
|
|
<div class="fixed inset-0 bg-slate-900/60 backdrop-blur-sm"></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-xl sm:w-full overflow-visible animate-luxury-in"
|
|
@click.away="isAdModalOpen = false">
|
|
|
|
<!-- Modal Header -->
|
|
<div class="flex justify-between items-center mb-8">
|
|
<div>
|
|
<h3 class="text-2xl font-black text-slate-800 dark:text-white font-display tracking-tight" x-text="adFormMode === 'add' ? '{{ __("Add Advertisement") }}' : '{{ __("Edit Advertisement") }}'"></h3>
|
|
<p class="text-[10px] font-bold text-slate-400 uppercase tracking-widest mt-1">{{ __('Manage your ad material details') }}</p>
|
|
</div>
|
|
<button @click="isAdModalOpen = false" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors">
|
|
<svg class="size-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>
|
|
|
|
<form :action="adFormMode === 'add' ? urls.store : urls.update.replace(':id', adForm.id)"
|
|
method="POST"
|
|
enctype="multipart/form-data"
|
|
@submit.prevent="submitAdForm"
|
|
class="space-y-6">
|
|
@csrf
|
|
<template x-if="adFormMode === 'edit'">
|
|
@method('PUT')
|
|
</template>
|
|
|
|
@if(auth()->user()->isSystemAdmin())
|
|
<div class="space-y-2">
|
|
<label class="text-xs font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest ml-1">
|
|
{{ __('Company Name') }}
|
|
</label>
|
|
<x-searchable-select
|
|
name="company_id"
|
|
id="ad_company_select"
|
|
:has-search="true"
|
|
:selected="null"
|
|
:options="['' => __('System Default (All Companies)')] + $companies->pluck('name', 'id')->toArray()"
|
|
@change="adForm.company_id = $event.target.value"
|
|
/>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="space-y-2">
|
|
<label class="text-xs font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest ml-1">
|
|
{{ __('Material Name') }}
|
|
<span class="text-rose-500 ml-0.5">*</span>
|
|
</label>
|
|
<input type="text" name="name" x-model="adForm.name" required
|
|
class="w-full h-12 bg-slate-50 dark:bg-slate-800/50 border-none rounded-xl px-4 text-sm font-bold text-slate-800 dark:text-white focus:ring-2 focus:ring-cyan-500/20 transition-all placeholder:text-slate-400"
|
|
placeholder="{{ __('Enter ad material name') }}">
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="space-y-2">
|
|
<label class="text-xs font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest ml-1">
|
|
{{ __('Material Type') }}
|
|
<span class="text-rose-500 ml-0.5">*</span>
|
|
</label>
|
|
<x-searchable-select
|
|
name="type"
|
|
id="ad_type_select"
|
|
:has-search="false"
|
|
:selected="null"
|
|
:options="['image' => __('image'), 'video' => __('video')]"
|
|
@change="adForm.type = $event.target.value; fileName = ''; document.querySelector('input[name=file]').value = ''"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Duration -->
|
|
<div class="space-y-2">
|
|
<label class="text-xs font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest ml-1">
|
|
{{ __('Duration (Seconds)') }}
|
|
<span class="text-rose-500 ml-0.5">*</span>
|
|
</label>
|
|
<x-searchable-select
|
|
name="duration"
|
|
id="ad_duration_select"
|
|
:has-search="false"
|
|
:selected="null"
|
|
:options="['15' => '15 ' . __('Seconds'), '30' => '30 ' . __('Seconds'), '60' => '60 ' . __('Seconds')]"
|
|
@change="adForm.duration = $event.target.value"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- File Upload -->
|
|
<div class="space-y-2">
|
|
<label class="text-xs font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest ml-1">
|
|
<span x-text="adForm.type === 'image' ? '{{ __("Upload Image") }}' : '{{ __("Upload Video") }}'"></span>
|
|
<template x-if="adFormMode === 'add'">
|
|
<span class="text-rose-500 ml-0.5">*</span>
|
|
</template>
|
|
</label>
|
|
<div class="relative group">
|
|
<div class="absolute inset-0 bg-gradient-to-tr from-cyan-500/5 to-indigo-500/5 rounded-2xl border-2 border-dashed border-slate-200 dark:border-white/10 group-hover:border-cyan-500/30 transition-all"></div>
|
|
<label class="relative flex flex-col items-center justify-center p-10 cursor-pointer">
|
|
<svg class="size-8 text-slate-300 group-hover:text-cyan-500 transition-colors mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" /></svg>
|
|
<span class="text-xs font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest group-hover:text-cyan-500 transition-colors">{{ __('Click to upload') }}</span>
|
|
<span class="text-[10px] font-bold text-slate-400 mt-1 uppercase" x-text="adForm.type === 'image' ? 'JPG, PNG, WEBP (' + '{{ __('Max 5MB') }}' + ')' : 'MP4, MOV (' + '{{ __('Max 50MB') }}' + ')'"></span>
|
|
<input type="file" name="file"
|
|
:accept="adForm.type === 'image' ? 'image/jpeg,image/png,image/gif,image/webp' : 'video/mp4,video/quicktime,video/x-msvideo'"
|
|
class="hidden" @change="handleFileChange">
|
|
</label>
|
|
</div>
|
|
<!-- Preview Filename -->
|
|
<p class="text-[10px] font-bold text-cyan-600 dark:text-cyan-400 italic px-2" x-show="fileName" x-text="fileName"></p>
|
|
</div>
|
|
|
|
<!-- Status -->
|
|
<div class="flex items-center gap-3 px-2">
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" name="is_active" x-model="adForm.is_active" value="1" class="sr-only peer">
|
|
<div class="w-11 h-6 bg-slate-200 dark:bg-slate-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-cyan-500"></div>
|
|
</label>
|
|
<span class="text-sm font-black text-slate-700 dark:text-slate-200 tracking-tight">{{ __('Active Status') }}</span>
|
|
</div>
|
|
|
|
<!-- Action Footer -->
|
|
<div class="flex items-center justify-end gap-3 pt-2">
|
|
<button type="button" @click="isAdModalOpen = 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">
|
|
{{ __('Cancel') }}
|
|
</button>
|
|
<button type="submit" class="btn-luxury-primary px-10 py-3">
|
|
{{ __('Save Material') }}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function handleFileChange(e) {
|
|
const file = e.target.files[0];
|
|
if (!file) return;
|
|
|
|
const type = this.adForm.type;
|
|
const maxSize = type === 'image' ? 5 * 1024 * 1024 : 50 * 1024 * 1024;
|
|
|
|
// Check size
|
|
if (file.size > maxSize) {
|
|
window.showToast?.('error', '{{ __("File is too large") }} (Max: ' + (maxSize / 1024 / 1024) + 'MB)');
|
|
e.target.value = '';
|
|
this.fileName = '';
|
|
return;
|
|
}
|
|
|
|
// Check extension/mime
|
|
const isImage = file.type.startsWith('image/');
|
|
const isVideo = file.type.startsWith('video/');
|
|
|
|
if (type === 'image' && !isImage) {
|
|
window.showToast?.('error', '{{ __("Please upload an image file") }}');
|
|
e.target.value = '';
|
|
this.fileName = '';
|
|
return;
|
|
}
|
|
|
|
if (type === 'video' && !isVideo) {
|
|
window.showToast?.('error', '{{ __("Please upload a video file") }}');
|
|
e.target.value = '';
|
|
this.fileName = '';
|
|
return;
|
|
}
|
|
|
|
this.fileName = file.name;
|
|
}
|
|
|
|
function submitAdForm(e) {
|
|
// Final check before submission
|
|
if (!this.adForm.name || !this.adForm.type || !this.adForm.duration) {
|
|
window.showToast?.('error', '{{ __("Please fill in all required fields") }}');
|
|
return;
|
|
}
|
|
|
|
if (this.adFormMode === 'add' && !this.fileName) {
|
|
window.showToast?.('error', '{{ __("Please upload a material file") }}');
|
|
return;
|
|
}
|
|
|
|
e.target.submit();
|
|
}
|
|
</script>
|