Merge pull request #5272 from devansh-webkul/layered-navigation-optimization
Layered navigation ajaxified and shop routes enhanced #4834
This commit is contained in:
commit
02a19aa6a5
|
|
@ -2,41 +2,73 @@
|
|||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Illuminate\Container\Container as App;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class ProductFlatRepository extends Repository
|
||||
{
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Product\Contracts\ProductFlat';
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum Price of Category Product
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @param \Webkul\Category\Contracts\Category $category
|
||||
* @return float
|
||||
* @param \Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
|
||||
* @param \Illuminate\Container\Container $app
|
||||
* @return void
|
||||
*/
|
||||
public function getCategoryProductMaximumPrice($category = null)
|
||||
{
|
||||
static $loadedCategoryMaxPrice = [];
|
||||
public function __construct(
|
||||
AttributeRepository $attributeRepository,
|
||||
App $app
|
||||
) {
|
||||
$this->attributeRepository = $attributeRepository;
|
||||
|
||||
if (! $category) {
|
||||
return $this->model->max('max_price');
|
||||
}
|
||||
|
||||
if (array_key_exists($category->id, $loadedCategoryMaxPrice)) {
|
||||
return $loadedCategoryMaxPrice[$category->id];
|
||||
}
|
||||
|
||||
return $loadedCategoryMaxPrice[$category->id] = $this->model
|
||||
->leftJoin('product_categories', 'product_flat.product_id', 'product_categories.product_id')
|
||||
->where('product_categories.category_id', $category->id)
|
||||
->max('max_price');
|
||||
parent::__construct($app);
|
||||
}
|
||||
|
||||
/**
|
||||
* get Category Product Attribute
|
||||
* Specify model.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function model(): string
|
||||
{
|
||||
return \Webkul\Product\Contracts\ProductFlat::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get category product model.
|
||||
*
|
||||
* @param int $categoryId
|
||||
* @return \Illuminate\Support\Querybuilder
|
||||
*/
|
||||
public function categoryProductQuerybuilder($categoryId)
|
||||
{
|
||||
return $this->model
|
||||
->leftJoin('product_categories', 'product_flat.product_id', 'product_categories.product_id')
|
||||
->where('product_categories.category_id', $categoryId)
|
||||
->where('product_flat.channel', core()->getCurrentChannelCode())
|
||||
->where('product_flat.locale', app()->getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update `product_flat` custom column.
|
||||
*
|
||||
* @param \Webkul\Attribute\Models\Attribute $attribute
|
||||
* @param \Webkul\Product\Listeners\ProductFlat $listener
|
||||
* @return object
|
||||
*/
|
||||
public function updateAttributeColumn(
|
||||
\Webkul\Attribute\Models\Attribute $attribute,
|
||||
\Webkul\Product\Listeners\ProductFlat $listener
|
||||
) {
|
||||
return $this->model
|
||||
->leftJoin('product_attribute_values as v', function ($join) use ($attribute) {
|
||||
$join->on('product_flat.id', '=', 'v.product_id')
|
||||
->on('v.attribute_id', '=', \DB::raw($attribute->id));
|
||||
})->update(['product_flat.' . $attribute->code => \DB::raw($listener->attributeTypeFields[$attribute->type] . '_value')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get category product attribute.
|
||||
*
|
||||
* @param int $categoryId
|
||||
* @return array
|
||||
|
|
@ -49,20 +81,20 @@ class ProductFlatRepository extends Repository
|
|||
$productIds = $qb->pluck('product_flat.product_id')->toArray();
|
||||
|
||||
$childProductIds = $this->model->distinct()
|
||||
->whereIn('parent_id', $productFlatIds)
|
||||
->pluck('product_id')->toArray();
|
||||
->whereIn('parent_id', $productFlatIds)
|
||||
->pluck('product_id')->toArray();
|
||||
|
||||
$productIds = array_merge($productIds, $childProductIds);
|
||||
|
||||
$attributeValues = $this->model
|
||||
->distinct()
|
||||
->leftJoin('product_attribute_values as pa', 'product_flat.product_id', 'pa.product_id')
|
||||
->leftJoin('attributes as at', 'pa.attribute_id', 'at.id')
|
||||
->leftJoin('product_super_attributes as ps', 'product_flat.product_id', 'ps.product_id')
|
||||
->select('pa.integer_value', 'pa.text_value', 'pa.attribute_id', 'ps.attribute_id as attributeId')
|
||||
->where('is_filterable', 1)
|
||||
->WhereIn('pa.product_id', $productIds)
|
||||
->get();
|
||||
->distinct()
|
||||
->leftJoin('product_attribute_values as pa', 'product_flat.product_id', 'pa.product_id')
|
||||
->leftJoin('attributes as at', 'pa.attribute_id', 'at.id')
|
||||
->leftJoin('product_super_attributes as ps', 'product_flat.product_id', 'ps.product_id')
|
||||
->select('pa.integer_value', 'pa.text_value', 'pa.attribute_id', 'ps.attribute_id as attributeId')
|
||||
->where('is_filterable', 1)
|
||||
->WhereIn('pa.product_id', $productIds)
|
||||
->get();
|
||||
|
||||
$attributeInfo['attributeOptions'] = $attributeInfo['attributes'] = [];
|
||||
|
||||
|
|
@ -92,24 +124,9 @@ class ProductFlatRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* get Category Product Model
|
||||
* Filter attributes according to products.
|
||||
*
|
||||
* @param int $categoryId
|
||||
* @return \Illuminate\Support\Querybuilder
|
||||
*/
|
||||
public function categoryProductQuerybuilder($categoryId) {
|
||||
|
||||
return $this->model
|
||||
->leftJoin('product_categories', 'product_flat.product_id', 'product_categories.product_id')
|
||||
->where('product_categories.category_id', $categoryId)
|
||||
->where('product_flat.channel', core()->getCurrentChannelCode())
|
||||
->where('product_flat.locale', app()->getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* filter attributes according to products
|
||||
*
|
||||
* @param array $category
|
||||
* @param \Webkul\Category\Contracts\Category $category
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getProductsRelatedFilterableAttributes($category)
|
||||
|
|
@ -129,32 +146,78 @@ class ProductFlatRepository extends Repository
|
|||
|
||||
$allFilterableAttributes = array_filter(array_unique(array_intersect($categoryFilterableAttributes, $productCategoryArrributes['attributes'])));
|
||||
|
||||
$attributes = app('Webkul\Attribute\Repositories\AttributeRepository')->getModel()::with(['options' => function($query) use ($productCategoryArrributes) {
|
||||
$attributes = $this->attributeRepository->getModel()::with([
|
||||
'options' => function ($query) use ($productCategoryArrributes) {
|
||||
return $query->whereIn('id', $productCategoryArrributes['attributeOptions'])
|
||||
->orderBy('sort_order');
|
||||
->orderBy('sort_order');
|
||||
}
|
||||
])->whereIn('id', $allFilterableAttributes)->get();
|
||||
|
||||
return $loadedCategoryAttributes[$category->id] = $attributes;
|
||||
} else {
|
||||
|
||||
return $loadedCategoryAttributes[$category->id] = $category->filterableAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update product_flat custom column
|
||||
* Maximum price of category product.
|
||||
*
|
||||
* @param \Webkul\Attribute\Models\Attribute $attribute
|
||||
* @param \Webkul\Product\Listeners\ProductFlat $listener
|
||||
* @param \Webkul\Category\Contracts\Category $category
|
||||
* @return float
|
||||
*/
|
||||
public function updateAttributeColumn(
|
||||
\Webkul\Attribute\Models\Attribute $attribute ,
|
||||
\Webkul\Product\Listeners\ProductFlat $listener ) {
|
||||
return $this->model
|
||||
->leftJoin('product_attribute_values as v', function($join) use ($attribute) {
|
||||
$join->on('product_flat.id', '=', 'v.product_id')
|
||||
->on('v.attribute_id', '=', \DB::raw($attribute->id));
|
||||
})->update(['product_flat.'.$attribute->code => \DB::raw($listener->attributeTypeFields[$attribute->type] .'_value')]);
|
||||
public function getCategoryProductMaximumPrice($category = null)
|
||||
{
|
||||
static $loadedCategoryMaxPrice = [];
|
||||
|
||||
if (! $category) {
|
||||
return $this->model->max('max_price');
|
||||
}
|
||||
|
||||
if (array_key_exists($category->id, $loadedCategoryMaxPrice)) {
|
||||
return $loadedCategoryMaxPrice[$category->id];
|
||||
}
|
||||
|
||||
return $loadedCategoryMaxPrice[$category->id] = $this->model
|
||||
->leftJoin('product_categories', 'product_flat.product_id', 'product_categories.product_id')
|
||||
->where('product_categories.category_id', $category->id)
|
||||
->max('max_price');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filter attributes.
|
||||
*
|
||||
* @param \Webkul\Category\Contracts\Category $category
|
||||
* @return array
|
||||
*/
|
||||
public function getFilterAttributes($category)
|
||||
{
|
||||
$filterAttributes = [];
|
||||
|
||||
if (isset($category)) {
|
||||
$filterAttributes = $this->getProductsRelatedFilterableAttributes($category);
|
||||
}
|
||||
|
||||
if (! count($filterAttributes) > 0) {
|
||||
$filterAttributes = $this->attributeRepository->getFilterAttributes();
|
||||
}
|
||||
|
||||
return $filterAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle category product max price.
|
||||
*
|
||||
* @param \Webkul\Category\Contracts\Category $category
|
||||
* @return float
|
||||
*/
|
||||
public function handleCategoryProductMaximumPrice($category)
|
||||
{
|
||||
$maxPrice = 0;
|
||||
|
||||
if (isset($category)) {
|
||||
$maxPrice = core()->convertPrice($this->getCategoryProductMaximumPrice($category));
|
||||
}
|
||||
|
||||
return $maxPrice;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class ShopServiceProvider extends ServiceProvider
|
|||
]);
|
||||
|
||||
/* loaders */
|
||||
$this->loadRoutesFrom(__DIR__ . '/../Http/routes.php');
|
||||
$this->loadRoutesFrom(__DIR__ . '/../Routes/web.php');
|
||||
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
|
||||
$this->loadTranslationsFrom(__DIR__ . '/../Resources/lang', 'shop');
|
||||
$this->loadViewsFrom(__DIR__ . '/../Resources/views', 'shop');
|
||||
|
|
@ -45,7 +45,7 @@ class ShopServiceProvider extends ServiceProvider
|
|||
Paginator::defaultSimpleView('shop::partials.pagination');
|
||||
|
||||
/* breadcrumbs */
|
||||
require __DIR__ . '/../Http/breadcrumbs.php';
|
||||
require __DIR__ . '/../Routes/breadcrumbs.php';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,49 +1,28 @@
|
|||
@inject ('attributeRepository', 'Webkul\Attribute\Repositories\AttributeRepository')
|
||||
|
||||
@inject ('productFlatRepository', 'Webkul\Product\Repositories\ProductFlatRepository')
|
||||
|
||||
@inject ('productRepository', 'Webkul\Product\Repositories\ProductRepository')
|
||||
|
||||
<?php
|
||||
$filterAttributes = $attributes = [];
|
||||
$maxPrice = 0;
|
||||
|
||||
if (isset($category)) {
|
||||
$filterAttributes = $productFlatRepository->getProductsRelatedFilterableAttributes($category);
|
||||
|
||||
$maxPrice = core()->convertPrice($productFlatRepository->getCategoryProductMaximumPrice($category));
|
||||
}
|
||||
|
||||
if (! count($filterAttributes) > 0) {
|
||||
$filterAttributes = $attributeRepository->getFilterAttributes();
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="layered-filter-wrapper">
|
||||
|
||||
{!! view_render_event('bagisto.shop.products.list.layered-nagigation.before') !!}
|
||||
|
||||
<layered-navigation></layered-navigation>
|
||||
<layered-navigation></layered-navigation>
|
||||
|
||||
{!! view_render_event('bagisto.shop.products.list.layered-nagigation.after') !!}
|
||||
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/x-template" id="layered-navigation-template">
|
||||
<div>
|
||||
|
||||
<div class="filter-title">
|
||||
{{ __('shop::app.products.layered-nav-title') }}
|
||||
</div>
|
||||
|
||||
<div class="filter-content">
|
||||
|
||||
<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]">
|
||||
<filter-attribute-item
|
||||
v-for='(attribute, index) in attributes'
|
||||
:key="index"
|
||||
:index="index"
|
||||
:attribute="attribute"
|
||||
:appliedFilterValues="appliedFilters[attribute.code]"
|
||||
@onFilterAdded="addFilters(attribute.code, $event)">
|
||||
</filter-attribute-item>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -51,8 +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">
|
||||
|
|
@ -65,16 +43,15 @@
|
|||
</div>
|
||||
|
||||
<div class="filter-attributes-content">
|
||||
|
||||
<ol class="items" v-if="attribute.type != 'price'">
|
||||
<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>
|
||||
</ol>
|
||||
|
||||
|
|
@ -86,39 +63,47 @@
|
|||
:tooltip-style="sliderConfig.tooltipStyle"
|
||||
:max="sliderConfig.max"
|
||||
:lazy="true"
|
||||
@change="priceRangeUpdated($event)"
|
||||
></vue-slider>
|
||||
@change="priceRangeUpdated($event)">
|
||||
</vue-slider>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('layered-navigation', {
|
||||
|
||||
template: '#layered-navigation-template',
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
attributes: @json($filterAttributes),
|
||||
|
||||
appliedFilters: {}
|
||||
appliedFilters: {},
|
||||
attributes: [],
|
||||
}
|
||||
},
|
||||
|
||||
created: function () {
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
this.setFilterAttributes();
|
||||
|
||||
var this_this = this;
|
||||
|
||||
urlParams.forEach(function (value, index) {
|
||||
this_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;
|
||||
|
|
@ -130,7 +115,7 @@
|
|||
},
|
||||
|
||||
applyFilter: function () {
|
||||
var params = [];
|
||||
let params = [];
|
||||
|
||||
for(key in this.appliedFilters) {
|
||||
if (key != 'page') {
|
||||
|
|
@ -144,27 +129,17 @@
|
|||
});
|
||||
|
||||
Vue.component('filter-attribute-item', {
|
||||
|
||||
template: '#filter-attribute-item-template',
|
||||
|
||||
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,
|
||||
value: [0, 0],
|
||||
max: 500,
|
||||
processStyle: {
|
||||
"backgroundColor": "#FF6472"
|
||||
},
|
||||
|
|
@ -177,8 +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;
|
||||
|
|
@ -189,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)
|
||||
},
|
||||
|
|
@ -212,8 +198,6 @@
|
|||
this.$emit('onFilterAdded', this.appliedFilters)
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
@endpush
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Webkul\Core\Http\Controllers\CountryStateController;
|
||||
use Webkul\Shop\Http\Controllers\CartController;
|
||||
use Webkul\Shop\Http\Controllers\OnepageController;
|
||||
|
||||
Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function () {
|
||||
/**
|
||||
* Country-State selector.
|
||||
*/
|
||||
Route::get('get/countries', [CountryStateController::class, 'getCountries'])->defaults('_config', [
|
||||
'view' => 'shop::test'
|
||||
])->name('get.countries');
|
||||
|
||||
/**
|
||||
* Get States when Country is passed.
|
||||
*/
|
||||
Route::get('get/states/{country}', [CountryStateController::class, 'getStates'])->defaults('_config', [
|
||||
'view' => 'shop::test'
|
||||
])->name('get.states');
|
||||
|
||||
/**
|
||||
* Cart routes.
|
||||
*/
|
||||
Route::get('checkout/cart', [CartController::class, 'index'])->defaults('_config', [
|
||||
'view' => 'shop::checkout.cart.index'
|
||||
])->name('shop.checkout.cart.index');
|
||||
|
||||
Route::post('checkout/cart/add/{id}', [CartController::class, 'add'])->defaults('_config', [
|
||||
'redirect' => 'shop.checkout.cart.index'
|
||||
])->name('cart.add');
|
||||
|
||||
Route::get('checkout/cart/remove/{id}', [CartController::class, 'remove'])->name('cart.remove');
|
||||
|
||||
Route::post('/checkout/cart', [CartController::class, 'updateBeforeCheckout'])->defaults('_config', [
|
||||
'redirect' => 'shop.checkout.cart.index'
|
||||
])->name('shop.checkout.cart.update');
|
||||
|
||||
Route::get('/checkout/cart/remove/{id}', [CartController::class, 'remove'])->defaults('_config', [
|
||||
'redirect' => 'shop.checkout.cart.index'
|
||||
])->name('shop.checkout.cart.remove');
|
||||
|
||||
Route::post('move/wishlist/{id}', [CartController::class, 'moveToWishlist'])->name('shop.movetowishlist');
|
||||
|
||||
/**
|
||||
* Coupon routes.
|
||||
*/
|
||||
Route::post('checkout/cart/coupon', [CartController::class, 'applyCoupon'])->name('shop.checkout.cart.coupon.apply');
|
||||
|
||||
Route::delete('checkout/cart/coupon', [CartController::class, 'removeCoupon'])->name('shop.checkout.coupon.remove.coupon');
|
||||
|
||||
/**
|
||||
* Checkout routes.
|
||||
*/
|
||||
Route::get('/checkout/onepage', [OnepageController::class, 'index'])->defaults('_config', [
|
||||
'view' => 'shop::checkout.onepage'
|
||||
])->name('shop.checkout.onepage.index');
|
||||
|
||||
Route::get('/checkout/summary', [OnepageController::class, 'summary'])->name('shop.checkout.summary');
|
||||
|
||||
Route::post('/checkout/save-address', [OnepageController::class, 'saveAddress'])->name('shop.checkout.save-address');
|
||||
|
||||
Route::post('/checkout/save-shipping', [OnepageController::class, 'saveShipping'])->name('shop.checkout.save-shipping');
|
||||
|
||||
Route::post('/checkout/save-payment', [OnepageController::class, 'savePayment'])->name('shop.checkout.save-payment');
|
||||
|
||||
Route::post('/checkout/check-minimum-order', [OnepageController::class, 'checkMinimumOrder'])->name('shop.checkout.check-minimum-order');
|
||||
|
||||
Route::post('/checkout/save-order', [OnepageController::class, 'saveOrder'])->name('shop.checkout.save-order');
|
||||
|
||||
Route::get('/checkout/success', [OnepageController::class, 'success'])->defaults('_config', [
|
||||
'view' => 'shop::checkout.success'
|
||||
])->name('shop.checkout.success');
|
||||
});
|
||||
195
packages/Webkul/Shop/src/Http/routes.php → packages/Webkul/Shop/src/Routes/customer-routes.php
Executable file → Normal file
195
packages/Webkul/Shop/src/Http/routes.php → packages/Webkul/Shop/src/Routes/customer-routes.php
Executable file → Normal file
|
|
@ -1,8 +1,6 @@
|
|||
<?php
|
||||
|
||||
// Controllers
|
||||
use Webkul\CMS\Http\Controllers\Shop\PagePresenterController;
|
||||
use Webkul\Core\Http\Controllers\CountryStateController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Webkul\Customer\Http\Controllers\AccountController;
|
||||
use Webkul\Customer\Http\Controllers\AddressController;
|
||||
use Webkul\Customer\Http\Controllers\CustomerController;
|
||||
|
|
@ -11,156 +9,10 @@ use Webkul\Customer\Http\Controllers\RegistrationController;
|
|||
use Webkul\Customer\Http\Controllers\ResetPasswordController;
|
||||
use Webkul\Customer\Http\Controllers\SessionController;
|
||||
use Webkul\Customer\Http\Controllers\WishlistController;
|
||||
use Webkul\Shop\Http\Controllers\CartController;
|
||||
use Webkul\Shop\Http\Controllers\DownloadableProductController;
|
||||
use Webkul\Shop\Http\Controllers\HomeController;
|
||||
use Webkul\Shop\Http\Controllers\OnepageController;
|
||||
use Webkul\Shop\Http\Controllers\OrderController;
|
||||
use Webkul\Shop\Http\Controllers\ProductController;
|
||||
use Webkul\Shop\Http\Controllers\ReviewController;
|
||||
use Webkul\Shop\Http\Controllers\SearchController;
|
||||
use Webkul\Shop\Http\Controllers\SubscriptionController;
|
||||
|
||||
Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function () {
|
||||
/**
|
||||
* Store front home.
|
||||
*/
|
||||
Route::get('/', [HomeController::class, 'index'])->defaults('_config', [
|
||||
'view' => 'shop::home.index'
|
||||
])->name('shop.home.index');
|
||||
|
||||
/**
|
||||
* Store front search.
|
||||
*/
|
||||
Route::get('/search', [SearchController::class, 'index'])->defaults('_config', [
|
||||
'view' => 'shop::search.search'
|
||||
])->name('shop.search.index');
|
||||
|
||||
Route::post('/upload-search-image', [HomeController::class, 'upload'])->name('shop.image.search.upload');
|
||||
|
||||
/**
|
||||
* Subscription.
|
||||
*/
|
||||
Route::get('/subscribe', [SubscriptionController::class, 'subscribe'])->name('shop.subscribe');
|
||||
|
||||
Route::get('/unsubscribe/{token}', [SubscriptionController::class, 'unsubscribe'])->name('shop.unsubscribe');
|
||||
|
||||
/**
|
||||
* Country-State selector.
|
||||
*/
|
||||
Route::get('get/countries', [CountryStateController::class, 'getCountries'])->defaults('_config', [
|
||||
'view' => 'shop::test'
|
||||
])->name('get.countries');
|
||||
|
||||
/**
|
||||
* Get States when Country is passed.
|
||||
*/
|
||||
Route::get('get/states/{country}', [CountryStateController::class, 'getStates'])->defaults('_config', [
|
||||
'view' => 'shop::test'
|
||||
])->name('get.states');
|
||||
|
||||
/**
|
||||
* Cart, coupons and checkout.
|
||||
*/
|
||||
// Cart items listing.
|
||||
Route::get('checkout/cart', [CartController::class, 'index'])->defaults('_config', [
|
||||
'view' => 'shop::checkout.cart.index'
|
||||
])->name('shop.checkout.cart.index');
|
||||
|
||||
// Add cart items.
|
||||
Route::post('checkout/cart/add/{id}', [CartController::class, 'add'])->defaults('_config', [
|
||||
'redirect' => 'shop.checkout.cart.index'
|
||||
])->name('cart.add');
|
||||
|
||||
// Cart items remove.
|
||||
Route::get('checkout/cart/remove/{id}', [CartController::class, 'remove'])->name('cart.remove');
|
||||
|
||||
// Cart update before checkout.
|
||||
Route::post('/checkout/cart', [CartController::class, 'updateBeforeCheckout'])->defaults('_config', [
|
||||
'redirect' => 'shop.checkout.cart.index'
|
||||
])->name('shop.checkout.cart.update');
|
||||
|
||||
// Cart items remove.
|
||||
Route::get('/checkout/cart/remove/{id}', [CartController::class, 'remove'])->defaults('_config', [
|
||||
'redirect' => 'shop.checkout.cart.index'
|
||||
])->name('shop.checkout.cart.remove');
|
||||
|
||||
// Move item to wishlist from cart.
|
||||
Route::post('move/wishlist/{id}', [CartController::class, 'moveToWishlist'])->name('shop.movetowishlist');
|
||||
|
||||
// Apply coupons.
|
||||
Route::post('checkout/cart/coupon', [CartController::class, 'applyCoupon'])->name('shop.checkout.cart.coupon.apply');
|
||||
|
||||
// Remove coupons.
|
||||
Route::delete('checkout/cart/coupon', [CartController::class, 'removeCoupon'])->name('shop.checkout.coupon.remove.coupon');
|
||||
|
||||
// Checkout index page.
|
||||
Route::get('/checkout/onepage', [OnepageController::class, 'index'])->defaults('_config', [
|
||||
'view' => 'shop::checkout.onepage'
|
||||
])->name('shop.checkout.onepage.index');
|
||||
|
||||
// Checkout get summary.
|
||||
Route::get('/checkout/summary',[OnepageController::class, 'summary'])->name('shop.checkout.summary');
|
||||
|
||||
// Checkout save address form.
|
||||
Route::post('/checkout/save-address', [OnepageController::class, 'saveAddress'])->name('shop.checkout.save-address');
|
||||
|
||||
// Checkout save shipping address form.
|
||||
Route::post('/checkout/save-shipping', [OnepageController::class, 'saveShipping'])->name('shop.checkout.save-shipping');
|
||||
|
||||
// Checkout save payment method form.
|
||||
Route::post('/checkout/save-payment', [OnepageController::class, 'savePayment'])->name('shop.checkout.save-payment');
|
||||
|
||||
// Check minimum order.
|
||||
Route::post('/checkout/check-minimum-order', [OnepageController::class, 'checkMinimumOrder'])->name('shop.checkout.check-minimum-order');
|
||||
|
||||
// Checkout save order.
|
||||
Route::post('/checkout/save-order', [OnepageController::class, 'saveOrder'])->name('shop.checkout.save-order');
|
||||
|
||||
// Checkout order successful.
|
||||
Route::get('/checkout/success', [OnepageController::class, 'success'])->defaults('_config', [
|
||||
'view' => 'shop::checkout.success'
|
||||
])->name('shop.checkout.success');
|
||||
|
||||
/**
|
||||
* Product reviews.
|
||||
*/
|
||||
// Show product review form.
|
||||
Route::get('/reviews/{slug}', [ReviewController::class, 'show'])->defaults('_config', [
|
||||
'view' => 'shop::products.reviews.index'
|
||||
])->name('shop.reviews.index');
|
||||
|
||||
// Show product review listing.
|
||||
Route::get('/product/{slug}/review', [ReviewController::class, 'create'])->defaults('_config', [
|
||||
'view' => 'shop::products.reviews.create'
|
||||
])->name('shop.reviews.create');
|
||||
|
||||
// Store product review.
|
||||
Route::post('/product/{slug}/review', [ReviewController::class, 'store'])->defaults('_config', [
|
||||
'redirect' => 'shop.home.index'
|
||||
])->name('shop.reviews.store');
|
||||
|
||||
/**
|
||||
* Downloadable products.
|
||||
*/
|
||||
Route::get('/downloadable/download-sample/{type}/{id}', [ProductController::class, 'downloadSample'])->name('shop.downloadable.download_sample');
|
||||
|
||||
Route::get('/product/{id}/{attribute_id}', [ProductController::class, 'download'])->defaults('_config', [
|
||||
'view' => 'shop.products.index'
|
||||
])->name('shop.product.file.download');
|
||||
|
||||
/**
|
||||
* These are the routes which are used during checkout for checking the customer.
|
||||
* So, placed outside the cart merger middleware.
|
||||
*/
|
||||
Route::prefix('customer')->group(function () {
|
||||
// For customer exist check.
|
||||
Route::post('/customer/exist', [OnepageController::class, 'checkExistCustomer'])->name('customer.checkout.exist');
|
||||
|
||||
// For customer login checkout.
|
||||
Route::post('/customer/checkout/login', [OnepageController::class, 'loginForCheckout'])->name('customer.checkout.login');
|
||||
});
|
||||
|
||||
/**
|
||||
* Cart merger middleware. This middleware will take care of the items
|
||||
* which are deactivated at the time of buy now functionality. If somehow
|
||||
|
|
@ -171,40 +23,31 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function
|
|||
* group.
|
||||
*/
|
||||
Route::group(['middleware' => ['cart.merger']], function () {
|
||||
/**
|
||||
* Customer routes.
|
||||
*/
|
||||
Route::prefix('customer')->group(function () {
|
||||
/**
|
||||
* Forgot password routes.
|
||||
*/
|
||||
// Show forgot password form.
|
||||
Route::get('/forgot-password', [ForgotPasswordController::class, 'create'])->defaults('_config', [
|
||||
'view' => 'shop::customers.signup.forgot-password'
|
||||
])->name('customer.forgot-password.create');
|
||||
|
||||
// Store forgot password.
|
||||
Route::post('/forgot-password', [ForgotPasswordController::class, 'store'])->name('customer.forgot-password.store');
|
||||
|
||||
// Reset password form.
|
||||
Route::get('/reset-password/{token}', [ResetPasswordController::class, 'create'])->defaults('_config', [
|
||||
'view' => 'shop::customers.signup.reset-password'
|
||||
])->name('customer.reset-password.create');
|
||||
|
||||
// Store reset password.
|
||||
Route::post('/reset-password',[ResetPasswordController::class, 'store'])->defaults('_config', [
|
||||
Route::post('/reset-password', [ResetPasswordController::class, 'store'])->defaults('_config', [
|
||||
'redirect' => 'customer.profile.index'
|
||||
])->name('customer.reset-password.store');
|
||||
|
||||
/**
|
||||
* Login routes.
|
||||
*/
|
||||
// Login form.
|
||||
Route::get('login', [SessionController::class, 'show'])->defaults('_config', [
|
||||
'view' => 'shop::customers.session.index',
|
||||
])->name('customer.session.index');
|
||||
|
||||
// Login.
|
||||
Route::post('login', [SessionController::class, 'create'])->defaults('_config', [
|
||||
'redirect' => 'customer.profile.index'
|
||||
])->name('customer.session.create');
|
||||
|
|
@ -212,24 +55,23 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function
|
|||
/**
|
||||
* Registration routes.
|
||||
*/
|
||||
// Show registration form.
|
||||
Route::get('register', [RegistrationController::class, 'show'])->defaults('_config', [
|
||||
'view' => 'shop::customers.signup.index'
|
||||
])->name('customer.register.index');
|
||||
|
||||
// Store new registered user.
|
||||
Route::post('register', [RegistrationController::class, 'create'])->defaults('_config', [
|
||||
'redirect' => 'customer.session.index',
|
||||
])->name('customer.register.create');
|
||||
|
||||
// Verify account.
|
||||
/**
|
||||
* Customer verification routes.
|
||||
*/
|
||||
Route::get('/verify-account/{token}', [RegistrationController::class, 'verifyAccount'])->name('customer.verify');
|
||||
|
||||
// Resend verification email.
|
||||
Route::get('/resend/verification/{email}', [RegistrationController::class, 'resendVerificationEmail'])->name('customer.resend.verification-email');
|
||||
|
||||
/**
|
||||
* Customer authented routes. All the below routes only be accessible
|
||||
* Customer authenticated routes. All the below routes only be accessible
|
||||
* if customer is authenticated.
|
||||
*/
|
||||
Route::group(['middleware' => ['customer']], function () {
|
||||
|
|
@ -362,20 +204,21 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* These are the routes which are used during checkout for checking the customer.
|
||||
* So, placed outside the cart merger middleware.
|
||||
*/
|
||||
Route::prefix('customer')->group(function () {
|
||||
/**
|
||||
* For customer exist check.
|
||||
*/
|
||||
Route::post('/customer/exist', [OnepageController::class, 'checkExistCustomer'])->name('customer.checkout.exist');
|
||||
|
||||
/**
|
||||
* CMS pages.
|
||||
* For customer login checkout.
|
||||
*/
|
||||
Route::get('page/{slug}', [PagePresenterController::class, 'presenter'])->name('shop.cms.page');
|
||||
|
||||
/**
|
||||
* Fallback route.
|
||||
*/
|
||||
Route::fallback(\Webkul\Shop\Http\Controllers\ProductsCategoriesProxyController::class . '@index')
|
||||
->defaults('_config', [
|
||||
'product_view' => 'shop::products.view',
|
||||
'category_view' => 'shop::products.index'
|
||||
])
|
||||
->name('shop.productOrCategory.index');
|
||||
Route::post('/customer/checkout/login', [OnepageController::class, 'loginForCheckout'])->name('customer.checkout.login');
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Webkul\CMS\Http\Controllers\Shop\PagePresenterController;
|
||||
use Webkul\Shop\Http\Controllers\HomeController;
|
||||
use Webkul\Shop\Http\Controllers\ProductController;
|
||||
use Webkul\Shop\Http\Controllers\ReviewController;
|
||||
use Webkul\Shop\Http\Controllers\SearchController;
|
||||
use Webkul\Shop\Http\Controllers\SubscriptionController;
|
||||
|
||||
Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function () {
|
||||
/**
|
||||
* Cart merger middleware. This middleware will take care of the items
|
||||
* which are deactivated at the time of buy now functionality. If somehow
|
||||
* user redirects without completing the checkout then this will merge
|
||||
* full cart.
|
||||
*
|
||||
* If some routes are not able to merge the cart, then place the route in this
|
||||
* group.
|
||||
*/
|
||||
Route::group(['middleware' => ['cart.merger']], function () {
|
||||
/**
|
||||
* CMS pages.
|
||||
*/
|
||||
Route::get('page/{slug}', [PagePresenterController::class, 'presenter'])->name('shop.cms.page');
|
||||
|
||||
/**
|
||||
* Fallback route.
|
||||
*/
|
||||
Route::fallback(\Webkul\Shop\Http\Controllers\ProductsCategoriesProxyController::class . '@index')
|
||||
->defaults('_config', [
|
||||
'product_view' => 'shop::products.view',
|
||||
'category_view' => 'shop::products.index'
|
||||
])
|
||||
->name('shop.productOrCategory.index');
|
||||
});
|
||||
|
||||
/**
|
||||
* Store front home.
|
||||
*/
|
||||
Route::get('/', [HomeController::class, 'index'])->defaults('_config', [
|
||||
'view' => 'shop::home.index'
|
||||
])->name('shop.home.index');
|
||||
|
||||
/**
|
||||
* Store front search.
|
||||
*/
|
||||
Route::get('/search', [SearchController::class, 'index'])->defaults('_config', [
|
||||
'view' => 'shop::search.search'
|
||||
])->name('shop.search.index');
|
||||
|
||||
Route::post('/upload-search-image', [HomeController::class, 'upload'])->name('shop.image.search.upload');
|
||||
|
||||
/**
|
||||
* Subscription routes.
|
||||
*/
|
||||
Route::get('/subscribe', [SubscriptionController::class, 'subscribe'])->name('shop.subscribe');
|
||||
|
||||
Route::get('/unsubscribe/{token}', [SubscriptionController::class, 'unsubscribe'])->name('shop.unsubscribe');
|
||||
|
||||
/**
|
||||
* Product and categories routes.
|
||||
*/
|
||||
Route::get('/reviews/{slug}', [ReviewController::class, 'show'])->defaults('_config', [
|
||||
'view' => 'shop::products.reviews.index'
|
||||
])->name('shop.reviews.index');
|
||||
|
||||
Route::get('/product/{slug}/review', [ReviewController::class, 'create'])->defaults('_config', [
|
||||
'view' => 'shop::products.reviews.create'
|
||||
])->name('shop.reviews.create');
|
||||
|
||||
Route::post('/product/{slug}/review', [ReviewController::class, 'store'])->defaults('_config', [
|
||||
'redirect' => 'shop.home.index'
|
||||
])->name('shop.reviews.store');
|
||||
|
||||
Route::get('/downloadable/download-sample/{type}/{id}', [ProductController::class, 'downloadSample'])->name('shop.downloadable.download_sample');
|
||||
|
||||
Route::get('/product/{id}/{attribute_id}', [ProductController::class, 'download'])->defaults('_config', [
|
||||
'view' => 'shop.products.index'
|
||||
])->name('shop.product.file.download');
|
||||
|
||||
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');
|
||||
});
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Store front routes.
|
||||
*/
|
||||
require 'store-front-routes.php';
|
||||
|
||||
/**
|
||||
* Customer routes. All routes related to customer
|
||||
* in storefront will be placed here.
|
||||
*/
|
||||
require 'customer-routes.php';
|
||||
|
||||
/**
|
||||
* Checkout routes. All routes related to checkout like
|
||||
* cart, coupons, etc will be placed here.
|
||||
*/
|
||||
require 'checkout-routes.php';
|
||||
|
|
@ -1,30 +1,9 @@
|
|||
@inject ('productRepository', 'Webkul\Product\Repositories\ProductRepository')
|
||||
@inject ('attributeRepository', 'Webkul\Attribute\Repositories\AttributeRepository')
|
||||
@inject ('productFlatRepository', 'Webkul\Product\Repositories\ProductFlatRepository')
|
||||
|
||||
<?php
|
||||
$filterAttributes = $attributes = [];
|
||||
$maxPrice = 0;
|
||||
|
||||
if (isset($category)) {
|
||||
$filterAttributes = $productFlatRepository->getProductsRelatedFilterableAttributes($category);
|
||||
|
||||
$maxPrice = core()->convertPrice($productFlatRepository->getCategoryProductMaximumPrice($category));
|
||||
}
|
||||
|
||||
if (! count($filterAttributes) > 0) {
|
||||
$filterAttributes = $attributeRepository->getFilterAttributes();
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="layered-filter-wrapper left">
|
||||
|
||||
{!! view_render_event('bagisto.shop.products.list.layered-nagigation.before') !!}
|
||||
|
||||
<layered-navigation></layered-navigation>
|
||||
|
||||
{!! view_render_event('bagisto.shop.products.list.layered-nagigation.after') !!}
|
||||
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
|
|
@ -38,14 +17,13 @@
|
|||
<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>
|
||||
</div>
|
||||
|
|
@ -53,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">
|
||||
|
|
@ -70,7 +48,6 @@
|
|||
<li
|
||||
class="item"
|
||||
v-for='(option, index) in attribute.options'>
|
||||
|
||||
<div
|
||||
class="checkbox"
|
||||
@click="optionClicked(option.id, $event)">
|
||||
|
|
@ -99,18 +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">
|
||||
type="text"
|
||||
name="price_to"
|
||||
:value="sliderConfig.priceTo"
|
||||
id="price_to"
|
||||
disabled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -120,22 +98,37 @@
|
|||
<script>
|
||||
Vue.component('layered-navigation', {
|
||||
template: '#layered-navigation-template',
|
||||
|
||||
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;
|
||||
|
|
@ -147,7 +140,7 @@
|
|||
},
|
||||
|
||||
applyFilter: function () {
|
||||
var params = [];
|
||||
let params = [];
|
||||
|
||||
for (key in this.appliedFilters) {
|
||||
if (key != 'page') {
|
||||
|
|
@ -162,6 +155,7 @@
|
|||
|
||||
Vue.component('filter-attribute-item', {
|
||||
template: '#filter-attribute-item-template',
|
||||
|
||||
props: [
|
||||
'index',
|
||||
'attribute',
|
||||
|
|
@ -170,26 +164,19 @@
|
|||
],
|
||||
|
||||
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"
|
||||
},
|
||||
|
||||
tooltipStyle: {
|
||||
"borderColor": "#FF6472",
|
||||
"backgroundColor": "#FF6472",
|
||||
},
|
||||
|
||||
priceTo: 0,
|
||||
priceFrom: 0,
|
||||
}
|
||||
|
|
@ -197,11 +184,11 @@
|
|||
},
|
||||
|
||||
created: function () {
|
||||
if (!this.index)
|
||||
this.active = false;
|
||||
if (! this.index) this.active = false;
|
||||
|
||||
if (this.appliedFilterValues && this.appliedFilterValues.length) {
|
||||
this.appliedFilters = this.appliedFilterValues;
|
||||
|
||||
if (this.attribute.type == 'price') {
|
||||
this.sliderConfig.value = this.appliedFilterValues;
|
||||
this.sliderConfig.priceFrom = this.appliedFilterValues[0];
|
||||
|
|
@ -210,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)
|
||||
},
|
||||
|
|
@ -234,14 +233,16 @@
|
|||
|
||||
optionClicked: function (id, {target}) {
|
||||
let checkbox = $(`#${id}`);
|
||||
|
||||
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);
|
||||
} else {
|
||||
let idPosition = this.appliedFilters.indexOf(id);
|
||||
|
||||
if (idPosition == -1)
|
||||
idPosition = this.appliedFilters.indexOf(id.toString());
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue