Compare commits

...

4 Commits

Author SHA1 Message Date
Bayu Lukman Yusuf 7fa95775f3 Merge branch 'feature-product' into development
WMS API/ECOMMERCE/pipeline/head This commit looks good Details
2026-02-24 11:50:44 +07:00
Bayu Lukman Yusuf b3630efd2e link product 2026-02-24 11:50:14 +07:00
Bayu Lukman Yusuf 7e820e7b45 init home store/marketplace 2026-02-24 11:30:42 +07:00
Bayu Lukman Yusuf e3b9dbea60 rename meta tag 2026-02-23 12:51:25 +07:00
26 changed files with 1212 additions and 1791 deletions

View File

@ -10,8 +10,12 @@ class HomeController extends Controller
public function index(Request $request)
{
return view('home.fashion-v1');
}
public function store(Request $request)
{
return view('home.grocery');
}
}

View File

@ -338,6 +338,11 @@ class Items extends Model
}
}
public function getDisplayPriceCurrencyAttribute()
{
return 'Rp ' . number_format($this->display_price, 0, ',', '.');
}
public function getDisplayDiscountPriceAttribute()
{
try {

View File

@ -23,5 +23,13 @@ class StoreCategory extends Model
return $this->hasMany(StoreCapacity::class);
}
public function items()
{
return $this->hasMany(Items::class, 'category_id', 'id');
}
public function productCount()
{
return $this->items()->count();
}
}

View File

@ -62,6 +62,10 @@ class User extends Authenticatable
{
return $this->hasMany(Address::class);
}
public function primary_address()
{
return $this->hasOne(Address::class)->where('is_primary', true);
}
public function getPhotoUrlAttribute()
{

View File

@ -0,0 +1,29 @@
<?php
namespace App\View\Components\Grocery;
use Illuminate\View\Component;
use Illuminate\View\View;
class DeliveryOptions extends Component
{
/**
* Create a new component instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the view/contents that represent the component.
*
* @return View|string
*/
public function render(): View|string
{
return view('components.grocery.delivery-options');
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\View\Components\Grocery;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class FeaturedCategories extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.grocery.featured-categories');
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\View\Components\Grocery;
use App\Repositories\Catalog\CategoryRepository;
use App\Repositories\Catalog\GenderRepository;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class HeaderCategoryDropdown extends Component
{
protected $categories = [];
protected $genders = [];
/**
* Create a new component instance.
*/
public function __construct(CategoryRepository $categoryRepository, GenderRepository $genderRepository)
{
$this->categories = $categoryRepository->getList([]);
$this->genders = $genderRepository->getList([]);
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.grocery.header-category-dropdown', [
'categories' => $this->categories,
'genders' => $this->genders,
]);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\View\Components\Grocery;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
use App\Repositories\Member\BannerRepository;
class HomeSlider extends Component
{
public $items;
public function __construct(BannerRepository $repository)
{
$this->items = $repository->getList([]);
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.grocery.home-slider', [
'items' => $this->items
]);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\View\Components\Grocery;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
use App\Repositories\Catalog\CategoryRepository;
use App\Repositories\Catalog\ProductRepository;
class PopularProducts extends Component
{
protected $categories = [];
protected $products = [];
/**
* Create a new component instance.
*/
public function __construct(CategoryRepository $categoryRepository, ProductRepository $productRepository)
{
//
$this->categories = $categoryRepository->getList([]);
$this->products = $productRepository->getList([
'limit' => 12,
]);
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.grocery.popular-products', [
'categories' => $this->categories,
'products' => $this->products,
]);
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\View\Components\Grocery;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
use App\Repositories\Catalog\BrandRepository;
class ShopByLifestyle extends Component
{
protected $brands = [];
/**
* Create a new component instance.
*/
public function __construct(BrandRepository $brandRepository)
{
//
$this->brands = $brandRepository->getList([]);
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.grocery.shop-by-lifestyle', [
'brands' => $this->brands,
]);
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\View\Components\Grocery;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
use App\Repositories\Catalog\ProductRepository;
class SpecialProducts extends Component
{
protected $products = [];
/**
* Create a new component instance.
*/
public function __construct(ProductRepository $productRepository)
{
$this->products = $productRepository->getList([
]);
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.grocery.special-products',[
'products' => $this->products,
]);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\View\Components\Grocery;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class TopHeader extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
$brands = app(\App\Repositories\Catalog\BrandRepository::class)->getList([]);
return view('components.grocery.top-header', compact('brands'));
}
}

34
lang/en/grocery.php Normal file
View File

@ -0,0 +1,34 @@
<?php
return [
// Delivery Options
'delivery_options_title' => 'Delivery options',
'delivery_tab' => 'Delivery',
'pickup_tab' => 'Pickup',
// Addresses
'address_1' => '567 Cherry Lane Apt B12 Sacramento, 95829',
'address_2' => '1901 Thornridge Cir. Shiloh, Hawaii, 81063',
'address_3' => '3517 W. Gray St. Utica, Pennsylvania, 57867',
'pickup_address_1' => '123 Main St. Downtown, New York, 10001',
'pickup_address_2' => '456 Oak Avenue Midtown, New York, 10002',
// Actions
'remove' => 'Remove',
'back_to_addresses' => 'Back to my addresses',
'add_address_title' => 'Add an address to start ordering',
'add_pickup_address_title' => 'Add a pickup address',
'find_on_map' => 'Find on map',
'add_delivery_address' => 'Add delivery address',
'add_pickup_address' => 'Add pickup address',
// Form Labels
'state_label' => 'State',
'postcode_label' => 'Postcode',
'city_label' => 'City',
'street_address_label' => 'Street address',
// Form Placeholders
'select_state' => 'Select state',
'select_city' => 'Select city',
];

34
lang/id/grocery.php Normal file
View File

@ -0,0 +1,34 @@
<?php
return [
// Delivery Options
'delivery_options_title' => 'Opsi pengiriman',
'delivery_tab' => 'Pengiriman',
'pickup_tab' => 'Ambil sendiri',
// Addresses
'address_1' => '567 Cherry Lane Apt B12 Sacramento, 95829',
'address_2' => '1901 Thornridge Cir. Shiloh, Hawaii, 81063',
'address_3' => '3517 W. Gray St. Utica, Pennsylvania, 57867',
'pickup_address_1' => '123 Main St. Downtown, New York, 10001',
'pickup_address_2' => '456 Oak Avenue Midtown, New York, 10002',
// Actions
'remove' => 'Hapus',
'back_to_addresses' => 'Kembali ke alamat saya',
'add_address_title' => 'Tambahkan alamat untuk mulai memesan',
'add_pickup_address_title' => 'Tambahkan alamat pengambilan',
'find_on_map' => 'Cari di peta',
'add_delivery_address' => 'Tambah alamat pengiriman',
'add_pickup_address' => 'Tambah alamat pengambilan',
// Form Labels
'state_label' => 'Provinsi',
'postcode_label' => 'Kode pos',
'city_label' => 'Kota',
'street_address_label' => 'Alamat jalan',
// Form Placeholders
'select_state' => 'Pilih provinsi',
'select_city' => 'Pilih kota',
];

View File

@ -0,0 +1,222 @@
<div class="offcanvas offcanvas-end pb-sm-2 px-sm-2" id="deliveryOptions" tabindex="-1"
aria-labelledby="deliveryOptionsLabel" style="width: 500px">
<!-- Header with nav tabs -->
<div class="offcanvas-header flex-column align-items-start py-3 pt-lg-4">
<div class="d-flex align-items-center justify-content-between w-100 pb-xl-1 mb-4">
<h4 class="offcanvas-title" id="deliveryOptionsLabel">{{ __('grocery.delivery_options_title') }}</h4>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<ul class="nav nav-pills nav-justified w-100" role="tablist">
<li class="nav-item" role="presentation">
<button type="button" class="nav-link active" id="delivery-tab" data-bs-toggle="tab"
data-bs-target="#delivery-tab-pane" role="tab" aria-controls="delivery-tab-pane"
aria-selected="true">
<i class="ci-shopping-bag fs-base ms-n1 me-2"></i>
{{ __('grocery.delivery_tab') }}
</button>
</li>
<li class="nav-item" role="presentation">
<button type="button" class="nav-link" id="pickup-tab" data-bs-toggle="tab"
data-bs-target="#pickup-tab-pane" role="tab" aria-controls="pickup-tab-pane"
aria-selected="false">
<i class="ci-box fs-base ms-n1 me-2"></i>
{{ __('grocery.pickup_tab') }}
</button>
</li>
</ul>
</div>
<div class="offcanvas-body tab-content py-2 py-sm-3">
<!-- Delivery tab -->
<div class="tab-pane fade show active" id="delivery-tab-pane" role="tabpanel" aria-labelledby="delivery-tab">
<!-- Address options collapse -->
<div class="collapse delivery-address show" id="deliveryAddressOptions">
<div class="mt-n3">
<div class="form-check border-bottom py-4 m-0">
<input type="radio" class="form-check-input" id="address-1" name="delivery-address" checked>
<label for="address-1" class="form-check-label text-dark-emphasis fw-semibold">{{ __('grocery.address_1') }}</label>
</div>
<div class="form-check border-bottom py-4 m-0">
<input type="radio" class="form-check-input" id="address-2" name="delivery-address">
<div class="d-flex w-100">
<label for="address-2" class="form-check-label text-dark-emphasis me-3">{{ __('grocery.address_2') }}</label>
<button type="button" class="btn-close fs-sm ms-auto" data-bs-toggle="tooltip"
data-bs-custom-class="tooltip-sm" data-bs-title="{{ __('grocery.remove') }}" aria-label="{{ __('grocery.remove') }}"></button>
</div>
</div>
<div class="form-check border-bottom py-4 m-0">
<input type="radio" class="form-check-input" id="address-3" name="delivery-address">
<div class="d-flex w-100">
<label for="address-3" class="form-check-label text-dark-emphasis me-3">{{ __('grocery.address_3') }}</label>
<button type="button" class="btn-close fs-sm ms-auto" data-bs-toggle="tooltip"
data-bs-custom-class="tooltip-sm" data-bs-title="{{ __('grocery.remove') }}" aria-label="{{ __('grocery.remove') }}"></button>
</div>
</div>
</div>
</div>
<!-- Add new address collapse -->
<div class="collapse delivery-address" id="deliveryAddressAdd">
<div class="nav mb-4">
<a class="nav-link animate-underline p-0" href=".delivery-address" data-bs-toggle="collapse"
aria-expanded="true" aria-controls="deliveryAddressOptions deliveryAddressAdd">
<i class="ci-chevron-left fs-lg ms-n1 me-1"></i>
<span class="animate-target">{{ __('grocery.back_to_addresses') }}</span>
</a>
</div>
<div class="d-flex align-items-center justify-content-between mb-3 mb-lg-4">
<h5 class="h6 mb-0 me-3">{{ __('grocery.add_address_title') }}</h5>
<a class="btn btn-sm btn-outline-primary rounded-pill" href="#!">
<i class="ci-map-pin fs-base ms-n1 me-1"></i>
{{ __('grocery.find_on_map') }}
</a>
</div>
<div class="mb-3 mb-lg-4">
<label class="form-label">{{ __('grocery.state_label') }} *</label>
<select class="form-select form-select-lg rounded-pill"
data-select='{
"classNames": {
"containerInner": ["form-select", "form-select-lg", "rounded-pill"]
}
}'
aria-label="Large pill select">
<option value="">{{ __('grocery.select_state') }}</option>
<option value="Arizona">Arizona</option>
<option value="California">California</option>
<option value="Montana">Montana</option>
<option value="Nevada">Nevada</option>
<option value="New Mexico">New Mexico</option>
<option value="Texas">Texas</option>
</select>
</div>
<div class="mb-3 mb-lg-4">
<label for="my-postcode" class="form-label">{{ __('grocery.postcode_label') }} *</label>
<input type="text" class="form-control form-control-lg rounded-pill" id="my-postcode">
</div>
<div class="mb-3 mb-lg-4">
<label class="form-label">{{ __('grocery.city_label') }} *</label>
<select class="form-select form-select-lg rounded-pill"
data-select='{
"classNames": {
"containerInner": ["form-select", "form-select-lg", "rounded-pill"]
}
}'
aria-label="Large pill select">
<option value="">{{ __('grocery.select_city') }}</option>
<option value="Austin">Austin</option>
<option value="Helena">Helena</option>
<option value="Sacramento">Sacramento</option>
<option value="Santa Fe">Santa Fe</option>
<option value="Las Vegas">Las Vegas</option>
<option value="Phoenix">Phoenix</option>
</select>
</div>
<label for="my-address" class="form-label">{{ __('grocery.street_address_label') }} *</label>
<input type="text" class="form-control form-control-lg rounded-pill" id="my-address">
</div>
<!-- Add address collapse toggle -->
<div class="nav">
<a class="nav-link hiding-collapse-toggle animate-underline collapsed px-0 mt-4"
href=".delivery-address" data-bs-toggle="collapse" aria-expanded="false"
aria-controls="deliveryAddressOptions deliveryAddressAdd">
<span class="animate-target">{{ __('grocery.add_delivery_address') }}</span>
<i class="ci-plus fs-base ms-1"></i>
</a>
</div>
</div>
<!-- Pickup tab -->
<div class="tab-pane fade" id="pickup-tab-pane" role="tabpanel" aria-labelledby="pickup-tab">
<div class="collapse delivery-address show" id="pickupAddressOptions">
<div class="mt-n3">
<div class="form-check border-bottom py-4 m-0">
<input type="radio" class="form-check-input" id="pickup-1" name="pickup-address" checked>
<label for="pickup-1" class="form-check-label text-dark-emphasis fw-semibold">{{ __('grocery.pickup_address_1') }}</label>
</div>
<div class="form-check border-bottom py-4 m-0">
<input type="radio" class="form-check-input" id="pickup-2" name="pickup-address">
<div class="d-flex w-100">
<label for="pickup-2" class="form-check-label text-dark-emphasis me-3">{{ __('grocery.pickup_address_2') }}</label>
<button type="button" class="btn-close fs-sm ms-auto" data-bs-toggle="tooltip"
data-bs-custom-class="tooltip-sm" data-bs-title="{{ __('grocery.remove') }}" aria-label="{{ __('grocery.remove') }}"></button>
</div>
</div>
</div>
</div>
<!-- Add new pickup address collapse -->
<div class="collapse delivery-address" id="pickupAddressAdd">
<div class="nav mb-4">
<a class="nav-link animate-underline p-0" href=".delivery-address" data-bs-toggle="collapse"
aria-expanded="true" aria-controls="pickupAddressOptions pickupAddressAdd">
<i class="ci-chevron-left fs-lg ms-n1 me-1"></i>
<span class="animate-target">{{ __('grocery.back_to_addresses') }}</span>
</a>
</div>
<div class="d-flex align-items-center justify-content-between mb-3 mb-lg-4">
<h5 class="h6 mb-0 me-3">{{ __('grocery.add_pickup_address_title') }}</h5>
<a class="btn btn-sm btn-outline-primary rounded-pill" href="#!">
<i class="ci-map-pin fs-base ms-n1 me-1"></i>
{{ __('grocery.find_on_map') }}
</a>
</div>
<div class="mb-3 mb-lg-4">
<label class="form-label">{{ __('grocery.state_label') }} *</label>
<select class="form-select form-select-lg rounded-pill"
data-select='{
"classNames": {
"containerInner": ["form-select", "form-select-lg", "rounded-pill"]
}
}'
aria-label="Large pill select">
<option value="">{{ __('grocery.select_state') }}</option>
<option value="Arizona">Arizona</option>
<option value="California">California</option>
<option value="Montana">Montana</option>
<option value="Nevada">Nevada</option>
<option value="New Mexico">New Mexico</option>
<option value="Texas">Texas</option>
</select>
</div>
<div class="mb-3 mb-lg-4">
<label for="pickup-postcode" class="form-label">{{ __('grocery.postcode_label') }} *</label>
<input type="text" class="form-control form-control-lg rounded-pill" id="pickup-postcode">
</div>
<div class="mb-3 mb-lg-4">
<label class="form-label">{{ __('grocery.city_label') }} *</label>
<select class="form-select form-select-lg rounded-pill"
data-select='{
"classNames": {
"containerInner": ["form-select", "form-select-lg", "rounded-pill"]
}
}'
aria-label="Large pill select">
<option value="">{{ __('grocery.select_city') }}</option>
<option value="Austin">Austin</option>
<option value="Helena">Helena</option>
<option value="Sacramento">Sacramento</option>
<option value="Santa Fe">Santa Fe</option>
<option value="Las Vegas">Las Vegas</option>
<option value="Phoenix">Phoenix</option>
</select>
</div>
<label for="pickup-address" class="form-label">{{ __('grocery.street_address_label') }} *</label>
<input type="text" class="form-control form-control-lg rounded-pill" id="pickup-address">
</div>
<!-- Add pickup address collapse toggle -->
<div class="nav">
<a class="nav-link hiding-collapse-toggle animate-underline collapsed px-0 mt-4"
href=".delivery-address" data-bs-toggle="collapse" aria-expanded="false"
aria-controls="pickupAddressOptions pickupAddressAdd">
<span class="animate-target">{{ __('grocery.add_pickup_address') }}</span>
<i class="ci-plus fs-base ms-1"></i>
</a>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,91 @@
<section class="container pt-4 pb-5 mb-2 mb-sm-3 mb-lg-4 mb-xl-5">
<div class="swiper"
data-swiper='{
"slidesPerView": 1,
"spaceBetween": 24,
"pagination": {
"el": ".swiper-pagination",
"clickable": true
},
"breakpoints": {
"680": {
"slidesPerView": 2
},
"992": {
"slidesPerView": 3
}
}
}'>
<div class="swiper-wrapper">
<!-- Category -->
<div class="swiper-slide h-auto">
<div
class="position-relative d-flex justify-content-between align-items-center h-100 bg-primary-subtle rounded-5 overflow-hidden ps-2 ps-xl-3">
<div class="d-flex flex-column pt-4 px-3 pb-3">
<p class="fs-xs pb-2 mb-1">124 products</p>
<h2 class="h5 mb-2 mb-xxl-3">Only fresh fish to your table</h2>
<div class="nav">
<a class="nav-link animate-underline stretched-link text-body-emphasis text-nowrap px-0"
href="{{ route('product.index', ['filter[category]' => 'fresh-fish']) }}">
<span class="animate-target">Shop now</span>
<i class="ci-chevron-right fs-base ms-1"></i>
</a>
</div>
</div>
<div class="ratio w-100 align-self-end rtl-flip"
style="max-width: 216px; --cz-aspect-ratio: calc(240 / 216 * 100%)">
<img src="/img/home/grocery/featured/01.png" alt="Image">
</div>
</div>
</div>
<!-- Category -->
<div class="swiper-slide h-auto">
<div
class="position-relative d-flex justify-content-between align-items-center h-100 bg-success-subtle rounded-5 overflow-hidden ps-2 ps-xl-3">
<div class="d-flex flex-column pt-4 px-3 pb-3">
<p class="fs-xs pb-2 mb-1">97 products</p>
<h2 class="h5 mb-2 mb-xxl-3">Products for Easter table</h2>
<div class="nav">
<a class="nav-link animate-underline stretched-link text-body-emphasis text-nowrap px-0"
href="{{ route('product.index', ['filter[category]' => 'easter-table']) }}">
<span class="animate-target">Shop now</span>
<i class="ci-chevron-right fs-base ms-1"></i>
</a>
</div>
</div>
<div class="ratio w-100 align-self-end rtl-flip"
style="max-width: 216px; --cz-aspect-ratio: calc(240 / 216 * 100%)">
<img src="/img/home/grocery/featured/02.png" alt="Image">
</div>
</div>
</div>
<!-- Category -->
<div class="swiper-slide h-auto">
<div
class="position-relative d-flex justify-content-between align-items-center h-100 bg-info-subtle rounded-5 overflow-hidden ps-2 ps-xl-3">
<div class="d-flex flex-column pt-4 px-3 pb-3">
<p class="fs-xs pb-2 mb-1">28 products</p>
<h2 class="h5 mb-2 mb-xxl-3">Berries from the garden</h2>
<div class="nav">
<a class="nav-link animate-underline stretched-link text-body-emphasis text-nowrap px-0"
href="{{ route('product.index', ['filter[category]' => 'berries']) }}">
<span class="animate-target">Shop now</span>
<i class="ci-chevron-right fs-base ms-1"></i>
</a>
</div>
</div>
<div class="ratio w-100 align-self-end rtl-flip"
style="max-width: 216px; --cz-aspect-ratio: calc(240 / 216 * 100%)">
<img src="/img/home/grocery/featured/03.png" alt="Image">
</div>
</div>
</div>
</div>
<!-- Slider pagination (Bullets) -->
<div class="swiper-pagination position-static mt-3 mt-sm-4"></div>
</div>
</section>

View File

@ -0,0 +1,40 @@
<div class="dropdown d-none d-lg-block w-100 me-4" style="max-width: 200px">
<button type="button" class="btn btn-lg btn-secondary w-100 border-0 rounded-pill" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="ci-grid fs-lg me-2 ms-n1"></i>
Categories
<i class="ci-chevron-down fs-lg me-2 ms-auto me-n1"></i>
</button>
<div class="dropdown-menu rounded-4 p-4" style="--cz-dropdown-spacer: .75rem; margin-left: -75px">
<div class="d-flex gap-4">
<div style="min-width: 170px">
<div class="h6">Kategori</div>
<ul class="nav flex-column gap-2 mt-n2">
@foreach ($categories as $category)
<li class="d-flex w-100 pt-1">
<a class="nav-link animate-underline animate-target d-inline fw-normal text-truncate p-0"
href="{{ route('product.index', ['category_id', $category->id]) }}">{{ $category->name }}</a>
</li>
@endforeach
</ul>
</div>
<div style="min-width: 170px">
<div class="h6">Gender</div>
<ul class="nav flex-column gap-2 mt-n2">
@foreach ($genders as $gender)
<li class="d-flex w-100 pt-1">
<a class="nav-link animate-underline animate-target d-inline fw-normal text-truncate p-0"
href="{{ route('product.index', ['filter[gender]' => $gender->id]) }}">{{ $gender->name }}</a>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,50 @@
<section class="position-relative">
<div class="swiper position-absolute top-0 start-0 w-100 h-100"
data-swiper='{
"effect": "fade",
"loop": true,
"speed": 400,
"pagination": {
"el": ".swiper-pagination",
"clickable": true
},
"autoplay": {
"delay": 5500,
"disableOnInteraction": false
}
}'
data-bs-theme="dark">
<div class="swiper-wrapper">
@foreach ($items as $item)
<div class="swiper-slide" style="background-color: #6dafca">
{{-- <div class="position-absolute d-flex align-items-center w-100 h-100 z-2">
<div class="container mt-lg-n4">
<div class="row">
<div class="col-9 col-sm-8 col-md-7 col-lg-6">
<p class="fs-sm text-white mb-lg-4">🔥 Free shipping - order over
<strong>50$</strong>
</p>
<h2 class="display-4 pb-2 pb-md-3 pb-lg-4">Healthy Food Available to Everyone</h2>
<a class="btn btn-lg btn-outline-light rounded-pill"
href="{{ route('second', ['shop', 'catalog-grocery']) }}">Shop now</a>
</div>
</div>
</div>
</div> --}}
<img src="{{ env('WMS_ASSET_URL') . '/' . $item->filename }}"
class="position-absolute top-0 start-0 w-100 h-100 object-fit-cover rtl-flip" alt="Image">
</div>
@endforeach
</div>
<!-- Slider pagination (Bullets) -->
<div class="swiper-pagination pb-sm-2"></div>
</div>
<div class="d-md-none" style="height: 380px"></div>
<div class="d-none d-md-block d-lg-none" style="height: 420px"></div>
<div class="d-none d-lg-block d-xl-none" style="height: 500px"></div>
<div class="d-none d-xl-block d-xxl-none" style="height: 560px"></div>
<div class="d-none d-xxl-block" style="height: 624px"></div>
</section>

View File

@ -0,0 +1,98 @@
<section class="container pb-5 mb-2 mb-sm-3 mb-lg-4 mb-xl-5">
<div class="row">
<!-- Categories list -->
<div class="col-lg-3 pb-2 pb-sm-3 pb-md-4 mb-5 mb-lg-0">
<h2 class="h3 border-bottom pb-3 pb-md-4 mb-4">Categories</h2>
<div class="row nav g-3 g-sm-4">
@foreach ($categories as $key => $value)
<div class="col-sm-6 col-md-4 col-lg-12 d-flex">
<div class="position-relative d-flex min-w-0 align-items-center">
<div class="d-flex flex-shrink-0 align-items-center justify-content-center bg-body-tertiary rounded-circle"
style="width: 56px; height: 56px">
<img src="{{ asset('logo/logo-app.png') }}" width="40" alt="Image">
</div>
<div class="min-w-0 ps-3">
<a class="nav-link animate-underline stretched-link fs-base fw-semibold p-0 mb-1"
href="{{ route('product.index', ['filter[category]' => $value->id]) }}">
<span class="animate-target text-truncate">{{ $value->name ?? '' }}</span>
</a>
<div class="fs-xs fw-normal text-body-secondary">{{ $value->productCount() }} products</div>
</div>
</div>
</div>
@endforeach
</div>
</div>
<div class="col-lg-9">
<div class="d-flex align-items-center justify-content-between border-bottom pb-3 pb-md-4 mb-3 mb-lg-4">
<h2 class="h3 mb-0">Popular products</h2>
<div class="nav ms-3">
<a class="nav-link animate-underline px-0 py-2"
href="{{ route('product.index') }}">
<span class="animate-target">View all</span>
<i class="ci-chevron-right fs-base ms-1"></i>
</a>
</div>
</div>
<!-- Products grid -->
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-3 row-cols-xl-4 g-4">
@foreach ($products as $key => $value)
<!-- Item -->
<div class="col">
<div class="card product-card h-100 bg-transparent border-0 shadow-none">
<div class="position-relative z-2">
<button type="button"
class="btn btn-icon btn-sm btn-secondary animate-pulse fs-sm bg-body border-0 position-absolute top-0 end-0 z-2 mt-1 mt-sm-2 me-1 me-sm-2"
aria-label="Add to Wishlist">
<i class="ci-heart animate-target"></i>
</button>
<a class="d-block p-2 p-lg-3" href="{{ route('product.detail', [ $value->slug]) }}">
<div class="ratio" style="--cz-aspect-ratio: calc(160 / 191 * 100%)">
<img src="{{ $value->image_url }}" alt="Image" loading="lazy">
</div>
</a>
<div class="position-absolute w-100 start-0 bottom-0">
<div class="d-flex justify-content-end px-2 px-lg-3 pb-2 pb-lg-3">
<div
class="count-input count-input-collapsible collapsed justify-content-between w-100 bg-transparent border-0 rounded-2">
<button type="button" class="btn btn-icon btn-sm btn-primary" data-decrement
aria-label="Decrement quantity">
<i class="ci-minus fs-sm"></i>
</button>
<input type="number"
class="form-control form-control-sm bg-primary text-white w-100"
value="0" min="0" readonly>
<button type="button"
class="product-card-button btn btn-icon btn-sm btn-secondary ms-auto"
data-increment aria-label="Increment quantity">
<span data-count-input-value></span>
<i class="ci-plus fs-sm"></i>
</button>
</div>
</div>
</div>
</div>
<div class="card-body pt-0 px-1 px-md-2 px-lg-3 pb-2">
<div class="h6 mb-2">{{ $value->display_price_currency }}</div>
<h3 class="fs-sm lh-base mb-0">
<a class="hover-effect-underline fw-normal"
href="{{ route('product.detail', [$value->slug]) }}">{{ $value->name }}</a>
</h3>
</div>
<div class="fs-xs text-body-secondary px-1 px-md-2 px-lg-3 pb-2 pb-md-3">{{ $value->unit }}</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,46 @@
<section class="container pb-5 mb-2 mb-sm-3 mb-lg-4 mb-xl-5">
<h2 class="h3 text-center pb-1 pb-sm-2 pb-md-3 pb-lg-0 mb-4 mb-lg-5">Brands</h2>
<div class="swiper pb-lg-2"
data-swiper='{
"slidesPerView": 1,
"spaceBetween": 24,
"pagination": {
"el": ".swiper-pagination",
"clickable": true
},
"breakpoints": {
"500": {
"slidesPerView": 2
},
"768": {
"slidesPerView": 3
},
"992": {
"slidesPerView": 4
}
}
}'>
<div class="swiper-wrapper">
@foreach($brands as $brand)
<!-- Category -->
<div class="swiper-slide text-center">
<div
class="position-relative d-inline-block text-dark-emphasis bg-warning-subtle rounded-circle p-5 mb-4">
<img width="64" height="64" src="{{ $brand->image_url }}" alt="{{ $brand->name }}" class="img-fluid">
</div>
<h3 class="h5 mb-2">
<a class="animate-underline stretched-link"
href="{{ route('product.index', ['filter[brand]' => $brand->id]) }}">
<span class="animate-target">{{ $brand->name }}</span>
</a>
</h3>
{{-- <p class="fs-sm mb-0">Foods that don't contain gluten</p> --}}
</div>
@endforeach
</div>
<!-- Slider pagination (Bullets) -->
<div class="swiper-pagination position-static mt-3 mt-sm-4"></div>
</div>
</section>

View File

@ -0,0 +1,113 @@
<section class="container pt-xl-2 pb-5 mb-2 mb-sm-3 mb-lg-4 mb-xl-5">
<div class="row">
<!-- Banner -->
<div class="col-sm-5 col-md-4 col-lg-3 mb-5 mb-sm-0">
<div class="pe-lg-2 pe-xl-4">
<div class="rounded-4 overflow-hidden" style="background-color: #a6cddc" data-bs-theme="light">
<div class="pt-3 px-3 mt-3 mx-3">
<h4 class="mb-2 mb-xl-3">Make breakfast healthy and easy</h4>
<div class="nav">
<a class="nav-link animate-underline stretched-link px-0" href="#!">
<span class="animate-target">Shop now</span>
<i class="ci-chevron-right fs-base mt-1 ms-1"></i>
</a>
</div>
</div>
<div class="ratio mt-n2" style="--cz-aspect-ratio: calc(240 / 282 * 100%)">
<img src="/img/shop/grocery/banner.jpg" alt="Banner">
</div>
</div>
</div>
</div>
<!-- Special products carousel -->
<div class="col-sm-7 col-md-8 col-lg-9">
<div class="d-flex align-items-center justify-content-between border-bottom pb-3 pb-md-4 mb-3 mb-lg-4">
<h2 class="h3 mb-0">Special products</h2>
<div class="nav ms-3">
<a class="nav-link animate-underline px-0 py-2" href="{{ route('product.index') }}">
<span class="animate-target text-nowrap">View all</span>
<i class="ci-chevron-right fs-base ms-1"></i>
</a>
</div>
</div>
<div class="swiper"
data-swiper='{
"slidesPerView": 2,
"spaceBetween": 24,
"pagination": {
"el": ".swiper-pagination",
"clickable": true
},
"breakpoints": {
"840": {
"slidesPerView": 3
},
"992": {
"slidesPerView": 4
}
}
}'>
<div class="swiper-wrapper">
@foreach ($products as $key => $value)
<div class="swiper-slide h-auto swiper-slide-active" role="group" aria-label="1 / 4"
style="width: 171.75px; margin-right: 24px;">
<div class="card product-card h-100 bg-transparent border-0 shadow-none">
<div class="position-relative z-2">
<button type="button"
class="btn btn-icon btn-sm btn-secondary animate-pulse fs-sm bg-body border-0 position-absolute top-0 end-0 z-2 mt-1 mt-sm-2 me-1 me-sm-2"
aria-label="Add to Wishlist">
<i class="ci-heart animate-target"></i>
</button>
<a class="d-block p-2 p-lg-3" href="{{ route('product.detail', $value->slug) }}">
<div class="ratio" style="--cz-aspect-ratio: calc(160 / 191 * 100%)">
<img src="{{ $value->image_url }}" alt="Image">
</div>
</a>
<div class="position-absolute w-100 start-0 bottom-0">
<div class="d-flex justify-content-end px-2 px-lg-3 pb-2 pb-lg-3">
<div
class="count-input count-input-collapsible collapsed justify-content-between w-100 bg-transparent border-0 rounded-2">
<button type="button" class="btn btn-icon btn-sm btn-primary"
data-decrement="" aria-label="Decrement quantity" disabled="">
<i class="ci-minus fs-sm"></i>
</button>
<input type="number"
class="form-control form-control-sm bg-primary text-white w-100"
value="0" min="0" readonly="">
<button type="button"
class="product-card-button btn btn-icon btn-sm btn-secondary ms-auto"
data-increment="" aria-label="Increment quantity">
<span data-count-input-value=""></span>
<i class="ci-plus fs-sm"></i>
</button>
</div>
</div>
</div>
</div>
<div class="card-body pt-0 px-1 px-md-2 px-lg-3 pb-2">
<div class="h6 mb-2">{{ $value->display_price_currency }}</div>
<h3 class="fs-sm lh-base mb-0">
<a class="hover-effect-underline fw-normal"
href="{{ route('product.detail', $value->slug) }}">{{ $value->name }}</a>
</h3>
</div>
@if ($value->variants->count() > 1)
<div class="fs-xs text-body-secondary px-1 px-md-2 px-lg-3 pb-2 pb-md-3">
+{{ $value->variants->count() - 1 }} Varian</div>
@endif
</div>
</div>
@endforeach
</div>
</div>
<!-- Slider pagination (Bullets) -->
<div class="swiper-pagination position-static mt-3 mt-sm-4"></div>
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,20 @@
<section class="border-top">
<div class="container py-lg-1">
<div class="overflow-auto" data-simplebar>
<div class="nav flex-nowrap justify-content-between gap-4 py-2">
@foreach ($brands as $key => $brand)
<a class="nav-link align-items-center animate-underline gap-2 p-0"
href="{{ route('product.index', ['filter[brand]' => $brand->id]) }}">
<span class="d-flex align-items-center justify-content-center bg-body-tertiary rounded-circle"
style="width: 40px; height: 40px">
<img src="{{ $brand->image_url }}" width="30" alt="Image">
</span>
<span class="d-block animate-target fw-semibold text-nowrap ms-1">{{ $brand->name }}</span>
</a>
@endforeach
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,170 @@
<div>
@include('layouts.partials/offcanvas2')
<x-grocery.delivery-options />
@include('layouts.partials/menu-offcanvas')
<header class="navbar navbar-expand navbar-sticky sticky-top d-block bg-body z-fixed py-1 py-lg-0 py-xl-1 px-0"
data-sticky-element>
<div class="container justify-content-start py-2 py-lg-3">
<!-- Offcanvas menu toggler (Hamburger) -->
<button type="button" class="navbar-toggler d-block flex-shrink-0 me-3 me-sm-4" data-bs-toggle="offcanvas"
data-bs-target="#navbarNav" aria-controls="navbarNav" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Navbar brand (Logo) -->
<a class="navbar-brand fs-2 p-0 pe-lg-2 pe-xxl-0 me-0 me-sm-3 me-md-4 me-xxl-5" href="/">AsiaGolf</a>
<!-- Categories dropdown visible on screens > 991px wide (lg breakpoint) -->
<x-grocery.header-category-dropdown />
<!-- Search bar visible on screens > 768px wide (md breakpoint) -->
<div class="position-relative w-100 d-none d-md-block me-3 me-xl-4">
<input type="search" class="form-control form-control-lg rounded-pill"
placeholder="Search for products" aria-label="Search">
<button type="button"
class="btn btn-icon btn-ghost fs-lg btn-secondary text-bo border-0 position-absolute top-0 end-0 rounded-circle mt-1 me-1"
aria-label="Search button">
<i class="ci-search"></i>
</button>
</div>
<!-- Delivery options toggle visible on screens > 1200px wide (xl breakpoint) -->
{{-- <div class="nav me-4 me-xxl-5 d-none d-xl-block">
<a class="nav-link flex-column align-items-start animate-underline p-0" href="#deliveryOptions"
data-bs-toggle="offcanvas" aria-controls="deliveryOptions">
<div class="h6 fs-sm mb-0">Delivery</div>
<div class="d-flex align-items-center fs-sm fw-normal text-body">
<span class="animate-target text-nowrap">Set your address</span>
<i class="ci-chevron-down fs-base ms-1"></i>
</div>
</a>
</div> --}}
<div class="nav me-4 me-xxl-5 d-none d-xl-block">
<a class="nav-link flex-column align-items-start animate-underline p-0" href="{{ route('addresses') }}">
<div class="h6 fs-sm mb-0">Delivery</div>
<div class="d-flex align-items-center fs-sm fw-normal text-body">
<span class="animate-target text-nowrap">{{ auth()->user()->primary_address->label ?? 'Set your address' }}</span>
<i class="ci-chevron-down fs-base ms-1"></i>
</div>
</a>
</div>
<!-- Button group -->
<div class="d-flex align-items-center gap-md-1 gap-lg-2 ms-auto">
<!-- Theme switcher (light/dark/auto) -->
<div class="dropdown">
<button type="button"
class="theme-switcher btn btn-icon btn-outline-secondary fs-lg border-0 rounded-circle animate-scale"
data-bs-toggle="dropdown" aria-expanded="false" aria-label="Toggle theme (light)">
<span class="theme-icon-active d-flex animate-target">
<i class="ci-sun"></i>
</span>
</button>
<ul class="dropdown-menu" style="--cz-dropdown-min-width: 9rem">
<li>
<button type="button" class="dropdown-item active" data-bs-theme-value="light"
aria-pressed="true">
<span class="theme-icon d-flex fs-base me-2">
<i class="ci-sun"></i>
</span>
<span class="theme-label">Light</span>
<i class="item-active-indicator ci-check ms-auto"></i>
</button>
</li>
<li>
<button type="button" class="dropdown-item" data-bs-theme-value="dark"
aria-pressed="false">
<span class="theme-icon d-flex fs-base me-2">
<i class="ci-moon"></i>
</span>
<span class="theme-label">Dark</span>
<i class="item-active-indicator ci-check ms-auto"></i>
</button>
</li>
<li>
<button type="button" class="dropdown-item" data-bs-theme-value="auto"
aria-pressed="false">
<span class="theme-icon d-flex fs-base me-2">
<i class="ci-auto"></i>
</span>
<span class="theme-label">Auto</span>
<i class="item-active-indicator ci-check ms-auto"></i>
</button>
</li>
</ul>
</div>
<!-- Search toggle button visible on screens < 768px wide (md breakpoint) -->
<button type="button"
class="btn btn-icon fs-xl btn-outline-secondary border-0 rounded-circle animate-shake d-md-none"
data-bs-toggle="collapse" data-bs-target="#searchBar" aria-controls="searchBar"
aria-label="Toggle search bar">
<i class="ci-search animate-target"></i>
</button>
<!-- Delivery options button visible on screens < 1200px wide (xl breakpoint) -->
<button type="button"
class="btn btn-icon fs-lg btn-outline-secondary border-0 rounded-circle animate-scale d-xl-none"
data-bs-toggle="offcanvas" data-bs-target="#deliveryOptions" aria-controls="deliveryOptions"
aria-label="Toggle delivery options offcanvas">
<i class="ci-map-pin animate-target"></i>
</button>
<!-- Account button visible on screens > 768px wide (md breakpoint) -->
<a class="btn btn-icon fs-lg btn-outline-secondary border-0 rounded-circle animate-shake d-none d-md-inline-flex"
href="{{ auth()->check() ? route('profile') : route('login') }}">
<i class="ci-user animate-target"></i>
<span class="visually-hidden">{{ __('header.account') }}</span>
</a>
<!-- Cart button -->
{{-- <button type="button"
class="btn btn-icon fs-xl btn-outline-secondary position-relative border-0 rounded-circle animate-scale"
data-bs-toggle="offcanvas" data-bs-target="#shoppingCart" aria-controls="shoppingCart"
aria-label="Shopping cart">
<span class="position-absolute top-0 start-100 badge fs-xs text-bg-primary rounded-pill ms-n3 z-2"
style="--cz-badge-padding-y: .25em; --cz-badge-padding-x: .42em">8</span>
<i class="ci-shopping-cart animate-target"></i>
</button> --}}
<a type="button" href="{{ route('cart.index') }}"
class="btn btn-icon btn-lg fs-xl btn-outline-secondary position-relative border-0 rounded-circle animate-scale"
aria-label="Shopping cart">
@if (auth()->check() && \App\Repositories\Member\Cart\MemberCartRepository::getCount() > 0)
<span
class="position-absolute top-0 start-100 badge fs-xs text-bg-primary rounded-pill mt-1 ms-n4 z-2 cart-count"
style="--cz-badge-padding-y: .25em; --cz-badge-padding-x: .42em">{{ auth()->check() ? \App\Repositories\Member\Cart\MemberCartRepository::getCount() : 0 }}</span>
@endif
<i class="ci-shopping-cart animate-target me-1"></i>
</a>
</div>
</div>
<!-- Search collapse available on screens < 768px wide (md breakpoint) -->
<div class="collapse d-md-none" id="searchBar">
<div class="container pt-2 pb-3">
<div class="position-relative">
<i class="ci-search position-absolute top-50 translate-middle-y d-flex fs-lg ms-3"></i>
<input type="search" class="form-control form-icon-start rounded-pill"
placeholder="Search for products" data-autofocus="collapse">
</div>
</div>
</div>
</header>
<x-grocery.top-header />
</div>

File diff suppressed because it is too large Load Diff

View File

@ -8,10 +8,10 @@
<!-- SEO Meta Tags -->
<title>{{ config('app.name') }} | {{ $title }}</title>
<meta name="description" content="AsiaGolf - Multipurpose Bootstrap E-Commerce HTML Template">
<meta name="description" content="AsiaGolf - AsiaGolf Store">
<meta name="keywords"
content="online shop, e-commerce, online store, market, multipurpose, product landing, cart, checkout, ui kit, light and dark mode, bootstrap, html5, css3, javascript, gallery, slider, mobile, pwa">
<meta name="author" content="Coderthemes">
content="AsiaGolf, AsiaGolf Store">
<meta name="author" content="AsiaGolf">
<!-- Webmanifest + Favicon / App icons -->
<meta name="apple-mobile-web-app-capable" content="yes">

View File

@ -38,6 +38,7 @@ Route::post('/locale/switch', [LocaleController::class, 'switch'])->name('locale
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::get('/products', [ProductController::class, 'index'])->name('product.index');
Route::get('/products/ajax', [ProductController::class, 'ajax'])->name('product.ajax');
Route::get('/products/ajax/populers', [ProductController::class, 'populers'])->name('product.ajax.populers');
@ -50,6 +51,9 @@ Route::get('/products/ajax/genders', [ProductController::class, 'genders'])->nam
Route::get('/products/ajax/announcements', [ProductController::class, 'announcements'])->name('product.ajax.announcements');
Route::get('/product/{slug}', [ProductController::class, 'detail'])->name('product.detail');
Route::get('/store', [HomeController::class, 'store'])->name('store');
// Search routes
Route::get('/search', [SearchController::class, 'search'])->name('search.ajax');