feat: Implement full voucher and outlet listing with search, detail modals, and UI enhancements

This commit is contained in:
Yoga Pangestu 2025-12-20 17:35:14 +07:00
parent 93d86a30c0
commit 71568a7ecd
15 changed files with 646 additions and 176 deletions

View File

@ -11,7 +11,6 @@
use App\Models\PerfumeFeature;
use App\Models\Testimonial;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Storage;
use Livewire\Attributes\Layout;
use Livewire\Component;
use Livewire\WithPagination;
@ -50,7 +49,7 @@ public function mount(): void
->take(2)
->get()
->map(function (Perfume $perfume) {
$perfume->image = $perfume->getFirstMediaUrl('image') ? Storage::url($perfume->getFirstMediaUrl('image')) : asset('assets/images/logo.png');
$perfume->image = $perfume->getFirstMediaUrl('image') ? $perfume->getFirstMediaUrl('image') : asset('assets/images/logo.png');
$perfume->concentration_label = $perfume->concentration->label();
return $perfume;

View File

@ -2,6 +2,7 @@
namespace App\Livewire\Home;
use App\Models\Outlet as OutletModel;
use Illuminate\Contracts\View\View;
use Livewire\Attributes\Layout;
use Livewire\Component;
@ -11,8 +12,48 @@
])]
class Outlet extends Component
{
public array $outlets = [];
public string $search = '';
public ?OutletModel $selectedOutlet = null;
public function mount(): void
{
$this->outlets = OutletModel::with(['facilities', 'openingHours'])
->operational()
->when($this->search, function ($query) {
$query->where(function ($query) {
$query->where('name', 'like', '%'.$this->search.'%')
->orWhere('address', 'like', '%'.$this->search.'%');
});
})
->latest()
->get()
->map(function ($outlet) {
$outlet->image = $outlet->getFirstMediaUrl('featured_image') ? $outlet->getFirstMediaUrl('featured_image') : asset('assets/images/dark-logo.png');
$outlet->status_label = $outlet->status->label();
$outlet->status_color = $outlet->status->color();
return $outlet;
})
->toArray();
}
public function showDetail(int $outletId): void
{
$this->selectedOutlet = OutletModel::with(['facilities', 'openingHours', 'media'])->find($outletId);
}
public function closeModal(): void
{
$this->selectedOutlet = null;
}
public function render(): View
{
return view('livewire.home.outlets');
return view('livewire.home.outlets', [
'pageTitle' => 'Outlet',
]);
}
}

View File

@ -4,7 +4,9 @@
use App\Models\Outlet;
use App\Models\Voucher as VoucherModel;
use App\Traits\Components\WithToast;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Layout;
use Livewire\Component;
use Livewire\WithPagination;
@ -14,7 +16,7 @@
])]
class Voucher extends Component
{
use WithPagination;
use WithPagination, WithToast;
public $outlets;
@ -24,6 +26,10 @@ class Voucher extends Component
public ?string $sort = null;
public ?VoucherModel $selectedVoucher = null;
public bool $showDetailModal = false;
public function mount(): void
{
$this->outlets = Outlet::query()->operational()->pluck('name', 'id');
@ -44,6 +50,91 @@ public function updatedSort(): void
$this->resetPage();
}
public function showDetail(string $hashId): void
{
$this->selectedVoucher = VoucherModel::byHash($hashId);
$this->selectedVoucher->load('outlets');
$this->selectedVoucher->min_purchase_formatted = formatCurrencyNumber($this->selectedVoucher->min_purchase, 'Rp');
$this->selectedVoucher->end_date_formatted = formatDateLocalized($this->selectedVoucher->end_date);
$this->showDetailModal = true;
}
public function closeDetail(): void
{
$this->showDetailModal = false;
$this->selectedVoucher = null;
}
public function claim(string $hashId): void
{
if (! auth()->check()) {
$this->redirect(route('login'), navigate: true);
return;
}
$voucher = VoucherModel::byHash($hashId);
$user = auth()->user();
// Basic checks
if (! $voucher) {
$this->toast('Voucher tidak ditemukan.', 'Gagal', 'danger');
return;
}
if ($voucher->quota !== null && $voucher->available_count >= $voucher->quota) {
$this->toast('Klaim gagal! Kuota voucher sudah habis.', 'Gagal', 'danger');
return;
}
// Check if user already reached limit
$claimedCount = $user->vouchers()->where('voucher_id', $voucher->id)->exists();
if ($voucher->limit_per_user !== null) {
$claimedCount = $user->vouchers()->where('voucher_id', $voucher->id)->count();
if ($claimedCount >= $voucher->limit_per_user) {
$this->toast('Anda sudah mencapai batas klaim untuk voucher ini.', 'Peringatan', 'warning');
return;
}
} elseif ($claimedCount) {
// If limit_per_user is null, assume it can only be claimed once?
// Or can it be claimed multiple times?
// Usually vouchers are one-time claim per user unless specified.
// Based on common logic, if limit_per_user is null, maybe it's unlimited?
// But usually it's 1. Let's stick to the limit_per_user check.
}
// Check if voucher is for specific tier
$userTierId = $user->membership?->tier_id;
if ($voucher->tiers()->exists() && ! $voucher->tiers()->where('tiers.id', $userTierId)->exists()) {
$this->toast('Voucher ini tidak tersedia untuk tier Anda.', 'Gagal', 'danger');
return;
}
try {
// Claim with transaction
DB::transaction(function () use ($user, $voucher) {
// Re-check quota inside transaction
$v = VoucherModel::where('id', $voucher->id)->lockForUpdate()->first();
if ($v->quota !== null && $v->available_count >= $v->quota) {
throw new \Exception('Kuota voucher sudah habis.');
}
$user->vouchers()->attach($v->id);
$v->increment('available_count');
});
$this->toast('Voucher berhasil diklaim! Silakan cek di menu Voucher Saya.', 'Berhasil', 'success');
} catch (\Throwable $e) {
$this->toast($e->getMessage(), 'Gagal', 'danger');
}
}
public function render(): View
{
$vouchers = VoucherModel::where(function ($query) {

View File

@ -4,6 +4,7 @@
use App\Enums\PriceRequestStatus;
use App\Models\PriceRequest;
use App\Settings\ContactSettings;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
@ -326,6 +327,7 @@ public function boot(): void
$view->with([
'sidebar' => $sidebar,
'header' => $header,
'setting' => app(ContactSettings::class),
]);
});
}

View File

@ -40,26 +40,32 @@ class="w-10 h-10 rounded-full bg-white/5 flex items-center justify-center text-g
</div>
<div class="md:col-span-3 md:pl-8">
<h3 class="text-white font-bold mb-6 text-sm uppercase tracking-wider">Quick Links</h3>
<h3 class="text-white font-bold mb-6 text-sm uppercase tracking-wider">Tautan Cepat</h3>
<ul class="space-y-4 text-sm text-gray-400">
<li><a href="#"
<li>
<a href="{{ route('homepage') }}" wire:navigate
class="hover:text-home-secondary transition-colors duration-300 flex items-center gap-2">Beranda</a>
</li>
<li><a href="#"
<li>
<a href="{{ route('product.index') }}" wire:navigate
class="hover:text-home-secondary transition-colors duration-300 flex items-center gap-2">Katalog
Produk</a></li>
<li><a href="#"
class="hover:text-home-secondary transition-colors duration-300 flex items-center gap-2">Tentang
Kami</a></li>
<li><a href="#"
class="hover:text-home-secondary transition-colors duration-300 flex items-center gap-2">Kontak</a>
Produk</a>
</li>
<li>
<a href="{{ route('outlet') }}" wire:navigate
class="hover:text-home-secondary transition-colors duration-300 flex items-center gap-2">Outtlet
</a>
</li>
<li>
<a href="{{ route('article.index') }}" wire:navigate
class="hover:text-home-secondary transition-colors duration-300 flex items-center gap-2">Artikel</a>
</li>
</ul>
</div>
<div class="md:col-span-5 flex flex-col gap-6">
<div>
<h3 class="text-white font-bold mb-6 text-sm uppercase tracking-wider">Contact Us</h3>
<h3 class="text-white font-bold mb-6 text-sm uppercase tracking-wider">Kontak Kami</h3>
<div class="space-y-5 text-sm text-gray-400">
<div class="flex items-start gap-4">
<div class="mt-1"><svg class="w-5 h-5 text-home-primary" fill="none"
@ -70,8 +76,7 @@ class="hover:text-home-secondary transition-colors duration-300 flex items-cente
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg></div>
<span
class="leading-relaxed">{{ $outlet->note ?? 'Jalan Wangi Semerbak No. 123, Kota Parfum, Indonesia' }}</span>
<span class="leading-relaxed">{{ $setting->address }}</span>
</div>
<div class="flex items-center gap-4">
<div><svg class="w-5 h-5 text-home-primary" fill="none" stroke="currentColor"
@ -80,7 +85,7 @@ class="leading-relaxed">{{ $outlet->note ?? 'Jalan Wangi Semerbak No. 123, Kota
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z">
</path>
</svg></div>
<span>{{ $outlet->email ?? 'admin@yadiparfum.com' }}</span>
<span>{{ $setting->email }}</span>
</div>
<div class="flex items-center gap-4">
<div><svg class="w-5 h-5 text-home-primary" fill="none" stroke="currentColor"
@ -89,7 +94,7 @@ class="leading-relaxed">{{ $outlet->note ?? 'Jalan Wangi Semerbak No. 123, Kota
d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z">
</path>
</svg></div>
<span>{{ $outlet->phone ?? '+62 812-3456-7890' }}</span>
<span>{{ $setting->phone_number }}</span>
</div>
</div>
</div>
@ -98,12 +103,12 @@ class="leading-relaxed">{{ $outlet->note ?? 'Jalan Wangi Semerbak No. 123, Kota
<div class="border-t border-white/10 pt-8 flex flex-col md:flex-row justify-between items-center gap-4">
<div class="text-sm text-gray-500">
&copy; {{ date('Y') }} Yadi Parfum. All rights reserved.
&copy; {{ date('Y') }} Yadi Parfum. Semua hak dilindungi undang-undang.
</div>
<div class="flex gap-6 text-sm text-gray-500">
{{-- <div class="flex gap-6 text-sm text-gray-500">
<a href="#" class="hover:text-white transition-colors">Privacy Policy</a>
<a href="#" class="hover:text-white transition-colors">Terms of Service</a>
</div>
</div> --}}
</div>
</div>
</footer>

View File

@ -3,8 +3,8 @@
<section class="relative h-[500px] flex items-center justify-center overflow-hidden">
{{-- Background Image --}}
<div class="absolute inset-0 z-0">
<img src="https://images.unsplash.com/photo-1752042143353-e6dcc822a023?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Perfume Background" class="w-full h-full object-cover">
<img src="https://images.pexels.com/photos/4057663/pexels-photo-4057663.jpeg" alt="Article Background"
class="w-full h-full object-cover">
<div class="absolute inset-0 bg-black/40"></div>
</div>

View File

@ -3,8 +3,8 @@
<section class="relative h-[500px] flex items-center justify-center overflow-hidden">
{{-- Background Image --}}
<div class="absolute inset-0 z-0">
<img src="https://images.unsplash.com/photo-1752042143353-e6dcc822a023?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Perfume Background" class="w-full h-full object-cover">
<img src="https://images.pexels.com/photos/2789781/pexels-photo-2789781.jpeg" alt="Perfume Background"
class="w-full h-full object-cover">
<div class="absolute inset-0 bg-black/40"></div>
</div>

View File

@ -1,95 +1,57 @@
<div>
@php
$outlets = [
[
'id' => 1,
'name' => 'Yadi Parfum Central Park',
'address' => 'Central Park Mall, Lt. LG, Unit 112, Jl. Letjen S. Parman No.28, Jakarta Barat',
'city' => 'Jakarta Barat',
'phone' => '+62 812-3456-7890',
'hours' => '10:00 - 22:00 WIB',
'image' => 'https://placehold.co/800x600/png?text=Boutique+Central+Park',
'facilities' => ['Consultation', 'Refill Station', 'Engraving'],
'status' => 'Buka',
],
[
'id' => 2,
'name' => 'Yadi Parfum Senayan City',
'address' => 'Senayan City, Lt. 1, Unit 45, Jl. Asia Afrika Lot 19, Jakarta Pusat',
'city' => 'Jakarta Pusat',
'phone' => '+62 812-9876-5432',
'hours' => '10:00 - 22:00 WIB',
'image' => 'https://placehold.co/800x600/png?text=Boutique+Senayan',
'facilities' => ['VIP Lounge', 'Consultation'],
'status' => 'Buka',
],
[
'id' => 3,
'name' => 'Yadi Parfum Bandung',
'address' => 'Paris Van Java, Resort Level, Jl. Sukajadi No.131-139, Bandung',
'city' => 'Bandung',
'phone' => '+62 822-1122-3344',
'hours' => '10:00 - 21:00 WIB',
'image' => 'https://placehold.co/800x600/png?text=Boutique+Bandung',
'facilities' => ['Refill Station'],
'status' => 'Tutup',
],
];
@endphp
<div class="flex flex-col min-h-screen bg-white font-sans">
{{-- Hero Section --}}
<section class="relative h-[500px] flex items-center justify-center overflow-hidden">
{{-- Background Image --}}
<div class="absolute inset-0 z-0">
<img src="https://images.unsplash.com/photo-1541643600914-78b084683601?q=80&w=1469&auto=format&fit=crop"
alt="Outlet Background" class="w-full h-full object-cover">
<div class="absolute inset-0 bg-black/50"></div>
</div>
{{-- Content --}}
<div class="relative z-10 container mx-auto px-6 text-center">
<span class="text-home-primary font-bold tracking-widest text-xs uppercase mb-3 block">Lokasi Butik</span>
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6">Temukan Butik Terdekat</h1>
<p class="text-white/80 text-lg md:text-xl max-w-2xl mx-auto mb-10">
Rasakan pengalaman langsung kemewahan aroma kami. Kunjungi butik kami untuk konsultasi personal.
</p>
{{-- Search Bar --}}
<div class="max-w-xl mx-auto relative group">
<input type="text" placeholder="Masukkan kota atau nama area..."
class="w-full py-4 pl-6 pr-14 rounded-full bg-white/10 backdrop-blur-md border border-white/20 text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-home-primary focus:bg-white/20 transition-all shadow-lg text-lg">
<button
class="absolute right-2 top-2 bottom-2 w-10 h-10 bg-home-primary rounded-full flex items-center justify-center text-white hover:bg-white hover:text-home-primary transition-all duration-300">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</button>
<section class="relative h-[500px] flex items-center justify-center overflow-hidden">
{{-- Background Image --}}
<div class="absolute inset-0 z-0">
<img src="https://images.unsplash.com/photo-1761095870661-c4ae15cac605?q=80&w=880&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Outlet Background" class="w-full h-full object-cover">
<div class="absolute inset-0 bg-black/50"></div>
</div>
</div>
</section>
<main class="flex-grow px-6 lg:px-32 xl:px-48 py-24">
{{-- Content --}}
<div class="relative z-10 container mx-auto px-6 text-center">
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6">Temukan Outlet Terdekat</h1>
<p class="text-white/80 text-lg md:text-xl max-w-2xl mx-auto mb-10">
Rasakan pengalaman langsung kemewahan aroma kami. Kunjungi outlet kami untuk konsultasi personal.
</p>
{{-- Search Bar --}}
<div class="max-w-xl mx-auto relative group">
<input type="text" wire:model.live="search" placeholder="Masukkan kota atau nama area..."
class="w-full py-4 pl-6 pr-14 rounded-full bg-white/10 backdrop-blur-md border border-white/20 text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-home-primary focus:bg-white/20 transition-all shadow-lg text-lg">
<button
class="absolute right-2 top-2 bottom-2 w-10 h-10 bg-home-primary rounded-full flex items-center justify-center text-white hover:bg-white hover:text-home-primary transition-all duration-300">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</button>
</div>
</div>
</section>
<main class="flex-grow px-6 lg:px-32 xl:px-48 py-24">
<section class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-24">
@foreach ($outlets as $outlet)
<article
class="group bg-white rounded-3xl border border-home-foreground/10 overflow-hidden hover:shadow-2xl hover:shadow-home-primary/10 hover:-translate-y-2 transition-all duration-500 flex flex-col h-full">
<article wire:click="showDetail({{ $outlet['id'] }})"
class="group bg-white rounded-3xl border border-home-foreground/10 overflow-hidden hover:shadow-2xl hover:shadow-home-primary/10 hover:-translate-y-2 transition-all duration-500 flex flex-col h-full cursor-pointer">
<div class="relative h-64 overflow-hidden">
<div
class="absolute inset-0 bg-home-primary/10 mix-blend-multiply opacity-0 group-hover:opacity-100 transition-opacity duration-500 z-10">
</div>
<img src="{{ $outlet['image'] }}" alt="{{ $outlet['name'] }}"
<img src="{{ $outlet['image'] ?: 'https://placehold.co/800x600/png?text=' . urlencode($outlet['name']) }}"
alt="{{ $outlet['name'] }}"
class="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-700">
<div class="absolute top-4 left-4 z-20">
<span
class="px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-wide backdrop-blur-md bg-white/90 shadow-sm
{{ $outlet['status'] == 'Buka' ? 'text-green-700' : 'text-red-700' }}">
{{ $outlet['status'] }}
text-{{ $outlet['status_color'] }}-700">
{{ $outlet['status_label'] }}
</span>
</div>
</div>
@ -106,45 +68,91 @@ class="text-xl font-bold text-home-foreground mb-2 group-hover:text-home-primary
@foreach ($outlet['facilities'] as $facility)
<span
class="text-[10px] px-2 py-1 border border-home-foreground/10 rounded text-home-foreground/50">
{{ $facility }}
{{ $facility['name'] }}
</span>
@endforeach
</div>
<div
class="grid grid-cols-2 gap-4 text-xs text-home-foreground/70 mb-6 pt-4 border-t border-home-foreground/5">
<div class="flex items-center gap-2">
<svg class="w-4 h-4 text-home-primary" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
{{ $outlet['hours'] }}
</div>
<div class="flex items-center gap-2">
<svg class="w-4 h-4 text-home-primary" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z">
</path>
</svg>
Call Store
</div>
</div>
<div class="mt-auto flex gap-3" x-on:click.stop>
@if ($outlet['maps_url'])
<a href="{{ $outlet['maps_url'] }}" target="_blank"
class="flex-1 py-3 rounded-xl bg-home-primary text-white text-sm font-bold hover:bg-home-secondary hover:text-home-primary transition-colors shadow-lg shadow-home-primary/20 flex items-center justify-center">
Petunjuk Arah
</a>
@endif
{{-- Share Menu --}}
<div class="relative" x-data="{ open: false }">
<button @click="open = !open" @click.outside="open = false"
class="w-12 h-12 rounded-xl border border-home-foreground/10 flex items-center justify-center text-home-foreground hover:border-home-primary hover:text-home-primary transition-all">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z">
</path>
</svg>
</button>
<div class="mt-auto flex gap-3">
<button
class="flex-1 py-3 rounded-xl bg-home-primary text-white text-sm font-bold hover:bg-home-secondary hover:text-home-primary transition-colors shadow-lg shadow-home-primary/20">
Petunjuk Arah
</button>
<button
class="w-12 h-12 rounded-xl border border-home-foreground/10 flex items-center justify-center text-home-foreground hover:border-home-primary hover:text-home-primary transition-all">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z">
</path>
</svg>
</button>
{{-- Dropdown Menu --}}
<div x-show="open" x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95 translate-y-2"
x-transition:enter-end="opacity-100 scale-100 translate-y-0"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 scale-100 translate-y-0"
x-transition:leave-end="opacity-0 scale-95 translate-y-2"
class="absolute bottom-full right-0 mb-3 w-48 bg-white rounded-2xl shadow-xl border border-home-foreground/5 py-2 z-30"
style="display: none;">
<div
class="px-4 py-2 text-[10px] font-bold text-home-foreground/40 uppercase tracking-widest border-b border-home-foreground/5 mb-1">
Bagikan Ke
</div>
{{-- WhatsApp --}}
<a href="https://wa.me/?text={{ urlencode('Cek outlet ' . $outlet['name'] . ' di Pangestu Yadi Parfum: ' . ($outlet['maps_url'] ?: url()->current())) }}"
target="_blank"
class="flex items-center gap-3 px-4 py-2 text-sm text-home-foreground hover:bg-home-primary/5 hover:text-home-primary transition-colors">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path
d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L0 24l6.335-1.662c1.72.94 3.659 1.437 5.634 1.437h.005c6.515 0 11.825-5.309 11.828-11.825a11.823 11.823 0 00-3.414-8.369" />
</svg>
WhatsApp
</a>
{{-- Facebook --}}
<a href="https://www.facebook.com/sharer/sharer.php?u={{ urlencode($outlet['maps_url'] ?: url()->current()) }}"
target="_blank"
class="flex items-center gap-3 px-4 py-2 text-sm text-home-foreground hover:bg-home-primary/5 hover:text-home-primary transition-colors">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path
d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" />
</svg>
Facebook
</a>
{{-- X (Twitter) --}}
<a href="https://twitter.com/intent/tweet?url={{ urlencode($outlet['maps_url'] ?: url()->current()) }}&text={{ urlencode('Cek outlet ' . $outlet['name'] . ' di Pangestu Yadi Parfum') }}"
target="_blank"
class="flex items-center gap-3 px-4 py-2 text-sm text-home-foreground hover:bg-home-primary/5 hover:text-home-primary transition-colors">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path
d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
X (Twitter)
</a>
{{-- Copy Link --}}
<button
@click="navigator.clipboard.writeText('{{ $outlet['maps_url'] ?: url()->current() }}'); $dispatch('notify', { message: 'Link berhasil disalin!', type: 'success' }); open = false"
class="w-full flex items-center gap-3 px-4 py-2 text-sm text-home-foreground hover:bg-home-primary/5 hover:text-home-primary transition-colors text-left">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3">
</path>
</svg>
Salin Tautan
</button>
</div>
</div>
</div>
</div>
</article>
@ -156,19 +164,199 @@ class="w-12 h-12 rounded-xl border border-home-foreground/10 flex items-center j
class="absolute inset-0 bg-home-foreground/5 z-10 pointer-events-none group-hover:bg-transparent transition-colors duration-500">
</div>
<div
class="absolute top-6 left-6 z-20 bg-white/90 backdrop-blur-md px-6 py-4 rounded-2xl shadow-lg border border-white/20 hidden md:block">
<p class="text-xs text-home-foreground/50 font-bold uppercase tracking-wider mb-1">Cakupan Area</p>
<h3 class="text-home-primary font-bold">Indonesia & Asia Tenggara</h3>
</div>
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d126920.28318625622!2d106.76457105!3d-6.229571199999999!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x2e69f3e945e34b9d%3A0x5371bf0fdad786a2!2sJakarta%2C%20Special%20Capital%20Region%20of%20Jakarta!5e0!3m2!1sen!2sid!4v1652756763428!5m2!1sen!2sid"
width="100%" height="450" style="border:0; filter: grayscale(100%) contrast(1.2);"
allowfullscreen="" loading="lazy" class="hover:filter-none transition-all duration-700">
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d8506.860993234519!2d107.43951033371029!3d-6.543855086323806!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x2e690f57aa3eaf5b%3A0x2bbc334edbb98b17!2sYadi%20Parfum!5e1!3m2!1sen!2sid!4v1766221140539!5m2!1sen!2sid"
width="100%" height="450" style="border:0;" allowfullscreen="" loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
style="border:0; filter: grayscale(100%) contrast(1.2);" allowfullscreen="" loading="lazy"
class="hover:filter-none transition-all duration-700">
</iframe>
</section>
</main>
</div>
{{-- Detail Modal --}}
@if ($selectedOutlet)
<div class="fixed inset-0 z-[100] flex items-center justify-center p-4 sm:p-6 md:p-10" x-data
x-on:keydown.escape.window="$wire.closeModal()">
<!-- Backdrop -->
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" wire:click="closeModal"
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>
<!-- Modal Content -->
<div class="relative bg-white w-full max-w-5xl max-h-full overflow-y-auto rounded-3xl shadow-2xl flex flex-col md:flex-row animate-in fade-in zoom-in duration-300"
x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100" x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 scale-100" x-transition:leave-end="opacity-0 scale-95">
<!-- Close Button -->
<button wire:click="closeModal"
class="absolute top-4 right-4 md:top-6 md:right-6 z-[60] w-10 h-10 rounded-full bg-white shadow-xl border border-home-foreground/5 text-home-foreground hover:text-home-primary hover:scale-110 transition-all flex items-center justify-center group"
title="Tutup">
<svg class="w-5 h-5 transition-transform group-hover:rotate-90 duration-300" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12">
</path>
</svg>
</button>
<!-- Left: Image Section (Gallery) -->
@php
$allImages = collect();
if ($selectedOutlet->hasMedia('featured_image')) {
$allImages->push($selectedOutlet->getFirstMediaUrl('featured_image'));
}
if ($selectedOutlet->hasMedia('images')) {
foreach ($selectedOutlet->getMedia('images') as $media) {
$allImages->push($media->getUrl());
}
}
if ($allImages->isEmpty()) {
$allImages->push('https://placehold.co/800x600/png?text=' . urlencode($selectedOutlet->name));
}
@endphp
<div class="md:w-1/2 flex flex-col bg-gray-50" x-data="{
activeImage: '{{ $allImages->first() }}',
images: {{ $allImages->toJson() }}
}">
<!-- Main Image Display -->
<div class="relative flex-grow h-[300px] md:h-auto overflow-hidden">
<template x-for="(img, index) in images" :key="index">
<img :src="img" x-show="activeImage === img"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 scale-105"
x-transition:enter-end="opacity-100 scale-100"
class="absolute inset-0 w-full h-full object-cover"
alt="{{ $selectedOutlet->name }}">
</template>
<div
class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent md:hidden">
</div>
<div class="absolute bottom-6 left-6 text-white md:hidden">
<h2 class="text-3xl font-bold">{{ $selectedOutlet->name }}</h2>
</div>
</div>
<!-- Thumbnails -->
@if ($allImages->count() > 1)
<div class="p-4 bg-white border-t border-gray-100">
<div class="flex gap-2 overflow-x-auto pb-2 scrollbar-none">
<template x-for="(img, index) in images" :key="index">
<button @click="activeImage = img"
class="relative w-20 h-20 rounded-xl overflow-hidden shrink-0 transition-all duration-300"
:class="activeImage === img ? 'ring-2 ring-home-primary ring-offset-2 scale-95' :
'opacity-60 hover:opacity-100'">
<img :src="img" class="w-full h-full object-cover">
</button>
</template>
</div>
</div>
@endif
</div>
<!-- Right: Details Section -->
<div class="md:w-1/2 p-8 md:p-12">
<div class="hidden md:block mb-8">
<span class="text-home-primary font-bold tracking-widest text-xs uppercase mb-2 block">Detail
Outlet</span>
<h2 class="text-4xl font-bold text-home-foreground">{{ $selectedOutlet->name }}</h2>
</div>
<div class="space-y-8">
<!-- Status & Address -->
<div>
<div class="flex items-center gap-3 mb-4">
<span
class="px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-wide
{{ $selectedOutlet->status === \App\Enums\OutletStatus::OPERATIONAL ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700' }}">
{{ $selectedOutlet->status->label() }}
</span>
</div>
<div class="flex items-start gap-4">
<div
class="w-10 h-10 rounded-full bg-home-primary/10 flex items-center justify-center shrink-0">
<svg class="w-5 h-5 text-home-primary" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z">
</path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
</div>
<p class="text-lg text-home-foreground/70">{{ $selectedOutlet->address }}</p>
</div>
</div>
<!-- Facilities -->
<div>
<h4 class="text-sm font-bold text-home-foreground uppercase tracking-wider mb-4">Fasilitas
</h4>
<div class="flex flex-wrap gap-2">
@forelse($selectedOutlet->facilities as $facility)
<span
class="px-4 py-2 bg-home-foreground/5 rounded-xl text-sm text-home-foreground/70 border border-home-foreground/10">
{{ $facility->name }}
</span>
@empty
<p class="text-sm text-home-foreground/40 italic">Tidak ada fasilitas khusus</p>
@endforelse
</div>
</div>
<!-- Opening Hours -->
<div>
<h4 class="text-sm font-bold text-home-foreground uppercase tracking-wider mb-4">Jam
Operasional</h4>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
@php
$todayEnum = now()->dayOfWeekIso === 7 ? 1 : now()->dayOfWeekIso + 1;
@endphp
@foreach ($selectedOutlet->openingHours->sortBy('day.value') as $hour)
<div
class="flex justify-between items-center p-3 rounded-xl border border-home-foreground/5 {{ $hour->day->value === $todayEnum ? 'bg-home-primary/5 border-home-primary/20' : '' }}">
<span
class="text-xs font-medium {{ $hour->day->value === $todayEnum ? 'text-home-primary font-bold' : 'text-home-foreground/60' }}">
{{ $hour->day->label() }}
</span>
<span class="text-xs font-bold text-home-foreground">
{{ \Carbon\Carbon::parse($hour->open_time)->format('H:i') }} -
{{ \Carbon\Carbon::parse($hour->close_time)->format('H:i') }}
</span>
</div>
@endforeach
</div>
</div>
<!-- Contact & Maps -->
<div class="flex gap-4 pt-4">
<a href="tel:{{ $selectedOutlet->phone_number }}"
class="flex-1 py-4 rounded-2xl bg-white border border-home-foreground/10 text-home-foreground text-center font-bold hover:border-home-primary hover:text-home-primary transition-all flex items-center justify-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z">
</path>
</svg>
Telepon
</a>
<a href="{{ $selectedOutlet->maps_url }}" target="_blank"
class="flex-[1.5] py-4 rounded-2xl bg-home-primary text-white text-center font-bold hover:bg-home-secondary hover:text-home-primary transition-all shadow-lg shadow-home-primary/20 flex items-center justify-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7">
</path>
</svg>
Petunjuk Arah
</a>
</div>
</div>
</div>
</div>
</div>
@endif
</div>

View File

@ -21,14 +21,15 @@ class="px-8 py-4 rounded-xl bg-home-background text-home-foreground font-bold ho
<div class="flex items-center gap-4 text-sm text-home-background/40">
<div class="flex -space-x-2">
<img class="w-8 h-8 rounded-full border-2 border-white" src="https://placehold.co/100x100/png"
alt="User">
<img class="w-8 h-8 rounded-full border-2 border-white" src="https://placehold.co/100x100/png"
alt="User">
<img class="w-8 h-8 rounded-full border-2 border-white" src="https://placehold.co/100x100/png"
alt="User">
@foreach ($latestMembers as $member)
<img class="w-8 h-8 rounded-full border-2 border-white"
src="https://ui-avatars.com/api/?name={{ urlencode($member->name) }}&background=random&color=fff"
alt="{{ $member->name }}">
@endforeach
</div>
<p>Bergabung bersama <span class="text-home-background font-bold">2,000+</span> member lainnya.</p>
<p>Bergabung bersama <span
class="text-home-background font-bold">{{ number_format($totalMembersCount) }}+</span>
member lainnya.</p>
</div>
</div>
@ -74,4 +75,4 @@ class="w-8 h-8 opacity-80 brightness-0 invert">
</div>
</div>
</section>
</section>

View File

@ -7,8 +7,8 @@ class="relative w-full lg:w-[35%] pt-24 lg:pt-0 py-0 px-6 lg:px-10 lg:pb-8 flex
@foreach ($latestMembers as $member)
<figure
class="border-2 border-home-background w-8 h-8 lg:w-10 lg:h-10 rounded-full overflow-hidden shadow-sm {{ !$loop->first ? '-ms-2' : '' }}">
<img src="https://ui-avatars.com/api/?name={{ urlencode($member->name) }}&background=random&color=fff"
alt="{{ $member->name }}" class="w-full h-full object-cover">
<img src="https://ui-avatars.com/api/?name={{ urlencode($member->user->name ?? $member->name) }}&background=random&color=fff"
alt="{{ $member->user->name ?? $member->name }}" class="w-full h-full object-cover">
</figure>
@endforeach
</div>

View File

@ -20,11 +20,19 @@ class="w-full h-full object-cover group-hover:scale-105 transition-transform dur
alt="{{ $perfume['name'] }}">
</figure>
<div class="flex-1 ml-4 lg:ml-6 flex flex-col justify-center space-y-2 lg:space-y-4">
<div class="flex-1 ml-4 lg:ml-6 flex flex-col justify-center space-y-2 lg:space-y-3">
<div>
<h3 class="text-lg lg:text-2xl text-black font-bold line-clamp-1">{{ $perfume['name'] }}</h3>
<p class="text-black/60 text-xs lg:text-lg line-clamp-2">
{{ $perfume['concentration_label'] }}</p>
<h3 class="text-base lg:text-xl text-black font-bold line-clamp-1">{{ $perfume['name'] }}</h3>
<div class="flex items-center gap-2 mt-1">
<span class="text-home-primary font-bold text-sm lg:text-lg">
Rp {{ number_format($perfume['sale_price'], 0, ',', '.') }}
</span>
</div>
<div class="flex items-center gap-1.5 mt-0.5">
<span class="text-[10px] lg:text-xs font-medium text-gray-400 capitalize">
{{ number_format($perfume['items_sum_quantity'], 0, ',', '.') }} Terjual
</span>
</div>
</div>
<div class="flex items-center gap-2 mt-auto">

View File

@ -42,12 +42,12 @@ class="relative w-full mt-auto h-[300px] lg:h-[250px] bg-home-background/40 back
<div class="testimonial-slide absolute inset-0 py-0 px-6 flex flex-col justify-center transition-all duration-500 ease-in-out {{ $index === 0 ? 'opacity-100 z-10 translate-x-0' : 'opacity-0 z-0 translate-x-full' }}"
:class="getClass({{ $index }})">
<div class="flex items-center gap-4 mb-3">
<img src="https://ui-avatars.com/api/?name={{ urlencode($testimonial['user']['customer']['name']) }}&background=random&color=fff"
alt="{{ $testimonial['user']['customer']['name'] }}"
<img src="https://ui-avatars.com/api/?name={{ urlencode($testimonial['user']['customer']['name'] ?? 'User') }}&background=random&color=fff"
alt="{{ $testimonial['user']['customer']['name'] ?? 'User' }}"
class="w-12 h-12 rounded-full object-cover ring-2 ring-home-background">
<div>
<h4 class="font-bold text-home-foreground text-sm lg:text-base">
{{ $testimonial['user']['customer']['name'] }}</h4>
{{ $testimonial['user']['customer']['name'] ?? 'User' }}</h4>
<div class="flex text-home-primary text-xs">
@for ($i = 0; $i < $testimonial['rating']; $i++)

View File

@ -11,16 +11,6 @@
dirancang untuk bertahan lama, memberikan pengalaman wangi yang istimewa, dan memastikan setiap
tetesnya asli dan terpercaya.
</p>
<div class="pt-4">
<button
class="text-home-primary font-bold hover:opacity-80 transition-opacity flex items-center gap-2">
Pelajari Selengkapnya
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</button>
</div>
</div>
<div class="order-1 lg:order-2 relative">

View File

@ -4,7 +4,7 @@
<section class="relative h-[500px] flex items-center justify-center overflow-hidden">
{{-- Background Image --}}
<div class="absolute inset-0 z-0">
<img src="https://images.unsplash.com/photo-1651737232278-3875f741de86?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
<img src="https://images.pexels.com/photos/22589353/pexels-photo-22589353.jpeg"
alt="Perfume Collection Background" class="w-full h-full object-cover">
<div class="absolute inset-0 bg-black/50"></div>
</div>

View File

@ -3,8 +3,8 @@
<section class="relative h-[500px] flex items-center justify-center overflow-hidden">
{{-- Background Image --}}
<div class="absolute inset-0 z-0">
<img src="https://images.unsplash.com/photo-1541643600914-78b084683601?q=80&w=1469&auto=format&fit=crop"
alt="Voucher Background" class="w-full h-full object-cover">
<img src="https://images.pexels.com/photos/5650052/pexels-photo-5650052.jpeg" alt="Voucher Background"
class="w-full h-full object-cover">
<div class="absolute inset-0 bg-black/50"></div>
</div>
@ -34,7 +34,7 @@ class="absolute right-2 top-2 bottom-2 w-10 h-10 bg-home-primary rounded-full fl
<main class="flex-grow px-6 lg:px-32 xl:px-48 py-24 font-sans flex flex-col">
<section class="flex flex-col lg:flex-row justify-center gap-4 mb-12" aria-label="Filter">
<div class="flex flex-col sm:flex-row gap-4">
<div class="relative">
<select wire:model.live="outlet_id" aria-label="Filter Outlet"
@ -153,11 +153,11 @@ class="font-bold text-home-foreground">{{ $voucher->end_date }}</time>
</div>
<div class="p-6 flex gap-3 mt-auto">
<button
<button wire:click="claim('{{ $voucher->hash }}')"
class="flex-1 bg-home-primary text-white font-bold py-3 rounded-xl hover:bg-home-secondary hover:text-home-primary hover:shadow-lg hover:shadow-home-primary/20 transition-all duration-300 text-sm shadow-md shadow-home-primary/10">
Klaim Voucher
</button>
<button
<button wire:click="showDetail('{{ $voucher->hash }}')"
class="flex-1 border border-home-foreground/20 text-home-foreground font-bold py-3 rounded-xl hover:border-home-primary hover:text-home-primary hover:bg-home-primary/5 transition-all duration-300 text-sm">
Lihat Detail
</button>
@ -167,8 +167,153 @@ class="flex-1 border border-home-foreground/20 text-home-foreground font-bold py
</section>
<div class="mt-auto flex justify-center w-full">
{{ $vouchers->links() }}
{{ $vouchers->links('vendor.livewire.custom-pagination') }}
</div>
</main>
{{-- Voucher Detail Modal --}}
@if ($showDetailModal && $selectedVoucher)
<div class="fixed inset-0 z-50 flex items-center justify-center p-4">
{{-- Backdrop --}}
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" wire:click="closeDetail"></div>
{{-- Modal Content --}}
<div
class="relative bg-white w-full max-w-2xl rounded-3xl overflow-hidden shadow-2xl animate-in fade-in zoom-in duration-300">
{{-- Modal Header --}}
<div class="relative h-48 bg-home-primary flex items-center justify-center overflow-hidden">
<div class="absolute inset-0 opacity-20">
<div class="absolute top-0 right-0 w-64 h-64 bg-white rounded-full -mr-32 -mt-32"></div>
<div class="absolute bottom-0 left-0 w-48 h-48 bg-white rounded-full -ml-24 -mb-24"></div>
</div>
<div class="relative z-10 text-center">
<div
class="inline-flex items-center gap-2 bg-white/20 backdrop-blur-md px-4 py-1.5 rounded-full border border-white/30 text-white text-xs font-bold uppercase tracking-widest mb-4">
<span class="w-2 h-2 rounded-full bg-white animate-pulse"></span>
{{ $selectedVoucher->tags }}
</div>
<h2 class="text-3xl font-bold text-white px-6">{{ $selectedVoucher->name }}</h2>
</div>
<button wire:click="closeDetail"
class="absolute top-6 right-6 w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 text-white flex items-center justify-center transition-all">
<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"
d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
{{-- Modal Body --}}
<div class="p-8 max-h-[60vh] overflow-y-auto custom-scrollbar">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
<div>
<h4 class="text-sm font-bold text-home-foreground/40 uppercase tracking-wider mb-4">Syarat
&
Ketentuan</h4>
<div class="space-y-4">
<div class="flex items-start gap-3">
<div
class="w-8 h-8 rounded-lg bg-home-primary/5 flex items-center justify-center text-home-primary mt-0.5">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2-1.343-2-3-2zm0 4c-2.485 0-4.5 1.567-4.5 3.5V18h9v-2.5c0-1.933-2.015-3.5-4.5-3.5z">
</path>
</svg>
</div>
<div>
<p class="text-sm font-medium text-home-foreground/50">Minimum Pembelian</p>
<p class="font-bold text-home-foreground">
{{ $selectedVoucher->min_purchase_formatted }}</p>
</div>
</div>
<div class="flex items-start gap-3">
<div
class="w-8 h-8 rounded-lg bg-home-primary/5 flex items-center justify-center text-home-primary mt-0.5">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z">
</path>
</svg>
</div>
<div>
<p class="text-sm font-medium text-home-foreground/50">Masa Berlaku</p>
<p class="font-bold text-home-foreground">Hingga
{{ $selectedVoucher->end_date_formatted }}</p>
</div>
</div>
@if ($selectedVoucher->limit_per_user)
<div class="flex items-start gap-3">
<div
class="w-8 h-8 rounded-lg bg-home-primary/5 flex items-center justify-center text-home-primary mt-0.5">
<svg class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z">
</path>
</svg>
</div>
<div>
<p class="text-sm font-medium text-home-foreground/50">Batas per Pengguna
</p>
<p class="font-bold text-home-foreground">
{{ $selectedVoucher->limit_per_user }}x Klaim</p>
</div>
</div>
@endif
</div>
</div>
<div>
<h4 class="text-sm font-bold text-home-foreground/40 uppercase tracking-wider mb-4">Outlet
Tersedia
</h4>
<div class="flex flex-wrap gap-2">
@forelse ($selectedVoucher->outlets as $outlet)
<span
class="px-4 py-2 bg-home-primary/5 border border-home-primary/10 rounded-xl text-sm font-semibold text-home-primary flex items-center gap-2">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z">
</path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
{{ $outlet->name }}
</span>
@empty
<span
class="px-4 py-2 bg-home-foreground/5 border border-home-foreground/10 rounded-xl text-sm font-semibold text-home-foreground/50">
Dapat digunakan di semua outlet
</span>
@endforelse
</div>
</div>
</div>
<div class="bg-home-foreground/5 rounded-2xl p-6">
<h4 class="text-sm font-bold text-home-foreground/40 uppercase tracking-wider mb-4">Ringkasan
</h4>
<p class="text-home-foreground/70 leading-relaxed italic">
"{{ $selectedVoucher->summary }}"
</p>
</div>
</div>
{{-- Modal Footer --}}
<div class="p-8 bg-white border-t border-home-foreground/5 flex gap-4">
<button wire:click="closeDetail"
class="flex-1 py-4 px-6 border border-home-foreground/20 text-home-foreground font-bold rounded-2xl hover:bg-home-foreground/5 transition-all">
Tutup
</button>
<button wire:click="claim('{{ $selectedVoucher->hashId }}')"
class="flex-[2] py-4 px-6 bg-home-primary text-white font-bold rounded-2xl hover:bg-home-secondary hover:text-home-primary hover:shadow-xl hover:shadow-home-primary/20 transition-all shadow-lg shadow-home-primary/10">
Klaim Sekarang
</button>
</div>
</div>
</div>
@endif
</div>