compare product's dynamic attributes

This commit is contained in:
shubhammehrotra.symfony@webkul.com 2020-02-27 16:14:00 +05:30
parent b56dc467f9
commit 13312e8234
20 changed files with 244 additions and 171 deletions

View File

@ -558,6 +558,7 @@ return [
'file' => 'File',
'checkbox' => 'Checkbox',
'use_in_flat' => "Create in Product Flat Table",
'is_comparable' => "Attribute is comparable",
'default_null_option' => 'Create default empty option',
],
'families' => [

View File

@ -278,6 +278,18 @@
</select>
</div>
<div class="control-group">
<label for="is_comparable">{{ __('admin::app.catalog.attributes.is_comparable') }}</label>
<select class="control" id="is_comparable" name="is_comparable">
<option value="0" {{ $attribute->is_comparable ? '' : 'selected' }}>
{{ __('admin::app.catalog.attributes.no') }}
</option>
<option value="1" {{ $attribute->is_comparable ? 'selected' : '' }}>
{{ __('admin::app.catalog.attributes.yes') }}
</option>
</select>
</div>
{!! view_render_event('bagisto.admin.catalog.attribute.edit_form_accordian.configuration.controls.after', ['attribute' => $attribute]) !!}
</div>

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIsComparableColumnInAttributesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('attributes', function (Blueprint $table) {
$table->boolean('is_comparable')->default(0);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('attributes', function (Blueprint $table) {
$table->dropColumn('is_comparable');
});
}
}

View File

@ -9,7 +9,7 @@ class Attribute extends TranslatableModel implements AttributeContract
{
public $translatedAttributes = ['name'];
protected $fillable = ['code', 'admin_name', 'type', 'position', 'is_required', 'is_unique', 'validation', 'value_per_locale', 'value_per_channel', 'is_filterable', 'is_configurable', 'is_visible_on_front', 'is_user_defined', 'swatch_type', 'use_in_flat'];
protected $fillable = ['code', 'admin_name', 'type', 'position', 'is_required', 'is_unique', 'validation', 'value_per_locale', 'value_per_channel', 'is_filterable', 'is_configurable', 'is_visible_on_front', 'is_user_defined', 'swatch_type', 'use_in_flat', 'is_comparable'];
// protected $with = ['options'];
@ -31,4 +31,9 @@ class Attribute extends TranslatableModel implements AttributeContract
{
return $query->where('is_filterable', 1)->where('swatch_type', '<>', 'image')->orderBy('position');
}
public function getComparableAttributes()
{
return $this->where('is_comparable', 1)->orderBy('position')->get();
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"/js/velocity.js": "/js/velocity.js?id=ea0f113122857a688255",
"/js/velocity.js": "/js/velocity.js?id=aef73c42397bf4f03142",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=612d35e452446366eef7",
"/css/velocity.css": "/css/velocity.css?id=01b995ccf539cbf38183"
"/css/velocity.css": "/css/velocity.css?id=5f7ada13d04d6f7e4d80"
}

View File

@ -34,16 +34,25 @@
if (existingItems) {
existingItems = JSON.parse(existingItems);
updatedItems = existingItems.concat([this.slug]);
if (existingItems.indexOf(this.slug) == -1) {
updatedItems = existingItems.concat([this.slug]);
window.localStorage.setItem('compared_product', JSON.stringify(updatedItems));
window.showAlert(
`alert-success`,
this.__('shop.general.alert.success'),
`${this.__('customer.compare.added')} <a href="${this.baseUrl}/comparison">compare</a>`
);
} else {
window.showAlert(
`alert-success`,
this.__('shop.general.alert.success'),
`${this.__('customer.compare.already_added')} <a href="${this.baseUrl}/comparison">compare</a>`
);
}
}
window.localStorage.setItem('compared_product', JSON.stringify(updatedItems));
window.showAlert(
`alert-success`,
this.__('shop.general.alert.success'),
`${this.__('customer.compare.added')} <a href="${this.baseUrl}/comparison">compare</a>`
);
}
}
}

View File

@ -11,9 +11,9 @@
:key="categoryIndex"
:id="`category-${category.id}`"
class="category-content cursor-pointer"
v-for="(category, categoryIndex) in slicedCategories"
@mouseout="toggleSidebar(id, $event, 'mouseout')"
@mouseover="toggleSidebar(id, $event, 'mouseover')">
@mouseover="toggleSidebar(id, $event, 'mouseover')"
v-for="(category, categoryIndex) in slicedCategories">
<a
:class="`category unset ${(category.children.length > 0) ? 'fw6' : ''}`"
@ -28,7 +28,9 @@
v-if="category.category_icon_path"
:src="`${$root.baseUrl}/storage/${category.category_icon_path}`" />
</div>
<span class="category-title">{{ category['name'] }}</span>
<i
class="rango-arrow-right pr15 pull-right"
@mouseout="toggleSidebar(id, $event, 'mouseout')"
@ -44,8 +46,9 @@
<div :class="`sub-categories sub-category-${sidebarLevel+categoryIndex}`">
<nav
class="sidebar"
@mouseover="remainBar(`sidebar-level-${sidebarLevel+categoryIndex}`)"
:id="`sidebar-level-${sidebarLevel+categoryIndex}`">
:id="`sidebar-level-${sidebarLevel+categoryIndex}`"
@mouseover="remainBar(`sidebar-level-${sidebarLevel+categoryIndex}`)">
<ul type="none">
<li
:key="`${subCategoryIndex}-${categoryIndex}`"
@ -143,7 +146,7 @@
slicedCategories['parentSlug'] = this.parentSlug;
this.slicedCategories = slicedCategories;
}
},
}
}
</script>

View File

@ -69,6 +69,12 @@ $(document).ready(function () {
route ? window.location.href = route : '';
},
debounceToggleSidebar: function (id, {target}, type) {
// setTimeout(() => {
this.toggleSidebar(id, target, type);
// }, 500);
},
toggleSidebar: function (id, {target}, type) {
if (
Array.from(target.classList)[0] == "main-category"

View File

@ -510,6 +510,18 @@ header {
}
}
}
~ .compare-btn {
height: 50px;
float: right;
font-size: 18px;
font-weight: 600;
padding: 10px 16px 6px 16px;
i {
vertical-align: middle;
}
}
}
.dropdown-menu-large {

View File

@ -2223,66 +2223,39 @@
}
.compare-products {
.col,
.col-2 {
padding: 0;
padding-left: 0;
max-width: 20%;
}
> .row:nth-child(1) {
margin: 0;
.image-wrapper {
width: 100%;
}
> div {
width: 100%;
margin-top: 25px;
.stars {
i {
font-size: 16px;
}
}
&.product-title {
margin: 0;
font-size: 16px;
.action {
position: relative;
h3 {
font-weight: 600;
}
}
.close-btn {
right: 0;
top: 6px;
position: absolute;
display: inline-block;
&.product-price {
margin-top: 15px;
}
&:hover {
font-weight: 600;
}
}
.image-wrapper {
overflow: hidden;
img {
width: 100%;
}
}
.stars {
i {
font-size: 16px;
}
}
.action {
position: relative;
.close-btn {
right: 0;
top: 6px;
position: absolute;
display: inline-block;
&:hover {
font-weight: 600;
}
}
.compare-icon {
display: none;
}
}
.compare-icon {
display: none;
}
}
}

View File

@ -124,7 +124,7 @@
margin-top: 10px;
}
.mt15 {
margin-top: 15px;
margin-top: 15px !important;
}
.mr5 {
margin-right: 5px;

View File

@ -13,6 +13,7 @@ return [
'compare_similar_items' => 'مقارنة العناصر المماثلة',
'added' => 'تمت إضافة العنصر بنجاح لمقارنة القائمة',
'removed' => 'تمت إزالة العنصر بنجاح من قائمة المقارنة',
'already_added' => 'تمت إضافة العنصر بالفعل لمقارنة القائمة',
'empty-text' => "ليس لديك أي عناصر في قائمة المقارنة الخاصة بك",
],
'login-form' => [

View File

@ -192,6 +192,7 @@ return [
'text' => 'Compare',
'compare_similar_items' => 'Compare Similar Items',
'added' => 'Item successfully added to compare list',
'already_added' => 'Item already added to compare list',
'removed' => 'Item successfully removed from compare list',
'empty-text' => "You don't have any items in your compare list",
],

View File

@ -11,6 +11,7 @@ return [
'compare' => [
'text' => 'Comparar',
'compare_similar_items' => 'Comparar itens semelhantes',
'already_added' => 'Item já adicionado à lista de comparação',
'added' => 'Item adicionado com sucesso à lista de comparação',
'removed' => 'Item removido com sucesso da lista de comparação',
'empty-text' => "Você não possui nenhum item na sua lista de comparação",

View File

@ -118,6 +118,13 @@
{!! view_render_event('bagisto.shop.layout.header.cart-item.before') !!}
@include('shop::checkout.cart.mini-cart')
{!! view_render_event('bagisto.shop.layout.header.cart-item.after') !!}
{!! view_render_event('bagisto.shop.layout.header.compare.before') !!}
<a class="compare-btn unset" href="{{ route('velocity.product.compare') }}">
<i class="material-icons">compare_arrows</i>
<span>Compare</span>
</a>
{!! view_render_event('bagisto.shop.layout.header.compare.after') !!}
</div>
</div>
</script>

View File

@ -98,7 +98,6 @@
</div>
</div>
</div>
</div>
@else
<div class="dropdown disable-active">

View File

@ -5,58 +5,66 @@
@endsection
@section('content-wrapper')
@php
$attributeModel = app('\Webkul\Attribute\Models\Attribute');
$comparableAttributes = $attributeModel->getComparableAttributes();
@endphp
<section class="cart-details row no-margin col-12">
<h1 class="fw6 col-12">
{{ __('velocity::app.customer.compare.compare_similar_items') }}
</h1>
{!! view_render_event('bagisto.shop.customers.account.compare.view.before') !!}
<compare-product></compare-product>
{!! view_render_event('bagisto.shop.customers.account.compare.view.after') !!}
</section>
<compare-product></compare-product>
@endsection
@push('scripts')
<script type="text/x-template" id="compare-product-template">
<div class="row compare-products col-12 ml0">
<div class="col" :key="index" v-for="(product, index) in products">
<div class="row col-12 pl0">
<div class="product-title">
<h3>@{{ product.name }}</h3>
</div>
<section class="cart-details row no-margin col-12">
<h1 class="fw6 col-6">
{{ __('velocity::app.customer.compare.compare_similar_items') }}
</h1>
<div class='image-wrapper'>
<img :src="product.image" />
</div>
<div class="product-price" v-html="product.priceHTML"></div>
<div class="product-reviews">
<star-ratings :ratings="product.avgRating"></star-ratings>
<a class="fs14 align-top unset active-hover" :href="`${$root.baseUrl}/reviews/${product.slug}`">
@{{ __('products.reviews-count', {'totalReviews': product.totalReviews}) }}
</a>
</div>
<div class="action">
<vnode-injector :nodes="getAddToCartHtml(product.addToCartHtml)"></vnode-injector>
<div class="close-btn rango-close fs18 cursor-pointer" @click="removeProductCompare(product.slug)"></div>
</div>
<div class="product-description">
<p v-html="product.description"></p>
</div>
</div>
<div class="col-6" v-if="products.length > 0">
<button class="theme-btn light pull-right" @click="removeProductCompare('all')">Clear All</button>
</div>
<span v-if="isProductListLoaded && products.length == 0">
@{{ __('customer.compare.empty-text') }}
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.compare.view.before') !!}
<div class="row compare-products col-12 ml0">
<template v-if="products.length > 0">
@php
$comparableAttributes = $comparableAttributes->toArray();
array_splice($comparableAttributes, 1, 0, [[
'code' => 'image',
'admin_name' => 'Product Image'
]]);
@endphp
@foreach ($comparableAttributes as $attribute)
<div class="row col-12 pr-0 mt15">
<div class="col-2">
<span>{{ $attribute['admin_name'] }}</span>
</div>
<div class="product-title col" :key="`title-${index}`" v-for="(product, index) in products">
@if ($attribute['code'] == 'name')
<h1 class="fw6" v-text="product['{{ $attribute['code'] }}']"></h1>
@elseif ($attribute['code'] == 'image')
<img :src="product['{{ $attribute['code'] }}']" class="image-wrapper"></span>
@elseif ($attribute['code'] == 'price')
<span v-html="product['priceHTML']"></span>
@else
<span v-html="product['{{ $attribute['code'] }}']"></span>
@endif
</div>
</div>
@endforeach
</template>
<span v-if="isProductListLoaded && products.length == 0">
@{{ __('customer.compare.empty-text') }}
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.compare.view.after') !!}
</section>
</script>
<script>
@ -120,8 +128,13 @@
let existingItems = window.localStorage.getItem('compared_product');
existingItems = JSON.parse(existingItems);
updatedItems = existingItems.filter(item => item != slug);
this.$set(this, 'products', this.products.filter(product => product.slug != slug));
if (slug == "all") {
updatedItems = [];
this.$set(this, 'products', []);
} else {
updatedItems = existingItems.filter(item => item != slug);
this.$set(this, 'products', this.products.filter(product => product.slug != slug));
}
window.localStorage.setItem('compared_product', JSON.stringify(updatedItems));
@ -148,6 +161,6 @@
return output;
}
}
})
});
</script>
@endpush

View File

@ -1,30 +1,8 @@
{!! view_render_event('bagisto.shop.products.add_to_cart.before', ['product' => $product]) !!}
<div class="row mx-0 col-12 no-padding">
<div class="add-to-cart-btn pl0">
@if (isset($form) && !$form)
<button
type="submit"
{{ ! $product->isSaleable() ? 'disabled' : '' }}
class="btn btn-add-to-cart {{ $addToCartBtnClass ?? '' }}">
@if (! (isset($showCartIcon) && !$showCartIcon))
<i class="material-icons text-down-3">shopping_cart</i>
@endif
<span class="fs14 fw6 text-uppercase text-up-4">
{{ __('shop::app.products.add-to-cart') }}
</span>
</button>
@else
<form
method="POST"
action="{{ route('cart.add', $product->product_id) }}">
@csrf
<input type="hidden" name="product_id" value="{{ $product->product_id }}">
<input type="hidden" name="quantity" value="1">
<div class="row mx-0 col-12 no-padding">
<div class="add-to-cart-btn pl0">
@if (isset($form) && !$form)
<button
type="submit"
{{ ! $product->isSaleable() ? 'disabled' : '' }}
@ -35,38 +13,58 @@
@endif
<span class="fs14 fw6 text-uppercase text-up-4">
{{ $btnText ?? __('shop::app.products.add-to-cart') }}
{{ __('shop::app.products.add-to-cart') }}
</span>
</button>
</form>
@else
<form method="POST" action="{{ route('cart.add', $product->product_id) }}">
@csrf
{{-- <add-to-cart
form="true"
csrf-token='{{ csrf_token() }}'
product-id="{{ $product->product_id }}"
add-class-to-btn="{{ $addToCartBtnClass ?? '' }}"
is-enable={{ ! $product->isSaleable() ? 'false' : 'true' }}
show-cart-icon={{ !(isset($showCartIcon) && !$showCartIcon) }}
btn-text="{{ $btnText ?? __('shop::app.products.add-to-cart') }}">
</add-to-cart> --}}
<input type="hidden" name="quantity" value="1" />
<input type="hidden" name="product_id" value="{{ $product->product_id }}" />
<button
type="submit"
{{ ! $product->isSaleable() ? 'disabled' : '' }}
class="btn btn-add-to-cart {{ $addToCartBtnClass ?? '' }}">
@if (! (isset($showCartIcon) && !$showCartIcon))
<i class="material-icons text-down-3">shopping_cart</i>
@endif
<span class="fs14 fw6 text-uppercase text-up-4">
{{ $btnText ?? __('shop::app.products.add-to-cart') }}
</span>
</button>
</form>
{{-- <add-to-cart
form="true"
csrf-token='{{ csrf_token() }}'
product-id="{{ $product->product_id }}"
add-class-to-btn="{{ $addToCartBtnClass ?? '' }}"
is-enable={{ ! $product->isSaleable() ? 'false' : 'true' }}
show-cart-icon={{ !(isset($showCartIcon) && !$showCartIcon) }}
btn-text="{{ $btnText ?? __('shop::app.products.add-to-cart') }}">
</add-to-cart> --}}
@endif
</div>
@if (isset($showCompare) && $showCompare)
@auth('customer')
<compare-component slug="{{ $product->url_key }}" customer="true"></compare-component>
@endif
@guest('customer')
<compare-component slug="{{ $product->url_key }}" customer="false"></compare-component>
@endif
@endif
@if (! (isset($showWishlist) && !$showWishlist))
@include('shop::products.wishlist', [
'addClass' => $addWishlistClass ?? ''
])
@endif
</div>
@if (isset($showCompare) && $showCompare)
@auth('customer')
<compare-component slug="{{ $product->url_key }}" customer="true"></compare-component>
@endif
@guest('customer')
<compare-component slug="{{ $product->url_key }}" customer="false"></compare-component>
@endif
@endif
@if (! (isset($showWishlist) && !$showWishlist))
@include('shop::products.wishlist', [
'addClass' => $addWishlistClass ?? ''
])
@endif
</div>
{!! view_render_event('bagisto.shop.products.add_to_cart.after', ['product' => $product]) !!}