193 lines
8.6 KiB
PHP
193 lines
8.6 KiB
PHP
<div class="mx-auto">
|
|
|
|
{{-- HEADER --}}
|
|
<div class="flex justify-between items-center mb-8">
|
|
<div>
|
|
<flux:heading size="xl">Manajemen Layanan</flux:heading>
|
|
<flux:subheading>Kelola daftar layanan dan galeri foto klinik.</flux:subheading>
|
|
</div>
|
|
|
|
<flux:button wire:click="create" variant="primary" icon="plus">
|
|
Tambah Layanan
|
|
</flux:button>
|
|
</div>
|
|
|
|
{{-- FILTER --}}
|
|
<div class="flex gap-4 mb-6">
|
|
<div class="flex-1">
|
|
<flux:input wire:model.live="search" placeholder="Cari nama layanan..." icon="magnifying-glass" />
|
|
</div>
|
|
|
|
<div class="w-64">
|
|
<flux:select wire:model.live="filterCategory">
|
|
<option value="">Semua Kategori</option>
|
|
@foreach ($categories as $id => $name)
|
|
<option value="{{ $id }}">{{ $name }}</option>
|
|
@endforeach
|
|
</flux:select>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- TABLE --}}
|
|
<flux:table>
|
|
<flux:table.columns>
|
|
<flux:table.column>Foto</flux:table.column>
|
|
<flux:table.column sortable>Nama Layanan</flux:table.column>
|
|
<flux:table.column>Kategori</flux:table.column>
|
|
<flux:table.column>Deskripsi</flux:table.column>
|
|
<flux:table.column align="end">Aksi</flux:table.column>
|
|
</flux:table.columns>
|
|
|
|
<flux:table.rows>
|
|
@forelse ($services as $s)
|
|
<flux:table.row :key="$s->id">
|
|
{{-- Avatar Stack untuk Foto --}}
|
|
<flux:table.cell>
|
|
<div class="flex -space-x-2 overflow-hidden">
|
|
@if ($s->photo && count($s->photo) > 0)
|
|
@foreach (array_slice($s->photo, 0, 3) as $img)
|
|
<img src="{{ asset('storage/' . $img) }}"
|
|
class="inline-block rounded-lg ring-2 ring-white w-10 h-10 object-cover">
|
|
@endforeach
|
|
@if (count($s->photo) > 3)
|
|
<div
|
|
class="flex justify-center items-center bg-gray-100 rounded-lg ring-2 ring-white w-10 h-10 font-medium text-[10px] text-gray-500">
|
|
+{{ count($s->photo) - 3 }}
|
|
</div>
|
|
@endif
|
|
@else
|
|
<div
|
|
class="flex justify-center items-center bg-gray-50 border border-gray-300 border-dashed rounded-lg w-10 h-10">
|
|
<flux:icon.photo class="w-5 h-5 text-gray-400" />
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</flux:table.cell>
|
|
|
|
<flux:table.cell class="font-medium text-zinc-800">{{ $s->name }}</flux:table.cell>
|
|
|
|
<flux:table.cell>
|
|
<flux:badge size="sm" inset="top bottom">{{ $s->category->name }}</flux:badge>
|
|
</flux:table.cell>
|
|
|
|
<flux:table.cell>
|
|
<p class="text-zinc-600 text-sm">
|
|
{{ Str::limit(strip_tags($s->description), 50, '...') }}
|
|
</p>
|
|
</flux:table.cell>
|
|
|
|
<flux:table.cell align="end">
|
|
<div class="flex justify-end gap-1">
|
|
<flux:button wire:click="edit({{ $s->id }})" icon="pencil" variant="ghost"
|
|
size="sm" />
|
|
<flux:button wire:click="delete({{ $s->id }})"
|
|
wire:confirm="Apakah Anda yakin ingin menghapus layanan ini?" icon="trash"
|
|
variant="ghost" size="sm" class="text-red-600" />
|
|
</div>
|
|
</flux:table.cell>
|
|
</flux:table.row>
|
|
@empty
|
|
<flux:table.row>
|
|
<flux:table.cell colspan="4" class="py-10 text-zinc-400 text-center">
|
|
Tidak ada data layanan ditemukan.
|
|
</flux:table.cell>
|
|
</flux:table.row>
|
|
@endforelse
|
|
</flux:table.rows>
|
|
</flux:table>
|
|
|
|
<div class="mt-6">
|
|
{{ $services->links() }}
|
|
</div>
|
|
|
|
{{-- MODAL FORM --}}
|
|
<flux:modal wire:model="isModalOpen" class="space-y-6 md:w-[700px]">
|
|
<div>
|
|
<flux:heading size="lg">{{ $serviceId ? 'Edit' : 'Tambah' }} Layanan</flux:heading>
|
|
<flux:subheading>Isi informasi detail mengenai layanan klinik di bawah ini.</flux:subheading>
|
|
</div>
|
|
|
|
<form wire:submit.prevent="save" class="space-y-6">
|
|
<div class="gap-4 grid grid-cols-1 md:grid-cols-2">
|
|
<flux:input wire:model="name" label="Nama Layanan" placeholder="Contoh: Scaling Gigi" />
|
|
|
|
<flux:select wire:model="category_id" label="Kategori">
|
|
<option value="">Pilih Kategori</option>
|
|
@foreach ($categories as $id => $name)
|
|
<option value="{{ $id }}">{{ $name }}</option>
|
|
@endforeach
|
|
</flux:select>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<flux:label for="description">Deskripsi Detail</flux:label>
|
|
|
|
<flux:textarea
|
|
id="description"
|
|
wire:model="description"
|
|
rows="8"
|
|
placeholder="Masukkan deskripsi detail..."
|
|
/>
|
|
|
|
@error('description')
|
|
<p class="mt-1 text-sm text-red-500">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
{{-- MULTIPLE PHOTO UPLOAD --}}
|
|
<div class="space-y-3">
|
|
<flux:label>Foto & Galeri (Multiple)</flux:label>
|
|
|
|
<flux:input type="file" wire:model="photos" multiple accept="image/*" />
|
|
|
|
<div wire:loading wire:target="photos">
|
|
<flux:subheading class="text-blue-600 animate-pulse">Sedang mengunggah foto...</flux:subheading>
|
|
</div>
|
|
|
|
{{-- Preview Foto yang Sudah Ada --}}
|
|
@if ($existingPhotos)
|
|
<div class="gap-3 grid grid-cols-4 md:grid-cols-6 bg-zinc-50 p-3 border border-zinc-100 rounded-xl">
|
|
@foreach ($existingPhotos as $index => $path)
|
|
<div class="group relative aspect-square">
|
|
<img src="{{ asset('storage/' . $path) }}"
|
|
class="shadow-sm border border-zinc-200 rounded-lg w-full h-full object-cover">
|
|
<button type="button" wire:click="removePhoto({{ $index }})"
|
|
class="-top-2 -right-2 absolute bg-red-500 shadow-lg p-1 rounded-full text-white hover:scale-110 transition-transform">
|
|
<flux:icon.x-mark variant="mini" />
|
|
</button>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Preview Foto Baru (Temporary) --}}
|
|
@if ($photos)
|
|
<div class="flex gap-3 pb-2 overflow-x-auto">
|
|
@foreach ($photos as $photo)
|
|
<div
|
|
class="relative flex-none shadow-md border-2 border-blue-400 rounded-lg overflow-hidden">
|
|
<img src="{{ $photo->temporaryUrl() }}" class="w-20 h-20 object-cover">
|
|
<div class="absolute inset-0 flex justify-center items-center bg-blue-500/20">
|
|
<flux:badge size="xs" variant="primary" class="opacity-90">Baru</flux:badge>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex justify-end gap-3 pt-4 border-zinc-100 border-t">
|
|
<flux:modal.close>
|
|
<flux:button variant="ghost">Batal</flux:button>
|
|
</flux:modal.close>
|
|
|
|
<flux:button type="submit" variant="primary" wire:loading.attr="disabled">
|
|
<span wire:loading.remove wire:target="save">Simpan Perubahan</span>
|
|
<span wire:loading wire:target="save">Memproses...</span>
|
|
</flux:button>
|
|
</div>
|
|
</form>
|
|
</flux:modal>
|
|
|
|
</div>
|