public function filtercatalog(Request $request)
{
$product_type = $request->productType;
- $filterValues = $request->filter ?? [];
+ $filter_values = $request->filter ?? [];
- return Product::getFilteredProducts($product_type, $filterValues);
+ return Product::getFilteredProducts($product_type, $filter_values);
}
}
// Get available filters
$filters = Product::getFilteredProducts($id);
$this->data['filters'] = $filters ? $filters['filters'] : []; // To be used by Vue component
+ $this->data['filter_results'] = $filters ? $filters['results'] : [];
return view('pages.products', $this->data);
}
if ($o) {
$nb = $values[$index] ?? 0;
if ($nb > 0) {
- $options[] = ['label' => $o, 'value' => $index, 'nb_products' => $nb];
+ $options[$index] = ['label' => $o, 'value' => $index, 'nb_products' => $nb];
}
}
}
if (isset($values['-'])) {
- $options[] = ['label' => __('Non défini'), 'value' => '-', 'nb_products' => $values['-']];
+ $options['-'] = ['label' => __('Non défini'), 'value' => '-', 'nb_products' => $values['-']];
}
$f['options'] = $options;
} else if ($data->type == 'numeric' || $data->type == 'range') {
--- /dev/null
+<template>
+
+ <div class="container flex relative items-start">
+
+ <!-- Filters column -->
+ <div class="products-filters-wrapper sticky top-0 mr-1v pt-4 whitespace-no-wrap">
+
+ <!-- Filters panel -->
+ <div class="products-filters bg-white p-4" v-for="filter in filterData" :key="filter.id">
+
+ <h3 class="text-base mb-2">{{ filter.label }}</h3>
+
+ <ul v-if="filter.type === 'list'">
+ <li v-for="(option, option_index) in filter.options" :key="option_index" class="flex justify-between py-1 text-sm">
+
+ <label>
+ <input type="checkbox" v-model="filters[filter.id]" :value="option.value">
+ {{ option.label }}
+ </label>
+
+ <div class="products-filters-count pl-8">({{ option.nb_products }})</div>
+
+ </li>
+ </ul>
+
+ <div v-if="filter.type === 'range'">
+ <!-- Todo: handle range using Vue slider component: https://github.com/NightCatSama/vue-slider-component -->
+ (RANGE SLIDER GOES HERE)
+ </div>
+
+ <hr class="h-px bg-grey-200 my-4" />
+
+ </div>
+
+ </div>
+
+ <!-- ======================= -->
+
+ <!-- Main Products Grid Area -->
+ <div class="products-grid flex-grow">
+
+ <!-- Grid summary header -->
+ <div class="products-grid-summary sticky top-0 z-10 bg-grey-100 pt-4 pb-4 flex justify-between items-center md:block">
+
+ <!-- Active filters -->
+ <div class="products-grid-active-filters flex-grow text-sm">
+
+ <ul class="flex flex-wrap -mb-3 md:mb-0">
+ <template v-for="(filter, filterID) in filters">
+
+ <li class="bg-white whitespace-no-wrap py-2 px-4 rounded-full mr-3 mb-3 hover:bg-grey-200 cursor-pointer"
+ v-for="filter_option in filter" v-if="filterData[filterID].options">
+
+ {{ filterData[filterID].options[filter_option].label }}
+
+ <!-- TODO: <img src="{{ asset('images/icon-close.svg') }}" alt="Remove" class="inline-block ml-3"> -->
+ </li>
+
+ </template>
+ </ul>
+
+ <div class="text-red mt-4">
+ QUERYSTRING: {{ filter_querystring }}
+ </div>
+
+ </div>
+
+ <!-- Total Results -->
+ <div class="products-grid-result-count pl-4 md:pl-0 font-display whitespace-no-wrap">
+ <!-- TODO: handle count and translations
+ {{ count($products) }}
+ @if(count($products) == 1)
+ {{ __('résultat') }}
+ @else
+ {{ __('résultats') }}
+ @endif
+ -->
+ </div>
+ </div>
+
+ <!-- Product Grid -->
+ <slot></slot>
+ </div>
+
+ </div>
+</template>
+
+<script>
+
+ export default {
+
+ props: {
+ filterData: {
+ required: true,
+ },
+ resultData: {
+ required: true,
+ },
+ },
+ data: () => ({
+ filters: {},
+ matches: {},
+ }),
+
+ computed: {
+ filter_querystring() {
+
+ let filter_list = [];
+
+ Object.keys(this.filters).forEach(filterID => {
+ filter_list.push(`filter[${filterID}]=` + this.filters[filterID].join(';'));
+ });
+
+ return filter_list.join('&');
+ },
+ },
+
+ mounted() {
+
+ // Initially, it will be all the IDs from the server
+ this.matches = this.resultData;
+
+ // Create dynamic data so we can bind the filter fields via v-model for each option
+ let filters = {};
+ Object.values(this.filterData).forEach(filter => {
+ filters[filter.id] = [];
+ });
+
+ this.filters = filters;
+ },
+
+ methods: {
+
+ },
+
+ }
+</script>
@intro(['padding' => 'pb-1v'])
<full-width class="bg-grey-100" padding="pt-1v pb-2v">
- <content class="flex relative items-start">
+ <products-filters class="" :filter-data='@json($filters)' :result-data='@json($filter_results)'>
- <div class="products-filters-wrapper sticky top-0 mr-1v pt-4 whitespace-no-wrap">
+ {{-- Product Grid --}}
+ <grid cols="auto" class="products-grid mt-6">
+ @foreach($products as $id => $product)
- <div class="products-filters bg-white p-4">
+ {{-- TODO: find a way to include easily hide products that don't match the filter. Maybe wrap in a <template v-if="matches.hits.includes($id)"> or make a child component similar to the Tabs / Tab setup and then pass the ID of the product to the child component or just a v-if on it? --}}
- @foreach ($filters as $filter)
- <h3 class="text-base mb-2">{{ $filter['label'] }}</h3>
+ @include('partials.product-link', ['id' => $id, 'product' => $product])
+ @endforeach
+ </grid>
- @if ($filter['type'] == 'list')
- @foreach ($filter['options'] as $option)
- <div class="flex justify-between py-1 text-sm">
- <label>
- <input type="checkbox" name="filter[{{ $filter['id'] }}][]" value="{{ $option['value'] }}" class="mr-2">
- {{ $option['label'] }}
- </label>
- <div class="products-filters-count pl-8">({{ $option['nb_products'] }})</div>
- </div>
- @endforeach
- @endif
-
- @if ($filter['type'] == 'range')
- (RANGE SLIDER)
- {{-- Todo: handle range using Vue slider component: https://github.com/NightCatSama/vue-slider-component --}}
- @endif
-
-
- @if (!$loop->last)
- <hr class="h-px bg-grey-200 my-4">
- @endif
-
- @endforeach
-
- </div>
- </div>
-
- {{-- Main Products Grid Area --}}
- <div class="products-grid flex-grow">
-
- {{-- Grid summary header --}}
- <div class="products-grid-summary
- sticky top-0 z-10 bg-grey-100 pt-4 pb-4 flex justify-between items-center
- md:block">
- <div class="products-grid-active-filters flex-grow text-sm">
- <ul class="flex flex-wrap -mb-3 md:mb-0">
- <li class="bg-white whitespace-no-wrap py-2 px-4 rounded-full mr-3 mb-3 hover:bg-grey-200 cursor-pointer">
- Capteur de force - Galette
- <img src="{{ asset('images/icon-close.svg') }}" alt="Remove" class="inline-block ml-3">
- </li>
- <li class="bg-white whitespace-no-wrap py-2 px-4 rounded-full mr-3 mb-3 hover:bg-grey-200 cursor-pointer">
- Option 01
- <img src="{{ asset('images/icon-close.svg') }}" alt="Remove" class="inline-block ml-3">
- </li>
- <li class="bg-white whitespace-no-wrap py-2 px-4 rounded-full mr-3 mb-3 hover:bg-grey-200 cursor-pointer">
- Option C
- <img src="{{ asset('images/icon-close.svg') }}" alt="Remove" class="inline-block ml-3">
- </li>
- <li class="bg-white whitespace-no-wrap py-2 px-4 rounded-full mr-3 mb-3 hover:bg-grey-200 cursor-pointer">
- Option D
- <img src="{{ asset('images/icon-close.svg') }}" alt="Remove" class="inline-block ml-3">
- </li>
- </ul>
- </div>
- <div class="products-grid-result-count pl-4 md:pl-0 font-display whitespace-no-wrap">
- {{ count($products) }}
- @if(count($products) == 1)
- {{ __('résultat') }}
- @else
- {{ __('résultats') }}
- @endif
- </div>
- </div>
-
- {{-- Product Grid --}}
- <grid cols="auto" class="products-grid mt-6">
- @foreach($products as $id => $product)
- @include('partials.product-link', ['id' => $id, 'product' => $product])
- @endforeach
- </grid>
- </div>
- </content>
+ </products-filters>
</full-width>
+
@endsection