]> _ Git - pmi.git/commitdiff
WIP #2962 @10
authorStephen Cameron <stephen@cubedesigners.com>
Thu, 29 Aug 2019 20:22:30 +0000 (22:22 +0200)
committerStephen Cameron <stephen@cubedesigners.com>
Thu, 29 Aug 2019 20:22:30 +0000 (22:22 +0200)
app/Http/Controllers/AjaxController.php
app/Http/Controllers/ProductController.php
app/Models/Product.php
resources/js/components/ProductsFilters.vue [new file with mode: 0644]
resources/views/pages/products.blade.php

index de423a5983ddf60d489ac8b3e82ef9f07d52c566..d5e06144b543c4530028e519dcdb8ae99ac7a5ea 100644 (file)
@@ -206,8 +206,8 @@ class AjaxController extends CubistFrontController
     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);
     }
 }
index 8232d42deec564b6c6df6eeb2a8482a2b32df4ba..ffdd06cf29849c4b7f5861415d50d3e6a0647f94 100644 (file)
@@ -35,6 +35,7 @@ class ProductController extends CubistFrontController
         // 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);
     }
index 64c28404f763fea37d4276d495ee7658baf62d83..c6d4f34c295920c9f4f8af22e9f162cf912d6829 100644 (file)
@@ -439,12 +439,12 @@ class Product extends CubistMagicPageModel
                     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') {
diff --git a/resources/js/components/ProductsFilters.vue b/resources/js/components/ProductsFilters.vue
new file mode 100644 (file)
index 0000000..de7bd06
--- /dev/null
@@ -0,0 +1,137 @@
+<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>
index 0075c3c2b31a4b214b4360067f2acfd73ac04fc5..891fcaebe7ae10e01d4c0c85c2301f810822b684 100644 (file)
@@ -4,86 +4,19 @@
     @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