feat: Implement role-based profile redirection, simplify header navigation, and refactor homepage data loading.
This commit is contained in:
parent
2c84184bf9
commit
72750090aa
20
app/Http/Controllers/ProfileRedirectController.php
Normal file
20
app/Http/Controllers/ProfileRedirectController.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Traits\Components\WithRoleRedirect;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProfileRedirectController extends Controller
|
||||
{
|
||||
use WithRoleRedirect;
|
||||
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*/
|
||||
public function __invoke(Request $request): RedirectResponse
|
||||
{
|
||||
return $this->goToProfile();
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,6 @@
|
||||
use App\Models\PerfumeFeature;
|
||||
use App\Models\Testimonial;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Component;
|
||||
@ -20,6 +19,8 @@
|
||||
])]
|
||||
class Index extends Component
|
||||
{
|
||||
public array $bestSellingPerfumes = [];
|
||||
|
||||
public array $brands = [];
|
||||
|
||||
public array $perfumeFeatures = [];
|
||||
@ -36,6 +37,23 @@ class Index extends Component
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->bestSellingPerfumes = Perfume::withSum(['items' => function ($query) {
|
||||
$query->whereHas('order', function ($q) {
|
||||
$q->paid();
|
||||
});
|
||||
}], 'quantity')
|
||||
->orderByDesc('items_sum_quantity')
|
||||
->take(2)
|
||||
->get()
|
||||
->map(function (Perfume $perfume) {
|
||||
$perfume->image = $perfume->getFirstMediaUrl('image') ? Storage::url($perfume->getFirstMediaUrl('image')) : asset('assets/images/logo.png');
|
||||
$perfume->concentration_label = $perfume->concentration->label();
|
||||
|
||||
return $perfume;
|
||||
})
|
||||
->filter(fn (Perfume $perfume) => $perfume->items_sum_quantity > 0)
|
||||
->toArray();
|
||||
|
||||
$this->brands = Brand::orderBy('sort_order')
|
||||
->get()
|
||||
->map(function (Brand $brand) {
|
||||
@ -45,6 +63,14 @@ public function mount(): void
|
||||
})
|
||||
->toArray();
|
||||
|
||||
$this->whyChooseUs = ChooseUs::orderBy('sort_order')
|
||||
->get()
|
||||
->map(fn (ChooseUs $chooseUs) => [
|
||||
'name' => $chooseUs->name,
|
||||
'description' => $chooseUs->description,
|
||||
])
|
||||
->toArray();
|
||||
|
||||
$this->perfumeFeatures = PerfumeFeature::orderBy('sort_order')
|
||||
->get()
|
||||
->map(fn (PerfumeFeature $perfumeFeature) => [
|
||||
@ -61,14 +87,6 @@ public function mount(): void
|
||||
])
|
||||
->toArray();
|
||||
|
||||
$this->whyChooseUs = ChooseUs::orderBy('sort_order')
|
||||
->get()
|
||||
->map(fn (ChooseUs $chooseUs) => [
|
||||
'name' => $chooseUs->name,
|
||||
'description' => $chooseUs->description,
|
||||
])
|
||||
->toArray();
|
||||
|
||||
$this->totalMembersCount = Customer::count();
|
||||
|
||||
$this->latestMembers = Customer::whereNotNull('user_id')
|
||||
@ -82,23 +100,6 @@ public function mount(): void
|
||||
->take(5)
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$this->bestSellingPerfumes = Perfume::withSum(['items' => function ($query) {
|
||||
$query->whereHas('order', function ($q) {
|
||||
$q->paid();
|
||||
});
|
||||
}], 'quantity')
|
||||
->orderByDesc('items_sum_quantity')
|
||||
->take(2)
|
||||
->get()
|
||||
->map(function (Perfume $perfume) {
|
||||
$perfume->image = $perfume->getFirstMediaUrl('image') ? Storage::url($perfume->getFirstMediaUrl('image')) : asset('assets/images/logo.png');
|
||||
$perfume->concentration_label = $perfume->concentration->label();
|
||||
|
||||
return $perfume;
|
||||
})
|
||||
->filter(fn (Perfume $perfume) => $perfume->items_sum_quantity > 0)
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
@ -107,16 +108,4 @@ public function render(): View
|
||||
'pageTitle' => 'Beranda',
|
||||
]);
|
||||
}
|
||||
|
||||
public function goToProduct(): RedirectResponse
|
||||
{
|
||||
return redirect('/product');
|
||||
}
|
||||
|
||||
public function goToVoucher(): RedirectResponse
|
||||
{
|
||||
return redirect('/voucher');
|
||||
}
|
||||
|
||||
public $bestSellingPerfumes = [];
|
||||
}
|
||||
|
||||
@ -293,37 +293,31 @@ public function boot(): void
|
||||
$header = [
|
||||
[
|
||||
'title' => 'Beranda',
|
||||
'type' => 'link',
|
||||
'route' => 'homepage',
|
||||
'match' => 'homepage',
|
||||
],
|
||||
[
|
||||
'title' => 'Outlet',
|
||||
'type' => 'link',
|
||||
'route' => 'outlet',
|
||||
'match' => 'outlet',
|
||||
],
|
||||
[
|
||||
'title' => 'Produk',
|
||||
'type' => 'link',
|
||||
'route' => 'product.index',
|
||||
'match' => 'product.*',
|
||||
],
|
||||
[
|
||||
'title' => 'Voucher',
|
||||
'type' => 'link',
|
||||
'route' => 'voucher',
|
||||
'match' => 'voucher',
|
||||
],
|
||||
[
|
||||
'title' => 'Artikel',
|
||||
'type' => 'link',
|
||||
'route' => 'article.index',
|
||||
'match' => 'article.*',
|
||||
],
|
||||
[
|
||||
'title' => 'FAQ',
|
||||
'type' => 'link',
|
||||
'route' => 'faq',
|
||||
'match' => 'faq',
|
||||
],
|
||||
|
||||
32
app/Traits/Components/WithRoleRedirect.php
Normal file
32
app/Traits/Components/WithRoleRedirect.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits\Components;
|
||||
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
trait WithRoleRedirect
|
||||
{
|
||||
public function goToProfile(): RedirectResponse
|
||||
{
|
||||
if (! auth()->check()) {
|
||||
return redirect('/login');
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$roles = $user->roles->pluck('name')->toArray();
|
||||
|
||||
if (array_intersect($roles, ['Developer', 'Owner', 'Leader', 'Admin'])) {
|
||||
return redirect('/studio/dashboard/overview');
|
||||
}
|
||||
|
||||
if (in_array('Partner', $roles, true)) {
|
||||
return redirect('/partner/overview');
|
||||
}
|
||||
|
||||
if (in_array('Customer', $roles, true)) {
|
||||
return redirect('/member/overview');
|
||||
}
|
||||
|
||||
return redirect('/login');
|
||||
}
|
||||
}
|
||||
@ -28,43 +28,17 @@ class="w-10 h-8 lg:w-16 lg:h-12 transition-all duration-200">
|
||||
class="hidden lg:flex items-center gap-6 font-medium px-8 py-3 rounded-full transition-all duration-200 border text-home-foreground"
|
||||
aria-label="Main Navigation">
|
||||
@foreach ($header as $item)
|
||||
@if ($item['type'] === 'link')
|
||||
<a href="{{ route($item['route']) }}"
|
||||
class="{{ request()->routeIs($item['route']) ? 'font-bold text-home-primary' : 'hover:opacity-80' }} transition-opacity"
|
||||
wire:navigate>
|
||||
{{ $item['title'] }}
|
||||
</a>
|
||||
@endif
|
||||
|
||||
@if ($item['type'] === 'dropdown')
|
||||
<div class="relative group">
|
||||
<button
|
||||
class="flex items-center gap-2 hover:opacity-80 transition-opacity {{ request()->routeIs($item['match']) ? 'font-bold text-home-primary' : 'hover:opacity-80' }}">
|
||||
<span>{{ $item['title'] }}</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="size-4 group-hover:rotate-180 transition-transform duration-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="absolute left-0 top-full hidden group-hover:block pt-2 w-40">
|
||||
<div class="bg-white/95 backdrop-blur-md shadow-lg rounded-lg py-2 border border-gray-200">
|
||||
@foreach ($item['items'] as $sub)
|
||||
<a href="{{ route($sub['route']) }}" wire:navigate
|
||||
class="{{ request()->routeIs($sub['match']) ? 'font-bold text-home-primary' : 'hover:opacity-80' }} block px-4 py-2 hover:bg-gray-50 transition-colors">
|
||||
{{ $sub['title'] }}
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<a href="{{ route($item['route']) }}"
|
||||
class="{{ request()->routeIs($item['route']) ? 'font-bold text-home-primary' : 'hover:opacity-80' }} transition-opacity"
|
||||
wire:navigate>
|
||||
{{ $item['title'] }}
|
||||
</a>
|
||||
@endforeach
|
||||
</nav>
|
||||
|
||||
<section class="flex items-center lg:gap-2 gap-1 z-50">
|
||||
<button id="cart"
|
||||
{{-- not used yet --}}
|
||||
{{-- <button id="cart"
|
||||
class="flex items-center rounded-full transition-all duration-200 border border-home-foreground lg:p-0 hover:scale-110">
|
||||
<div id="cart-icon"
|
||||
class="w-8 h-8 lg:w-10 lg:h-10 flex justify-center items-center rounded-full transition-all duration-200 text-white bg-home-foreground">
|
||||
@ -75,24 +49,40 @@ class="w-8 h-8 lg:w-10 lg:h-10 flex justify-center items-center rounded-full tra
|
||||
</svg>
|
||||
</div>
|
||||
<span class="ms-2 me-3 transition-all duration-200 hidden lg:block text-home-foreground">Keranjang</span>
|
||||
</button>
|
||||
</button> --}}
|
||||
|
||||
<button id="login"
|
||||
class="hidden lg:flex items-center border px-4 py-2 rounded-full transition-all duration-200 hover:scale-105 font-medium border-home-foreground text-home-foreground">
|
||||
Masuk
|
||||
</button>
|
||||
@guest
|
||||
<a href="{{ route('login') }}" id="login" wire:navigate
|
||||
class="hidden lg:flex items-center border px-4 py-2 rounded-full transition-all duration-200 hover:scale-105 font-medium border-home-foreground text-home-foreground">
|
||||
Masuk
|
||||
</a>
|
||||
|
||||
<button id="profile"
|
||||
class="flex items-center rounded-full transition-all duration-200 lg:p-0 lg:border-0 hover:scale-110">
|
||||
<div id="profile-icon"
|
||||
class="w-8 h-8 lg:w-10 lg:h-10 flex justify-center items-center rounded-full transition-all duration-200 text-white bg-home-foreground">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2"
|
||||
stroke="currentColor" class="size-4 lg:size-6 transition-all duration-200" id="profile-svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
<button id="profile-mobile" wire:navigate
|
||||
class="flex lg:hidden items-center rounded-full transition-all duration-200 lg:p-0 lg:border-0 hover:scale-110">
|
||||
<div id="profile-icon-mobile"
|
||||
class="w-8 h-8 lg:w-10 lg:h-10 flex justify-center items-center rounded-full transition-all duration-200 text-white bg-home-foreground">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2"
|
||||
stroke="currentColor" class="size-4 lg:size-6 transition-all duration-200">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
@endguest
|
||||
|
||||
@auth
|
||||
<a href="{{ route('profile.redirect') }}" id="profile"
|
||||
class="flex items-center rounded-full transition-all duration-200 lg:p-0 lg:border-0 hover:scale-110">
|
||||
<div id="profile-icon"
|
||||
class="w-8 h-8 lg:w-10 lg:h-10 flex justify-center items-center rounded-full transition-all duration-200 text-white bg-home-foreground">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2"
|
||||
stroke="currentColor" class="size-4 lg:size-6 transition-all duration-200" id="profile-svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
@endauth
|
||||
</section>
|
||||
|
||||
<nav id="mobile-menu"
|
||||
|
||||
@ -27,3 +27,5 @@
|
||||
Route::get('/faq', FaqComponent::class)->name('faq');
|
||||
|
||||
Route::get('/cart', CartComponent::class)->name('cart');
|
||||
|
||||
Route::get('/profile/redirect', \App\Http\Controllers\ProfileRedirectController::class)->name('profile.redirect');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user