diff --git a/app/Livewire/Forms/Studio/Stock/StockOpnameForm.php b/app/Livewire/Forms/Studio/Stock/StockOpnameForm.php index a79493f..42045e0 100644 --- a/app/Livewire/Forms/Studio/Stock/StockOpnameForm.php +++ b/app/Livewire/Forms/Studio/Stock/StockOpnameForm.php @@ -54,7 +54,7 @@ public function update(): void continue; } - $item->qty_physical = $qtyPhysical; + $item->qty_physical = str_replace('.', '', (string) $qtyPhysical); $item->save(); } } diff --git a/app/Livewire/Home/Index.php b/app/Livewire/Home/Index.php index 007ec74..9f5e4cb 100644 --- a/app/Livewire/Home/Index.php +++ b/app/Livewire/Home/Index.php @@ -22,6 +22,8 @@ class Index extends Component { use WithPagination; + public array $testimonials = []; + public array $bestSellingPerfumes = []; public array $brands = []; @@ -34,23 +36,39 @@ class Index extends Component public int $totalMembersCount = 0; - public $latestMembers = []; + public string $formattedTotalMembersCount = ''; - public array $testimonials = []; + public array $latestMembers = []; public function mount(): void { + $this->testimonials = Testimonial::with(['user', 'user.customer']) + ->show() + ->latest() + ->take(5) + ->get() + ->map(function (Testimonial $testimonial) { + $name = $testimonial->user->customer->name ?? 'User'; + $testimonial->customer_name = $name; + $testimonial->avatar_url = 'https://ui-avatars.com/api/?name='.urlencode($name).'&background=random&color=fff'; + + return $testimonial; + }) + ->toArray(); + $this->bestSellingPerfumes = Perfume::withSum(['items' => function ($query) { $query->whereHas('order', function ($q) { $q->paid(); }); }], 'quantity') ->orderByDesc('items_sum_quantity') - ->take(2) + ->take(5) ->get() ->map(function (Perfume $perfume) { - $perfume->image = $perfume->getFirstMediaUrl('image') ? $perfume->getFirstMediaUrl('image') : asset('assets/images/logo.png'); + $perfume->image = $perfume->getFirstMediaUrl('image') ?: asset('assets/images/logo.png'); $perfume->concentration_label = $perfume->concentration->label(); + $perfume->formatted_price = formatCurrencyNumber($perfume->sale_price, 'Rp'); + $perfume->formatted_sold_count = formatCurrencyNumber($perfume->items_sum_quantity); return $perfume; }) @@ -60,7 +78,7 @@ public function mount(): void $this->brands = Brand::orderBy('sort_order') ->get() ->map(function (Brand $brand) { - $brand->image = $brand->getFirstMediaUrl('image') ? $brand->getFirstMediaUrl('image') : asset('assets/images/dark-logo.png'); + $brand->image = $brand->getFirstMediaUrl('image') ?: asset('assets/images/dark-logo.png'); return $brand; }) @@ -70,33 +88,27 @@ public function mount(): void $this->perfumeFeatures = PerfumeFeature::orderBy('sort_order')->get()->toArray(); - $this->faqs = Faq::orderBy('sort_order') - ->get() - ->map(fn (Faq $faq) => [ - 'question' => $faq->question, - 'answer' => $faq->answer, - ]) - ->toArray(); + $this->faqs = Faq::orderBy('sort_order')->get()->toArray(); $this->totalMembersCount = Customer::count(); + $this->formattedTotalMembersCount = number_format($this->totalMembersCount); $this->latestMembers = Customer::whereNotNull('user_id') ->inRandomOrder() ->take(3) - ->get(); - - $this->testimonials = Testimonial::with(['user', 'user.customer']) - ->show() - ->latest() - ->take(5) ->get() + ->map(function (Customer $member) { + $member->avatar_url = 'https://ui-avatars.com/api/?name='.urlencode($member->name).'&background=random&color=fff'; + + return $member; + }) ->toArray(); } public function render(): View { return view('livewire.home.index', [ - 'pageTitle' => 'Beranda', + 'pageTitle' => 'Selamat Datang! ✨', 'categories' => Category::perfume() ->orderBy('sort_order') ->paginate(12) diff --git a/app/Livewire/Home/Outlet.php b/app/Livewire/Home/Outlet.php index 9c25453..221d08b 100644 --- a/app/Livewire/Home/Outlet.php +++ b/app/Livewire/Home/Outlet.php @@ -12,15 +12,30 @@ ])] class Outlet extends Component { - public array $outlets = []; - public string $search = ''; public ?OutletModel $selectedOutlet = null; - public function mount(): void + public function showDetail(OutletModel $outletModel): void { - $this->outlets = OutletModel::with(['facilities', 'openingHours']) + $this->selectedOutlet = $outletModel; + $this->selectedOutlet->load(['openingHours' => function ($query) { + $query->orderBy('day'); + }]); + $this->selectedOutlet->openingHours->each(function ($hour) { + $hour->formatted_open_time = \Carbon\Carbon::parse($hour->open_time)->format('H:i'); + $hour->formatted_close_time = \Carbon\Carbon::parse($hour->close_time)->format('H:i'); + }); + } + + public function closeModal(): void + { + $this->selectedOutlet = null; + } + + public function render(): View + { + $outlets = OutletModel::with(['facilities', 'openingHours']) ->operational() ->when($this->search, function ($query) { $query->where(function ($query) { @@ -31,29 +46,17 @@ public function mount(): void ->latest() ->get() ->map(function ($outlet) { - $outlet->image = $outlet->getFirstMediaUrl('featured_image') ? $outlet->getFirstMediaUrl('featured_image') : asset('assets/images/dark-logo.png'); + $outlet->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'])->find($outletId); - } - - public function closeModal(): void - { - $this->selectedOutlet = null; - } - - public function render(): View - { return view('livewire.home.outlets', [ - 'pageTitle' => 'Outlet', + 'pageTitle' => 'Outlet Terdekat ✨', + 'pageDesc' => 'Temukan outlet kami di sekitarmu dan rasakan langsung kemewahan aromanya! 🚗🏢', + 'outlets' => $outlets, ]); } } diff --git a/app/Livewire/Studio/Stock/StockOpname/Index.php b/app/Livewire/Studio/Stock/StockOpname/Index.php index 0044516..9f7162a 100644 --- a/app/Livewire/Studio/Stock/StockOpname/Index.php +++ b/app/Livewire/Studio/Stock/StockOpname/Index.php @@ -30,13 +30,7 @@ protected function loadItems(): void ->where('period_month', now()->format('Y-m')) ->get() ->map(function ($stockOpname) { - $outlet = $stockOpname->outlet; - - $parfumCount = $outlet->perfumes()->count(); - $botolCount = $outlet->bottles()->count(); - $produkCount = $outlet->products()->count(); - - $total = $parfumCount + $botolCount + $produkCount; + $total = $stockOpname->items()->count(); $filled = $stockOpname->items() ->whereNotNull('qty_physical') diff --git a/app/Livewire/Studio/Stock/StockOpname/Manage.php b/app/Livewire/Studio/Stock/StockOpname/Manage.php index 5596d4b..a8948ed 100644 --- a/app/Livewire/Studio/Stock/StockOpname/Manage.php +++ b/app/Livewire/Studio/Stock/StockOpname/Manage.php @@ -8,6 +8,7 @@ use App\Models\StockOpnameItem; use App\Traits\Authorization\WithAuthorization; use App\Traits\Components\WithConfirmation; +use App\Traits\Components\WithToast; use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Collection; use Livewire\Attributes\Title; @@ -16,7 +17,7 @@ #[Title('Kelola Stock Opname')] class Manage extends Component { - use WithAuthorization, WithConfirmation; + use WithAuthorization, WithConfirmation, WithToast; public StockOpnameForm $form; @@ -46,19 +47,27 @@ public function updated(string $propertyName, $value): void { $this->canOrAbort('manage stock opname'); - $this->form->update(); - if (str_starts_with($propertyName, 'form.outlet_stock.')) { $itemId = explode('.', $propertyName)[2]; $item = $this->items->firstWhere('id', $itemId); if ($item) { - $item->qty_physical = $value; - $item->difference = $value - $item->qty_system; + $normalizedValue = str_replace('.', '', (string) $value); + $item->qty_physical = (int) $normalizedValue; + $item->difference = (int) $normalizedValue - $item->qty_system; } } } + public function save(): void + { + $this->canOrAbort('manage stock opname'); + + $this->form->update(); + + $this->toast('Data stock opname berhasil disimpan.', 'Berhasil'); + } + public function render(): View { return view('livewire.studio.stock.stock-opname.manage', [ diff --git a/resources/views/components/animations/lottie/boxing-cat.blade.php b/resources/views/components/animations/lottie/boxing-cat.blade.php index e999aa6..becbccf 100644 --- a/resources/views/components/animations/lottie/boxing-cat.blade.php +++ b/resources/views/components/animations/lottie/boxing-cat.blade.php @@ -1,8 +1,8 @@ -
- {!! isset($message) ? $message : 'Yahhh, sepertinya belum ada data yang tersedia.' !!} +
+ {!! $message ?? 'Yahhh, sepertinya belum ada data yang tersedia. 😉✨' !!}
- Setiap parfum dibuat dengan standar tinggi agar kamu mendapatkan kualitas terbaik dan pengalaman - wangi yang tak terlupakan. + Tiap tetesnya dibikin spesial buat kamu, biar wangimu tahan lama dan bikin happy sepanjang hari! + 💖✨
- Pilih kategori aroma yang paling menggambarkan dirimu dan ciptakan kesan tak terlupakan. + Pilih kategori aroma yang paling menggambarkan dirimu dan bikin kesan tak terlupakan! 🌹
- Dapatkan akses awal ke koleksi terbaru, diskon member khusus, dan tips perawatan parfum langsung - dari ahlinya. + Dapetin akses VIP ke koleksi terbaru, diskon spesial, dan tips wangi-wangian eksklusif cuma buat + kamu! 😉🎉
Bergabung bersama {{ number_format($totalMembersCount) }}+ - member lainnya.
+Gabung sama {{ $formattedTotalMembersCount }}+ + parfum lovers lainnya! 💕