ECOMMERCE/resources/views/shop/catalog-fashion.blade.php

1087 lines
63 KiB
PHP

@extends('layouts.landing', ['title' => 'Store - Catalog'])
@section('content')
<x-layout.header />
<main class="content-wrapper">
<!-- Breadcrumb -->
<nav class="container pt-2 pt-xxl-3 my-3 my-md-4" aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ route('second', ['home', 'fashion-v1']) }}">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ __('catalog_fashion.title') }}</li>
</ol>
</nav>
<!-- Page title -->
<h1 class="h3 container pb-3 pb-lg-4">{{ __('catalog_fashion.title') }}</h1>
<!-- Products grid + Sidebar with filters -->
<section class="container">
<div class="row">
<!-- Filter sidebar that turns into offcanvas on screens < 992px wide (lg breakpoint) -->
<aside class="col-lg-3">
<div class="offcanvas-lg offcanvas-start pe-lg-4" id="filterSidebar">
<div class="offcanvas-header py-3">
<h5 class="offcanvas-title"> {{ __('catalog_fashion.filter') }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"
data-bs-target="#filterSidebar" aria-label="Close"></button>
</div>
<div class="offcanvas-body flex-column pt-2 py-lg-0 filter-sidebar">
<div class="accordion">
<!-- Genders -->
<div class="accordion-item border-0 pb-1 pb-xl-2">
<h4 class="accordion-header" id="headingGenders">
<button type="button" class="accordion-button p-0 pb-3" data-bs-toggle="collapse"
data-bs-target="#genders" aria-expanded="true" aria-controls="genders">
{{ __('catalog_fashion.genders') }}
</button>
</h4>
<div class="accordion-collapse collapse show" id="genders"
aria-labelledby="headingGenders">
<div class="accordion-body p-0 pb-4 mb-1 mb-xl-2">
<div style="height: 220px" data-simplebar data-simplebar-auto-hide="false">
<ul class="nav flex-column gap-2 pe-3" id="genders-list">
<!-- Genders will be loaded here via AJAX -->
</ul>
</div>
</div>
</div>
</div>
<!-- Categories -->
<div class="accordion-item border-0 pb-1 pb-xl-2">
<h4 class="accordion-header" id="headingCategories">
<button type="button" class="accordion-button p-0 pb-3" data-bs-toggle="collapse"
data-bs-target="#categories" aria-expanded="true" aria-controls="categories">
{{ __('catalog_fashion.categories') }}
</button>
</h4>
<div class="accordion-collapse collapse show" id="categories"
aria-labelledby="headingCategories">
<div class="accordion-body p-0 pb-4 mb-1 mb-xl-2">
<div style="height: 220px" data-simplebar data-simplebar-auto-hide="false">
<ul class="nav flex-column gap-2 pe-3" id="categories-list">
<!-- Categories will be loaded here via AJAX -->
</ul>
</div>
</div>
</div>
</div>
<!-- Brands -->
<div class="accordion-item border-0 pb-1 pb-xl-2">
<h4 class="accordion-header" id="headingBrands">
<button type="button" class="accordion-button p-0 pb-3" data-bs-toggle="collapse"
data-bs-target="#brands" aria-expanded="true" aria-controls="brands">
{{ __('catalog_fashion.brands') }}
</button>
</h4>
<div class="accordion-collapse collapse show" id="brands"
aria-labelledby="headingBrands">
<div class="accordion-body p-0 pb-4 mb-1 mb-xl-2">
<div style="height: 220px" data-simplebar data-simplebar-auto-hide="false">
<ul class="nav flex-column gap-2 pe-3" id="brands-list">
<!-- Brands will be loaded here via AJAX -->
</ul>
</div>
</div>
</div>
</div>
<!-- Price -->
{{-- <div class="accordion-item border-0 pb-1 pb-xl-2">
<h4 class="accordion-header" id="headingPrice">
<button type="button" class="accordion-button p-0 pb-3" data-bs-toggle="collapse"
data-bs-target="#price" aria-expanded="true" aria-controls="price">
{{ __('catalog_fashion.price') }}
</button>
</h4>
<div class="accordion-collapse collapse show" id="price"
aria-labelledby="headingPrice">
<div class="accordion-body p-0 pb-4 mb-1 mb-xl-2">
<div class="range-slider"
data-range-slider='{"startMin": 0, "startMax": {{ $min_max_price['max'] }}, "min": 0, "max": {{ $min_max_price['max'] }}, "step": 1000000, "tooltipPrefix": "Rp"}'
aria-labelledby="headingPrice">
<div class="range-slider-ui"></div>
<div class="d-flex align-items-center">
<div class="position-relative w-50">
<input type="number" class="form-control" min="0"
data-range-slider-min>
</div>
<i class="ci-minus text-body-emphasis mx-2"></i>
<div class="position-relative w-50">
<input type="number" class="form-control" min="0"
data-range-slider-max>
</div>
</div>
</div>
</div>
</div>
</div> --}}
<!-- Brands -->
{{-- <div class="accordion-item border-0 pb-1 pb-xl-2">
<h4 class="accordion-header" id="headingBrands">
<button type="button" class="accordion-button p-0 pb-3"
data-bs-toggle="collapse" data-bs-target="#brands" aria-expanded="true"
aria-controls="brands">
Brands
</button>
</h4>
<div class="accordion-collapse collapse show" id="brands"
aria-labelledby="headingBrands">
<div class="accordion-body p-0 pb-4 mb-1 mb-xl-2"
data-filter-list='{"searchClass": "brands-search", "listClass": "brands-list", "valueNames": ["form-check-label"]}'>
<div class="position-relative mb-3">
<i
class="ci-search position-absolute top-50 start-0 translate-middle-y ms-3"></i>
<input type="search" class="brands-search form-control form-icon-start"
placeholder="Search">
</div>
<div style="height: 210px" data-simplebar data-simplebar-auto-hide="false">
<div class="brands-list d-flex flex-column gap-2">
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="adidas"
checked>
<label for="adidas" class="form-check-label text-body-emphasis">
Adidas<span class="fs-xs text-body-secondary ms-1">(425)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="taylor">
<label for="taylor" class="form-check-label text-body-emphasis">
Ann Taylor<span
class="fs-xs text-body-secondary ms-1">(15)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="armani">
<label for="armani" class="form-check-label text-body-emphasis">
Armani<span class="fs-xs text-body-secondary ms-1">(18)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="banana">
<label for="banana" class="form-check-label text-body-emphasis">
Banana Republic<span
class="fs-xs text-body-secondary ms-1">(103)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="bilabong"
checked>
<label for="bilabong" class="form-check-label text-body-emphasis">
Bilabong<span
class="fs-xs text-body-secondary ms-1">(27)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="birkenstock">
<label for="birkenstock"
class="form-check-label text-body-emphasis">
Birkenstock<span
class="fs-xs text-body-secondary ms-1">(10)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="klein">
<label for="klein" class="form-check-label text-body-emphasis">
Calvin Klein<span
class="fs-xs text-body-secondary ms-1">(365)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="columbia">
<label for="columbia" class="form-check-label text-body-emphasis">
Columbia<span
class="fs-xs text-body-secondary ms-1">(508)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="converse">
<label for="converse" class="form-check-label text-body-emphasis">
Converse<span
class="fs-xs text-body-secondary ms-1">(176)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="dockers">
<label for="dockers" class="form-check-label text-body-emphasis">
Dockers<span class="fs-xs text-body-secondary ms-1">(54)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="fruit">
<label for="fruit" class="form-check-label text-body-emphasis">
Fruit of the Loom<span
class="fs-xs text-body-secondary ms-1">(739)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="hanes">
<label for="hanes" class="form-check-label text-body-emphasis">
Hanes<span class="fs-xs text-body-secondary ms-1">(92)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="choo">
<label for="choo" class="form-check-label text-body-emphasis">
Jimmy Choo<span
class="fs-xs text-body-secondary ms-1">(17)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="levis">
<label for="levis" class="form-check-label text-body-emphasis">
Levi's<span class="fs-xs text-body-secondary ms-1">(361)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="wearhouse">
<label for="wearhouse"
class="form-check-label text-body-emphasis">
Men's Wearhouse<span
class="fs-xs text-body-secondary ms-1">(75)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="newbalance">
<label for="newbalance"
class="form-check-label text-body-emphasis">
New Balance<span
class="fs-xs text-body-secondary ms-1">(218)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="nike">
<label for="nike" class="form-check-label text-body-emphasis">
Nike<span class="fs-xs text-body-secondary ms-1">(810)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="navy">
<label for="navy" class="form-check-label text-body-emphasis">
Old Navy<span
class="fs-xs text-body-secondary ms-1">(147)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="puma">
<label for="puma" class="form-check-label text-body-emphasis">
Puma<span class="fs-xs text-body-secondary ms-1">(370)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="skechers">
<label for="skechers" class="form-check-label text-body-emphasis">
Skechers<span
class="fs-xs text-body-secondary ms-1">(209)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="hilfiger">
<label for="hilfiger" class="form-check-label text-body-emphasis">
Tommy Hilfiger<span
class="fs-xs text-body-secondary ms-1">(487)</span>
</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="armour">
<label for="armour" class="form-check-label text-body-emphasis">
Under Armour<span
class="fs-xs text-body-secondary ms-1">(90)</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div> --}}
<!-- Size -->
{{-- <div class="accordion-item border-0 pb-1 pb-xl-2">
<h4 class="accordion-header" id="headingSize">
<button type="button" class="accordion-button p-0 pb-3"
data-bs-toggle="collapse" data-bs-target="#size" aria-expanded="true"
aria-controls="size">
Size
</button>
</h4>
<div class="accordion-collapse collapse show" id="size"
aria-labelledby="headingSize">
<div class="accordion-body p-0 pb-4 mb-1 mb-xl-2">
<div class="d-flex flex-wrap gap-2">
<input type="checkbox" class="btn-check" id="size-xxs" checked>
<label for="size-xxs" class="btn btn-sm btn-outline-secondary">XXS</label>
<input type="checkbox" class="btn-check" id="size-xs">
<label for="size-xs" class="btn btn-sm btn-outline-secondary">XS</label>
<input type="checkbox" class="btn-check" id="size-s">
<label for="size-s" class="btn btn-sm btn-outline-secondary">S</label>
<input type="checkbox" class="btn-check" id="size-m">
<label for="size-m" class="btn btn-sm btn-outline-secondary">M</label>
<input type="checkbox" class="btn-check" id="size-l">
<label for="size-l" class="btn btn-sm btn-outline-secondary">L</label>
<input type="checkbox" class="btn-check" id="size-xl">
<label for="size-xl" class="btn btn-sm btn-outline-secondary"><span
class="mx-n1">XL</span></label>
<input type="checkbox" class="btn-check" id="size-2xl">
<label for="size-2xl" class="btn btn-sm btn-outline-secondary">2XL</label>
<input type="checkbox" class="btn-check" id="size-40">
<label for="size-40" class="btn btn-sm btn-outline-secondary">40</label>
<input type="checkbox" class="btn-check" id="size-42">
<label for="size-42" class="btn btn-sm btn-outline-secondary">42</label>
<input type="checkbox" class="btn-check" id="size-44">
<label for="size-44" class="btn btn-sm btn-outline-secondary">44</label>
<input type="checkbox" class="btn-check" id="size-45">
<label for="size-45" class="btn btn-sm btn-outline-secondary">45</label>
<input type="checkbox" class="btn-check" id="size-46">
<label for="size-46" class="btn btn-sm btn-outline-secondary">46</label>
<input type="checkbox" class="btn-check" id="size-48">
<label for="size-48" class="btn btn-sm btn-outline-secondary">48</label>
<input type="checkbox" class="btn-check" id="size-50">
<label for="size-50" class="btn btn-sm btn-outline-secondary">50</label>
<input type="checkbox" class="btn-check" id="size-52">
<label for="size-52" class="btn btn-sm btn-outline-secondary">52</label>
</div>
</div>
</div>
</div> --}}
<!-- Color -->
{{-- <div class="accordion-item border-0 pb-1 pb-xl-2">
<h4 class="accordion-header" id="headingColor">
<button type="button" class="accordion-button p-0 pb-3"
data-bs-toggle="collapse" data-bs-target="#color" aria-expanded="true"
aria-controls="color">
Color
</button>
</h4>
<div class="accordion-collapse collapse show" id="color"
aria-labelledby="headingColor">
<div class="accordion-body p-0 pb-4 mb-1 mb-xl-2">
<div class="d-flex flex-column gap-2">
<div class="d-flex align-items-center mb-1">
<input type="checkbox" class="btn-check" id="green">
<label for="green" class="btn btn-color fs-xl"
style="color: #8bc4ab"></label>
<label for="green" class="fs-sm ms-2">Green</label>
</div>
<div class="d-flex align-items-center mb-1">
<input type="checkbox" class="btn-check" id="red">
<label for="red" class="btn btn-color fs-xl"
style="color: #ee7976"></label>
<label for="red" class="fs-sm ms-2">Coral red</label>
</div>
<div class="d-flex align-items-center mb-1">
<input type="checkbox" class="btn-check" id="pink">
<label for="pink" class="btn btn-color fs-xl"
style="color: #df8fbf"></label>
<label for="pink" class="fs-sm ms-2">Pink</label>
</div>
<div class="d-flex align-items-center mb-1">
<input type="checkbox" class="btn-check" id="blue">
<label for="blue" class="btn btn-color fs-xl"
style="color: #9acbf1"></label>
<label for="blue" class="fs-sm ms-2">Sky blue</label>
</div>
<div class="d-flex align-items-center mb-1">
<input type="checkbox" class="btn-check" id="black">
<label for="black" class="btn btn-color fs-xl"
style="color: #364254"></label>
<label for="black" class="fs-sm ms-2">Black</label>
</div>
<div class="d-flex align-items-center mb-1">
<input type="checkbox" class="btn-check" id="white">
<label for="white" class="btn btn-color fs-xl"
style="color: #e0e5eb"></label>
<label for="white" class="fs-sm ms-2">White</label>
</div>
</div>
</div>
</div>
</div> --}}
<!-- Status -->
{{-- <div class="accordion-item border-0">
<h4 class="accordion-header" id="headingStatus">
<button type="button" class="accordion-button p-0 pb-3" data-bs-toggle="collapse"
data-bs-target="#status" aria-expanded="true" aria-controls="status">
Status
</button>
</h4>
<div class="accordion-collapse collapse show" id="status"
aria-labelledby="headingStatus">
<div class="accordion-body p-0 pb-2 pb-lg-0">
<div class="d-flex flex-column gap-2">
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="instock">
<label for="instock" class="form-check-label text-body-emphasis">In
stock</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="sale"
checked>
<label for="sale" class="form-check-label text-body-emphasis">%
Sale</label>
</div>
<div class="form-check mb-0">
<input type="checkbox" class="form-check-input" id="delivery">
<label for="delivery" class="form-check-label text-body-emphasis">Free
delivery</label>
</div>
</div>
</div>
</div>
</div> --}}
</div>
</div>
</div>
</aside>
<!-- Product grid -->
<div class="col-lg-9">
<!-- Sorting -->
<div class="d-sm-flex align-items-center justify-content-between mt-n2 mb-3 mb-sm-4">
<div class="fs-sm text-body-emphasis text-nowrap">Found <span class="fw-semibold"
id="product-count">Loading...</span>
items
</div>
<div class="d-flex align-items-center text-nowrap">
<label class="form-label fw-semibold mb-0 me-2">{{ __('catalog_fashion.sort_by') }}:</label>
<div style="width: 190px">
<select class="form-select border-0 rounded-0 px-1"
data-select='{
"removeItemButton": false,
"classNames": {
"containerInner": ["form-select", "border-0", "rounded-0", "px-1"]
}
}'
onchange="window.location.href='{{ route('product.index') }}?sort_by='+this.value+'&{{ http_build_query(request()->except('sort_by')) }}'">
<option value="relevance" {{ request('sort_by') == 'relevance' ? 'selected' : '' }}>
{{ __('catalog_fashion.sort_relevance') }}</option>
<option value="popularity" {{ request('sort_by') == 'popularity' ? 'selected' : '' }}>
{{ __('catalog_fashion.sort_popularity') }}</option>
<option value="price_low_to_high"
{{ request('sort_by') == 'price_low_to_high' ? 'selected' : '' }}>
{{ __('catalog_fashion.sort_price_low_to_high') }}</option>
<option value="price_high_to_low"
{{ request('sort_by') == 'price_high_to_low' ? 'selected' : '' }}>
{{ __('catalog_fashion.sort_price_high_to_low') }}</option>
<option value="new"
{{ request('sort_by') == 'newest_arrivals' ? 'selected' : '' }}>
{{ __('catalog_fashion.sort_newest_arrivals') }}</option>
</select>
</div>
</div>
</div>
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-4 g-3" id="products-container">
<!-- Products will be loaded here via AJAX -->
</div>
{{-- <div class="col-12 col-md-8 mb-2 mb-sm-3 mb-md-0">
<div
class="position-relative text-center rounded-4 p-4 p-sm-5 py-md-4 py-xl-5">
<p class="fs-xs text-body-secondary mb-1">Sweatshirts</p>
<h2 class="h4 mb-4">Colors for your mood</h2>
<div class="swiper user-select-none mb-4"
data-swiper='{
"allowTouchMove": false,
"loop": true,
"effect": "fade",
"autoplay": {
"delay": 1500,
"disableOnInteraction": false
}
}'
style="max-width: 342px">
<div class="swiper-wrapper">
<div class="swiper-slide">
<div class="ratio" style="--cz-aspect-ratio: calc(230 / 342 * 100%)">
<img src="/img/shop/fashion/banner01.png" alt="Image">
</div>
</div>
<div class="swiper-slide">
<div class="ratio" style="--cz-aspect-ratio: calc(230 / 342 * 100%)">
<img src="/img/shop/fashion/banner02.png" alt="Image">
</div>
</div>
<div class="swiper-slide">
<div class="ratio" style="--cz-aspect-ratio: calc(230 / 342 * 100%)">
<img src="/img/shop/fashion/banner03.png" alt="Image">
</div>
</div>
</div>
</div>
<a class="btn btn-sm btn-dark stretched-link"
href="{{ route('second', ['shop', 'product-fashion']) }}">Shop
now</a>
</div>
</div> --}}
</div>
<!-- Show more button -->
<button type="button" class="btn btn-lg btn-outline-secondary w-100" id="show-more-btn">
Show more
<i class="ci-chevron-down fs-xl ms-2 me-n1"></i>
</button>
</div>
</div>
</section>
<!-- Instagram feed -->
<x-home.instagram-feed />
</main>
@include('layouts.partials.footer2')
<button type="button"
class="fixed-bottom z-sticky w-100 btn btn-lg btn-dark border-0 border-top border-light border-opacity-10 rounded-0 pb-4 d-lg-none"
data-bs-toggle="offcanvas" data-bs-target="#filterSidebar" aria-controls="filterSidebar" data-bs-theme="light">
<i class="ci-filter fs-base me-2"></i>
Filters
</button>
<style>
.shimmer-wrapper {
overflow: hidden;
}
.shimmer {
position: relative;
overflow: hidden;
}
.shimmer::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.3) 50%,
rgba(255, 255, 255, 0) 100%);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
.shimmer-line {
background-color: rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
.shimmer-content {
position: relative;
overflow: hidden;
}
</style>
@endsection
@section('scripts')
<script>
// Loading state lock
let isLoading = false;
document.addEventListener('DOMContentLoaded', function() {
loadGenders();
loadCategories();
loadBrands();
loadProducts();
// Handle sort change
const sortSelect = document.querySelector('select[onchange*="sort_by"]');
if (sortSelect) {
sortSelect.removeAttribute('onchange');
sortSelect.addEventListener('change', function() {
loadProducts({
sort_by: this.value
});
});
}
// Handle price range changes
const priceInputs = document.querySelectorAll('[data-range-slider-min], [data-range-slider-max]');
priceInputs.forEach(input => {
input.addEventListener('change', function() {
debouncePriceSlider(function() {
const minVal = document.querySelector('[data-range-slider-min]').value;
const maxVal = document.querySelector('[data-range-slider-max]').value;
loadProducts({
price_range_start: minVal || null,
price_range_end: maxVal || null
});
});
});
});
// Debounce function for price slider
let priceSliderTimeout;
function debouncePriceSlider(callback, delay = 300) {
clearTimeout(priceSliderTimeout);
priceSliderTimeout = setTimeout(callback, delay);
}
// Handle range slider UI changes
const rangeSliderUI = document.querySelector('.range-slider-ui');
if (rangeSliderUI) {
// Use MutationObserver to detect slider changes
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList' || mutation.type === 'attributes') {
debouncePriceSlider(function() {
const minVal = document.querySelector('[data-range-slider-min]').value;
const maxVal = document.querySelector('[data-range-slider-max]').value;
loadProducts({
price_range_start: minVal || null,
price_range_end: maxVal || null
});
});
}
});
});
observer.observe(rangeSliderUI, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['style', 'class']
});
// Also handle mouseup/touchend events on the slider
rangeSliderUI.addEventListener('mouseup', function() {
debouncePriceSlider(function() {
const minVal = document.querySelector('[data-range-slider-min]').value;
const maxVal = document.querySelector('[data-range-slider-max]').value;
loadProducts({
price_range_start: minVal || null,
price_range_end: maxVal || null
});
});
});
rangeSliderUI.addEventListener('touchend', function() {
debouncePriceSlider(function() {
const minVal = document.querySelector('[data-range-slider-min]').value;
const maxVal = document.querySelector('[data-range-slider-max]').value;
loadProducts({
price_range_start: minVal || null,
price_range_end: maxVal || null
});
});
});
}
// Attach initial filter event listeners
attachFilterEventListeners();
// Handle show more button
const showMoreBtn = document.getElementById('show-more-btn');
if (showMoreBtn) {
showMoreBtn.addEventListener('click', function() {
loadMoreProducts();
});
}
});
function loadMoreProducts() {
const container = document.getElementById('products-container');
const showMoreBtn = document.getElementById('show-more-btn');
// Get current page from URL or default to 2 (next page)
const urlParams = new URLSearchParams(window.location.search);
const currentPage = parseInt(urlParams.get('page')) || 1;
const nextPage = currentPage + 1;
// Show loading state
showMoreBtn.innerHTML =
'<div class="spinner-border spinner-border-sm me-2" role="status"><span class="visually-hidden">Loading...</span></div> Loading...';
showMoreBtn.disabled = true;
// Set page parameter and load products
urlParams.set('page', nextPage);
fetch(`{{ route('product.ajax') }}?${urlParams.toString()}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Append new products to existing container
const tempDiv = document.createElement('div');
tempDiv.innerHTML = data.products;
// Append each new product
while (tempDiv.firstChild) {
container.appendChild(tempDiv.firstChild);
}
// Update show more button
if (data.has_more) {
showMoreBtn.innerHTML = 'Show more <i class="ci-chevron-down fs-xl ms-2 me-n1"></i>';
showMoreBtn.disabled = false;
} else {
showMoreBtn.style.display = 'none';
}
// Update URL
window.history.pushState({
path: window.location.pathname + '?' + urlParams.toString()
}, '', window.location.pathname + '?' + urlParams.toString());
} else {
showMoreBtn.innerHTML = 'Show more <i class="ci-chevron-down fs-xl ms-2 me-n1"></i>';
showMoreBtn.disabled = false;
}
})
.catch(error => {
console.error('Error loading more products:', error);
showMoreBtn.innerHTML = 'Show more <i class="ci-chevron-down fs-xl ms-2 me-n1"></i>';
showMoreBtn.disabled = false;
});
}
function removeFilter(filterKey) {
const urlParams = new URLSearchParams(window.location.search);
urlParams.delete(`filter[${filterKey}]`);
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
history.replaceState(null, '', newUrl);
// remove button
const button = document.querySelector(`.remove-filter[data-filter-key="${filterKey}"]`);
if (button) {
button.remove();
}
loadGenders();
loadCategories();
loadBrands();
loadProducts(Object.fromEntries(urlParams.entries()));
}
function clearAllFilters() {
const urlParams = new URLSearchParams(window.location.search);
// Collect all filter keys first
const filterKeys = [];
for (const [key] of urlParams.entries()) {
if (key.startsWith('filter[')) {
filterKeys.push(key);
}
}
// Delete all filter keys
filterKeys.forEach(key => urlParams.delete(key));
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
history.replaceState(null, '', newUrl);
// remove all button
const buttons = document.querySelectorAll('.remove-filter');
buttons.forEach(button => {
button.remove();
});
loadGenders();
loadCategories();
loadBrands();
loadProducts(Object.fromEntries(urlParams.entries()));
}
function loadGenders() {
const currentGenderId = new URLSearchParams(window.location.search).get('filter[gender]');
fetch(`{{ route('product.ajax.genders') }}?current_gender=${currentGenderId || ''}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('genders-list').innerHTML = data.genders;
// Attach event listeners to newly loaded gender links
const genderLinks = document.querySelectorAll('#genders-list a[data-gender-id]');
genderLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
// Remove active class from all gender links
genderLinks.forEach(g => g.classList.remove('active', 'text-primary'));
// Add active class to clicked link
this.classList.add('active', 'text-primary');
const genderId = this.getAttribute('data-gender-id');
loadProducts({
'filter[gender]': genderId
});
});
});
}
})
.catch(error => {
console.error('Error loading genders:', error);
document.getElementById('genders-list').innerHTML =
'<li class="nav-item mb-1"><span class="text-danger">Error loading genders</span></li>';
});
}
function loadCategories() {
const currentCategoryId = new URLSearchParams(window.location.search).get('filter[category]');
fetch(`{{ route('product.ajax.categories') }}?current_category=${currentCategoryId || ''}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('categories-list').innerHTML = data.categories;
// Attach event listeners to newly loaded category links
const categoryLinks = document.querySelectorAll('#categories-list a[data-category-id]');
categoryLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
// Remove active class from all category links
categoryLinks.forEach(c => c.classList.remove('active',
'text-primary'));
// Add active class to clicked link
this.classList.add('active', 'text-primary');
const categoryId = this.getAttribute('data-category-id');
loadProducts({
'filter[category]': categoryId
});
});
});
}
})
.catch(error => {
console.error('Error loading categories:', error);
document.getElementById('categories-list').innerHTML =
'<li class="nav-item mb-1"><span class="text-danger">Error loading categories</span></li>';
});
}
function loadBrands() {
const currentBrandId = new URLSearchParams(window.location.search).get('filter[brand]');
fetch(`{{ route('product.ajax.brands') }}?current_brand=${currentBrandId || ''}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('brands-list').innerHTML = data.brands;
// Attach event listeners to newly loaded brand links
const brandLinks = document.querySelectorAll('#brands-list a[data-brand-id]');
brandLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
// Remove active class from all brand links
brandLinks.forEach(b => b.classList.remove('active', 'text-primary'));
// Add active class to clicked link
this.classList.add('active', 'text-primary');
const brandId = this.getAttribute('data-brand-id');
loadProducts({
'filter[brand]': brandId
});
});
});
}
})
.catch(error => {
console.error('Error loading brands:', error);
document.getElementById('brands-list').innerHTML =
'<li class="nav-item mb-1"><span class="text-danger">Error loading brands</span></li>';
});
}
function loadProducts(params = {}) {
// Prevent multiple simultaneous calls
if (isLoading) {
return;
}
isLoading = true;
const container = document.getElementById('products-container');
const countElement = document.getElementById('product-count');
const shimmerItem = `<div class="col-6 col-md-4 mb-2 mb-sm-3 mb-md-0">
<div class="shimmer-wrapper">
<div class="shimmer">
<div class="shimmer-content rounded">
<div class="shimmer-line shimmer-image rounded mb-3" style="height: 0; padding-bottom: 100%; position: relative;">
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.1); border-radius: 4px;"></div>
</div>
<div class="shimmer-line shimmer-title rounded mb-2" style="height: 20px; width: 80%;"></div>
<div class="shimmer-line shimmer-price rounded" style="height: 16px; width: 60%;"></div>
</div>
</div>
</div>
</div>`;
// Show loading state
container.innerHTML = shimmerItem.repeat(12);
countElement.textContent = 'Loading...';
// Get current URL parameters
const urlParams = new URLSearchParams(window.location.search);
// Add custom parameters
Object.keys(params).forEach(key => {
if (params[key] !== null) {
urlParams.set(key, params[key]);
}
});
// Make AJAX request
fetch(`{{ route('product.ajax') }}?${urlParams.toString()}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
container.innerHTML = data.products;
countElement.textContent = data.count;
// Update filters section
updateFiltersSection(data.filters);
// Update URL without page reload
const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '');
window.history.pushState({
path: newUrl
}, '', newUrl);
} else {
container.innerHTML = '<div class="col-12 text-center py-5 text-danger">Error loading products</div>';
countElement.textContent = '0';
}
})
.catch(error => {
console.error('Error:', error);
container.innerHTML = '<div class="col-12 text-center py-5 text-danger">Error loading products</div>';
countElement.textContent = '0';
})
.finally(() => {
isLoading = false;
});
}
function updateFiltersSection(filters) {
const filtersContainer = document.querySelector('.filter-sidebar');
const filtersSection = filtersContainer.querySelector('.pb-4.mb-2.mb-xl-3');
if (Object.keys(filters).length > 0) {
// Build filters HTML
let filtersHtml = `
<div class="pb-4 mb-2 mb-xl-3">
<div class="d-flex align-items-center justify-content-between mb-3">
<h4 class="h6 mb-0">Filter</h4>
<a type="button" href="#"
class="btn btn-sm btn-secondary bg-transparent border-0 text-decoration-underline p-0 ms-2 clear-all-filters">
Clear all
</a>
</div>
<div class="d-flex flex-wrap gap-2">
`;
Object.keys(filters).forEach(key => {
filtersHtml += `
<button type="button" class="btn btn-sm btn-secondary remove-filter"
data-filter-key="${key}">
<i class="ci-close fs-sm ms-n1 me-1"></i>
${filters[key]}
</button>
`;
});
filtersHtml += `
</div>
</div>
`;
// Update or create filters section
if (filtersSection) {
filtersSection.outerHTML = filtersHtml;
} else {
filtersContainer.insertAdjacentHTML('afterbegin', filtersHtml);
}
// Re-attach event listeners for new filter buttons
attachFilterEventListeners();
} else {
// Remove filters section if no filters
if (filtersSection) {
filtersSection.remove();
}
}
}
function attachFilterEventListeners() {
// Handle filter removal
const removeFilterButtons = document.querySelectorAll('.remove-filter');
removeFilterButtons.forEach(button => {
button.addEventListener('click', function() {
const filterKey = this.getAttribute('data-filter-key');
removeFilter(filterKey);
});
});
// Handle clear all filters
const clearAllButton = document.querySelector('.clear-all-filters');
if (clearAllButton) {
clearAllButton.addEventListener('click', function(e) {
e.preventDefault();
clearAllFilters();
});
}
}
</script>
@endsection