Attributes Ajaxified

This commit is contained in:
Devansh 2021-10-26 11:27:38 +05:30
parent b320507ec2
commit f6e3569106
4 changed files with 170 additions and 76 deletions

View File

@ -3,70 +3,93 @@
namespace Webkul\Shop\Http\Controllers;
use Illuminate\Support\Facades\Storage;
use Webkul\Product\Repositories\ProductRepository;
use Webkul\Category\Repositories\CategoryRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductDownloadableSampleRepository;
use Webkul\Product\Repositories\ProductDownloadableLinkRepository;
use Webkul\Product\Repositories\ProductDownloadableSampleRepository;
use Webkul\Product\Repositories\ProductFlatRepository;
use Webkul\Product\Repositories\ProductRepository;
class ProductController extends Controller
{
/**
* ProductRepository object
* Product repository instance.
*
* @var \Webkul\Product\Repositories\ProductRepository
*/
protected $productRepository;
/**
* ProductAttributeValueRepository object
* Product flat repository instance.
*
* @var \Webkul\Product\Repositories\ProductFlatRepository
*/
protected $productFlatRepository;
/**
* Product attribute value repository instance.
*
* @var \Webkul\Product\Repositories\ProductAttributeValueRepository
*/
protected $productAttributeValueRepository;
/**
* ProductDownloadableSampleRepository object
* Product downloadable sample repository instance.
*
* @var \Webkul\Product\Repositories\ProductDownloadableSampleRepository
*/
protected $productDownloadableSampleRepository;
/**
* ProductDownloadableLinkRepository object
* Product downloadable link repository instance.
*
* @var \Webkul\Product\Repositories\ProductDownloadableLinkRepository
*/
protected $productDownloadableLinkRepository;
/**
* Category repository instance.
*
* @var \Webkul\Category\Repositories\CategoryRepository
*/
protected $categoryRepository;
/**
* Create a new controller instance.
*
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Product\Repositories\productAttributeValueRepository $productAttributeValueRepository
* @param \Webkul\Product\Repositories\ProductFlatRepository $productFlatRepository
* @param \Webkul\Product\Repositories\ProductAttributeValueRepository $productAttributeValueRepository
* @param \Webkul\Product\Repositories\ProductDownloadableSampleRepository $productDownloadableSampleRepository
* @param \Webkul\Product\Repositories\ProductDownloadableLinkRepository $productDownloadableLinkRepository
* @param \Webkul\Category\Repositories\CategoryRepository $categoryRepository
* @return void
*/
public function __construct(
ProductRepository $productRepository,
ProductFlatRepository $productFlatRepository,
ProductAttributeValueRepository $productAttributeValueRepository,
ProductDownloadableSampleRepository $productDownloadableSampleRepository,
ProductDownloadableLinkRepository $productDownloadableLinkRepository
)
{
ProductDownloadableLinkRepository $productDownloadableLinkRepository,
CategoryRepository $categoryRepository
) {
$this->productRepository = $productRepository;
$this->productFlatRepository = $productFlatRepository;
$this->productAttributeValueRepository = $productAttributeValueRepository;
$this->productDownloadableSampleRepository = $productDownloadableSampleRepository;
$this->productDownloadableLinkRepository = $productDownloadableLinkRepository;
$this->categoryRepository = $categoryRepository;
parent::__construct();
}
/**
* Download image or file
* Download image or file.
*
* @param int $productId
* @param int $attributeId
@ -102,7 +125,7 @@ class ProductController extends Controller
? $privateDisk->download($productDownloadableLink->sample_file)
: abort(404);
} else {
$fileName = $name = substr($productDownloadableLink->sample_url, strrpos($productDownloadableLink->sample_url, '/') + 1);
$fileName = substr($productDownloadableLink->sample_url, strrpos($productDownloadableLink->sample_url, '/') + 1);
$tempImage = tempnam(sys_get_temp_dir(), $fileName);
@ -116,7 +139,7 @@ class ProductController extends Controller
if ($productDownloadableSample->type == 'file') {
return Storage::download($productDownloadableSample->file);
} else {
$fileName = $name = substr($productDownloadableSample->url, strrpos($productDownloadableSample->url, '/') + 1);
$fileName = substr($productDownloadableSample->url, strrpos($productDownloadableSample->url, '/') + 1);
$tempImage = tempnam(sys_get_temp_dir(), $fileName);
@ -125,8 +148,48 @@ class ProductController extends Controller
return response()->download($tempImage, $fileName);
}
}
} catch(\Exception $e) {
} catch (\Exception $e) {
abort(404);
}
}
/**
* Get filter attributes for product.
*
* @return \Illuminate\Http\Response
*/
public function getFilterAttributes($categoryId)
{
$category = $this->categoryRepository->find($categoryId);
if ($category) {
return response()->json([
'filter_attributes' => $this->productFlatRepository->getFilterAttributes($category)
]);
}
return response()->json([
'filter_attributes' => []
]);
}
/**
* Get category product maximum price.
*
* @return \Illuminate\Http\Response
*/
public function getCategoryProductMaximumPrice($categoryId)
{
$category = $this->categoryRepository->find($categoryId);
if ($category) {
return response()->json([
'max_price' => $this->productFlatRepository->handleCategoryProductMaximumPrice($category)
]);
}
return response()->json([
'max_price' => 0
]);
}
}

View File

@ -149,6 +149,13 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function
'view' => 'shop.products.index'
])->name('shop.product.file.download');
/**
* Product related attributes.
*/
Route::get('products/get-filter-attributes/{categoryId}', [ProductController::class, 'getFilterAttributes'])->name('admin.catalog.products.get-filter-attributes');
Route::get('products/get-category-product-maximum-price/{categoryId}', [ProductController::class, 'getCategoryProductMaximumPrice'])->name('admin.catalog.products.get-category-product-maximum-price');
/**
* These are the routes which are used during checkout for checking the customer.
* So, placed outside the cart merger middleware.

View File

@ -1,11 +1,3 @@
@inject ('productFlatRepository', 'Webkul\Product\Repositories\ProductFlatRepository')
<?php
$filterAttributes = $productFlatRepository->getFilterAttributes($category);
$maxPrice = $productFlatRepository->handleCategoryProductMaximumPrice($category);
?>
<div class="layered-filter-wrapper">
{!! view_render_event('bagisto.shop.products.list.layered-nagigation.before') !!}
@ -25,11 +17,11 @@
<div class="filter-attributes">
<filter-attribute-item
v-for='(attribute, index) in attributes'
:attribute="attribute"
:key="index"
:index="index"
@onFilterAdded="addFilters(attribute.code, $event)"
:appliedFilterValues="appliedFilters[attribute.code]">
:attribute="attribute"
:appliedFilterValues="appliedFilters[attribute.code]"
@onFilterAdded="addFilters(attribute.code, $event)">
</filter-attribute-item>
</div>
</div>
@ -38,7 +30,7 @@
<script type="text/x-template" id="filter-attribute-item-template">
<div class="filter-attributes-item" :class="[active ? 'active' : '']">
<div class="filter-attributes-title" @click="active = !active">
<div class="filter-attributes-title" @click="active = ! active">
@{{ attribute.name ? attribute.name : attribute.admin_name }}
<div class="pull-right">
@ -55,7 +47,9 @@
<li class="item" v-for='(option, index) in attribute.options'>
<span class="checkbox">
<input type="checkbox" :id="option.id" v-bind:value="option.id" v-model="appliedFilters" @change="addFilter($event)"/>
<label class="checkbox-view" :for="option.id"></label>
@{{ option.label ? option.label : option.admin_name }}
</span>
</li>
@ -69,8 +63,8 @@
:tooltip-style="sliderConfig.tooltipStyle"
:max="sliderConfig.max"
:lazy="true"
@change="priceRangeUpdated($event)"
></vue-slider>
@change="priceRangeUpdated($event)">
</vue-slider>
</div>
</div>
</div>
@ -82,23 +76,34 @@
data: function() {
return {
attributes: @json($filterAttributes),
appliedFilters: {}
appliedFilters: {},
attributes: [],
}
},
created: function () {
let urlParams = new URLSearchParams(window.location.search);
this.setFilterAttributes();
let self = this;
urlParams.forEach(function (value, index) {
self.appliedFilters[index] = value.split(',');
});
this.setAppliedFilters();
},
methods: {
setFilterAttributes: function () {
axios
.get('{{ route('admin.catalog.products.get-filter-attributes', $category->id) }}')
.then((response) => {
this.attributes = response.data.filter_attributes;
});
},
setAppliedFilters: function () {
let urlParams = new URLSearchParams(window.location.search);
urlParams.forEach((value, index) => {
this.appliedFilters[index] = value.split(',');
});
},
addFilters: function (attributeCode, filters) {
if (filters.length) {
this.appliedFilters[attributeCode] = filters;
@ -129,18 +134,12 @@
props: ['index', 'attribute', 'appliedFilterValues'],
data: function() {
let maxPrice = @json($maxPrice);
maxPrice = maxPrice ? ((parseInt(maxPrice) !== 0 || maxPrice) ? parseInt(maxPrice) : 500) : 500;
return {
appliedFilters: [],
active: false,
sliderConfig: {
value: [0, 0],
max: maxPrice,
max: 500,
processStyle: {
"backgroundColor": "#FF6472"
},
@ -153,7 +152,7 @@
},
created: function () {
if (!this.index) this.active = true;
if (! this.index) this.active = true;
if (this.appliedFilterValues && this.appliedFilterValues.length) {
this.appliedFilters = this.appliedFilterValues;
@ -164,9 +163,21 @@
this.active = true;
}
this.setMaxPrice();
},
methods: {
setMaxPrice: function () {
axios
.get('{{ route('admin.catalog.products.get-category-product-maximum-price', $category->id) }}')
.then((response) => {
let maxPrice = response.data.max_price;
this.sliderConfig.max = maxPrice ? ((parseInt(maxPrice) !== 0 || maxPrice) ? parseInt(maxPrice) : 500) : 500;
});
},
addFilter: function (e) {
this.$emit('onFilterAdded', this.appliedFilters)
},

View File

@ -1,11 +1,3 @@
@inject ('productFlatRepository', 'Webkul\Product\Repositories\ProductFlatRepository')
<?php
$filterAttributes = $productFlatRepository->getFilterAttributes($category);
$maxPrice = $productFlatRepository->handleCategoryProductMaximumPrice($category);
?>
<div class="layered-filter-wrapper left">
{!! view_render_event('bagisto.shop.products.list.layered-nagigation.before') !!}
@ -25,12 +17,12 @@
<div class="filter-content">
<div class="filter-attributes">
<filter-attribute-item
v-for='(attribute, index) in attributes'
:key="index"
:index="index"
:attribute="attribute"
v-for='(attribute, index) in attributes'
@onFilterAdded="addFilters(attribute.code, $event)"
:appliedFilterValues="appliedFilters[attribute.code]">
:appliedFilterValues="appliedFilters[attribute.code]"
@onFilterAdded="addFilters(attribute.code, $event)">
</filter-attribute-item>
</div>
</div>
@ -39,7 +31,7 @@
<script type="text/x-template" id="filter-attribute-item-template">
<div :class="`cursor-pointer filter-attributes-item ${active ? 'active' : ''}`">
<div class="filter-attributes-title" @click="active = !active">
<div class="filter-attributes-title" @click="active = ! active">
<h6 class="fw6 display-inbl">@{{ attribute.name ? attribute.name : attribute.admin_name }}</h6>
<div class="float-right display-table">
@ -84,19 +76,19 @@
<div class="filter-input row col-12 no-padding">
<input
type="text"
disabled
name="price_from"
:value="sliderConfig.priceFrom"
id="price_from" />
id="price_from"
disabled>
<label class="col text-center" for="to">{{ __('shop::app.products.filter-to') }}</label>
<input
type="text"
disabled
name="price_to"
:value="sliderConfig.priceTo"
id="price_to">
id="price_to"
disabled>
</div>
</div>
</div>
@ -110,19 +102,33 @@
data: function() {
return {
appliedFilters: {},
attributes: @json($filterAttributes),
attributes: [],
}
},
created: function () {
let urlParams = new URLSearchParams(window.location.search);
this.setFilterAttributes();
urlParams.forEach((value, index) => {
this.appliedFilters[index] = value.split(',');
});
this.setAppliedFilters();
},
methods: {
setFilterAttributes: function () {
axios
.get('{{ route('admin.catalog.products.get-filter-attributes', $category->id) }}')
.then((response) => {
this.attributes = response.data.filter_attributes;
});
},
setAppliedFilters: function () {
let urlParams = new URLSearchParams(window.location.search);
urlParams.forEach((value, index) => {
this.appliedFilters[index] = value.split(',');
});
},
addFilters: function (attributeCode, filters) {
if (filters.length) {
this.appliedFilters[attributeCode] = filters;
@ -134,7 +140,7 @@
},
applyFilter: function () {
var params = [];
let params = [];
for (key in this.appliedFilters) {
if (key != 'page') {
@ -158,16 +164,12 @@
],
data: function() {
let maxPrice = @json($maxPrice);
maxPrice = maxPrice ? ((parseInt(maxPrice) !== 0 || maxPrice) ? parseInt(maxPrice) : 500) : 500;
return {
active: false,
appliedFilters: [],
sliderConfig: {
max: maxPrice,
value: [ 0, 0 ],
max: 500,
value: [0, 0],
processStyle: {
"backgroundColor": "#FF6472"
},
@ -182,8 +184,7 @@
},
created: function () {
if (!this.index)
this.active = false;
if (! this.index) this.active = false;
if (this.appliedFilterValues && this.appliedFilterValues.length) {
this.appliedFilters = this.appliedFilterValues;
@ -196,9 +197,21 @@
this.active = true;
}
this.setMaxPrice();
},
methods: {
setMaxPrice: function () {
axios
.get('{{ route('admin.catalog.products.get-category-product-maximum-price', $category->id) }}')
.then((response) => {
let maxPrice = response.data.max_price;
this.sliderConfig.max = maxPrice ? ((parseInt(maxPrice) !== 0 || maxPrice) ? parseInt(maxPrice) : 500) : 500;
});
},
addFilter: function (e) {
this.$emit('onFilterAdded', this.appliedFilters)
},
@ -223,7 +236,7 @@
if (checkbox && checkbox.length > 0 && target.type != "checkbox") {
checkbox = checkbox[0];
checkbox.checked = !checkbox.checked;
checkbox.checked = ! checkbox.checked;
if (checkbox.checked) {
this.appliedFilters.push(id);