Merge pull request #651 from rahulshukla-webkul/development
Development
This commit is contained in:
commit
2a9293448b
|
|
@ -375,7 +375,12 @@ return [
|
|||
'categories' => 'Categories',
|
||||
'images' => 'Images',
|
||||
'inventories' => 'Inventories',
|
||||
'variations' => 'Variations'
|
||||
'variations' => 'Variations',
|
||||
'product-link' => 'Linked Products',
|
||||
'cross-selling' => 'Cross Selling',
|
||||
'up-selling' => 'Up Selling',
|
||||
'related-products' => 'Related Products',
|
||||
'product-search-hint' => 'Start typing product name'
|
||||
],
|
||||
|
||||
'attributes' => [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,283 @@
|
|||
<accordian :title="'{{ __('admin::app.catalog.products.product-link') }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
|
||||
<up-selling></up-selling>
|
||||
|
||||
<cross-selling></cross-selling>
|
||||
|
||||
<related-product></related-product>
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
</accordian>
|
||||
|
||||
|
||||
@push('scripts')
|
||||
|
||||
<script type="text/x-template" id="up-selling-template">
|
||||
<div>
|
||||
<div class="control-group">
|
||||
<label for="up-selling">{{ __('admin::app.catalog.products.up-selling') }}</label>
|
||||
<input type="text" class="control" autocomplete="off" v-model="search_term" placeholder="{{ __('admin::app.catalog.products.product-search-hint') }}">
|
||||
|
||||
<input type="hidden" name="up_sell[]" v-for='(product, index) in this.addedProduct' :value="product.id"/>
|
||||
|
||||
<span class="filter-tag" style="text-transform: capitalize; margin-top: 10px; margin-right: 0px; justify-content: flex-start">
|
||||
<span class="wrapper" style="margin-left: 0px; margin-right: 10px;" v-for='(product, index) in this.addedProduct'>
|
||||
@{{ product.name }}
|
||||
<span class="icon cross-icon" @click="removeProduct(product)"></span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<ul>
|
||||
<li v-for='(product, index) in products' style="padding: 10px; border-bottom: 1px solid #e8e8e8; width: 70%; cursor: pointer;" @click="addProduct(product)">
|
||||
@{{ product.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
Vue.component('up-selling', {
|
||||
|
||||
template: '#up-selling-template',
|
||||
|
||||
data: () => ({
|
||||
allProduct: @json($allProducts),
|
||||
|
||||
search_term: '',
|
||||
|
||||
addedProduct: [],
|
||||
|
||||
upSellingProduct: @json($product->up_sells()->get()),
|
||||
}),
|
||||
|
||||
created () {
|
||||
if (this.upSellingProduct.length >= 1) {
|
||||
for (var index in this.upSellingProduct) {
|
||||
this.addedProduct.push(this.upSellingProduct[index]);
|
||||
|
||||
for (var index1 in this.allProduct) {
|
||||
if (this.allProduct[index1].id == this.upSellingProduct[index].id) {
|
||||
this.allProduct.splice(index1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
products () {
|
||||
if (this.search_term.length >= 1) {
|
||||
return this.allProduct.filter(product => {
|
||||
return product.name.toLowerCase().includes(this.search_term.toLowerCase())
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
addProduct(product) {
|
||||
this.addedProduct.push(product);
|
||||
this.search_term = '';
|
||||
|
||||
for (var index in this.allProduct) {
|
||||
if (this.allProduct[index].id == product.id) {
|
||||
this.allProduct.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeProduct(product) {
|
||||
for (var index in this.addedProduct) {
|
||||
if (this.addedProduct[index].id == product.id ) {
|
||||
this.allProduct.push(product);
|
||||
this.addedProduct.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="cross-selling-template">
|
||||
<div>
|
||||
<div class="control-group">
|
||||
<label for="up-selling">{{ __('admin::app.catalog.products.cross-selling') }}</label>
|
||||
<input type="text" class="control" autocomplete="off" v-model="search_term" placeholder="{{ __('admin::app.catalog.products.product-search-hint') }}">
|
||||
|
||||
<input type="hidden" name="cross_sell[]" v-for='(product, index) in this.addedProduct' :value="product.id"/>
|
||||
|
||||
<span class="filter-tag" style="text-transform: capitalize; margin-top: 10px; margin-right: 0px; justify-content: flex-start">
|
||||
<span class="wrapper" style="margin-left: 0px; margin-right: 10px;" v-for='(product, index) in this.addedProduct'>
|
||||
@{{ product.name }}
|
||||
<span class="icon cross-icon" @click="removeProduct(product)"></span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<ul>
|
||||
<li v-for='(product, index) in products' style="padding: 10px; border-bottom: 1px solid #e8e8e8; width: 70%; cursor: pointer;" @click="addProduct(product)">
|
||||
@{{ product.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
Vue.component('cross-selling', {
|
||||
|
||||
template: '#cross-selling-template',
|
||||
|
||||
data: () => ({
|
||||
allProduct: @json($allProducts),
|
||||
|
||||
search_term: '',
|
||||
|
||||
addedProduct: [],
|
||||
|
||||
crossSellingProduct: @json($product->cross_sells()->get()),
|
||||
}),
|
||||
|
||||
created () {
|
||||
if (this.crossSellingProduct.length >= 1) {
|
||||
for (var index in this.crossSellingProduct) {
|
||||
this.addedProduct.push(this.crossSellingProduct[index]);
|
||||
|
||||
for (var index1 in this.allProduct) {
|
||||
if (this.allProduct[index1].id == this.crossSellingProduct[index].id) {
|
||||
this.allProduct.splice(index1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
products () {
|
||||
if (this.search_term.length >= 1) {
|
||||
return this.allProduct.filter(product => {
|
||||
return product.name.toLowerCase().includes(this.search_term.toLowerCase())
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
addProduct(product) {
|
||||
this.addedProduct.push(product);
|
||||
this.search_term = '';
|
||||
|
||||
for (var index in this.allProduct) {
|
||||
if (this.allProduct[index].id == product.id) {
|
||||
this.allProduct.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeProduct(product) {
|
||||
for (var index in this.addedProduct) {
|
||||
if (this.addedProduct[index].id == product.id ) {
|
||||
this.allProduct.push(product);
|
||||
this.addedProduct.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="related-product-template">
|
||||
<div>
|
||||
<div class="control-group">
|
||||
<label for="up-selling">{{ __('admin::app.catalog.products.related-products') }}</label>
|
||||
<input type="text" class="control" autocomplete="off" v-model="search_term" placeholder="{{ __('admin::app.catalog.products.product-search-hint') }}">
|
||||
|
||||
<input type="hidden" name="related_products[]" v-for='(product, index) in this.addedProduct' :value="product.id"/>
|
||||
|
||||
<span class="filter-tag" style="text-transform: capitalize; margin-top: 10px; margin-right: 0px; justify-content: flex-start">
|
||||
<span class="wrapper" style="margin-left: 0px; margin-right: 10px;" v-for='(product, index) in this.addedProduct'>
|
||||
@{{ product.name }}
|
||||
<span class="icon cross-icon" @click="removeProduct(product)"></span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<ul>
|
||||
<li v-for='(product, index) in products' style="padding: 10px; border-bottom: 1px solid #e8e8e8; width: 70%; cursor: pointer;" @click="addProduct(product)">
|
||||
@{{ product.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
Vue.component('related-product', {
|
||||
|
||||
template: '#related-product-template',
|
||||
|
||||
data: () => ({
|
||||
allProduct: @json($allProducts),
|
||||
|
||||
search_term: '',
|
||||
|
||||
addedProduct: [],
|
||||
|
||||
relatedProduct: @json($product->related_products()->get()),
|
||||
}),
|
||||
|
||||
created () {
|
||||
if (this.relatedProduct.length >= 1) {
|
||||
for (var index in this.relatedProduct) {
|
||||
this.addedProduct.push(this.relatedProduct[index]);
|
||||
|
||||
for (var index1 in this.allProduct) {
|
||||
if (this.allProduct[index1].id == this.relatedProduct[index].id) {
|
||||
this.allProduct.splice(index1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
products () {
|
||||
if (this.search_term.length >= 1) {
|
||||
return this.allProduct.filter(product => {
|
||||
return product.name.toLowerCase().includes(this.search_term.toLowerCase())
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
addProduct(product) {
|
||||
this.addedProduct.push(product);
|
||||
this.search_term = '';
|
||||
|
||||
for (var index in this.allProduct) {
|
||||
if (this.allProduct[index].id == product.id) {
|
||||
this.allProduct.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeProduct(product) {
|
||||
for (var index in this.addedProduct) {
|
||||
if (this.addedProduct[index].id == product.id ) {
|
||||
this.allProduct.push(product);
|
||||
this.addedProduct.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@endpush
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
@foreach ($product->attribute_family->attribute_groups as $attributeGroup)
|
||||
|
||||
@if (count($attributeGroup->custom_attributes))
|
||||
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.' . $attributeGroup->name . '.before', ['product' => $product]) !!}
|
||||
|
||||
<accordian :title="'{{ __($attributeGroup->name) }}'" :active="true">
|
||||
|
|
@ -154,24 +154,26 @@
|
|||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.images.before', ['product' => $product]) !!}
|
||||
|
||||
@include ('admin::catalog.products.accordians.images')
|
||||
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.images.after', ['product' => $product]) !!}
|
||||
|
||||
|
||||
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.categories.before', ['product' => $product]) !!}
|
||||
|
||||
@include ('admin::catalog.products.accordians.categories')
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.categories.after', ['product' => $product]) !!}
|
||||
|
||||
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.variations.before', ['product' => $product]) !!}
|
||||
|
||||
@include ('admin::catalog.products.accordians.variations')
|
||||
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.variations.after', ['product' => $product]) !!}
|
||||
|
||||
@include ('admin::catalog.products.accordians.product-links')
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
</head>
|
||||
|
||||
<body @if (app()->getLocale() == 'ar') class="rtl" @endif style="scroll-behavior: smooth;">
|
||||
<body @if (app()->getLocale() == 'ar') @endif style="scroll-behavior: smooth;">
|
||||
{!! view_render_event('bagisto.admin.layout.body.before') !!}
|
||||
|
||||
<div id="app">
|
||||
|
|
|
|||
|
|
@ -173,7 +173,9 @@ class ProductController extends Controller
|
|||
|
||||
$inventorySources = $this->inventorySource->all();
|
||||
|
||||
return view($this->_config['view'], compact('product', 'categories', 'inventorySources'));
|
||||
$allProducts = $this->productGrid->all();
|
||||
|
||||
return view($this->_config['view'], compact('product', 'categories', 'inventorySources', 'allProducts'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ class Product extends Model implements ProductContract
|
|||
*/
|
||||
public function related_products()
|
||||
{
|
||||
return $this->belongsToMany(self::class, 'product_relations');
|
||||
return $this->belongsToMany(self::class, 'product_relations', 'parent_id', 'child_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -136,7 +136,7 @@ class Product extends Model implements ProductContract
|
|||
*/
|
||||
public function cross_sells()
|
||||
{
|
||||
return $this->belongsToMany(self::class, 'product_cross_sells');
|
||||
return $this->belongsToMany(self::class, 'product_cross_sells', 'parent_id', 'child_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -194,6 +194,18 @@ class ProductRepository extends Repository
|
|||
$product->categories()->sync($data['categories']);
|
||||
}
|
||||
|
||||
if (isset($data['up_sell'])) {
|
||||
$product->up_sells()->sync($data['up_sell']);
|
||||
}
|
||||
|
||||
if (isset($data['cross_sell'])) {
|
||||
$product->cross_sells()->sync($data['cross_sell']);
|
||||
}
|
||||
|
||||
if (isset($data['related_products'])) {
|
||||
$product->related_products()->sync($data['related_products']);
|
||||
}
|
||||
|
||||
$previousVariantIds = $product->variants->pluck('id');
|
||||
|
||||
if (isset($data['variants'])) {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"/js/shop.js": "/js/shop.js?id=e019a3a0b0cbcc981fd8",
|
||||
"/css/shop.css": "/css/shop.css?id=eaecc148d722f7ddb419"
|
||||
"/css/shop.css": "/css/shop.css?id=6a1fef3231745a7b94ce"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1679,6 +1679,7 @@ section.product-detail {
|
|||
div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
cursor: pointer;
|
||||
|
||||
.thumb-list {
|
||||
display: flex;
|
||||
|
|
@ -3461,13 +3462,6 @@ section.review {
|
|||
}
|
||||
}
|
||||
|
||||
// .sticky {
|
||||
// position: fixed;
|
||||
// top: 10px;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
/// rtl css start here
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
|
|
|
|||
|
|
@ -311,6 +311,8 @@ return [
|
|||
'total-rating' => ':total_rating Ratings & :total_reviews Reviews',
|
||||
'by' => 'By :name',
|
||||
'up-sell-title' => 'We found other products you might like!',
|
||||
'related-product-title' => 'Related Products',
|
||||
'cross-sell-title' => 'More choices',
|
||||
'reviews-title' => 'Ratings & Reviews',
|
||||
'write-review-btn' => 'Write Review',
|
||||
'choose-option' => 'Choose an option',
|
||||
|
|
|
|||
|
|
@ -138,6 +138,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
@include ('shop::products.view.cross-sells')
|
||||
|
||||
@else
|
||||
|
||||
<div class="title">
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@
|
|||
</product-view>
|
||||
</div>
|
||||
|
||||
@include ('shop::products.view.related-products')
|
||||
|
||||
@include ('shop::products.view.up-sells')
|
||||
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
@foreach ($cart->items as $item)
|
||||
<?php
|
||||
$products[] = $item->product;
|
||||
?>
|
||||
@endforeach
|
||||
|
||||
@if ($products)
|
||||
<div class="attached-products-wrapper mt-50">
|
||||
|
||||
<div class="title">
|
||||
{{ __('shop::app.products.cross-sell-title') }}
|
||||
<span class="border-bottom"></span>
|
||||
</div>
|
||||
|
||||
<div class="product-grid-4">
|
||||
|
||||
@foreach ($products as $product)
|
||||
|
||||
@foreach ($product->cross_sells()->paginate(4) as $cross_sell_product)
|
||||
|
||||
@include ('shop::products.list.card', ['product' => $cross_sell_product])
|
||||
|
||||
@endforeach
|
||||
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
@if ($product->related_products()->count())
|
||||
<div class="attached-products-wrapper">
|
||||
|
||||
<div class="title">
|
||||
{{ __('shop::app.products.related-product-title') }}
|
||||
<span class="border-bottom"></span>
|
||||
</div>
|
||||
|
||||
<div class="product-grid-4">
|
||||
|
||||
@foreach ($product->related_products()->paginate(4) as $related_product)
|
||||
|
||||
@include ('shop::products.list.card', ['product' => $related_product])
|
||||
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<span class="border-bottom"></span>
|
||||
</div>
|
||||
|
||||
<div class="product-grid max-4-col">
|
||||
<div class="product-grid-4">
|
||||
|
||||
@foreach ($product->up_sells()->paginate(4) as $up_sell_product)
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"/js/ui.js": "/js/ui.js?id=83b5b520995eba4ce1f3",
|
||||
"/js/ui.js": "/js/ui.js?id=a848b9f99be94788bc58",
|
||||
"/css/ui.css": "/css/ui.css?id=6e9dd13119891a48ec16"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue