Merge branch 'master' into issue-4119

Merged With Master
This commit is contained in:
devansh bawari 2020-11-10 14:52:22 +05:30
commit 4a7f4bf986
65 changed files with 1819 additions and 2433 deletions

View File

@ -5,9 +5,9 @@
"framework",
"laravel"
],
"license": "MIT",
"type": "project",
"require": {
"php": "^7.2.5",
"ext-curl": "*",
@ -25,6 +25,7 @@
"doctrine/dbal": "2.9.2",
"fideloper/proxy": "^4.2",
"flynsarmy/db-blade-compiler": "^5.5",
"fzaninotto/faker": "^1.4",
"guzzlehttp/guzzle": "~6.3",
"intervention/image": "^2.4",
"intervention/imagecache": "^2.3",
@ -48,7 +49,6 @@
"codeception/module-laravel5": "^1.0",
"codeception/module-webdriver": "^1.0",
"filp/whoops": "^2.0",
"fzaninotto/faker": "^1.4",
"mockery/mockery": "^1.3.1",
"nunomaduro/collision": "^4.1",
"phpunit/phpunit": "^8.5"
@ -123,7 +123,6 @@
"extra": {
"laravel": {
"dont-discover": [
"barryvdh/laravel-debugbar",
"laravel/dusk"
]
}
@ -143,6 +142,7 @@
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover"
],
"test": [
"set -e",
"@php artisan migrate:fresh --env=testing",

2743
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -246,8 +246,6 @@ return [
//Laravel Maatwebsite
Maatwebsite\Excel\ExcelServiceProvider::class,
Barryvdh\Debugbar\ServiceProvider::class,
//Repository
Prettus\Repository\Providers\RepositoryServiceProvider::class,
Konekt\Concord\ConcordServiceProvider::class,

View File

@ -31,6 +31,8 @@ class Product extends JsonResource
{
$product = $this->product ? $this->product : $this;
$prices = $product->getTypeInstance()->getProductPrices();
return [
'id' => $product->id,
'type' => $product->type,
@ -49,13 +51,21 @@ class Product extends JsonResource
'super_attributes' => Attribute::collection($product->super_attributes),
]),
'special_price' => $this->when(
$product->getTypeInstance()->haveSpecialPrice(),
$product->getTypeInstance()->getSpecialPrice()
),
$product->getTypeInstance()->haveSpecialPrice(),
$product->getTypeInstance()->getSpecialPrice()
),
'formated_special_price' => $this->when(
$product->getTypeInstance()->haveSpecialPrice(),
core()->currency($product->getTypeInstance()->getSpecialPrice())
),
$product->getTypeInstance()->haveSpecialPrice(),
core()->currency($product->getTypeInstance()->getSpecialPrice())
),
'regular_price' => $this->when(
$product->getTypeInstance()->haveSpecialPrice(),
data_get($prices, 'regular_price.price')
),
'formated_regular_price' => $this->when(
$product->getTypeInstance()->haveSpecialPrice(),
data_get($prices, 'regular_price.formated_price')
),
'reviews' => [
'total' => $total = $this->productReviewHelper->getTotalReviews($product),
'total_rating' => $total ? $this->productReviewHelper->getTotalRating($product) : 0,
@ -67,4 +77,4 @@ class Product extends JsonResource
'updated_at' => $this->updated_at,
];
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/js/admin.js": "/js/admin.js?id=b022291aa1cad7dfcc84",
"/js/admin.js": "/js/admin.js?id=c849d3c02afc5071f801",
"/css/admin.css": "/css/admin.css?id=f2b20e4283a639808ef6"
}

View File

@ -99,6 +99,14 @@ class CategoryDataGrid extends DataGrid
'route' => 'admin.catalog.categories.delete',
'confirm_text' => trans('ui::app.datagrid.massaction.delete', ['resource' => 'product']),
'icon' => 'icon trash-icon',
'function' => 'deleteFunction($event, "delete")'
]);
$this->addMassAction([
'type' => 'delete',
'label' => trans('admin::app.datagrid.delete'),
'action' => route('admin.catalog.categories.massdelete'),
'method' => 'DELETE',
]);
}
}

View File

@ -7,18 +7,6 @@ use Excel;
class ExportController extends Controller
{
protected $exportableGrids = [
'OrderDataGrid',
'OrderInvoicesDataGrid',
'OrderShipmentsDataGrid',
'OrderRefundDataGrid',
'CustomerDataGrid',
'TaxRateDataGrid',
'ProductDataGrid',
'CMSPageDataGrid',
'CartRuleCouponDataGrid'
];
/**
* Create a new controller instance.
*
@ -44,18 +32,6 @@ class ExportController extends Controller
$path = '\Webkul\Admin\DataGrids'.'\\'.last($gridName);
$proceed = false;
foreach ($this->exportableGrids as $exportableGrid) {
if (last($gridName) == $exportableGrid) {
$proceed = true;
}
}
if (! $proceed) {
return redirect()->back();
}
$gridInstance = new $path;
$records = $gridInstance->export();

View File

@ -335,6 +335,13 @@ Route::group(['middleware' => ['web']], function () {
Route::post('/categories/delete/{id}', 'Webkul\Category\Http\Controllers\CategoryController@destroy')->name('admin.catalog.categories.delete');
//category massdelete
Route::post('categories/massdelete', 'Webkul\Category\Http\Controllers\CategoryController@massDestroy')->defaults('_config', [
'redirect' => 'admin.catalog.categories.index',
])->name('admin.catalog.categories.massdelete');
Route::post('/categories/product/count', 'Webkul\Category\Http\Controllers\CategoryController@categoryProductCount')->name('admin.catalog.categories.product.count');
// Catalog Attribute Routes
Route::get('/attributes', 'Webkul\Attribute\Http\Controllers\AttributeController@index')->defaults('_config', [

View File

@ -17,6 +17,8 @@ Vue.use(VeeValidate, {
});
Vue.prototype.$http = axios
Vue.component('required-if', require('./components/validators/required-if').default);
window.eventBus = new Vue();
$(document).ready(function () {

View File

@ -0,0 +1,78 @@
<template>
<div class="control-group" :class="[errors.has(name) ? 'has-error' : '']">
<label :for="name" :class="checkValidations">
{{ label }}
<span class="locale"> [{{ channel_locale }}] </span>
</label>
<select v-if="this.options.length" v-validate="checkValidations" class="control" :id = "name" :name = "name" v-model="savedValue"
:data-vv-as="label">
<option v-for='(option, index) in this.options' :value="option.value"> {{ option.title }} </option>
</select>
<input v-else type="text" class="control" v-validate="checkValidations" :id = "name" :name = "name" v-model="savedValue"
:data-vv-as="label">
<span class="control-error" v-if="errors.has(name)">
{{ errors.first(name) }}
</span>
</div>
</template>
<script>
export default {
props: [
'name',
'label',
'options',
'result',
'validations',
'depend',
'dependResult',
'channel_locale',
],
inject: ['$validator'],
data: function() {
return {
isRequire: false,
checkValidations: [],
savedValue: this.result,
dependSavedValue: parseInt(this.dependResult)
}
},
mounted: function () {
this.isRequire = this.dependSavedValue ? true : false;
this.updateValidations();
$(document.getElementById(this.depend)).on('change', (e) => {
this.dependSavedValue = !this.dependSavedValue;
this.dependSavedValue = this.dependSavedValue ? 1 : 0;
this.isRequire = this.dependSavedValue ? true : false;
this.updateValidations();
});
},
methods: {
updateValidations: function () {
this.checkValidations = this.validations.split('|').filter(validation => !this.validations.includes('required_if'));
if (this.isRequire) {
this.checkValidations.push('required');
} else {
this.checkValidations = this.checkValidations.filter((value) => {
return value !== 'required';
});
}
this.checkValidations = this.checkValidations.join('|');
}
}
}
</script>

View File

@ -1355,12 +1355,19 @@ return [
'vat-number' => 'ظريبه الشراء',
'contact-number' => 'رقم الاتصال',
'bank-details' => 'التفاصيل المصرفية',
'instructions' => 'Instructions',
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.',
'mailing-address' => 'أرسل الشيك إلى',
'instructions' => 'تعليمات',
'custom-scripts' => 'البرامج النصية المخصصة',
'custom-css' => 'لغة تنسيق ويب حسب الطلب',
'custom-javascript' => 'جافا سكريبت مخصص',
'paypal-smart-button' => 'زر Paypal الذكي',
'paypal-smart-button' => 'زر PayPal الذكي',
'client-id' => 'معرف العميل',
'client-id-info' => 'استخدم "sb" للاختبار.'
]

View File

@ -1338,7 +1338,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
],

View File

@ -1290,7 +1290,7 @@ return [
'payment-methods' => 'Payment Methods',
'cash-on-delivery' => 'Cash On Delivery',
'money-transfer' => 'Money Transfer',
'paypal-standard' => 'Paypal Standard',
'paypal-standard' => 'PayPal Standard',
'business-account' => 'Business Account',
'newsletter' => 'NewsLetter Subscription',
'newsletter-subscription' => 'Allow NewsLetter Subscription',
@ -1364,7 +1364,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
]

View File

@ -1274,7 +1274,7 @@ return [
'payment-methods' => 'Métodos de pago',
'cash-on-delivery' => 'Pago contraentrega',
'money-transfer' => 'Transferencia',
'paypal-standard' => 'Paypal',
'paypal-standard' => 'PayPal',
'business-account' => 'Cuenta de negocio',
'newsletter' => 'Suscripción a newsletter',
'newsletter-subscription' => 'Permitir suscripciones a newsletter',
@ -1320,7 +1320,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
]

View File

@ -1356,7 +1356,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
]

View File

@ -1285,7 +1285,7 @@ return [
'payment-methods' => 'Metodi di Pagamento',
'cash-on-delivery' => 'Contrassegno',
'money-transfer' => 'Bonifico',
'paypal-standard' => 'Paypal Standard',
'paypal-standard' => 'PayPal Standard',
'business-account' => 'Account Business',
'newsletter' => 'Iscrizione a NewsLetter',
'newsletter-subscription' => 'Consenti Iscrizione a NewsLetter',
@ -1361,7 +1361,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
]

View File

@ -1281,7 +1281,7 @@ return [
'payment-methods' => 'Betaalmethodes',
'cash-on-delivery' => 'Rembours',
'money-transfer' => 'Overschrijving',
'paypal-standard' => 'Paypal Standard',
'paypal-standard' => 'PayPal Standard',
'business-account' => 'Zakelijk account',
'newsletter' => 'Nieuwsbrief',
'newsletter-subscription' => 'Abonnement op Nieuwsbrief toestaan',
@ -1356,7 +1356,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
]

View File

@ -1282,7 +1282,7 @@ return [
'payment-methods' => 'Metody płatności',
'cash-on-delivery' => 'Za pobraniem',
'money-transfer' => 'Przekaz pieniężny',
'paypal-standard' => 'Paypal Standard',
'paypal-standard' => 'PayPal Standard',
'business-account' => 'Konto biznesowe',
'newsletter' => 'Subskrypcja newslettera',
'newsletter-subscription' => 'Zezwól na subskrypcję newslettera',
@ -1345,7 +1345,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
]

View File

@ -1281,7 +1281,7 @@ return [
'payment-methods' => 'Métodos de Pagamento',
'cash-on-delivery' => 'Dinheiro na entrega',
'money-transfer' => 'Transferência de dinheiro',
'paypal-standard' => 'Padrão Paypal',
'paypal-standard' => 'Padrão PayPal',
'business-account' => 'Conta de negócios',
'newsletter' => 'Assinatura de Newsletter',
'newsletter-subscription' => 'Permitir assinatura do NewsLetter',
@ -1359,7 +1359,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
]

View File

@ -1269,7 +1269,7 @@ return [
'payment-methods' => 'Ödeme Türleri',
'cash-on-delivery' => 'Kapıda Ödeme',
'money-transfer' => 'Havale/EFT',
'paypal-standard' => 'Paypal',
'paypal-standard' => 'PayPal',
'business-account' => 'İş Hesabı',
'newsletter' => 'Bülten Aboneliği',
'newsletter-subscription' => 'Bülten Aboneliğine İzin Ver',
@ -1342,7 +1342,7 @@ return [
'custom-scripts' => 'Custom Scripts',
'custom-css' => 'Custom CSS',
'custom-javascript' => 'Custom Javascript',
'paypal-smart-button' => 'Paypal Smart Button',
'paypal-smart-button' => 'PayPal',
'client-id' => 'Client Id',
'client-id-info' => 'Use "sb" for testing.'
]

View File

@ -26,4 +26,58 @@
{!! view_render_event('bagisto.admin.catalog.categories.list.after') !!}
</div>
@stop
@stop
@push('scripts')
<script>
$(document).ready(function(){
$("input[type='checkbox']").change(deleteFunction);
});
var deleteFunction = function(e,type) {
if (type == 'delete') {
var indexes = $(e.target).parent().attr('id');
} else {
$("input[type='checkbox']").attr('disabled', true);
var formData = {};
$.each($('form').serializeArray(), function(i, field) {
formData[field.name] = field.value;
});
var indexes = formData.indexes;
}
if (indexes) {
$.ajax({
type : 'POST',
url : '{{route("admin.catalog.categories.product.count")}}',
data : {
_token: '{{csrf_token()}}',
indexes: indexes
},
success:function(data) {
$("input[type='checkbox']").attr('disabled', false);
if (data.product_count > 0) {
var message = "{{trans('ui::app.datagrid.massaction.delete-category-product')}}";
if (type == 'delete') {
doAction(e, message);
} else {
$('form').attr('onsubmit', 'return confirm("'+message+'")');
}
} else {
var message = "{{ __('ui::app.datagrid.click_on_action') }}";
if (type == 'delete') {
doAction(e, message);
} else {
$('form').attr('onsubmit', 'return confirm("'+message+'")');
}
}
}
});
} else {
$("input[type='checkbox']").attr('disabled', false);
}
}
</script>
@endpush

View File

@ -65,18 +65,33 @@
}
$selectedOption = core()->getConfigData($name) ?? '';
$dependSelectedOption = core()->getConfigData(implode('.', [$firstField, $secondField, $thirdField, $dependField])) ?? '';
?>
<depends
:options = '@json($field['options'])'
:name = "'{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]'"
:validations = "'{{ $validations }}'"
:depend = "'{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $dependField }}]'"
:value = "'{{ $dependValue }}'"
:field_name = "'{{ trans($field['title']) }}'"
:channel_locale = "'{{ $channel_locale }}'"
:result = "'{{ $selectedOption }}'"
></depends>
@if (strpos($field['validation'], 'required_if') !== false)
<required-if
:name = "'{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]'"
:label = "'{{ trans($field['title']) }}'"
:options = '@json($field['options'])'
:result = "'{{ $selectedOption }}'"
:validations = "'{{ $validations }}'"
:depend = "'{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $dependField }}]'"
:depend-result= "'{{ $dependSelectedOption }}'"
:channel_locale = "'{{ $channel_locale }}'"
></required-if>
@else
<depends
:options = '@json($field['options'])'
:name = "'{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]'"
:validations = "'{{ $validations }}'"
:depend = "'{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $dependField }}]'"
:value = "'{{ $dependValue }}'"
:field_name = "'{{ trans($field['title']) }}'"
:channel_locale = "'{{ $channel_locale }}'"
:result = "'{{ $selectedOption }}'"
:depend-saved-value= "'{{ $dependSelectedOption }}'"
></depends>
@endif
@else
@ -99,7 +114,7 @@
@elseif ($field['type'] == 'password')
<input type="password" v-validate="'{{ $validations }}'" class="control" id="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" name="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" value="{{ old($name) ?: core()->getConfigData($name) }}" data-vv-as="&quot;{{ trans($field['title']) }}&quot;">
@elseif ($field['type'] == 'number')
<input type="number" min="0" v-validate="'{{ $validations }}'" class="control" id="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" name="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" value="{{ old($name) ?: core()->getConfigData($name) }}" data-vv-as="&quot;{{ trans($field['title']) }}&quot;">
@ -111,7 +126,7 @@
@elseif ($field['type'] == 'textarea')
<textarea v-validate="'{{ $validations }}'" class="control" id="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" name="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" data-vv-as="&quot;{{ trans($field['title']) }}&quot;">{{ old($name) ?: core()->getConfigData($name) }}</textarea>
<textarea v-validate="'{{ $validations }}'" class="control" id="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" name="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" data-vv-as="&quot;{{ trans($field['title']) }}&quot;">{{ old($name) ? core()->getConfigData($name) : (isset($field['default_value']) ? $field['default_value'] : '') }}</textarea>
@elseif ($field['type'] == 'select')
@ -215,7 +230,7 @@
@elseif ($field['type'] == 'boolean')
<?php $selectedOption = core()->getConfigData($name) ?? ''; ?>
<?php $selectedOption = core()->getConfigData($name) ?? (isset($field['default_value']) ? $field['default_value'] : ''); ?>
<label class="switch">
<input type="hidden" name="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" value="0" />

View File

@ -153,7 +153,10 @@ class CategoryController extends Controller
try {
Event::dispatch('catalog.category.delete.before', $id);
$this->categoryRepository->delete($id);
if($category->products->count() > 0) {
$category->products()->delete();
}
$category->delete();
Event::dispatch('catalog.category.delete.after', $id);
@ -175,36 +178,52 @@ class CategoryController extends Controller
*/
public function massDestroy()
{
$suppressFlash = false;
$suppressFlash = true;
$categoryIds = explode(',', request()->input('indexes'));
if (request()->isMethod('delete') || request()->isMethod('post')) {
$indexes = explode(',', request()->input('indexes'));
foreach ($categoryIds as $categoryId) {
$category = $this->categoryRepository->find($categoryId);
foreach ($indexes as $key => $value) {
try {
Event::dispatch('catalog.category.delete.before', $value);
if (isset($category)) {
if(strtolower($category->name) == "root") {
$suppressFlash = false;
session()->flash('warning', trans('admin::app.response.delete-category-root', ['name' => 'Category']));
} else {
try {
$suppressFlash = true;
Event::dispatch('catalog.category.delete.before', $categoryId);
$this->categoryRepository->delete($value);
if($category->products->count() > 0) {
$category->products()->delete();
}
$category->delete();
Event::dispatch('catalog.category.delete.after', $value);
} catch(\Exception $e) {
$suppressFlash = true;
continue;
Event::dispatch('catalog.category.delete.after', $categoryId);
} catch(\Exception $e) {
session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Category']));
}
}
}
if (! $suppressFlash) {
session()->flash('success', trans('admin::app.datagrid.mass-ops.delete-success'));
} else {
session()->flash('info', trans('admin::app.datagrid.mass-ops.partial-action', ['resource' => 'Attribute Family']));
}
return redirect()->back();
} else {
session()->flash('error', trans('admin::app.datagrid.mass-ops.method-error'));
return redirect()->back();
}
if (count($categoryIds) != 1 || $suppressFlash == true) {
session()->flash('success', trans('admin::app.datagrid.mass-ops.delete-success', ['resource' => 'Category']));
}
return redirect()->route($this->_config['redirect']);
}
public function categoryProductCount() {
$indexes = explode(",", request()->input('indexes'));
$product_count = 0;
foreach($indexes as $index) {
$category = $this->categoryRepository->find($index);
$product_count += $category->products->count();
}
return response()->json(['product_count' => $product_count], 200);
}
}

View File

@ -9,6 +9,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Webkul\Category\Contracts\Category as CategoryContract;
use Webkul\Attribute\Models\AttributeProxy;
use Webkul\Category\Repositories\CategoryRepository;
use Webkul\Product\Models\ProductProxy;
/**
* Class Category
@ -129,4 +130,12 @@ class Category extends TranslatableModel implements CategoryContract
return $this->findInTree($category->children);
}
/**
* The products that belong to the category.
*/
public function products()
{
return $this->belongsToMany(ProductProxy::modelClass(), 'product_categories');
}
}

View File

@ -29,7 +29,6 @@
}
.main-container-wrapper .product-card .product-image img {
height: auto;
max-width: 100%;
}
</style>
@ -102,7 +101,7 @@
}
$('.path-hint-tooltip').css('left', left - minus)
$('.path-hint-tooltip').css('top', currentElement.offset().top + 20)
})

View File

@ -17,8 +17,9 @@ return [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'text',
'validation' => 'required',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => false,
'locale_based' => true,
], [
@ -69,8 +70,9 @@ return [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'text',
'validation' => 'required',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => false,
'locale_based' => true,
], [

View File

@ -1,24 +1,24 @@
<?php
return [
'paypal_smart_button' => [
'code' => 'paypal_smart_button',
'title' => 'PayPal',
'description' => 'PayPal',
'client_id' => 'sb',
'class' => 'Webkul\Paypal\Payment\SmartButton',
'sandbox' => true,
'active' => true,
'sort' => 0,
],
'paypal_standard' => [
'code' => 'paypal_standard',
'title' => 'Paypal Standard',
'description' => 'Paypal Standard',
'title' => 'PayPal Standard',
'description' => 'PayPal Standard',
'class' => 'Webkul\Paypal\Payment\Standard',
'sandbox' => true,
'active' => true,
'business_account' => 'test@webkul.com',
'sort' => 3,
],
'paypal_smart_button' => [
'code' => 'paypal_smart_button',
'title' => 'Paypal Smart Button',
'description' => 'Paypal Smart Button',
'client_id' => 'sb',
'class' => 'Webkul\Paypal\Payment\SmartButton',
'sandbox' => true,
'active' => true,
'sort' => 4,
]
];

View File

@ -9,8 +9,9 @@ return [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'text',
'validation' => 'required',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => false,
'locale_based' => true,
], [
@ -20,11 +21,11 @@ return [
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'business_account',
'title' => 'admin::app.admin.system.business-account',
'type' => 'select',
'type' => 'text',
'validation' => 'required',
'name' => 'business_account',
'title' => 'admin::app.admin.system.business-account',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
], [
'name' => 'active',
'title' => 'admin::app.admin.system.status',
@ -36,7 +37,6 @@ return [
'name' => 'sandbox',
'title' => 'admin::app.admin.system.sandbox',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => true,
], [
@ -63,13 +63,14 @@ return [
], [
'key' => 'sales.paymentmethods.paypal_smart_button',
'name' => 'admin::app.admin.system.paypal-smart-button',
'sort' => 3,
'sort' => 0,
'fields' => [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'text',
'validation' => 'required',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => false,
'locale_based' => true,
], [
@ -82,9 +83,9 @@ return [
'name' => 'client_id',
'title' => 'admin::app.admin.system.client-id',
'info' => 'admin::app.admin.system.client-id-info',
'type' => 'select',
'type' => 'text',
'validation' => 'required',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
], [
'name' => 'active',
'title' => 'admin::app.admin.system.status',

View File

@ -80,7 +80,12 @@ class SmartButtonController extends Controller
],
'application_context' => [
'shipping_preference' => 'NO_SHIPPING'
'user_action' => 'PAY_NOW',
'shipping_preference' => 'SET_PROVIDED_ADDRESS',
'payment_method' => [
'payee_preferred' => 'IMMEDIATE_PAYMENT_REQUIRED',
]
],
'purchase_units' => [
@ -156,6 +161,7 @@ class SmartButtonController extends Controller
'quantity' => $item->quantity,
'name' => $item->name,
'sku' => $item->sku,
'category' => $item->product->getTypeInstance()->isStockable() ? 'PHYSICAL_GOODS' : 'DIGITAL_GOODS',
];
}

View File

@ -46,26 +46,46 @@
onApprove: function(data, actions) {
app.showLoader();
return actions.order.capture().then(function(details) {
return window.axios.post("{{ route('paypal.smart_button.save_order') }}", {
'_token': "{{ csrf_token() }}",
'data' : details
})
.then(function(response) {
if (response.data.success) {
if (response.data.redirect_url) {
window.location.href = response.data.redirect_url;
} else {
window.location.href = "{{ route('shop.checkout.success') }}";
return actions.order.capture()
.then(function(response) {
if (response.error == 'INSTRUMENT_DECLINED') {
return actions.restart();
} else {
return response;
}
})
.then(function(details) {
return window.axios.post("{{ route('paypal.smart_button.save_order') }}", {
'_token': "{{ csrf_token() }}",
'data' : details
})
.then(function(response) {
if (response.data.success) {
if (response.data.redirect_url) {
window.location.href = response.data.redirect_url;
} else {
window.location.href = "{{ route('shop.checkout.success') }}";
}
}
}
app.hideLoader()
})
.catch(function (error) {
window.location.href = "{{ route('shop.checkout.cart.index') }}";
})
});
app.hideLoader()
})
.catch(function (error) {
window.location.href = "{{ route('shop.checkout.cart.index') }}";
})
});
},
onCancel: function (data) {
console.log('Canceled payment')
},
onError: function (err) {
window.flashMessages = [{'type': 'alert-error', 'message': err }];
window.flashMessages.alertMessage = err;
app.addFlashMessages();
}
};

View File

@ -17,8 +17,9 @@ return [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'text',
'validation' => 'required',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => false,
'locale_based' => true,
], [
@ -44,8 +45,9 @@ return [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'text',
'validation' => 'required',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => true,
'locale_based' => true,
], [
@ -57,14 +59,16 @@ return [
], [
'name' => 'default_rate',
'title' => 'admin::app.admin.system.rate',
'type' => 'text',
'validation' => 'required',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => true,
'locale_based' => false,
], [
'name' => 'type',
'title' => 'admin::app.admin.system.type',
'type' => 'select',
'type' => 'depends',
'depend' => 'active:1',
'options' => [
[
'title' => 'Per Unit',
@ -74,7 +78,7 @@ return [
'value' => 'per_order',
]
],
'validation' => 'required'
'validation' => 'required_if:active,1'
], [
'name' => 'active',
'title' => 'admin::app.admin.system.status',

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>arrow-down</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="arrow-down" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<polygon id="Rectangle-2" fill="#A5A5A5" transform="translate(9.000000, 8.000000) rotate(-45.000000) translate(-9.000000, -8.000000) " points="6 5 12 11 6 11"></polygon>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 633 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>arrow-down</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="arrow-down" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<polygon id="Rectangle-2" fill="#A5A5A5" transform="translate(9.000000, 8.000000) rotate(-45.000000) translate(-9.000000, -8.000000) " points="6 5 12 11 6 11"></polygon>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 633 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'هل تريد حقا تحديث الحالة من منتقى :resource?',
'delete' => 'هل تريد حقا حذف هذا :resource?',
'edit' => 'هل تريد حقا تحرير هذا :resource?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'يمكن أن تحتوي أعمدة الفهرس على قيم أكبر من الصفر فقط',

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'Möchten Sie den Status der ausgewählten :resource wirklich aktualisieren?',
'delete' => 'Möchten Sie diese Aktion wirklich ausführen?',
'edit' => 'Möchten Sie :resource wirklich bearbeiten?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'Indexspalten können nur Werte größer als Null haben',

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'Do you really want to update status of these selected :resource?',
'delete' => 'Do you really want to perform this action?',
'edit' => 'Do you really want to edit this :resource?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'Index columns can have values greater than zero only',

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'آیا واقعاً می خواهید وضعیت انتخاب شده را به روز کنید :resource?',
'delete' => 'آیا واقعاً می خواهید این عمل را انجام دهید؟',
'edit' => 'آیا واقعاً می خواهید این را ویرایش کنید :resource?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'ستون های فهرست می توانند مقادیری بیشتر از صفر داشته باشند',

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'Vuoi aggiornare davvero lo stato dei :resource selezionati?',
'delete' => 'Vuoi davvero effettuare questa azione?',
'edit' => 'Vuoi davvero modificare questo :resource?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'Le colonnne indice possono avere solo valori maggiori di zero',

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'Do you really want to update status of these selected :resource?',
'delete' => 'Wilt u deze actie echt uitvoeren?',
'edit' => 'Wil je dit echt bewerken :resource?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'Index columns can have values greater than zero only',

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'Czy naprawdę chcesz zaktualizować status tych wybranych :resource?',
'delete' => 'Czy naprawdę chcesz wykonać tę akcję?',
'edit' => 'Czy naprawdę chcesz edytować :resource?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'Kolumny indeksu mogą mieć wartości większe niż tylko zero',

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'Você realmente deseja atualizar o status desses itens selecionados :resource?',
'delete' => 'Você realmente deseja excluir este :resource?',
'edit' => 'Você realmente quer editar este :resource?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'Colunas do índice podem ter valores maiores que zero apenas',

View File

@ -9,6 +9,7 @@ return [
'mass-update-status' => 'Seçili :resource kayıtlarının durumunu güncellemek istediğinizden emin misiniz?',
'delete' => 'Bu işlemi gerçekleştirmek istediğinizden emin misiniz?',
'edit' => ':resource kaydını düzenlemek istediğinizden emin misiniz?',
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'zero-index' => 'Index sütunları sadece sıfırdan büyük değere sahip olmalı',

View File

@ -48,25 +48,32 @@
@if ($toDisplay)
<a
@if ($action['method'] == 'GET')
href="{{ route($action['route'], $record->{$action['index'] ?? $index}) }}"
@endif
id="{{ $record->{$action['index'] ?? $index} }}"
@if ($action['method'] != 'GET')
v-on:click="doAction($event)"
@endif
@if ($action['method'] == 'GET')
href="{{ route($action['route'], $record->{$action['index'] ?? $index}) }}"
@endif
data-method="{{ $action['method'] }}"
data-action="{{ route($action['route'], $record->{$index}) }}"
data-token="{{ csrf_token() }}"
@if ($action['method'] != 'GET')
@if (isset($action['function']))
v-on:click="{{$action['function']}}"
@else
v-on:click="doAction($event)"
@endif
@endif
@if (isset($action['target']))
target="{{ $action['target'] }}"
@endif
data-method="{{ $action['method'] }}"
data-action="{{ route($action['route'], $record->{$index}) }}"
data-token="{{ csrf_token() }}"
@if (isset($action['title']))
title="{{ $action['title'] }}"
@endif>
@if (isset($action['target']))
target="{{ $action['target'] }}"
@endif
@if (isset($action['title']))
title="{{ $action['title'] }}"
@endif
>
<span class="{{ $action['icon'] }}"></span>
</a>
@endif

View File

@ -8,7 +8,7 @@
<span class="icon checkbox-dash-icon"></span>
</span>
<form method="POST" id="mass-action-form" style="display: inline-flex;" action="" onsubmit="return confirm('{{ __('ui::app.datagrid.click_on_action') }}')">
<form method="POST" id="mass-action-form" style="display: inline-flex;" action="" :onsubmit="`return confirm('${massActionConfirmText}')`">
@csrf()
<input type="hidden" id="indexes" name="indexes" v-model="dataIds">

View File

@ -272,6 +272,7 @@
massActions: @json($results['massactions']),
massActionsToggle: false,
massActionTarget: null,
massActionConfirmText: '{{ __('ui::app.datagrid.click_on_action') }}',
massActionType: null,
massActionValues: [],
massActionTargets: [],
@ -457,7 +458,8 @@
for (let id in this.massActions) {
targetObj = {
'type': this.massActions[id].type,
'action': this.massActions[id].action
'action': this.massActions[id].action,
'confirm_text': this.massActions[id].confirm_text
};
this.massActionTargets.push(targetObj);
@ -483,6 +485,7 @@
for (let i in this.massActionTargets) {
if (this.massActionTargets[i].type === 'delete') {
this.massActionTarget = this.massActionTargets[i].action;
this.massActionConfirmText = this.massActionTargets[i].confirm_text ? this.massActionTargets[i].confirm_text : this.massActionConfirmText;
break;
}
@ -493,6 +496,7 @@
for (let i in this.massActionTargets) {
if (this.massActionTargets[i].type === 'update') {
this.massActionTarget = this.massActionTargets[i].action;
this.massActionConfirmText = this.massActionTargets[i].confirm_text ? this.massActionTargets[i].confirm_text : this.massActionConfirmText;
break;
}
@ -816,31 +820,6 @@
}
},
doAction: function (e) {
var element = e.currentTarget;
if (confirm('{{__('ui::app.datagrid.massaction.delete') }}')) {
axios.post(element.getAttribute('data-action'), {
_token: element.getAttribute('data-token'),
_method: element.getAttribute('data-method')
}).then(function (response) {
this.result = response;
if (response.data.redirect) {
window.location.href = response.data.redirect;
} else {
location.reload();
}
}).catch(function (error) {
location.reload();
});
e.preventDefault();
} else {
e.preventDefault();
}
},
captureColumn: function (id) {
element = document.getElementById(id);
@ -869,6 +848,37 @@
}
}
});
function doAction(e, message, type) {
var element = e.currentTarget;
if (message) {
element = e.target.parentElement;
}
message = message || '{{__('ui::app.datagrid.massaction.delete') }}';
if (confirm(message)) {
axios.post(element.getAttribute('data-action'), {
_token: element.getAttribute('data-token'),
_method: element.getAttribute('data-method')
}).then(function (response) {
this.result = response;
if (response.data.redirect) {
window.location.href = response.data.redirect;
} else {
location.reload();
}
}).catch(function (error) {
location.reload();
});
e.preventDefault();
} else {
e.preventDefault();
}
}
</script>
@endpush
</div>

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=b9eef40002c7ceeef010",
"/js/velocity.js": "/js/velocity.js?id=718060b43be7aaf645f7",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=4322502d80a0e4a0affd",
"/css/velocity.css": "/css/velocity.css?id=fda6b6f28d7565f01457"
"/css/velocity.css": "/css/velocity.css?id=bbe2b8053a6406fd7f64"
}

View File

@ -253,6 +253,7 @@ class ConfigurationController extends Controller
\DB::table('velocity_meta_data')->insert([
'locale' => $locale,
'channel' => $channel,
'header_content_count' => '5',
'home_page_content' => "<p>@include('shop::home.advertisements.advertisement-four')@include('shop::home.featured-products') @include('shop::home.product-policy') @include('shop::home.advertisements.advertisement-three') @include('shop::home.new-products') @include('shop::home.advertisements.advertisement-two')</p>",
'footer_left_content' => __('velocity::app.admin.meta-data.footer-left-raw-content'),

View File

@ -1,98 +0,0 @@
<template>
<div class="container-fluid remove-padding-margin">
<shimmer-component v-if="isLoading && !isMobileView"></shimmer-component>
<template v-else-if="categoryProducts.length > 0">
<card-list-header
:heading="categoryDetails.name"
:view-all="`${this.baseUrl}/${categoryDetails.slug}`">
</card-list-header>
<div class="carousel-products vc-full-screen ltr" v-if="!isMobileView">
<carousel-component
slides-per-page="6"
navigation-enabled="hide"
pagination-enabled="hide"
:slides-count="categoryProducts.length"
locale-direction="localeDirection"
:id="`${categoryDetails.name}-carousel`">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in categoryProducts">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
<div class="carousel-products vc-small-screen" v-else>
<carousel-component
slides-per-page="2"
navigation-enabled="hide"
pagination-enabled="hide"
:slides-count="categoryProducts.length"
locale-direction="localeDirection"
:id="`${categoryDetails.name}-carousel`">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in categoryProducts">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
</template>
</div>
</template>
<script>
export default {
props: [
'categorySlug',
'localeDirection'
],
data: function () {
return {
isLoading: true,
isCategory: false,
heading: 'customer',
categoryProducts: [],
isMobileView: this.$root.isMobile(),
}
},
mounted: function () {
this.getCategoryDetails();
},
methods: {
'getCategoryDetails': function () {
this.$http.get(`${this.baseUrl}/category-details?category-slug=${this.categorySlug}`)
.then(response => {
if (response.data.status) {
this.list = response.data.list;
this.categoryDetails = response.data.categoryDetails;
this.categoryProducts = response.data.categoryProducts;
this.isCategory = true;
}
this.isLoading = false;
})
.catch(error => {
this.isLoading = false;
console.log(this.__('error.something_went_wrong'));
});
}
}
}
</script>

View File

@ -0,0 +1,147 @@
<template>
<div class="container-fluid">
<shimmer-component v-if="isLoading"></shimmer-component>
<template v-else-if="productCollections.length > 0">
<card-list-header
:heading="isCategory ? categoryDetails.name : productTitle"
:view-all="isCategory ? `${this.baseUrl}/${categoryDetails.slug}` : ''">
</card-list-header>
<div class="row" :class="localeDirection">
<div
class="col-md-12 no-padding carousel-products"
:class="showRecentlyViewed ? 'with-recent-viewed col-lg-9' : 'col-lg-12'">
<carousel-component
:slides-per-page="slidesPerPage"
navigation-enabled="hide"
pagination-enabled="hide"
:id="isCategory ? `${categoryDetails.name}-carousel` : productId"
:locale-direction="localeDirection"
:slides-count="productCollections.length"
v-if="count != 0">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in productCollections">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
<recently-viewed
:title="recentlyViewedTitle"
:no-data-text="noDataText"
:add-class="`col-lg-3 col-md-12 ${localeDirection}`"
quantity="3"
add-class-wrapper=""
v-if="showRecentlyViewed">
</recently-viewed>
</div>
</template>
</div>
</template>
<script>
export default {
props: {
count: {
type: Number,
default: 10
},
productId: {
type: String,
default: ''
},
productTitle: String,
productRoute: String,
localeDirection: String,
showRecentlyViewed: {
type: Boolean,
default: false
},
recentlyViewedTitle: String,
noDataText: String,
},
data: function () {
return {
list: false,
isLoading: true,
isCategory: false,
productCollections: [],
slidesPerPage: 6,
windowWidth: window.innerWidth,
}
},
mounted: function () {
this.$nextTick(() => {
window.addEventListener('resize', this.onResize);
});
this.getProducts();
this.setSlidesPerPage(this.windowWidth);
},
watch: {
/* checking the window width */
windowWidth(newWidth, oldWidth) {
this.setSlidesPerPage(newWidth);
}
},
methods: {
/* fetch product collections */
getProducts: function () {
this.$http.get(this.productRoute)
.then(response => {
let count = this.count;
if (response.data.status && count != 0) {
if (response.data.categoryProducts !== undefined) {
this.isCategory = true;
this.categoryDetails = response.data.categoryDetails;
this.productCollections = response.data.categoryProducts;
} else {
this.productCollections = response.data.products;
}
} else {
this.productCollections = 0;
}
this.isLoading = false;
})
.catch(error => {
this.isLoading = false;
console.log(this.__('error.something_went_wrong'));
})
},
/* on resize set window width */
onResize: function () {
this.windowWidth = window.innerWidth;
},
/* setting slides on the basis of window width */
setSlidesPerPage: function (width) {
if (width >= 992) {
this.slidesPerPage = 6;
} else if (width < 992 && width >= 420) {
this.slidesPerPage = 4;
} else {
this.slidesPerPage = 2;
}
}
},
/* removing event */
beforeDestroy: function () {
window.removeEventListener('resize', this.onResize);
},
}
</script>

View File

@ -0,0 +1,98 @@
<template>
<div :class="addClass">
<div class="row remove-padding-margin">
<div class="col-12 no-padding">
<h2 class="fs20 fw6 mb15" v-text="title"></h2>
</div>
</div>
<div :class="`recetly-viewed-products-wrapper ${addClassWrapper}`">
<div
:key="Math.random()"
class="row small-card-container"
v-for="(product, index) in recentlyViewed">
<div class="col-4 product-image-container mr15">
<a :href="`${baseUrl}/${product.urlKey}`" class="unset">
<div class="product-image" :style="`background-image: url(${product.image})`"></div>
</a>
</div>
<div class="col-8 no-padding card-body align-vertical-top" v-if="product.urlKey">
<a :href="`${baseUrl}/${product.urlKey}`" class="unset no-padding">
<div class="product-name">
<span class="fs16 text-nowrap" v-text="product.name"></span>
</div>
<div
v-html="product.priceHTML"
class="fs18 card-current-price fw6">
</div>
<star-ratings v-if="product.rating > 0"
push-class="display-inbl"
:ratings="product.rating">
</star-ratings>
</a>
</div>
</div>
<span
class="fs16"
v-if="!recentlyViewed ||(recentlyViewed && Object.keys(recentlyViewed).length == 0)"
v-text="noDataText">
</span>
</div>
</div>
</template>
<script>
export default {
props: [
'title',
'noDataText',
'quantity',
'addClass',
'addClassWrapper'
],
data: function () {
return {
recentlyViewed: (() => {
let storedRecentlyViewed = window.localStorage.recentlyViewed;
if (storedRecentlyViewed) {
var slugs = JSON.parse(storedRecentlyViewed);
var updatedSlugs = {};
slugs = slugs.reverse();
slugs.forEach(slug => {
updatedSlugs[slug] = {};
});
return updatedSlugs;
}
})(),
}
},
created: function () {
for (const slug in this.recentlyViewed) {
if (slug) {
this.$http(`${this.baseUrl}/product-details/${slug}`)
.then(response => {
if (response.data.status) {
this.$set(this.recentlyViewed, response.data.details.urlKey, response.data.details);
} else {
delete this.recentlyViewed[response.data.slug];
this.$set(this, 'recentlyViewed', this.recentlyViewed);
this.$forceUpdate();
}
})
.catch(error => {})
}
}
},
}
</script>

View File

@ -52,7 +52,8 @@ Vue.component("shimmer-component", require("./UI/components/shimmer-component"))
Vue.component('responsive-sidebar', require('./UI/components/responsive-sidebar'));
Vue.component('product-quick-view', require('./UI/components/product-quick-view'));
Vue.component('product-quick-view-btn', require('./UI/components/product-quick-view-btn'));
Vue.component('category-products', require('./UI/components/category-products'));
Vue.component('recently-viewed', require('./UI/components/recently-viewed'));
Vue.component('product-collections', require('./UI/components/product-collections'));
Vue.component('hot-category', require('./UI/components/hot-category'));
Vue.component('popular-category', require('./UI/components/popular-category'));

View File

@ -1866,6 +1866,7 @@
top: -1px;
left: 100%;
height: 100%;
min-height: 330px;
z-index: 100;
padding-top: 10px;
position: absolute;

View File

@ -171,13 +171,9 @@
.product-card-new {
max-width: 16rem;
max-width: 19rem;
&.grid-card {
.product-image-container {
height: 165px;
}
.card-body {
.product-name {
width: 13rem;
@ -787,6 +783,7 @@
font-size: 18px;
padding-right: 5px;
display: contents;
&.profile::before {
content: "\E995";
@ -989,7 +986,7 @@
}
}
/* small devices */
/* medium devices */
@media only screen and (max-width: 768px) {
.sticky-header {
display: none !important;
@ -1044,15 +1041,6 @@
margin-left: -158px;
}
.lg-card-container.list-card .product-image {
max-height: 85px;
}
.quick-view-btn-container {
left: -26px;
width: 109px;
}
.quick-view-btn-container span {
left: 24%;
top: -24px;
@ -1062,6 +1050,22 @@
.quick-view-in-list {
display: none;
}
.product-card-new {
max-width: 18rem;
}
}
/* small devices */
@media only screen and (max-width: 420px) {
.sticky-header {
display: none !important;
}
#home-right-bar-container {
position: unset;
top: unset;
}
}
/* very small devices */
@ -1074,4 +1078,8 @@
position: unset;
top: unset;
}
.quick-view-in-list {
display: none;
}
}

View File

@ -241,6 +241,14 @@ body {
a {
padding: 7px 15px 5px 15px;
}
ul.nested {
li {
a {
padding-right: 25px;
}
}
}
}
}

View File

@ -323,7 +323,8 @@
</div>
@php
$showCompare = core()->getConfigData('general.content.shop.compare_option') == "1" ? true : false
$showCompare = core()->getConfigData('general.content.shop.compare_option') == "1" ? true : false;
$showWishlist = core()->getConfigData('general.content.shop.wishlist_option') == "1" ? true : false;
@endphp
<div class="right-vc-header col-6">
@ -346,12 +347,14 @@
</a>
@endif
<a class="wishlist-btn unset" :href="`{{ route('customer.wishlist.index') }}`">
<div class="badge-container" v-if="wishlistCount > 0">
<span class="badge" v-text="wishlistCount"></span>
</div>
<i class="material-icons">favorite_border</i>
</a>
@if ($showWishlist)
<a class="wishlist-btn unset" :href="`{{ route('customer.wishlist.index') }}`">
<div class="badge-container" v-if="wishlistCount > 0">
<span class="badge" v-text="wishlistCount"></span>
</div>
<i class="material-icons">favorite_border</i>
</a>
@endif
<a class="unset cursor-pointer" @click="openSearchBar">
<i class="material-icons">search</i>

View File

@ -1,4 +1,5 @@
<category-products
category-slug="{{ $category }}"
<product-collections
product-title="{{ __('shop::app.home.featured-products') }}"
product-route="{{ route('velocity.category.details', ['category-slug' => $category]) }}"
locale-direction="{{ core()->getCurrentLocale()->direction == 'rtl' ? 'rtl' : 'ltr' }}">
</category-products>
</product-collections>

View File

@ -4,102 +4,10 @@
$direction = core()->getCurrentLocale()->direction == 'rtl' ? 'rtl' : 'ltr';
@endphp
<featured-products></featured-products>
@push('scripts')
<script type="text/x-template" id="featured-products-template">
<div class="container-fluid featured-products">
<shimmer-component v-if="isLoading"></shimmer-component>
<template v-else-if="featuredProducts.length > 0">
<card-list-header heading="{{ __('shop::app.home.featured-products') }}">
</card-list-header>
<div class="carousel-products vc-full-screen {{ $direction }}">
<carousel-component
slides-per-page="6"
navigation-enabled="hide"
pagination-enabled="hide"
id="fearured-products-carousel"
locale-direction="{{ $direction }}"
:autoplay="false"
:slides-count="featuredProducts.length">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in featuredProducts">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
<div class="carousel-products vc-small-screen {{ $direction }}">
<carousel-component
slides-per-page="2"
navigation-enabled="hide"
pagination-enabled="hide"
id="fearured-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="featuredProducts.length">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in featuredProducts">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
</template>
</div>
</script>
<script type="text/javascript">
(() => {
Vue.component('featured-products', {
'template': '#featured-products-template',
data: function () {
return {
'list': false,
'isLoading': true,
'featuredProducts': [],
'isMobileView': this.$root.isMobile(),
}
},
mounted: function () {
this.getFeaturedProducts();
},
methods: {
'getFeaturedProducts': function () {
this.$http.get(`${this.baseUrl}/category-details?category-slug=featured-products&count={{ $count }}`)
.then(response => {
var count = '{{$count}}';
if (response.data.status && count != 0 )
{
this.featuredProducts = response.data.products;
}else{
this.featuredProducts = 0;
}
this.isLoading = false;
})
.catch(error => {
this.isLoading = false;
console.log(this.__('error.something_went_wrong'));
})
}
}
})
})()
</script>
@endpush
<product-collections
product-id="fearured-products-carousel"
product-title="{{ __('shop::app.home.featured-products') }}"
product-route="{{ route('velocity.category.details', ['category-slug' => 'featured-products', 'count' => $count]) }}"
locale-direction="{{ $direction }}"
count="{{ (int) $count }}">
</product-collections>

View File

@ -4,185 +4,17 @@
$direction = core()->getCurrentLocale()->direction == 'rtl' ? 'rtl' : 'ltr';
@endphp
<new-products></new-products>
{!! view_render_event('bagisto.shop.new-products.before') !!}
@push('scripts')
<script type="text/x-template" id="new-products-template">
<div class="container-fluid">
<shimmer-component v-if="isLoading"></shimmer-component>
<product-collections
count="{{ (int) $count }}"
product-id="new-products-carousel"
product-title="{{ __('shop::app.home.new-products') }}"
product-route="{{ route('velocity.category.details', ['category-slug' => 'new-products', 'count' => $count]) }}"
locale-direction="{{ $direction }}"
show-recently-viewed="{{ (Boolean) $showRecentlyViewed }}"
recently-viewed-title="{{ __('velocity::app.products.recently-viewed') }}"
no-data-text="{{ __('velocity::app.products.not-available') }}">
</product-collections>
<template v-else-if="newProducts.length > 0">
<card-list-header heading="{{ __('shop::app.home.new-products') }}">
</card-list-header>
{!! view_render_event('bagisto.shop.new-products.before') !!}
@if ($showRecentlyViewed)
@push('css')
<style>
.recently-viewed {
padding-right: 0px;
}
</style>
@endpush
<div class="row {{ $direction }}">
<div class="col-9 no-padding carousel-products vc-full-screen with-recent-viewed">
<carousel-component
slides-per-page="5"
navigation-enabled="hide"
pagination-enabled="hide"
id="new-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="newProducts.length">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in newProducts">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
<div class="col-12 no-padding carousel-products vc-small-screen">
<carousel-component
slides-per-page="2"
navigation-enabled="hide"
pagination-enabled="hide"
id="new-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="newProducts.length">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in newProducts">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
@include ('shop::products.list.recently-viewed', [
'quantity' => 3,
'addClass' => 'col-lg-3 col-md-12',
])
</div>
@else
<div class="carousel-products vc-full-screen {{ $direction }}">
<carousel-component
slides-per-page="6"
navigation-enabled="hide"
pagination-enabled="hide"
id="new-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="newProducts.length">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in newProducts">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
<div class="carousel-products vc-small-screen {{ $direction }}">
<carousel-component
slides-per-page="2"
navigation-enabled="hide"
pagination-enabled="hide"
id="new-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="newProducts.length">
<slide
:key="index"
:slot="`slide-${index}`"
v-for="(product, index) in newProducts">
<product-card
:list="list"
:product="product">
</product-card>
</slide>
</carousel-component>
</div>
@endif
{!! view_render_event('bagisto.shop.new-products.after') !!}
</template>
@if ($count==0)
<template>
@if ($showRecentlyViewed)
@push('css')
<style>
.recently-viewed {
padding-right: 0px;
}
</style>
@endpush
<div class="row {{ $direction }}">
<div class="col-9 no-padding carousel-products vc-full-screen with-recent-viewed" v-if="!isMobileView"></div>
@include ('shop::products.list.recently-viewed', [
'quantity' => 3,
'addClass' => 'col-lg-3 col-md-12',
])
</div>
@endif
</template>
@endif
</div>
</script>
<script type="text/javascript">
(() => {
Vue.component('new-products', {
'template': '#new-products-template',
data: function () {
return {
'list': false,
'isLoading': true,
'newProducts': [],
'isMobileView': this.$root.isMobile(),
}
},
mounted: function () {
this.getNewProducts();
},
methods: {
'getNewProducts': function () {
this.$http.get(`${this.baseUrl}/category-details?category-slug=new-products&count={{ $count }}`)
.then(response => {
var count = '{{$count}}';
if (response.data.status && count != 0){
this.newProducts = response.data.products;
}else{
this.newProducts = 0;
}
this.isLoading = false;
})
.catch(error => {
this.isLoading = false;
console.log(this.__('error.something_went_wrong'));
})
}
}
})
})()
</script>
@endpush
{!! view_render_event('bagisto.shop.new-products.after') !!}

View File

@ -15,7 +15,7 @@
autoplay="true"
slides-per-page="1"
navigation-enabled="hide"
locale-direction="direction"
:locale-direction="direction"
:slides-count="{{ ! empty($sliderData) ? sizeof($sliderData) : 1 }}">
@if (! empty($sliderData))

View File

@ -1,111 +1,11 @@
@inject ('velocityHelper', 'Webkul\Velocity\Helpers\Helper')
@inject ('productRatingHelper', 'Webkul\Product\Helpers\Review')
@inject ('productImageHelper', 'Webkul\Product\Helpers\ProductImage')
@php
$direction = core()->getCurrentLocale()->direction;
@endphp
<recently-viewed
title="{{ __('velocity::app.products.recently-viewed') }}"
no-data-text="{{ __('velocity::app.products.not-available') }}"
add-class="{{ isset($addClass) ? $addClass . " $direction": '' }}"
quantity="{{ isset($quantity) ? $quantity : null }}"
add-class-wrapper="{{ isset($addClassWrapper) ? $addClassWrapper : '' }}">
</recently-viewed>
@push('scripts')
<script type="text/x-template" id="recently-viewed-template">
<div :class="`${addClass} recently-viewed`">
<div class="row remove-padding-margin">
<div class="col-12 no-padding">
<h2 class="fs20 fw6 mb15">{{ __('velocity::app.products.recently-viewed') }}</h2>
</div>
</div>
<div :class="`recetly-viewed-products-wrapper ${addClassWrapper}`">
<div
:key="Math.random()"
class="row small-card-container"
v-for="(product, index) in recentlyViewed">
<div class="col-4 product-image-container mr15">
<a :href="`${baseUrl}/${product.urlKey}`" class="unset">
<div class="product-image" :style="`background-image: url(${product.image})`"></div>
</a>
</div>
<div class="col-8 no-padding card-body align-vertical-top" v-if="product.urlKey">
<a :href="`${baseUrl}/${product.urlKey}`" class="unset no-padding">
<div class="product-name">
<span class="fs16 text-nowrap">@{{ product.name }}</span>
</div>
<div
v-html="product.priceHTML"
class="fs18 card-current-price fw6">
</div>
<star-ratings v-if="product.rating > 0"
push-class="display-inbl"
:ratings="product.rating">
</star-ratings>
</a>
</div>
</div>
<span
class="fs16"
v-if="!recentlyViewed ||(recentlyViewed && Object.keys(recentlyViewed).length == 0)"
v-text="'{{ __('velocity::app.products.not-available') }}'">
</span>
</div>
</div>
</script>
<script type="text/javascript">
(() => {
Vue.component('recently-viewed', {
template: '#recently-viewed-template',
props: ['quantity', 'addClass', 'addClassWrapper'],
data: function () {
return {
recentlyViewed: (() => {
let storedRecentlyViewed = window.localStorage.recentlyViewed;
if (storedRecentlyViewed) {
var slugs = JSON.parse(storedRecentlyViewed);
var updatedSlugs = {};
slugs = slugs.reverse();
slugs.forEach(slug => {
updatedSlugs[slug] = {};
});
return updatedSlugs;
}
})(),
}
},
created: function () {
for (slug in this.recentlyViewed) {
if (slug) {
this.$http(`${this.baseUrl}/product-details/${slug}`)
.then(response => {
if (response.data.status) {
this.$set(this.recentlyViewed, response.data.details.urlKey, response.data.details);
} else {
delete this.recentlyViewed[response.data.slug];
this.$set(this, 'recentlyViewed', this.recentlyViewed);
this.$forceUpdate();
}
})
.catch(error => {})
}
}
},
})
})()
</script>
@endpush