From 307213c7d2b9e9774faec3d8f5a09def410ae479 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Tue, 10 Feb 2026 15:02:08 +0700 Subject: [PATCH] refactor: Consolidate home page UI into new hero and brands components and improve stock opname quantity handling. --- .../Forms/Studio/Stock/StockOpnameForm.php | 2 +- app/Livewire/Home/Index.php | 50 ++-- app/Livewire/Home/Outlet.php | 45 ++-- .../Studio/Stock/StockOpname/Index.php | 8 +- .../Studio/Stock/StockOpname/Manage.php | 19 +- .../animations/lottie/boxing-cat.blade.php | 6 +- .../views/components/layouts/home.blade.php | 4 +- .../sections/ui/home}/benefits.blade.php | 6 +- .../sections/ui/home/brands.blade.php | 18 ++ .../sections/ui/home}/categories.blade.php | 5 +- .../sections/ui/home}/cta.blade.php | 25 +- .../{_footer.blade.php => footer.blade.php} | 6 +- .../{_header.blade.php => header.blade.php} | 2 +- .../sections/ui/home/hero.blade.php | 193 ++++++++++++++++ .../sections/ui/home}/why.blade.php | 7 +- resources/views/livewire/home/index.blade.php | 217 ++++-------------- .../livewire/home/partials/brands.blade.php | 12 - .../home/partials/jumbotron.blade.php | 4 - .../home/partials/jumbotron/left.blade.php | 49 ---- .../home/partials/jumbotron/right.blade.php | 58 ----- .../partials/jumbotron/testimonial.blade.php | 85 ------- .../livewire/home/product/index.blade.php | 13 +- .../livewire/home/product/show.blade.php | 8 +- .../stock/stock-opname/manage.blade.php | 15 +- 24 files changed, 389 insertions(+), 468 deletions(-) rename resources/views/{livewire/home/partials => components/sections/ui/home}/benefits.blade.php (94%) create mode 100644 resources/views/components/sections/ui/home/brands.blade.php rename resources/views/{livewire/home/partials => components/sections/ui/home}/categories.blade.php (95%) rename resources/views/{livewire/home/partials => components/sections/ui/home}/cta.blade.php (85%) rename resources/views/components/sections/ui/home/{_footer.blade.php => footer.blade.php} (97%) rename resources/views/components/sections/ui/home/{_header.blade.php => header.blade.php} (99%) create mode 100644 resources/views/components/sections/ui/home/hero.blade.php rename resources/views/{livewire/home/partials => components/sections/ui/home}/why.blade.php (85%) delete mode 100644 resources/views/livewire/home/partials/brands.blade.php delete mode 100644 resources/views/livewire/home/partials/jumbotron.blade.php delete mode 100644 resources/views/livewire/home/partials/jumbotron/left.blade.php delete mode 100644 resources/views/livewire/home/partials/jumbotron/right.blade.php delete mode 100644 resources/views/livewire/home/partials/jumbotron/testimonial.blade.php 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. 😉✨' !!}

diff --git a/resources/views/components/layouts/home.blade.php b/resources/views/components/layouts/home.blade.php index b48d9c4..799cbc5 100644 --- a/resources/views/components/layouts/home.blade.php +++ b/resources/views/components/layouts/home.blade.php @@ -13,7 +13,7 @@ - @include('components.sections.ui.home._header') + @persist('toast') @@ -21,7 +21,7 @@ {{ $slot }} - @include('components.sections.ui.home._footer') + @fluxScripts diff --git a/resources/views/livewire/home/partials/benefits.blade.php b/resources/views/components/sections/ui/home/benefits.blade.php similarity index 94% rename from resources/views/livewire/home/partials/benefits.blade.php rename to resources/views/components/sections/ui/home/benefits.blade.php index 12dd0bc..cd69a6b 100644 --- a/resources/views/livewire/home/partials/benefits.blade.php +++ b/resources/views/components/sections/ui/home/benefits.blade.php @@ -12,11 +12,11 @@ class="w-full h-[400px] lg:h-[600px] object-cover rounded-2xl shadow-lg">

- Keunggulan Produk Kami. + Kenapa Harus Kami? 🏆✨

- 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! + 💖✨

diff --git a/resources/views/components/sections/ui/home/brands.blade.php b/resources/views/components/sections/ui/home/brands.blade.php new file mode 100644 index 0000000..ede5b08 --- /dev/null +++ b/resources/views/components/sections/ui/home/brands.blade.php @@ -0,0 +1,18 @@ +
+
+
+ @foreach (array_merge($brands, $brands) as $brand) +
+
+ {{ $brand['name'] }} +

+ {{ $brand['name'] }} +

+
+
+ @endforeach +
+
+
diff --git a/resources/views/livewire/home/partials/categories.blade.php b/resources/views/components/sections/ui/home/categories.blade.php similarity index 95% rename from resources/views/livewire/home/partials/categories.blade.php rename to resources/views/components/sections/ui/home/categories.blade.php index 5242144..7c4e385 100644 --- a/resources/views/livewire/home/partials/categories.blade.php +++ b/resources/views/components/sections/ui/home/categories.blade.php @@ -4,11 +4,10 @@

- Temukan Aroma yang - Cocok dengan Kepribadianmu. + Temukan Aroma yang Kamu Banget! 💃✨

- Pilih kategori aroma yang paling menggambarkan dirimu dan ciptakan kesan tak terlupakan. + Pilih kategori aroma yang paling menggambarkan dirimu dan bikin kesan tak terlupakan! 🌹

diff --git a/resources/views/livewire/home/partials/cta.blade.php b/resources/views/components/sections/ui/home/cta.blade.php similarity index 85% rename from resources/views/livewire/home/partials/cta.blade.php rename to resources/views/components/sections/ui/home/cta.blade.php index cd2a429..c7ac37f 100644 --- a/resources/views/livewire/home/partials/cta.blade.php +++ b/resources/views/components/sections/ui/home/cta.blade.php @@ -1,3 +1,9 @@ +@props([ + 'totalMembersCount' => 0, + 'formattedTotalMembersCount' => '', + 'latestMembers' => [], +]) +
@@ -5,31 +11,30 @@

- Bergabung dengan Member Eksklusif. + Jadi Bagian Keluarga Eksklusif Kami! 👑✨

- 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! 😉🎉

@foreach ($latestMembers as $member) - {{ $member->name }} + {{ $member['name'] }} @endforeach
-

Bergabung bersama {{ number_format($totalMembersCount) }}+ - member lainnya.

+

Gabung sama {{ $formattedTotalMembersCount }}+ + parfum lovers lainnya! 💕

diff --git a/resources/views/components/sections/ui/home/_footer.blade.php b/resources/views/components/sections/ui/home/footer.blade.php similarity index 97% rename from resources/views/components/sections/ui/home/_footer.blade.php rename to resources/views/components/sections/ui/home/footer.blade.php index c0dd998..0918b31 100644 --- a/resources/views/components/sections/ui/home/_footer.blade.php +++ b/resources/views/components/sections/ui/home/footer.blade.php @@ -39,7 +39,7 @@ class="w-10 h-10 rounded-full bg-white/5 flex items-center justify-center text-g
-

Tautan Cepat

+

Cek Link Ini ✨

  • -

    Kontak Kami

    +

    Sapa Kami Yuk! 👋

    - © {{ date('Y') }} Yadi Parfum. Semua hak dilindungi undang-undang. + © {{ date('Y') }} Yadi Parfum. Dibuat dengan cinta untuk kamu! ❤️✨
    {{--
    Privacy Policy diff --git a/resources/views/components/sections/ui/home/_header.blade.php b/resources/views/components/sections/ui/home/header.blade.php similarity index 99% rename from resources/views/components/sections/ui/home/_header.blade.php rename to resources/views/components/sections/ui/home/header.blade.php index d9f5331..35f4324 100644 --- a/resources/views/components/sections/ui/home/_header.blade.php +++ b/resources/views/components/sections/ui/home/header.blade.php @@ -62,7 +62,7 @@ class="{{ request()->routeIs($item['match']) ? 'font-bold text-home-primary' : ' 'border-home-foreground text-home-foreground': !scrolled || isOpen }" class="hidden lg:flex items-center border px-4 py-2 rounded-full transition-all duration-200 hover:scale-105 font-medium"> - Masuk + Yuk Masuk! ✨ 0, + 'formattedTotalMembersCount' => '', + 'latestMembers' => [], + 'testimonials' => [], + 'bestSellingPerfumes' => [], +]) + +
    + {{-- Left Section --}} +
    + + + {{-- Testimonial Section --}} +
    + @if (!empty($testimonials)) +
    +
    +
    + @foreach ($testimonials as $testimonial) +
    +
    + {{ $testimonial['customer_name'] }} +
    +

    + {{ $testimonial['customer_name'] }}

    +
    + @for ($i = 0; $i < $testimonial['rating']; $i++) + ★ + @endfor +
    +
    +
    +

    + "{{ $testimonial['content'] }}" +

    +
    + @endforeach +
    +
    + +
    + + +
    +
    + @endif +
    +
    + + {{-- Right Section --}} +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + @foreach ($bestSellingPerfumes as $perfume) +
    +
    + +
    + {{ $perfume['name'] }} +
    + +
    +
    +

    + {{ $perfume['name'] }} +

    +
    + + {{ $perfume['formatted_price'] }} + +
    +
    + + {{ $perfume['formatted_sold_count'] }} + +
    +
    + + +
    +
    +
    + @endforeach +
    +
    +
    +
    +
    +
    diff --git a/resources/views/livewire/home/partials/why.blade.php b/resources/views/components/sections/ui/home/why.blade.php similarity index 85% rename from resources/views/livewire/home/partials/why.blade.php rename to resources/views/components/sections/ui/home/why.blade.php index 43e5e6a..c0f40c8 100644 --- a/resources/views/livewire/home/partials/why.blade.php +++ b/resources/views/components/sections/ui/home/why.blade.php @@ -4,12 +4,11 @@

    - Temukan Parfum Favorit dengan Kualitas Terbaik + Parfum Favorit Kualitas Juara! 🏅✨

    - Kami menghadirkan parfum original berkualitas tinggi langsung dari distributor resmi. Setiap aroma - dirancang untuk bertahan lama, memberikan pengalaman wangi yang istimewa, dan memastikan setiap - tetesnya asli dan terpercaya. + Kami bawa parfum original kualitas terbaik langsung dari sumbernya! Wanginya awet, bikin kamu makin + pede dan happy seharian! 💃💖

    diff --git a/resources/views/livewire/home/index.blade.php b/resources/views/livewire/home/index.blade.php index 99b3f16..2c53da7 100644 --- a/resources/views/livewire/home/index.blade.php +++ b/resources/views/livewire/home/index.blade.php @@ -8,58 +8,17 @@
    + @assets + + @endassets @@ -67,130 +26,54 @@ @script @endscript diff --git a/resources/views/livewire/home/partials/brands.blade.php b/resources/views/livewire/home/partials/brands.blade.php deleted file mode 100644 index d779719..0000000 --- a/resources/views/livewire/home/partials/brands.blade.php +++ /dev/null @@ -1,12 +0,0 @@ -
    -
    - @foreach ($brands as $brand) -
    - {{ $brand['name'] }} -

    - {{ $brand['name'] }} -

    -
    - @endforeach -
    -
    diff --git a/resources/views/livewire/home/partials/jumbotron.blade.php b/resources/views/livewire/home/partials/jumbotron.blade.php deleted file mode 100644 index a023635..0000000 --- a/resources/views/livewire/home/partials/jumbotron.blade.php +++ /dev/null @@ -1,4 +0,0 @@ -
    - @include('livewire.home.partials.jumbotron.left') - @include('livewire.home.partials.jumbotron.right') -
    \ No newline at end of file diff --git a/resources/views/livewire/home/partials/jumbotron/left.blade.php b/resources/views/livewire/home/partials/jumbotron/left.blade.php deleted file mode 100644 index 1fd9b7e..0000000 --- a/resources/views/livewire/home/partials/jumbotron/left.blade.php +++ /dev/null @@ -1,49 +0,0 @@ -
    -
    - @if ($totalMembersCount > 0) -
    -
    - @foreach ($latestMembers as $member) -
    - {{ $member->user->name ?? $member->name }} -
    - @endforeach -
    - -
    - {{ $totalMembersCount }}+ Customer Mempercayai Kami -
    -
    - @endif - -

    - Temukan
    - - signature scent-mu - hari ini -

    - -

    - Setiap parfum punya cerita. Pilih aroma yang sesuai dengan gaya hidupmu dan kesan yang ingin kamu tampilkan. -

    - - -
    - @include('livewire.home.partials.jumbotron.testimonial') -
    diff --git a/resources/views/livewire/home/partials/jumbotron/right.blade.php b/resources/views/livewire/home/partials/jumbotron/right.blade.php deleted file mode 100644 index 3d18b25..0000000 --- a/resources/views/livewire/home/partials/jumbotron/right.blade.php +++ /dev/null @@ -1,58 +0,0 @@ - diff --git a/resources/views/livewire/home/partials/jumbotron/testimonial.blade.php b/resources/views/livewire/home/partials/jumbotron/testimonial.blade.php deleted file mode 100644 index 15bb0f1..0000000 --- a/resources/views/livewire/home/partials/jumbotron/testimonial.blade.php +++ /dev/null @@ -1,85 +0,0 @@ -
    - @if (!empty($testimonials)) -
    - -
    - @foreach ($testimonials as $index => $testimonial) -
    -
    - {{ $testimonial['user']['customer']['name'] ?? 'User' }} -
    -

    - {{ $testimonial['user']['customer']['name'] ?? 'User' }}

    -
    - @for ($i = 0; $i < $testimonial['rating']; $i++) - ★ - @endfor -
    -
    -
    -

    - "{{ $testimonial['content'] }}" -

    -
    - @endforeach -
    - -
    - - -
    -
    - @endif -
    diff --git a/resources/views/livewire/home/product/index.blade.php b/resources/views/livewire/home/product/index.blade.php index 886e1c4..ac96391 100644 --- a/resources/views/livewire/home/product/index.blade.php +++ b/resources/views/livewire/home/product/index.blade.php @@ -17,7 +17,7 @@ class="w-full h-full object-cover"> {{-- Search Bar --}}
    -