Merge branch 'master' of https://github.com/bagisto/bagisto into sarga-v1

This commit is contained in:
merdan 2022-04-05 16:43:35 +05:00
commit 0a5d418095
39 changed files with 1836 additions and 1650 deletions

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,4 +1,4 @@
{
"/js/admin.js": "/js/admin.js?id=68621909141b010f749f",
"/css/admin.css": "/css/admin.css?id=0597ed69210c620608a4"
"/js/admin.js": "/js/admin.js?id=1dddbb0d655216b79be5",
"/css/admin.css": "/css/admin.css?id=d35081df99f6ce2df4ff"
}

View File

@ -106,6 +106,15 @@ class OrderDataGrid extends DataGrid
'index' => 'status',
'label' => trans('admin::app.datagrid.status'),
'type' => 'string',
'options' => [
'processing' => trans('shop::app.customer.account.order.index.processing'),
'completed' => trans('shop::app.customer.account.order.index.completed'),
'canceled' => trans('shop::app.customer.account.order.index.canceled'),
'closed' => trans('shop::app.customer.account.order.index.closed'),
'pending' => trans('shop::app.customer.account.order.index.pending'),
'pending_payment' => trans('shop::app.customer.account.order.index.pending-payment'),
'fraud' => trans('shop::app.customer.account.order.index.fraud'),
],
'sortable' => true,
'searchable' => true,
'filterable' => true,

View File

@ -57,7 +57,7 @@ class SitemapDataGrid extends DataGrid
'sortable' => false,
'filterable' => false,
'closure' => function ($row) {
return '<a href="' . ($url = Storage::url($row->path . '/' . $row->file_name)) . '">' . $url . '</a>';
return '<a href="' . ($url = Storage::url($row->path . '/' . $row->file_name)) . '" target="_blank">' . $url . '</a>';
},
]);
}

View File

@ -341,10 +341,15 @@ body {
font-weight: 200;
display: inline-block;
color: $black;
width: 115px;
word-break: break-all;
vertical-align: middle;
}
.arrow-icon {
display: inline-block;
position: absolute;
right: 0;
}
}
@ -360,6 +365,10 @@ body {
a {
padding-left: 56px;
font-size: 14px;
.menu-label {
width: auto;
}
}
}
}

View File

@ -1161,7 +1161,7 @@ return [
'action-type' => 'प्रक्रिया का प्रकार',
'percentage-product-price' => 'उत्पाद मूल्य का प्रतिशत',
'fixed-amount' => 'निश्चित राशि',
'fixed-amount-whole-cart' => 'निश्चित राशि से पूरी गाड़ी',
'fixed-amount-whole-cart' => 'निश्चित राशि से पूरी कार्ट',
'buy-x-get-y-free' => 'X खरीदें, Y मुफ़्त पाएं',
'discount-amount' => 'छूट राशि',
'discount-quantity' => 'अधिकतम मात्रा में छूट दी जाने की अनुमति',

View File

@ -47,6 +47,10 @@
<textarea v-validate="'{{ $validations }}'" class="control" id="{{ $name }}" name="{{ $name }}" data-vv-as="&quot;{{ trans($field['title']) }}&quot;">{{ old($nameKey) ?: core()->getConfigData($nameKey, $channel, $locale) ?: (isset($field['default_value']) ? $field['default_value'] : '') }}</textarea>
@elseif ($field['type'] == 'editor')
<textarea v-validate="'{{ $validations }}'" class="editor control" id="{{ $name }}" name="{{ $name }}" data-vv-as="&quot;{{ trans($field['title']) }}&quot;">{{ old($nameKey) ?: core()->getConfigData($nameKey, $channel, $locale) ?: (isset($field['default_value']) ? $field['default_value'] : '') }}</textarea>
@elseif ($field['type'] == 'select')
<select v-validate="'{{ $validations }}'" class="control" id="{{ $name }}" name="{{ $name }}" data-vv-as="&quot;{{ trans($field['title']) }}&quot;" >
@ -305,3 +309,21 @@
</script>
@endif
@endpush
@pushonce('scripts')
@include('admin::layouts.tinymce')
<script>
$(document).ready(function () {
tinyMCEHelper.initTinyMCE({
selector: 'textarea.editor',
height: 200,
width: "100%",
plugins: 'image imagetools media wordcount save fullscreen code table lists link hr',
toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor link hr | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat | code | table',
image_advtab: true,
});
});
</script>
@endpushonce

View File

@ -135,7 +135,7 @@ trait Mails
public function sendNewShipmentMail($shipment)
{
$customerLocale = $this->getLocale($shipment);
try {
if ($shipment->email_sent) {
return;
@ -248,7 +248,15 @@ trait Mails
app()->setLocale($locale);
Mail::queue($notification);
try {
Mail::queue($notification);
} catch(\Exception $e) {
app()->setLocale($previousLocale);
\Log::error(
'prepareMail' . $e->getMessage()
);
}
app()->setLocale($previousLocale);
}

View File

@ -1 +1 @@
.switch-view-container{margin-left:-5px;margin-right:6px;vertical-align:top;display:inline-block}.switch-view-container .icon-container{height:36px;cursor:pointer;display:inline-block;padding:6px 10px 10px;border:1px solid #c7c7c7}.switch-view-container .icon-container:first-child{left:5px;position:relative;border-radius:3px 0 0 3px}.switch-view-container .icon-container:last-child{border-radius:0 3px 3px 0}.switch-view-container .icon-container.active{cursor:not-allowed;border-color:#0041ff;background-color:#0041ff}.switch-view-container .icon-container .icon{vertical-align:middle;width:22px;height:22px}.vuecal__event{background:#0041ff!important;color:#fff!important;cursor:pointer}.vuecal__event:hover{height:-webkit-max-content!important;height:-moz-max-content!important;height:max-content!important}.rtl .switch-view-container{margin-left:unset}.rtl .switch-view-container .icon-container.active{margin-left:-9px}.calendar-icon{background-image:url(../images/calendar-icon.svg)}.calendar-white-icon{background-image:url(../images/calendar-white-icon.svg)}.table-icon{background-image:url(../images/table-icon.svg)}.table-white-icon{background-image:url(../images/table-white-icon.svg)}
.switch-view-container{margin-left:-5px;margin-right:6px;vertical-align:top;display:inline-block}.switch-view-container .icon-container{height:36px;cursor:pointer;display:inline-block;padding:6px 10px 10px;border:1px solid #c7c7c7}.switch-view-container .icon-container:first-child{left:5px;position:relative;border-radius:3px 0 0 3px}.switch-view-container .icon-container:last-child{border-radius:0 3px 3px 0}.switch-view-container .icon-container.active{cursor:not-allowed;background-color:#0041ff;border:1px solid}.switch-view-container .icon-container .icon{vertical-align:middle;width:22px;height:22px}.vuecal__event{background:#0041ff!important;color:#fff!important;cursor:pointer}.vuecal__event:hover{height:-webkit-max-content!important;height:-moz-max-content!important;height:max-content!important}.rtl .switch-view-container{margin-left:unset}.rtl .switch-view-container .icon-container.active{margin-left:-9px}.calendar-icon{background-image:url(../images/calendar-icon.svg)}.calendar-white-icon{background-image:url(../images/calendar-white-icon.svg)}.table-icon{background-image:url(../images/table-icon.svg)}.table-white-icon{background-image:url(../images/table-white-icon.svg)}

View File

@ -2,5 +2,5 @@
"/css/default-booking.css": "/css/default-booking.css?id=76de1f2b8e064c1e9043",
"/css/velocity-booking.css": "/css/velocity-booking.css?id=481d94b621e06671752a",
"/js/admin-booking.js": "/js/admin-booking.js?id=5cc56229ce47cbecd1be",
"/css/admin-booking.css": "/css/admin-booking.css?id=97f40d778fa7f81d69ff"
"/css/admin-booking.css": "/css/admin-booking.css?id=02be5e2fa5a499045cbe"
}

View File

@ -25,6 +25,7 @@
cursor: not-allowed;
border-color: #0041ff;
background-color: #0041ff;
border: 1px solid;
}
.icon {

View File

@ -274,7 +274,7 @@ class Cart
if ($cartItem = $cart->items()->find($itemId)) {
$cartItem->delete();
if ($cart->items->count() == 0) {
if ($cart->items()->get()->count() == 0) {
$this->cartRepository->delete($cart->id);
if (session()->has('cart')) {

View File

@ -76,6 +76,15 @@ class OrderDataGrid extends DataGrid
'index' => 'status',
'label' => trans('shop::app.customer.account.order.index.status'),
'type' => 'string',
'options' => [
'processing' => trans('shop::app.customer.account.order.index.processing'),
'completed' => trans('shop::app.customer.account.order.index.completed'),
'canceled' => trans('shop::app.customer.account.order.index.canceled'),
'closed' => trans('shop::app.customer.account.order.index.closed'),
'pending' => trans('shop::app.customer.account.order.index.pending'),
'pending_payment' => trans('shop::app.customer.account.order.index.pending-payment'),
'fraud' => trans('shop::app.customer.account.order.index.fraud'),
],
'searchable' => false,
'sortable' => true,
'closure' => function ($value) {

View File

@ -35,10 +35,9 @@ return [
'sign-in' => 'साइन इन करें',
'sign-up' => 'साइन अप करें',
'account' => 'हेतु',
'cart' => 'गाड़ी',
'cart' => 'कार्ट',
'profile' => 'प्रोफाइल',
'wishlist' => 'इच्छा सूची',
'cart' => 'गाड़ी',
'logout' => 'लॉग आउट',
'search-text' => 'यहां उत्पाद खोजें',
],
@ -46,7 +45,7 @@ return [
'minicart' => [
'view-cart' => 'की हुई खरीददारी देखो',
'checkout' => 'चेक आउट',
'cart' => 'गाड़ी',
'cart' => 'कार्ट',
'zero' => '0',
],
@ -355,7 +354,7 @@ return [
'deleteall' => 'सभी हटा दो',
'confirm-delete-all' => 'क्या आप वाकई सभी इच्छा सूची हटाना चाहते हैं?',
'moveall' => 'सभी उत्पादों को कार्ट में ले जाएं',
'move-to-cart' => 'गाड़ी को चलाना',
'move-to-cart' => 'कार्ट को चलाना',
'error' => 'अज्ञात समस्याओं के कारण उत्पाद को विशलिस्ट में नहीं जोड़ा जा सकता, कृपया बाद में चेकबैक करें',
'add' => 'आइटम सफलतापूर्वक इच्छा सूची में जोड़ा गया',
'remove' => 'आइटम को इच्छा सूची से सफलतापूर्वक हटा दिया गया',

View File

@ -87,6 +87,10 @@
<div class="item-qty">Quantity - {{ $item->quantity }}</div>
{!! view_render_event('bagisto.shop.checkout.cart-mini.item.quantity.after', ['item' => $item]) !!}
<div class="item-remove">
<a href="{{ route('shop.checkout.cart.remove', $item->id) }}" onclick="removeLink('{{ __('shop::app.checkout.cart.cart-remove-action') }}')">{{ __('shop::app.checkout.cart.remove-link') }}</a>
</div>
</div>
</div>

View File

@ -54,7 +54,7 @@
<div class="control-group">
<select class="control locale-switcher" id="locale-switcher" onchange="window.location.href = this.value" @if (count(core()->getCurrentChannel()->locales) == 1) disabled="disabled" @endif>
@foreach (core()->getCurrentChannel()->locales as $locale)
@foreach (core()->getCurrentChannel()->locales()->orderBy('name')->get() as $locale)
@if (isset($serachQuery))
<option value="?{{ $serachQuery }}&locale={{ $locale->code }}" {{ $locale->code == app()->getLocale() ? 'selected' : '' }}>{{ $locale->name }}</option>
@else

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/js/ui.js": "/js/ui.js?id=e136e7c7f62341fd089a",
"/js/ui.js": "/js/ui.js?id=4dc59bc61e8f3eff9489",
"/css/ui.css": "/css/ui.css?id=c8a7ade09358a1d61a4a"
}

View File

@ -28,12 +28,25 @@ import Debounce from './directives/debounce';
import Slugify from './directives/slugify';
import SlugifyTarget from './directives/slugify-target';
/* config section */
/**
* Configs.
*/
VTooltip.options.defaultDelay = 0;
Vue.config.productionTip = false;
/* component section */
/**
* Directives.
*/
Vue.directive('tooltip', VTooltip.VTooltip);
Vue.directive('slugify', Slugify);
Vue.directive('slugify-target', SlugifyTarget);
Vue.directive('code', Code);
Vue.directive('alert', Alert);
Vue.directive('debounce', Debounce);
/**
* Components.
*/
Vue.component('datagrid-plus', DatagridPlus);
Vue.component('flash-wrapper', FlashWrapper);
Vue.component('flash', Flash);
@ -48,21 +61,18 @@ Vue.component('modal', Modal);
Vue.component('image-upload', ImageUpload);
Vue.component('image-wrapper', ImageWrapper);
Vue.component('image-item', ImageItem);
Vue.directive('slugify', Slugify);
Vue.directive('slugify-target', SlugifyTarget);
Vue.directive('code', Code);
Vue.directive('alert', Alert);
Vue.component('datetime', DatetimeComponent);
Vue.component('date', DateComponent);
Vue.component('time-component', TimeComponent);
Vue.component('swatch-picker', SwatchPicker);
Vue.directive('debounce', Debounce);
Vue.component('overlay-loader', OverlayLoader);
Vue.component('multiselect', Multiselect);
Vue.component('default-image', DefaultImage);
Vue.component('draggable', Draggable);
/* filter section */
/**
* Filter.
*/
Vue.filter('truncate', function(value, limit, trail) {
if (!value) value = '';
@ -72,7 +82,24 @@ Vue.filter('truncate', function(value, limit, trail) {
return value.length > limit ? value.substring(0, limit) + trail : value;
});
/* require section */
/**
* Get laravel CSRF token.
*/
Vue.prototype.getCsrf = () => {
let token = document.head.querySelector('meta[name="csrf-token"]');
if (!token) {
console.error(
'CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token'
);
}
return token.content;
};
/**
* Require.
*/
require('flatpickr/dist/flatpickr.css');
require('vue-swatches/dist/vue-swatches.min.css');
require('vue-multiselect/dist/vue-multiselect.min.css');

View File

@ -1,38 +0,0 @@
<template>
<Flatpickr class="datetime-field" :options="fpOptions" />
</template>
<script>
window.Vue = require("vue");
import VueFlatpickr from "vue-flatpickr";
import "vue-flatpickr/theme/airbnb.css";
Vue.use(VueFlatpickr);
export default {
data() {
const now = new Date();
return {
fpOptions: {
utc: false,
defaultDate: now,
enableTime: true
}
};
},
mounted: function() {
console.log("Date time compoenent mounted");
}
};
</script>
<style>
.datetime-field {
border: 2px solid #c7c7c7;
border-radius: 3px;
font-family: "Montserrat", sans-serif;
height: 35px;
padding-left: 5px;
color: gray;
}
</style>

View File

@ -0,0 +1,37 @@
<template>
<div class="control-group">
<select class="control" name="channel" @change="changeChannel($event)">
<option
value="all"
:selected="extraFilters.current.channel == 'all'"
v-text="translations.allChannels"
></option>
<option
:key="channelKey"
v-for="(channel, channelKey) in extraFilters.channels"
v-text="channel.name"
:value="channel.code"
:selected="channel.code == extraFilters.current.channel"
></option>
</select>
</div>
</template>
<script>
export default {
props: ['translations', 'extraFilters'],
data() {
return {};
},
methods: {
changeChannel({ target }) {
this.$emit('onFilter', {
data: { type: 'channel', value: target.value }
});
}
}
};
</script>

View File

@ -0,0 +1,457 @@
<template>
<div>
<div class="dropdown-toggle">
<div class="grid-dropdown-header">
<span class="name" v-text="translations.filter"></span>
<i class="icon arrow-down-icon active"></i>
</div>
</div>
<div class="dropdown-list dropdown-container" style="display: none">
<ul>
<li>
<div class="control-group">
<select
class="filter-column-select control"
v-model="filterColumn"
v-on:change="getColumnOrAlias(filterColumn)"
>
<option
v-text="translations.column"
selected
disabled
></option>
<option
:key="columnKey"
v-for="(column, columnKey) in columns"
:value="column.index"
v-text="column.label"
v-if="
typeof column.filterable !== 'undefined' &&
column.filterable
"
></option>
</select>
</div>
</li>
<li v-if="stringConditionSelect">
<div class="control-group">
<select class="control" v-model="stringCondition">
<option
v-text="translations.condition"
selected
disabled
></option>
<option
v-text="translations.contains"
value="like"
></option>
<option
v-text="translations.ncontains"
value="nlike"
></option>
<option
v-text="translations.equals"
value="eq"
></option>
<option
v-text="translations.nequals"
value="neqs"
></option>
</select>
</div>
</li>
<li v-if="stringCondition != null">
<div
class="control-group"
v-if="isCurrentFilterColumnHasOptions()"
>
<select class="control" v-model="stringValue">
<option
:key="key"
v-text="option"
v-value="key"
v-for="(option,
key) in this.getCurrentFilterOptions()"
></option>
</select>
</div>
<div class="control-group" v-else>
<input
type="text"
class="control response-string"
:placeholder="translations.valueHere"
v-model="stringValue"
/>
</div>
</li>
<li v-if="numberConditionSelect">
<div class="control-group">
<select class="control" v-model="numberCondition">
<option
v-text="translations.condition"
selected
disabled
></option>
<option
v-text="translations.equals"
value="eq"
></option>
<option
v-text="translations.nequals"
value="neqs"
></option>
<option
v-text="translations.greater"
value="gt"
></option>
<option
v-text="translations.less"
value="lt"
></option>
<option
v-text="translations.greatere"
value="gte"
></option>
<option
v-text="translations.lesse"
value="lte"
></option>
</select>
</div>
</li>
<li v-if="numberCondition != null">
<div class="control-group">
<input
type="text"
class="control response-number"
v-on:input="filterNumberInput"
v-model="numberValue"
:placeholder="translations.numericValueHere"
/>
</div>
</li>
<li v-if="booleanConditionSelect">
<div class="control-group">
<select class="control" v-model="booleanCondition">
<option
v-text="translations.condition"
selected
disabled
></option>
<option
v-text="translations.equals"
value="eq"
></option>
<option
v-text="translations.nequals"
value="neqs"
></option>
</select>
</div>
</li>
<li v-if="booleanCondition != null">
<div class="control-group">
<select class="control" v-model="booleanValue">
<option
v-text="translations.value"
selected
disabled
></option>
<option
v-text="translations.true"
value="1"
></option>
<option
v-text="translations.false"
value="0"
></option>
</select>
</div>
</li>
<li v-if="datetimeConditionSelect">
<div class="control-group">
<select class="control" v-model="datetimeCondition">
<option
v-text="translations.condition"
selected
disabled
></option>
<option
v-text="translations.equals"
value="eq"
></option>
<option
v-text="translations.nequals"
value="neqs"
></option>
<option
v-text="translations.greater"
value="gt"
></option>
<option
v-text="translations.less"
value="lt"
></option>
<option
v-text="translations.greatere"
value="gte"
></option>
<option
v-text="translations.lesse"
value="lte"
></option>
</select>
</div>
</li>
<li v-if="datetimeCondition != null">
<div class="control-group">
<input
class="control"
v-model="datetimeValue"
type="date"
/>
</div>
</li>
<button
v-text="translations.apply"
class="btn btn-sm btn-primary apply-filter"
v-on:click="getResponse"
></button>
</ul>
</div>
</div>
</template>
<script>
export default {
props: ['columns', 'translations'],
data() {
/**
* To Do (@devansh-webkul):
*
* - Try to minimize these data props also.
* - Refactor all repeative properties.
*/
return {
type: null,
columnOrAlias: '',
stringConditionSelect: false,
numberConditionSelect: false,
booleanConditionSelect: false,
datetimeConditionSelect: false,
stringCondition: null,
numberCondition: null,
booleanCondition: null,
datetimeCondition: null,
stringValue: null,
numberValue: 0,
booleanValue: null,
datetimeValue: '2000-01-01'
};
},
methods: {
filterNumberInput: function(e) {
this.numberValue = e.target.value.replace(/[^0-9\,\.]+/g, '');
},
getCurrentFilterColumn() {
return this.columns.find(
column => column.index === this.filterColumn
);
},
isCurrentFilterColumnHasOptions() {
let currentFilterColumn = this.getCurrentFilterColumn();
return (
currentFilterColumn && currentFilterColumn.options !== undefined
);
},
getCurrentFilterOptions() {
if (this.isCurrentFilterColumnHasOptions()) {
return this.getCurrentFilterColumn().options ?? [];
}
throw "Options are not defined. Don't use this method if options are not available.";
},
getColumnOrAlias(columnOrAlias) {
this.columnOrAlias = columnOrAlias;
for (let column in this.columns) {
if (this.columns[column].index === this.columnOrAlias) {
this.type = this.columns[column].type;
switch (this.type) {
case 'string': {
this.stringConditionSelect = true;
this.numberConditionSelect = false;
this.booleanConditionSelect = false;
this.datetimeConditionSelect = false;
this.nullify();
break;
}
case 'datetime': {
this.stringConditionSelect = false;
this.numberConditionSelect = false;
this.booleanConditionSelect = false;
this.datetimeConditionSelect = true;
this.nullify();
break;
}
case 'boolean': {
this.stringConditionSelect = false;
this.numberConditionSelect = false;
this.booleanConditionSelect = true;
this.datetimeConditionSelect = false;
this.nullify();
break;
}
case 'number': {
this.stringConditionSelect = false;
this.numberConditionSelect = true;
this.booleanConditionSelect = false;
this.datetimeConditionSelect = false;
this.nullify();
break;
}
case 'price': {
this.stringConditionSelect = false;
this.numberConditionSelect = true;
this.booleanConditionSelect = false;
this.datetimeConditionSelect = false;
this.nullify();
break;
}
}
}
}
},
getResponse: function() {
let label = '';
for (let colIndex in this.columns) {
if (this.columns[colIndex].index == this.columnOrAlias) {
label = this.columns[colIndex].label;
break;
}
}
if (this.type === 'string' && this.stringValue !== null) {
this.$emit('onFilter', {
data: {
column: this.columnOrAlias,
condition: this.stringCondition,
response: encodeURIComponent(this.stringValue),
label
}
});
} else if (this.type === 'number') {
let indexConditions = true;
if (
this.filterIndex === this.columnOrAlias &&
(this.numberValue === 0 || this.numberValue < 0)
) {
indexConditions = false;
alert(this.translations.zeroIndex);
}
if (indexConditions) {
this.$emit('onFilter', {
data: {
column: this.columnOrAlias,
condition: this.numberCondition,
response: this.numberValue,
label
}
});
}
} else if (this.type === 'boolean') {
this.$emit('onFilter', {
data: {
column: this.columnOrAlias,
condition: this.booleanCondition,
response: this.booleanValue,
label
}
});
} else if (this.type === 'datetime') {
this.$emit('onFilter', {
data: {
column: this.columnOrAlias,
condition: this.datetimeCondition,
response: this.datetimeValue,
label
}
});
} else if (this.type === 'price') {
this.$emit('onFilter', {
data: {
column: this.columnOrAlias,
condition: this.numberCondition,
response: this.numberValue,
label
}
});
}
},
nullify() {
this.stringCondition = null;
this.datetimeCondition = null;
this.booleanCondition = null;
this.numberCondition = null;
}
}
};
</script>

View File

@ -0,0 +1,45 @@
<template>
<div class="control-group">
<select
class="control"
id="customer-group-switcher"
name="customer_group"
@change="changeCustomerGroup($event)"
>
<option
value="all"
:selected="extraFilters.current.customer_group == 'all'"
v-text="translations.allCustomerGroups"
></option>
<option
:key="customerGroupKey"
v-for="(customerGroup,
customerGroupKey) in extraFilters.customer_groups"
v-text="customerGroup.name"
:value="customerGroup.id"
:selected="
customerGroup.id == extraFilters.current.customer_group
"
></option>
</select>
</div>
</template>
<script>
export default {
props: ['extraFilters', 'translations'],
data() {
return {};
},
methods: {
changeCustomerGroup({ target }) {
this.$emit('onFilter', {
data: { type: 'customer_group', value: target.value }
});
}
}
};
</script>

View File

@ -0,0 +1,37 @@
<template>
<div class="control-group">
<select class="control" name="locale" @change="changeLocale($event)">
<option
value="all"
:selected="extraFilters.current.locale == 'all'"
v-text="translations.allLocales"
></option>
<option
:key="localeKey"
v-for="(locale, localeKey) in extraFilters.locales"
v-text="locale.name"
:value="locale.code"
:selected="locale.code == extraFilters.current.locale"
></option>
</select>
</div>
</template>
<script>
export default {
props: ['extraFilters', 'translations'],
data() {
return {};
},
methods: {
changeLocale({ target }) {
this.$emit('onFilter', {
data: { type: 'locale', value: target.value }
});
}
}
};
</script>

View File

@ -0,0 +1,45 @@
<template>
<div class="control-group">
<label
class="per-page-label"
for="perPage"
v-text="translations.itemsPerPage"
></label>
<select
id="perPage"
class="control"
name="perPage"
v-model="currentSelection"
v-on:change="paginate"
>
<option
v-for="index in this.perPageCount"
v-text="index"
:key="index"
:value="index"
></option>
</select>
</div>
</template>
<script>
export default {
props: ['perPage', 'translations'],
data() {
return {
perPageCount: [10, 20, 30, 40, 50],
currentSelection: this.perPage
};
},
methods: {
paginate() {
this.$emit('onFilter', {
data: { perPage: this.currentSelection }
});
}
}
};
</script>

View File

@ -0,0 +1,37 @@
<template>
<div class="search-filter">
<input
type="search"
id="search-field"
class="control"
:placeholder="translations.search"
v-model="searchValue"
v-on:keyup.enter="search(searchValue)"
/>
<div class="icon-wrapper">
<span
class="icon search-icon search-btn"
v-on:click="search(searchValue)"
></span>
</div>
</div>
</template>
<script>
export default {
props: ['translations'],
data() {
return {
searchValue: ''
};
},
methods: {
search(searchValue) {
this.$emit('onFilter', { data: { searchValue } });
}
}
};
</script>

View File

@ -0,0 +1,99 @@
export default {
methods: {
getDatagridsInfoStorageKey() {
return 'datagridsInfo';
},
analyzeDatagridsInfo() {
if (!this.isDataLoaded && this.url === `${this.src}?v=1`) {
let datagridInfo = this.getCurrentDatagridInfo();
if (datagridInfo) {
/**
* Will check this later. Don't remove it.
*/
// this.filterCurrentDatagridFromDatagridsInfo();
this.url = datagridInfo.previousUrl;
this.filters = datagridInfo.previousFilters;
}
} else {
let datagridsInfo = this.getDatagridsInfo();
if (datagridsInfo && datagridsInfo.length > 0) {
if (this.isCurrentDatagridInfoExists()) {
datagridsInfo = datagridsInfo.map(datagrid => {
if (datagrid.id === this.id) {
return this.getDatagridsInfoDefaults();
}
return datagrid;
});
} else {
datagridsInfo.push(this.getDatagridsInfoDefaults());
}
} else {
datagridsInfo = [this.getDatagridsInfoDefaults()];
}
this.updateDatagridsInfo(datagridsInfo);
}
},
isCurrentDatagridInfoExists() {
let datagridsInfo = this.getDatagridsInfo();
return !!datagridsInfo.find(({ id }) => id === this.id);
},
getCurrentDatagridInfo() {
let datagridsInfo = this.getDatagridsInfo();
return this.isCurrentDatagridInfoExists()
? datagridsInfo.find(({ id }) => id === this.id)
: null;
},
getDatagridsInfoDefaults() {
return {
id: this.id,
previousFilters: this.filters,
previousUrl: this.url
};
},
getDatagridsInfo() {
let storageInfo = localStorage.getItem(
this.getDatagridsInfoStorageKey()
);
return !this.isValidJsonString(storageInfo)
? []
: JSON.parse(storageInfo) ?? [];
},
updateDatagridsInfo(info) {
localStorage.setItem(
this.getDatagridsInfoStorageKey(),
JSON.stringify(info)
);
},
filterCurrentDatagridFromDatagridsInfo() {
let datagridsInfo = this.getDatagridsInfo();
datagridsInfo = datagridsInfo.filter(({ id }) => id !== this.id);
this.updateDatagridsInfo(datagridsInfo);
},
isValidJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
}
};

View File

@ -0,0 +1,58 @@
<template>
<div class="">
<div
class="dropdown-filters per-page"
v-if="extraFilters.channels != undefined"
>
<channel-filter
:extra-filters="extraFilters"
:translations="translations"
@onFilter="changeExtraFilter($event)"
></channel-filter>
</div>
<div
class="dropdown-filters per-page"
v-if="extraFilters.locales != undefined"
>
<locale-filter
:extra-filters="extraFilters"
:translations="translations"
@onFilter="changeExtraFilter($event)"
></locale-filter>
</div>
<div
class="dropdown-filters per-page"
v-if="extraFilters.customer_groups != undefined"
>
<customer-group-filter
:extra-filters="extraFilters"
:translations="translations"
@onFilter="changeExtraFilter($event)"
></customer-group-filter>
</div>
</div>
</template>
<script>
import ChannelFilter from '../filters/channel-filter';
import CustomerGroupFilter from '../filters/customer-group-filter';
import LocaleFilter from '../filters/locale-filter';
export default {
props: ['extraFilters', 'translations'],
components: {
ChannelFilter,
CustomerGroupFilter,
LocaleFilter
},
methods: {
changeExtraFilter($event) {
this.$emit('onFilter', $event);
}
}
};
</script>

View File

@ -0,0 +1,39 @@
<template>
<span class="filter-tag" style="text-transform: capitalize">
<span v-if="filter.column == 'perPage'">perPage</span>
<span v-else>{{ filter.label }}</span>
<span class="wrapper" v-if="filter.prettyValue">
{{ filter.prettyValue }}
<span
class="icon cross-icon"
v-on:click="removeFilter(filter)"
></span>
</span>
<span class="wrapper" v-else>
{{ decodeURIComponent(filter.val) }}
<span
class="icon cross-icon"
v-on:click="removeFilter(filter)"
></span>
</span>
</span>
</template>
<script>
export default {
props: ['filter'],
data() {
return {};
},
methods: {
removeFilter() {
this.$emit('onRemoveFilter');
}
}
};
</script>

View File

@ -0,0 +1,34 @@
<template>
<div class="filtered-tags">
<template v-if="filters.length > 0">
<datagrid-filter-tag
:key="filterKey"
:filter="filter"
v-for="(filter, filterKey) in filters"
@onRemoveFilter="removeFilter(filter)"
></datagrid-filter-tag>
</template>
</div>
</template>
<script>
import DatagridFilterTag from './datagrid-filter-tag.vue';
export default {
props: ['filters'],
components: {
DatagridFilterTag
},
data() {
return {};
},
methods: {
removeFilter(filter) {
this.$emit('onRemoveFilter', { data: { filter } });
}
}
};
</script>

View File

@ -0,0 +1,48 @@
<template>
<div
class="pagination shop mt-50"
v-if="
typeof paginated !== 'undefined' &&
paginated &&
records.last_page > 1
"
>
<a
v-for="(link, index) in records.links"
:key="index"
href="javascript:void(0);"
:data-page="link.url"
:class="
`page-item ${index == 0 ? 'previous' : ''} ${
link.active ? 'active' : ''
} ${index == records.links.length - 1 ? 'next' : ''}`
"
@click="changePage(link.url)"
>
<i class="icon angle-left-icon" v-if="index == 0"></i>
<i
class="icon angle-right-icon"
v-else-if="index == records.links.length - 1"
></i>
<span v-text="link.label" v-else></span>
</a>
</div>
</template>
<script>
export default {
props: ['paginated', 'records'],
data() {
return {};
},
methods: {
changePage(pageLink) {
this.$emit('onChangePage', { data: { pageLink } });
}
}
};
</script>

View File

@ -0,0 +1,449 @@
<template>
<table class="table">
<thead v-if="massActionsToggle">
<tr
class="mass-action"
v-if="massActionsToggle"
style="height: 65px"
>
<th colspan="100%">
<div
class="mass-action-wrapper"
style="display: flex; flex-direction: row; align-items: center; justify-content: flex-start;"
>
<span
class="massaction-remove"
v-on:click="removeMassActions"
style="margin-right: 10px; margin-top: 5px"
>
<span class="icon checkbox-dash-icon"></span>
</span>
<form
method="POST"
id="mass-action-form"
style="display: inline-flex"
action=""
:onsubmit="
`return confirm('${massActionConfirmText}')`
"
>
<input
type="hidden"
name="_token"
:value="getCsrf()"
/>
<input
type="hidden"
id="indexes"
name="indexes"
v-model="dataIds"
/>
<div class="control-group">
<select
class="control"
v-model="massActionType"
@change="changeMassActionTarget"
name="massaction-type"
required
>
<option
v-for="(massAction,
index) in massActions"
v-text="massAction.label"
:key="index"
:value="{
id: index,
value: massAction.type
}"
></option>
</select>
</div>
<div
class="control-group"
style="margin-left: 10px"
v-if="massActionType.value == 'update'"
>
<select
class="control"
v-model="massActionUpdateValue"
name="update-options"
required
>
<option
:key="id"
v-for="(massActionValue,
id) in massActionValues"
:value="massActionValue"
v-text="id"
></option>
</select>
</div>
<button
v-text="translations.submit"
type="submit"
class="btn btn-sm btn-primary"
style="margin-left: 10px; white-space: nowrap;"
></button>
</form>
</div>
</th>
</tr>
</thead>
<thead v-if="massActionsToggle == false">
<tr style="height: 65px">
<th
v-if="enableMassActions"
class="grid_head"
id="mastercheckbox"
style="width: 50px"
>
<span class="checkbox">
<input
type="checkbox"
v-model="allSelected"
v-on:change="selectAll"
:disabled="!records.data.length"
/>
<label class="checkbox-view" for="checkbox"></label>
</span>
</th>
<th
:key="columnKey"
v-for="(column, columnKey) in columns"
v-text="column.label"
class="grid_head"
:class="{ sortable: column.sortable }"
:style="
typeof column.width !== 'undefined' && column.width
? `width: ${column.width}`
: ''
"
v-on:click="
typeof column.sortable !== 'undefined' &&
column.sortable
? sortCollection(column.index)
: {}
"
></th>
<th v-if="enableActions" v-text="translations.actions"></th>
</tr>
</thead>
<tbody>
<template v-if="records.data.length">
<tr
:key="recordKey"
v-for="(record, recordKey) in records.data"
>
<td v-if="enableMassActions">
<span class="checkbox">
<input
type="checkbox"
v-model="dataIds"
@change="select"
:value="record[index]"
/>
<label class="checkbox-view" for="checkbox"></label>
</span>
</td>
<td
:key="columnKey"
v-for="(column, columnKey) in columns"
v-html="record[column.index]"
:data-value="column.label"
></td>
<td
class="actions"
style="white-space: nowrap; width: 100px"
v-if="enableActions"
:data-value="translations.actions"
>
<div class="action">
<a
:key="actionIndex"
v-for="(action, actionIndex) in actions"
v-if="record[`${action.key}_to_display`]"
:id="
record[
typeof action.index !== 'undefined' &&
action.index
? action.index
: index
]
"
:href="
action.method == 'GET'
? record[`${action.key}_url`]
: 'javascript:void(0);'
"
v-on:click="
action.method != 'GET'
? doAction($event)
: {}
"
:data-method="action.method"
:data-action="record[`${action.key}_url`]"
:data-token="getCsrf()"
:target="
typeof action.target !== 'undefined' &&
action.target
? action.target
: ''
"
:title="
typeof action.title !== 'undefined' &&
action.title
? action.title
: ''
"
>
<span :class="action.icon"></span>
</a>
</div>
</td>
</tr>
</template>
<template v-else>
<tr>
<td colspan="10">
<p
style="text-align: center"
v-text="translations.norecords"
></p>
</td>
</tr>
</template>
</tbody>
</table>
</template>
<script>
export default {
props: [
'actions',
'columns',
'enableActions',
'enableMassActions',
'index',
'massActions',
'massActionTargets',
'records',
'translations'
],
data() {
return {
allSelected: false,
dataIds: [],
gridCurrentData: this.records,
massActionTarget: null,
massActionsToggle: false,
massActionType: this.getDefaultMassActionType(),
massActionUpdateValue: null,
massActionValues: [],
massActionConfirmText: this.translations.clickOnAction
};
},
methods: {
select() {
this.allSelected = false;
if (this.dataIds.length === 0) {
this.massActionsToggle = false;
this.massActionType = this.getDefaultMassActionType();
} else {
this.massActionsToggle = true;
}
},
selectAll() {
this.dataIds = [];
this.massActionsToggle = true;
if (this.allSelected) {
if (this.gridCurrentData.hasOwnProperty('data')) {
for (let currentData in this.gridCurrentData.data) {
let i = 0;
for (let currentId in this.gridCurrentData.data[
currentData
]) {
if (i == 0) {
this.dataIds.push(
this.gridCurrentData.data[currentData][
this.index
]
);
}
i++;
}
}
} else {
for (let currentData in this.gridCurrentData) {
let i = 0;
for (let currentId in this.gridCurrentData[
currentData
]) {
if (i === 0)
this.dataIds.push(
this.gridCurrentData[currentData][currentId]
);
i++;
}
}
}
}
},
getDefaultMassActionType: function() {
return {
id: null,
value: null
};
},
changeMassActionTarget: function() {
if (this.massActionType.value === 'delete') {
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;
}
}
}
if (this.massActionType.value === 'update') {
for (let i in this.massActionTargets) {
if (this.massActionTargets[i].type === 'update') {
this.massActionValues = this.massActions[
this.massActionType.id
].options;
this.massActionTarget = this.massActionTargets[
i
].action;
this.massActionConfirmText = this.massActionTargets[i]
.confirm_text
? this.massActionTargets[i].confirm_text
: this.massActionConfirmText;
break;
}
}
}
document.getElementById(
'mass-action-form'
).action = this.massActionTarget;
},
removeMassActions() {
this.dataIds = [];
this.massActionsToggle = false;
this.allSelected = false;
this.massActionType = this.getDefaultMassActionType();
},
sortCollection(alias) {
let label = '';
for (let colIndex in this.columns) {
if (this.columns[colIndex].index === alias) {
label = this.columns[colIndex].label;
break;
}
}
this.$emit('onSorting', {
data: {
column: 'sort',
condition: alias,
response: 'asc',
label
}
});
},
doAction(e, message, type) {
let self = this;
let element = e.currentTarget;
if (message) {
element = e.target.parentElement;
}
message = message || this.translations.massActionDelete;
if (confirm(message)) {
axios
.post(element.getAttribute('data-action'), {
_token: element.getAttribute('data-token'),
_method: element.getAttribute('data-method')
})
.then(function(response) {
const { data } = response;
/**
* If refirect is true, then pass redirect url in the response.
*
* Else, it will reload table only.
*/
if (data.redirect !== undefined && data.redirect) {
window.location.href = data.redirect;
} else {
self.$emit('onActionSuccess');
window.flashMessages.push({
type: 'alert-success',
message: data.message
});
self.$root.addFlashMessages();
}
})
.catch(function(error) {
const { response } = error;
window.flashMessages.push({
type: 'alert-error',
message:
response.data.message ?? 'Something went wrong!'
});
self.$root.addFlashMessages();
});
e.preventDefault();
} else {
e.preventDefault();
}
}
}
};
</script>

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
"/js/velocity.js": "/js/velocity.js?id=f655ac65cbd1aa549cba57f77b9a4344",
"/js/manifest.js": "/js/manifest.js?id=e069a8f952a02ea0f290bcca8fab930e",
"/js/components.js": "/js/components.js?id=13ebf112e40292178d2386143e9d75cd",
"/css/velocity.css": "/css/velocity.css?id=f0b348e63aeb729dfa6f16132f3a877a",
"/css/velocity.css": "/css/velocity.css?id=63b696d9af02aa4e86927bc29a63da5f",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=b67a82956e53163b5e3ff45a44f9778f",
"/images/icon-calendar.svg": "/images/icon-calendar.svg?id=870d0f733a58377422766f3152e15486",
"/images/icon-camera.svg": "/images/icon-camera.svg?id=b2fd2f9e17e1ccee96e29f6c6cec91e8",

View File

@ -34,6 +34,10 @@
background: #f8f9fa;
color: $font-color;
border-right: 1px solid #ccc !important;
&.sortable {
cursor: pointer;
}
&:last-child {
border-right: none;

View File

@ -184,7 +184,7 @@ return [
],
'header' => [
'cart' => 'गाड़ी',
'cart' => 'कार्ट',
'guest' => 'अतिथि',
'logout' => 'लॉग आउट',
'title' => 'हेतु',
@ -203,7 +203,7 @@ return [
],
'minicart' => [
'cart' => 'गाड़ी',
'cart' => 'कार्ट',
'view-cart' => 'गाडी देंखे',
],
@ -212,7 +212,7 @@ return [
'checkout' => 'चेक आउट',
'cart' => [
'view-cart' => 'गाडी देंखे',
'cart-summary' => 'गाड़ी का संक्षिप्त विवरण',
'cart-summary' => 'कार्ट का संक्षिप्त विवरण',
],
'qty' => 'मात्रा',
'items' => 'आइटम',

View File

@ -11,7 +11,7 @@
cart-items-count="{{ $cartItemsCount }}"
cart-route="{{ route('shop.checkout.cart.index') }}"
:locale="{{ json_encode(core()->getCurrentLocale()) }}"
:all-locales="{{ json_encode(core()->getCurrentChannel()->locales) }}"
:all-locales="{{ json_encode(core()->getCurrentChannel()->locales()->orderBy('name')->get()) }}"
:currency="{{ json_encode(core()->getCurrentCurrency()) }}"
:all-currencies="{{ json_encode(core()->getCurrentChannel()->currencies) }}"
>