]> _ Git - pmi.git/commitdiff
WIP #2961 @6
authorStephen Cameron <stephen@cubedesigners.com>
Wed, 28 Aug 2019 17:48:11 +0000 (19:48 +0200)
committerStephen Cameron <stephen@cubedesigners.com>
Wed, 28 Aug 2019 17:48:11 +0000 (19:48 +0200)
app/Http/Controllers/AjaxController.php
app/Http/Controllers/ProductController.php
app/Models/Product.php
resources/views/pages/product-detail.blade.php
resources/views/pages/products.blade.php

index cb4a890368c91a0630c002825448a030e1df7cb1..de423a5983ddf60d489ac8b3e82ef9f07d52c566 100644 (file)
@@ -208,123 +208,6 @@ class AjaxController extends CubistFrontController
         $product_type = $request->productType;
         $filterValues = $request->filter ?? [];
 
-        $res = [];
-        $type = ProductType::find($product_type);
-        $rawproducts = Product::where('product_type', $product_type)->where('online', 1)->where('public', 1)->get();
-        $products = [];
-        foreach ($rawproducts as $idx => $rawproduct) {
-            $products[$idx] = $rawproduct->getPageData();
-        }
-        $locale = App::getLocale();
-
-        $specifications = $type->filters;
-
-        $allmatches = [];
-
-        $filters = Specification::whereIn('id', $specifications)->get();
-        $res['filters'] = [];
-        foreach ($filters as $filter) {
-
-            $filterValue = null;
-            if (isset($filterValues[$filter->id])) {
-                $filterValue = explode(';', $filterValues[$filter->id]);
-                sort($filterValue);
-            }
-
-            $specname = 's_' . Str::snake($filter->name);
-            $data = $filter->getPageData();
-            $f = ['label' => $data->label,
-                'id' => $data->id,
-                'type' => $data->type,
-            ];
-
-            $matching = [];
-
-            if ($data->type == 'list') {
-                $options = [];
-                $values = [];
-                foreach ($products as $product) {
-                    $v = $product->get($specname);
-                    if (!$v) {
-                        $v = '-';
-                    }
-                    if (!isset($values[$v])) {
-                        $values[$v] = 0;
-                    }
-                    $values[$v]++;
-                    if (null === $filterValue) {
-                        $matching[] = $product->id;
-                    } else {
-                        if (in_array($v, $filterValue)) {
-                            $matching[] = $product->id;
-                        }
-                    }
-                }
-                foreach ($data->options as $index => $option) {
-                    if (is_scalar($option)) {
-                        $o = $option;
-                    } else {
-                        $o = $option[$locale] ?? $option['fr'];
-                    }
-                    if ($o) {
-                        $nb = $values[$index] ?? 0;
-                        if ($nb > 0) {
-                            $options[] = ['label' => $o, 'value' => $index, 'nb_products' => $nb];
-                        }
-                    }
-                }
-                if (isset($values['-'])) {
-                    $options[] = ['label' => __('Non défini'), 'value' => '-', 'nb_products' => $values['-']];
-                }
-                $f['options'] = $options;
-            } else if ($data->type == 'numeric' || $data->type == 'range') {
-                $f['min'] = INF;
-                $f['max'] = -INF;
-                $f['unit'] = $data->unit;
-
-                if ($data->type == 'numeric') {
-                    $f['prefix'] = $data['prefix'];
-                } else {
-                    $f['prefix'] = '';
-                }
-
-                foreach ($products as $product) {
-                    $v = $product->get($specname);
-                    if ($data->type == 'range') {
-                        $f['min'] = min($f['min'], $v['first'] ?? INF, $v['second'] ?? INF);
-                        $f['max'] = max($f['max'], $v['first'] ?? -INF, $v['second'] ?? -INF);
-                        if (null !== $filterValue && !($v['first'] == '' && $v['second'] == '')) {
-                            $min = min($v['first'], $v['second']);
-                            $max = max($v['first'], $v['second']);
-
-                            if ($min <= $filterValue[1] && $max >= $filterValue[0]) {
-                                $matching[] = $product->id;
-                            }
-                        }
-                    } else {
-                        $f['min'] = min($f['min'], $v);
-                        $f['max'] = min($f['max'], $v);
-                        if (null !== $filterValue) {
-                            if ($v >= $filterValue[0] && $v <= $filterValue[0]) {
-                                $matching[] = $product->id;
-                            }
-                        }
-                    }
-                    if (null === $filterValue && $v != '') {
-                        $matching[] = $product->id;
-                    }
-                }
-            } else {
-                continue;
-            }
-            $f['matching'] = ['count' => count($matching), 'hits' => $matching];
-            $allmatches[] = $matching;
-
-            $res['filters'][$data->id] = $f;
-        }
-
-        $intersection = call_user_func_array('array_intersect', $allmatches);
-        $res['results'] = ['count' => count($intersection), 'hits' => $intersection];
-        return $res;
+        return Product::getFilteredProducts($product_type, $filterValues);
     }
 }
index de13e7367e3669abdb5bed1bce584c20386fbdbd..8232d42deec564b6c6df6eeb2a8482a2b32df4ba 100644 (file)
@@ -13,24 +13,29 @@ class ProductController extends CubistFrontController
     public function productList(Request $request, $id)
     {
         $productType = ProductType::find($id);
+
         if (!$productType) {
             $this->_404();
         }
 
         $this->data['title'] = $productType->name;
-
         $this->data['page'] = $this->data['product_type'] = $productType->getPageData();
-        $this->data['products'] = [];
 
         $products = Product::with('media') // Eager load media to avoid N+1 query problem
-        ->where('product_type', $id)
+            ->where('product_type', $id)
             ->where('online', 1)
+            ->where('public', 1)
             ->get();
 
+        $this->data['products'] = [];
         foreach ($products as $item) {
             $this->data['products'][$item->id] = $item->getPageData();
         }
 
+        // Get available filters
+        $filters = Product::getFilteredProducts($id);
+        $this->data['filters'] = $filters ? $filters['filters'] : []; // To be used by Vue component
+
         return view('pages.products', $this->data);
     }
 
index d73ebce5a7e8d6fde76c49fea578c7b140a9ee8f..fbc4f34311a84e60ae2afba26f36aff2983d5859 100644 (file)
@@ -369,4 +369,132 @@ class Product extends CubistMagicPageModel
         return $cart_data;
     }
 
+
+    public static function getFilteredProducts($product_type, $filter_values = []) {
+
+        $res = [];
+        $type = ProductType::find($product_type);
+
+        if (!$type || !$type->filters) {
+            return $res;
+        }
+
+        $raw_products = Product::where('product_type', $product_type)->where('online', 1)->where('public', 1)->get();
+        $products = [];
+        foreach ($raw_products as $idx => $raw_product) {
+            $products[$idx] = $raw_product->getPageData();
+        }
+        $locale = App::getLocale();
+
+        $specifications = $type->filters;
+
+        $all_matches = [];
+
+        $filters = Specification::whereIn('id', $specifications)->get();
+        $res['filters'] = [];
+        foreach ($filters as $filter) {
+
+            $filter_value = null;
+            if (isset($filter_values[$filter->id])) {
+                $filter_value = explode(';', $filter_values[$filter->id]);
+                sort($filter_value);
+            }
+
+            $spec_name = 's_' . Str::snake($filter->name);
+            $data = $filter->getPageData();
+            $f = ['label' => $data->label,
+                  'id' => $data->id,
+                  'type' => $data->type,
+            ];
+
+            $matching = [];
+
+            if ($data->type == 'list') {
+                $options = [];
+                $values = [];
+                foreach ($products as $product) {
+                    $v = $product->get($spec_name);
+                    if (!$v) {
+                        $v = '-';
+                    }
+                    if (!isset($values[$v])) {
+                        $values[$v] = 0;
+                    }
+                    $values[$v]++;
+                    if (null === $filter_value) {
+                        $matching[] = $product->id;
+                    } else {
+                        if (in_array($v, $filter_value)) {
+                            $matching[] = $product->id;
+                        }
+                    }
+                }
+                foreach ($data->options as $index => $option) {
+                    if (is_scalar($option)) {
+                        $o = $option;
+                    } else {
+                        $o = $option[$locale] ?? $option['fr'];
+                    }
+                    if ($o) {
+                        $nb = $values[$index] ?? 0;
+                        if ($nb > 0) {
+                            $options[] = ['label' => $o, 'value' => $index, 'nb_products' => $nb];
+                        }
+                    }
+                }
+                if (isset($values['-'])) {
+                    $options[] = ['label' => __('Non défini'), 'value' => '-', 'nb_products' => $values['-']];
+                }
+                $f['options'] = $options;
+            } else if ($data->type == 'numeric' || $data->type == 'range') {
+                $f['min'] = INF;
+                $f['max'] = -INF;
+                $f['unit'] = $data->unit;
+
+                if ($data->type == 'numeric') {
+                    $f['prefix'] = $data['prefix'];
+                } else {
+                    $f['prefix'] = '';
+                }
+
+                foreach ($products as $product) {
+                    $v = $product->get($spec_name);
+                    if ($data->type == 'range') {
+                        $f['min'] = min($f['min'], $v['first'] ?? INF, $v['second'] ?? INF);
+                        $f['max'] = max($f['max'], $v['first'] ?? -INF, $v['second'] ?? -INF);
+                        if (null !== $filter_value && !($v['first'] == '' && $v['second'] == '')) {
+                            $min = min($v['first'], $v['second']);
+                            $max = max($v['first'], $v['second']);
+
+                            if ($min <= $filter_value[1] && $max >= $filter_value[0]) {
+                                $matching[] = $product->id;
+                            }
+                        }
+                    } else {
+                        $f['min'] = min($f['min'], $v);
+                        $f['max'] = min($f['max'], $v);
+                        if (null !== $filter_value) {
+                            if ($v >= $filter_value[0] && $v <= $filter_value[0]) {
+                                $matching[] = $product->id;
+                            }
+                        }
+                    }
+                    if (null === $filter_value && $v != '') {
+                        $matching[] = $product->id;
+                    }
+                }
+            } else {
+                continue;
+            }
+            $f['matching'] = ['count' => count($matching), 'hits' => $matching];
+            $all_matches[] = $matching;
+
+            $res['filters'][$data->id] = $f;
+        }
+
+        $intersection = call_user_func_array('array_intersect', $all_matches);
+        $res['results'] = ['count' => count($intersection), 'hits' => $intersection];
+        return $res;
+    }
+
 }
index d29a1724463f7e6a173be34ef625e6b79affd2da..2dac6ff6f69cef56ac2199b579a5949c9ccc7b37 100644 (file)
@@ -1,5 +1,5 @@
 @php
-    $technical_sheet=$product->getMediaUrl('technical_sheet',false)
+    $technical_sheet = $product->getMediaUrl('technical_sheet', false)
 @endphp
 
 @extends('layouts/app')
@@ -18,7 +18,7 @@
 
             {{-- Product images --}}
             <product-gallery
-                :images='@json($product->getImageURLList('images', '', [asset('images/product-details/product-placeholder.svg')]))'
+                :images='@json($product->getImageURLList('images', '', [$product->getEntity()->image_fallback]))'
                 class="flex-grow"
                 style="max-width: 348px">
             </product-gallery>
@@ -32,7 +32,7 @@
 
                 @if($technical_sheet)
                     <p class="mt-4">
-                        <a href="{{$technical_sheet}}">
+                        <a href="{{ $technical_sheet }}">
                             {{ __('Télécharger la fiche produit') }}
                         </a>
                     </p>
@@ -41,7 +41,7 @@
 
                 @if(config('features.quote'))
                     <cart-add :product-id="{{ $product->id }}" class="align-middle">
-                        {{__('Ajouter à ma sélection')}}
+                        {{ __('Ajouter à ma sélection') }}
 
                         <template v-slot:success-message>
                             @svg('tick', 'w-4 mr-3') {{ __('Produit ajouté') }}
             @if ($product->specifications)
                 <tab name="{{ __('Spécifications') }}">
                     <dl>
-                        @foreach($product->getEntity()->getSpecificationsValues() as $title=>$value)
+                        @foreach($product->getEntity()->getSpecificationsValues() as $title => $value)
                             <div>
-                                <dt>{{$title}}</dt>
-                                <dd>{{$value}}</dd>
+                                <dt>{{ $title }}</dt>
+                                <dd>{{ $value }}</dd>
                             </div>
                         @endforeach
                     </dl>
                     <ul>
                         @foreach($product->getEntity()->getDocuments() as $document)
                             <li>
-                                <a href="{{$document['media']->getUrl()}}" target="_blank"
+                                <a href="{{ $document['media']->getUrl() }}" target="_blank"
                                    class="flex items-center text-grey-dark hover:text-blue">
                                     <img class="mr-4 mb-2"
                                          src="{{asset('images/product-details/icon-'.$document['type'].'.svg')}}"
                                          alt="">
-                                    {{$document['label']}}
+                                    {{ $document['label'] }}
                                 </a>
                             </li>
                         @endforeach
     </content>
 
 
-    @if(count($related)>0)
+    @if (count($related) > 0)
         <full-width class="bg-grey-100">
             <content>
 
index af9c202797b1eb940c91f811bbb14f54cecb9b0b..0075c3c2b31a4b214b4360067f2acfd73ac04fc5 100644 (file)
@@ -6,90 +6,76 @@
     <full-width class="bg-grey-100" padding="pt-1v pb-2v">
         <content class="flex relative items-start">
 
-            {{--            <div class="products-filters-wrapper sticky top-0 mr-1v pt-4 whitespace-no-wrap">--}}
+            <div class="products-filters-wrapper sticky top-0 mr-1v pt-4 whitespace-no-wrap">
 
-            {{--                <div class="products-filters bg-white p-4">--}}
-            {{--                    <h3 class="text-base mb-2">Catégorie</h3>--}}
-            {{--                    @php--}}
-            {{--                        $categories = [--}}
-            {{--                            'Capteur de force - Galette',--}}
-            {{--                            'Capteur en "S" et miniatures',--}}
-            {{--                            'Capteur bouton inox',--}}
-            {{--                            'Conditionneurs et acquistion',--}}
-            {{--                            'Capteur 3 axes',--}}
-            {{--                            'Capteur 6 axes',--}}
-            {{--                            'Plateforme 6 axes',--}}
-            {{--                        ];--}}
-            {{--                    @endphp--}}
+                <div class="products-filters bg-white p-4">
 
-            {{--                    @foreach ($categories as $i => $category)--}}
-            {{--                        <div class="flex justify-between py-1 text-sm">--}}
-            {{--                            <label for="cat_{{ $i }}">--}}
-            {{--                                <input type="checkbox" id="cat_{{ $i }}" class="mr-2">--}}
-            {{--                                {{ $category }}--}}
-            {{--                            </label>--}}
-            {{--                            <div class="products-filters-count pl-8">({{ rand(10, 95) }})</div>--}}
-            {{--                        </div>--}}
-            {{--                    @endforeach--}}
+                    @foreach ($filters as $filter)
+                        <h3 class="text-base mb-2">{{ $filter['label'] }}</h3>
 
-            {{--                    <hr class="h-px bg-grey-200 my-4">--}}
+                        @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
 
-            {{--                    <h3 class="text-base mb-2">Filtre 01</h3>--}}
-            {{--                    @for ($i = 1; $i <= 5; $i++)--}}
-            {{--                        <div class="flex justify-between py-1 text-sm">--}}
-            {{--                            <label for="filter_1_{{ $i }}">--}}
-            {{--                                <input type="checkbox" id="filter_1_{{ $i }}" class="mr-2">--}}
-            {{--                                Option 0{{ $i }}--}}
-            {{--                            </label>--}}
-            {{--                            <div class="products-filters-count pl-8">({{ rand(10, 95) }})</div>--}}
-            {{--                        </div>--}}
-            {{--                    @endfor--}}
+                        @if ($filter['type'] == 'range')
+                            (RANGE SLIDER)
+                            {{-- Todo: handle range using Vue slider component: https://github.com/NightCatSama/vue-slider-component --}}
+                        @endif
 
-            {{--                    <hr class="h-px bg-grey-200 my-4">--}}
 
-            {{--                    <h3 class="text-base mb-2">Filtre 02</h3>--}}
-            {{--                    @for ($i = 1; $i <= 5; $i++)--}}
-            {{--                        <div class="flex justify-between py-1 text-sm">--}}
-            {{--                            <label for="filter_2_{{ $i }}">--}}
-            {{--                                <input type="checkbox" id="filter_2_{{ $i }}" class="mr-2">--}}
-            {{--                                Option {{ chr($i + 64) }}--}}
-            {{--                            </label>--}}
-            {{--                            <div class="products-filters-count pl-8">({{ rand(10, 95) }})</div>--}}
-            {{--                        </div>--}}
-            {{--                    @endfor--}}
+                        @if (!$loop->last)
+                            <hr class="h-px bg-grey-200 my-4">
+                        @endif
 
-            {{--                </div>--}}
-            {{--            </div>--}}
+                    @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">12 Résultats</div>--}}
-                {{--                </div>--}}
+                <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">