akaunting 3.0 (the last dance)
This commit is contained in:
@ -50,75 +50,3 @@
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.document-loading {
|
||||
width: 1140px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.document-loading div {
|
||||
margin-top: unset;
|
||||
margin-left: unset;
|
||||
}
|
||||
|
||||
.current-tab {
|
||||
background-color: #f6f9fc;
|
||||
}
|
||||
|
||||
.current-tab-btn {
|
||||
text-align: right;
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
.form-container .invalid-feedback {
|
||||
position: absolute;
|
||||
bottom: -18px;
|
||||
}
|
||||
|
||||
.form-container .has-error {
|
||||
position: relative;
|
||||
margin-bottom: unset !important;
|
||||
}
|
||||
|
||||
.form-container .has-error .form-control {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
border-right: 1px solid;
|
||||
}
|
||||
|
||||
.el-step__icon {
|
||||
-webkit-transition: unset;
|
||||
transition: unset;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 991px) {
|
||||
.form-container .has-error {
|
||||
position: relative;
|
||||
margin-bottom: 1.5rem !important;
|
||||
}
|
||||
|
||||
.current-tab-btn {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.form-container .form-group {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
77
resources/assets/js/bootstrap.js
vendored
77
resources/assets/js/bootstrap.js
vendored
@ -7,14 +7,6 @@ window._ = require('lodash');
|
||||
* code may be modified to fit the specific needs of your application.
|
||||
*/
|
||||
|
||||
try {
|
||||
if (!window.$) {
|
||||
window.$ = window.jQuery = require('jquery');
|
||||
}
|
||||
|
||||
//require('bootstrap-sass');
|
||||
} catch (e) {}
|
||||
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
@ -41,72 +33,3 @@ window.axios.defaults.headers.common['Content-Type'] = 'multipart/form-data';
|
||||
// broadcaster: 'pusher',
|
||||
// key: 'your-pusher-key'
|
||||
// });
|
||||
|
||||
//(function ($) {
|
||||
jQuery.fn.serializeFormJSON = function () {
|
||||
var o = {};
|
||||
var a = this.serializeArray();
|
||||
|
||||
$.each(a, function () {
|
||||
if (o[this.name]) {
|
||||
if (!o[this.name].push) {
|
||||
o[this.name] = [o[this.name]];
|
||||
}
|
||||
|
||||
o[this.name].push(this.value || '');
|
||||
} else {
|
||||
o[this.name] = this.value || '';
|
||||
}
|
||||
});
|
||||
|
||||
return o;
|
||||
};
|
||||
|
||||
jQuery.fn.serializeFormJSONShow = function () {
|
||||
var o = {};
|
||||
var a = this.serializeArray();
|
||||
|
||||
$.each(a, function () {
|
||||
if (o[this.name]) {
|
||||
if (!o[this.name].push) {
|
||||
o[this.name] = [o[this.name]];
|
||||
}
|
||||
|
||||
o[this.name].push(true);
|
||||
} else {
|
||||
o[this.name] = true;
|
||||
}
|
||||
});
|
||||
|
||||
return o;
|
||||
};
|
||||
|
||||
jQuery.fn.serializeAll = function () {
|
||||
var o = {};
|
||||
var a = this;
|
||||
|
||||
$.each(this, function () {
|
||||
if (o[this.name]) {
|
||||
if (!o[this.name].push) {
|
||||
o[this.name] = [o[this.name]];
|
||||
}
|
||||
|
||||
o[this.name].push(this.value || '');
|
||||
} else {
|
||||
o[this.name] = this.value || '';
|
||||
}
|
||||
});
|
||||
|
||||
return o;
|
||||
};
|
||||
//})(jQuery);
|
||||
|
||||
jQuery(document).ready(function () {
|
||||
jQuery('input[type="radio"]').each(function () {
|
||||
if (jQuery(this).parent().parent().hasClass('radio-yes-no')) {
|
||||
if (jQuery(this).val() == 1) {
|
||||
jQuery(this).parent().trigger('click');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1,159 +0,0 @@
|
||||
<template>
|
||||
<div v-if="video || screenshots">
|
||||
<el-carousel :height="height"
|
||||
:initial-index="initial_index"
|
||||
:trigger="trigger" :autoplay="autoplay"
|
||||
:indicator-position="indicator_position"
|
||||
:type="type" :loop="loop" :direction="direction"
|
||||
:interval="interval" :arrow="arrow">
|
||||
|
||||
<el-carousel-item v-if="video">
|
||||
<iframe class="carousel-frame w-100" height="365px"
|
||||
:src="'https://www.youtube-nocookie.com/embed/' + video"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
<div class="carousel-description py-2">
|
||||
{{ name }}
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
|
||||
<el-carousel-item v-for="(screenshot, index) in screenshots" :key="index">
|
||||
<img @click="openGallery(index)" class="d-block w-100 carousel-frame" height="365px" :src="screenshot.path_string" :alt="screenshot.alt_attribute">
|
||||
<div class="carousel-description py-2" v-if="screenshot.description">
|
||||
{{ screenshot.description }}
|
||||
</div>
|
||||
<div class="carousel-description py-2" v-else>
|
||||
{{ name }}
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
|
||||
<LightBox
|
||||
v-if="media.length"
|
||||
ref="lightbox"
|
||||
:media="media"
|
||||
:show-caption="true"
|
||||
:show-light-box="false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import {Image, Carousel, CarouselItem} from 'element-ui';
|
||||
|
||||
import LightBox from 'vue-image-lightbox';
|
||||
import 'vue-image-lightbox/dist/vue-image-lightbox.min.css';
|
||||
import VueLazyLoad from 'vue-lazyload';
|
||||
|
||||
Vue.use(VueLazyLoad);
|
||||
|
||||
export default {
|
||||
name: "akaunting-carousel",
|
||||
|
||||
components: {
|
||||
[Image.name]: Image,
|
||||
[Carousel.name]: Carousel,
|
||||
[CarouselItem.name]: CarouselItem,
|
||||
LightBox
|
||||
},
|
||||
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
default: null,
|
||||
description: "App Name"
|
||||
},
|
||||
video: {
|
||||
type: String,
|
||||
default: null,
|
||||
description: "App Video"
|
||||
},
|
||||
screenshots: {
|
||||
type: Array,
|
||||
default: false,
|
||||
description: "App Screenshots"
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: null,
|
||||
description: "height of the carousel"
|
||||
},
|
||||
initial_index: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
description: "index of the initially active slide (starting from 0)"
|
||||
},
|
||||
trigger: {
|
||||
type: String,
|
||||
default: 'hover',
|
||||
description: "how indicators are triggered (hover/click)"
|
||||
},
|
||||
autoplay: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: "whether automatically loop the slides"
|
||||
},
|
||||
interval: {
|
||||
type: Number,
|
||||
default: 3000,
|
||||
description: "interval of the auto loop, in milliseconds"
|
||||
},
|
||||
indicator_position: {
|
||||
type: String,
|
||||
default: 'none',
|
||||
description: "position of the indicators (outside/none)"
|
||||
},
|
||||
arrow: {
|
||||
type: String,
|
||||
default: 'hover',
|
||||
description: "when arrows are shown (always/hover/never)"
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "type of the Carousel (card)"
|
||||
},
|
||||
loop: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
description: "display the items in loop"
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'horizontal',
|
||||
description: "display direction (horizontal/vertical)"
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
let media = [];
|
||||
|
||||
if (this.screenshots.length) {
|
||||
let name = this.name;
|
||||
|
||||
this.screenshots.forEach(function(screenshot) {
|
||||
media.push({ // For image
|
||||
thumb: screenshot.path_string,
|
||||
src: screenshot.path_string,
|
||||
caption: (screenshot.description.length) ? screenshot.description : name,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.media = media;
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
media: [],
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
openGallery(index) {
|
||||
this.$refs.lightbox.showImage(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
222
resources/assets/js/components/AkauntingColor.vue
Normal file
222
resources/assets/js/components/AkauntingColor.vue
Normal file
@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<base-input :label="title" :name="name"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:class="[
|
||||
{'readonly': readonly},
|
||||
{'disabled': disabled},
|
||||
formClasses
|
||||
]"
|
||||
:error="formError">
|
||||
<div class="flex justify-between relative mt-1">
|
||||
<input type="text" @change="change" :name="name" :id="name" v-model="color" @keyup="addColor" class="form-element">
|
||||
|
||||
<div class="absolute w-7 h-7 flex rounded-full my-auto bottom-2 right-2 cursor-pointer"
|
||||
ref="dropdownMenu"
|
||||
@click="openPalette"
|
||||
:class="`bg-${color}`"
|
||||
:style="{ backgroundColor: color }"
|
||||
></div>
|
||||
|
||||
<transition name="fade">
|
||||
<div v-show="isOpen" class="w-full border border-gray-300 origin-top-right absolute left-0 top-full mt-2 rounded-md shadow-lg z-10">
|
||||
<div class="rounded-md bg-white shadow-xs p-2">
|
||||
<div class="flex">
|
||||
<div class="w-full flex flex-wrap justify-between">
|
||||
<div v-for="color in colors" :key="color">
|
||||
<div v-for="variant in variants"
|
||||
:key="variant"
|
||||
:colorId="`${color}-${variant}`"
|
||||
class="rounded-full m-1 color cursor-pointer"
|
||||
:class="[`bg-${color}-${variant}`, small ? 'w-6 h-6 lg:w-4 lg:h-4' : 'w-8 h-8 xl:w-6 xl:h-6 2xl:w-8 2xl:h-8']"
|
||||
@click="setColor($event)"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</base-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-color',
|
||||
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Selectbox label text"
|
||||
},
|
||||
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Selectbox input placeholder text"
|
||||
},
|
||||
|
||||
formClasses: {
|
||||
type: Array,
|
||||
default: null,
|
||||
description: "Selectbox input class name"
|
||||
},
|
||||
|
||||
formError: {
|
||||
type: String,
|
||||
default: null,
|
||||
description: "Selectbox input error message"
|
||||
},
|
||||
|
||||
icon: {
|
||||
type: String,
|
||||
description: "Prepend icon (left)"
|
||||
},
|
||||
|
||||
name: {
|
||||
type: String,
|
||||
default: null,
|
||||
description: "Selectbox attribute name"
|
||||
},
|
||||
|
||||
value: {
|
||||
type: [String, Number, Array, Object],
|
||||
default: '',
|
||||
description: "Selectbox selected value"
|
||||
},
|
||||
|
||||
model: {
|
||||
type: [String, Number, Array, Object],
|
||||
default: '',
|
||||
description: "Selectbox selected model"
|
||||
},
|
||||
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: "Selectbox disabled status"
|
||||
},
|
||||
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: "Selectbox disabled status"
|
||||
},
|
||||
|
||||
small: {
|
||||
type: [Boolean, String],
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
color: 'green-500',
|
||||
hexCode: null,
|
||||
|
||||
colors: [
|
||||
'gray',
|
||||
'red',
|
||||
'yellow',
|
||||
'green',
|
||||
'blue',
|
||||
'indigo',
|
||||
'purple',
|
||||
'pink',
|
||||
],
|
||||
|
||||
variants: [
|
||||
50,
|
||||
100,
|
||||
200,
|
||||
300,
|
||||
400,
|
||||
500,
|
||||
600,
|
||||
700,
|
||||
800,
|
||||
900,
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
document.addEventListener('click', this.closeIfClickedOutside);
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Check Here..
|
||||
if (this.value) {
|
||||
this.color = this.value;
|
||||
}
|
||||
|
||||
this.$emit('interface', this.color);
|
||||
|
||||
setTimeout(function() {
|
||||
this.change();
|
||||
}.bind(this), 800);
|
||||
},
|
||||
|
||||
methods: {
|
||||
change() {
|
||||
this.$emit('interface', this.color);
|
||||
|
||||
this.$emit('change', this.color);
|
||||
},
|
||||
|
||||
openPalette() {
|
||||
this.isOpen = ! this.isOpen;
|
||||
},
|
||||
|
||||
setColor(event) {
|
||||
this.isOpen = false;
|
||||
this.color = event.target.getAttribute('colorid');
|
||||
this.hexCode = null;
|
||||
},
|
||||
|
||||
addColor() {
|
||||
let code = this.color;
|
||||
|
||||
this.hexCode = code.includes('#') ? code : '#' + code;
|
||||
},
|
||||
|
||||
closeIfClickedOutside(event) {
|
||||
let el = this.$refs.dropdownMenu;
|
||||
let target = event.target;
|
||||
|
||||
if (el !== target && ! el.contains(target)) {
|
||||
this.isOpen = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
color: function (value) {
|
||||
this.change();
|
||||
},
|
||||
|
||||
value: function (value) {
|
||||
this.color = value;
|
||||
},
|
||||
|
||||
model: function (value) {
|
||||
this.color = value;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .2s
|
||||
}
|
||||
|
||||
.fade-enter, .fade-leave-to
|
||||
/* .fade-leave-active in <2.1.8 */
|
||||
{
|
||||
opacity: 0
|
||||
}
|
||||
</style>
|
@ -1,35 +1,35 @@
|
||||
<template>
|
||||
<div class="document-add-info-content-info-business fs-exclude">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-borderless p-0">
|
||||
<div class="">
|
||||
<div class="flex items-start">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="text-right p-0">
|
||||
<strong class="text-strong">{{ company.name }}</strong>
|
||||
<th class="text-left p-0">
|
||||
<span class="font-medium text-left text-sm p-0">{{ company.name }}</span>
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="company.address">
|
||||
<th class="text-right p-0">
|
||||
<th class="font-normal text-sm text-left p-0">
|
||||
{{ company.address }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="company.location">
|
||||
<th class="text-right p-0">
|
||||
<th class="font-normal text-sm text-left p-0">
|
||||
{{ company.location }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="company.tax_number">
|
||||
<th class="text-right p-0">
|
||||
<th class="font-normal text-sm text-left p-0">
|
||||
{{ taxNumberText }}: {{ company.tax_number }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="company.phone">
|
||||
<th class="text-right p-0">
|
||||
<th class="font-normal text-sm text-left p-0">
|
||||
{{ company.phone }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-right p-0">
|
||||
<th class="font-normal text-sm text-left p-0">
|
||||
{{ company.email }}
|
||||
</th>
|
||||
</tr>
|
||||
@ -37,7 +37,11 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-link text-right" @click="onEditCompany">{{ buttonText }}</button>
|
||||
<div class="absolute right-0 top-0 group">
|
||||
<div class="w-6 h-7 flex items-center justify-center rounded-lg p-0 group-hover:bg-gray-100">
|
||||
<span class="material-icons-outlined text-lg opacity-70 group-hover:text-gray-500 cursor-pointer" @click="onEditCompany">edit</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<component v-bind:is="company_html" @submit="onSubmit" @cancel="onCancel"></component>
|
||||
</div>
|
||||
@ -51,7 +55,7 @@ import { Select, Option, OptionGroup, ColorPicker } from 'element-ui';
|
||||
import AkauntingModalAddNew from './AkauntingModalAddNew';
|
||||
import AkauntingModal from './AkauntingModal';
|
||||
import AkauntingMoney from './AkauntingMoney';
|
||||
import AkauntingRadioGroup from './forms/AkauntingRadioGroup';
|
||||
import AkauntingRadioGroup from './AkauntingRadioGroup';
|
||||
import AkauntingSelect from './AkauntingSelect';
|
||||
import AkauntingDate from './AkauntingDate';
|
||||
|
||||
@ -74,11 +78,6 @@ export default {
|
||||
},
|
||||
|
||||
props: {
|
||||
buttonText: {
|
||||
type: String,
|
||||
default: 'Edit your business address ',
|
||||
description: 'Input placeholder'
|
||||
},
|
||||
taxNumberText: {
|
||||
type: String,
|
||||
default: 'Tax Number',
|
||||
@ -223,7 +222,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
@ -240,7 +239,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
456
resources/assets/js/components/AkauntingConnectTransactions.vue
Normal file
456
resources/assets/js/components/AkauntingConnectTransactions.vue
Normal file
@ -0,0 +1,456 @@
|
||||
<template>
|
||||
<SlideYUpTransition :duration="animationDuration">
|
||||
<div class="modal w-full h-full fixed top-0 left-0 right-0 z-50 overflow-y-auto overflow-hidden modal-add-new fade items-center justify-center"
|
||||
:class="[{'show flex flex-wrap modal-background': show}, {'hidden': !show}]"
|
||||
v-show="show"
|
||||
tabindex="-1"
|
||||
role="dialog"
|
||||
:aria-hidden="!show">
|
||||
<div class="w-full my-10 m-auto flex flex-col" :class="modalDialogClass ? modalDialogClass : 'max-w-screen-sm'">
|
||||
<slot name="modal-content">
|
||||
<div class="modal-content">
|
||||
<div class="p-5 bg-body rounded-tl-lg rounded-tr-lg">
|
||||
<div class="flex items-center justify-between border-b pb-5">
|
||||
<slot name="card-header">
|
||||
<h4 class="text-base font-medium">
|
||||
{{ translations.title }}
|
||||
</h4>
|
||||
|
||||
<button type="button" class="text-lg" @click="onCancel" aria-hidden="true">
|
||||
<span class="rounded-md border-b-2 px-2 py-1 text-sm bg-gray-100">esc</span>
|
||||
</button>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<slot name="modal-body">
|
||||
<div class="px-5 bg-body">
|
||||
<template v-if="transaction">
|
||||
<div class="flex flex-col items-start gap-y-3">
|
||||
<div class="text-left text-sm">
|
||||
<div class="font-medium">
|
||||
{{ translations.contact }}
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ transaction.contact.name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="text-left text-sm">
|
||||
<div class="font-medium">
|
||||
{{ translations.category }}
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ transaction.category.name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="text-left text-sm">
|
||||
<div class="font-medium">
|
||||
{{ translations.account }}
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ transaction.account.name }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="relative sm:col-span-6 mt-3">
|
||||
<div style="table-layout: fixed;">
|
||||
<div class="overflow-x-visible overflow-y-hidden">
|
||||
<table class="w-full" id="items" style="table-layout: fixed">
|
||||
<thead class="border-b">
|
||||
<tr>
|
||||
<th colspan="3" class="w-12/12 px-0 text-left border-t-0 border-r-0 border-b-0">
|
||||
{{ translations.document }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<colgroup>
|
||||
<col style="width: 20%;">
|
||||
<col style="width: 80%;">
|
||||
</colgroup>
|
||||
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in form.items" :index="index" class="border-b border-gray-200">
|
||||
<td class="px-0 border-r-0 border-b-0 truncate">
|
||||
<div class="text-sm">
|
||||
<div class="truncate">
|
||||
<b>{{ translations.number }}:</b> {{ row.number }}
|
||||
</div>
|
||||
|
||||
<div class="truncate" v-if="row.notes">
|
||||
<b>{{ translations.notes }}:</b> {{ row.notes }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" style="font-size: 13px;">
|
||||
<div class="col-md-12 long-texts">
|
||||
<b>{{ translations.contact }}:</b> {{ row.contact }}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="px-0 border-l-0 border-b-0 border-r-0">
|
||||
<div class="flex items-center justify-end">
|
||||
<akaunting-money
|
||||
:col="''"
|
||||
:masked="true"
|
||||
name="amount"
|
||||
title=""
|
||||
:currency="currency"
|
||||
:dynamic-currency="currency"
|
||||
:value="row.amount"
|
||||
:row-input="true"
|
||||
:money-class="'text-right input-price'"
|
||||
@input="checkAmount(index, $event)"
|
||||
></akaunting-money>
|
||||
|
||||
<akaunting-money
|
||||
class="hidden"
|
||||
:masked="true"
|
||||
name="max_amount"
|
||||
title=""
|
||||
:group_class="null"
|
||||
:currency="currency"
|
||||
v-model="row.max_amount"
|
||||
:dynamic-currency="currency"
|
||||
:row-input="true"
|
||||
:disabled="true"
|
||||
></akaunting-money>
|
||||
|
||||
<div class="pl-2 group">
|
||||
<button type="button" @click="onDeleteItem(index)" class="w-6 h-7 flex items-center rounded-lg p-0 group-hover:bg-gray-100">
|
||||
<span class="w-full material-icons-outlined text-lg text-gray-300 group-hover:text-gray-500">delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id="addItem">
|
||||
<td colspan="3" class="w-12/12 p-0">
|
||||
<akaunting-document-button
|
||||
:items="documents"
|
||||
:selectedItems="form.items"
|
||||
:dynamic-currency="currency"
|
||||
@document-selected="onAddItem($event)"
|
||||
:no-data-text="translations.no_data"
|
||||
:placeholder="translations.placeholder_search"
|
||||
:add-item-text="translations.add_an"
|
||||
></akaunting-document-button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-6">
|
||||
<div class="overflow-y-hidden py-5">
|
||||
<table id="totals" class="float-right">
|
||||
<colgroup>
|
||||
<col style="width: 51.5%;">
|
||||
<col style="width: 30%;">
|
||||
<col style="width: 18.5%;">
|
||||
</colgroup>
|
||||
<tbody id="document-total-rows">
|
||||
<tr id="tr-total">
|
||||
<td class="border-t-0 p-0"></td>
|
||||
|
||||
<td class="font-medium text-sm text-right border-r-0 border-b-0 align-middle py-0 pr-0">
|
||||
{{ translations.total }}
|
||||
</td>
|
||||
|
||||
<td class="text-sm text-right border-b-0 p-0">
|
||||
<div>
|
||||
<money
|
||||
:name="'total_amount'"
|
||||
:value="total_amount"
|
||||
v-bind="money"
|
||||
masked
|
||||
disabled
|
||||
class="px-0 disabled-money text-right banking-price-text"
|
||||
style="height: unset;"
|
||||
></money>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id="tr-transaction-amount">
|
||||
<td class="border-t-0 p-0"></td>
|
||||
|
||||
<td class="font-medium text-sm text-right border-r-0 border-b-0 align-middle py-0 pr-0">
|
||||
{{ translations.transaction + ' ' + translations.amount }}
|
||||
</td>
|
||||
|
||||
<td class="text-sm text-right border-b-0 p-0">
|
||||
<div>
|
||||
<money
|
||||
:name="'transaction_amount'"
|
||||
:value="transaction.amount"
|
||||
v-bind="money"
|
||||
masked
|
||||
disabled
|
||||
class="px-0 disabled-money text-right banking-price-text"
|
||||
style="height: unset;"
|
||||
v-if="transaction"
|
||||
></money>
|
||||
</div>
|
||||
<akaunting-money
|
||||
class="hidden"
|
||||
:masked="true"
|
||||
name="transaction_amount"
|
||||
title=""
|
||||
:group_class="null"
|
||||
:currency="currency"
|
||||
:value="transaction_amount"
|
||||
@input="transaction_amount = $event"
|
||||
:dynamic-currency="currency"
|
||||
:row-input="true"
|
||||
:disabled="true"
|
||||
></akaunting-money>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id="tr-difference">
|
||||
<td class="border-t-0 p-0"></td>
|
||||
|
||||
<td class="font-medium text-sm text-right border-r-0 border-b-0 align-middle py-0 pr-0">
|
||||
{{ translations.difference }}
|
||||
</td>
|
||||
|
||||
<td class="text-right text-sm border-b-0 p-0">
|
||||
<div>
|
||||
<money
|
||||
:name="'difference_amount'"
|
||||
:value="difference_amount"
|
||||
v-bind="money"
|
||||
masked
|
||||
disabled
|
||||
class="px-0 disabled-money text-right banking-price-text"
|
||||
style="height: unset;"
|
||||
></money>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
<div class="p-5 bg-body rounded-bl-lg rounded-br-lg border-gray-300">
|
||||
<slot name="card-footer">
|
||||
<div class="flex items-center justify-end">
|
||||
<button type="button" class="px-6 py-1.5 mr-2 hover:bg-gray-200 rounded-lg" @click="onCancel">
|
||||
{{ translations.cancel }}
|
||||
</button>
|
||||
|
||||
<button type="button"
|
||||
:disabled="this.difference_amount != 0 || (this.difference_amount == 0 && form.loading)"
|
||||
class="relative px-6 py-1.5 bg-green hover:bg-green-700 text-white rounded-lg disabled:bg-green-100"
|
||||
@click="onConfirm"
|
||||
>
|
||||
<i
|
||||
v-if="form.loading"
|
||||
class="animate-submit delay-[0.28s] absolute w-2 h-2 rounded-full left-0 right-0 -top-3.5 m-auto before:absolute before:w-2 before:h-2 before:rounded-full before:animate-submit before:delay-[0.14s] after:absolute after:w-2 after:h-2 after:rounded-full after:animate-submit before:-left-3.5 after:-right-3.5 after:delay-[0.42s]"
|
||||
>
|
||||
</i>
|
||||
<span :class="[{'opacity-0': this.difference_amount != 0}]">{{ translations.save }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</SlideYUpTransition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { SlideYUpTransition } from "vue2-transitions";
|
||||
import AkauntingSelect from './AkauntingSelect';
|
||||
import AkauntingMoney from './AkauntingMoney';
|
||||
import AkauntingDocumentButton from './AkauntingDocumentButton';
|
||||
import {Money} from 'v-money';
|
||||
|
||||
export default {
|
||||
name: 'akaunting-connect-transactions',
|
||||
|
||||
components: {
|
||||
SlideYUpTransition,
|
||||
AkauntingSelect,
|
||||
AkauntingMoney,
|
||||
AkauntingDocumentButton,
|
||||
Money,
|
||||
},
|
||||
|
||||
props: {
|
||||
show: Boolean,
|
||||
transaction: Object,
|
||||
currency: Object,
|
||||
documents: Array,
|
||||
translations: Object,
|
||||
modalDialogClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Modal Body size Class"
|
||||
},
|
||||
animationDuration: {
|
||||
type: Number,
|
||||
default: 800,
|
||||
description: "Modal transition duration"
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
items: [],
|
||||
loading: false,
|
||||
},
|
||||
transaction_amount: "",
|
||||
money: {},
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
window.addEventListener('keyup',(e) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.onCancel();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
onConfirm() {
|
||||
this.form.loading = true;
|
||||
|
||||
this.$emit("confirm");
|
||||
this.onConnectTransaction();
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.$emit('close-modal');
|
||||
},
|
||||
|
||||
onAddItem(document) {
|
||||
this.form.items.push(
|
||||
Object.assign({}, {
|
||||
id: document.id,
|
||||
document_id: document.id,
|
||||
number: document.document_number,
|
||||
contact: document.contact_name,
|
||||
notes: document.notes,
|
||||
amount: (document.amount - document.paid).toFixed(this.currency.precision),
|
||||
max_amount: (document.amount - document.paid).toFixed(this.currency.precision),
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
onDeleteItem(index) {
|
||||
this.form.items.splice(index, 1);
|
||||
},
|
||||
|
||||
async onConnectTransaction() {
|
||||
let self = this;
|
||||
|
||||
let connect_transaction = Promise.resolve(window.axios.post(url + '/banking/transactions/' + this.transaction.id + '/connect', {
|
||||
data: {
|
||||
items: this.form.items
|
||||
}
|
||||
}));
|
||||
|
||||
connect_transaction.then(response => {
|
||||
if (response.data.redirect) {
|
||||
window.location.href = response.data.redirect;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
self.$emit("close-modal");
|
||||
});
|
||||
},
|
||||
|
||||
convertMoneyToFloat(money) {
|
||||
// "$198.4"
|
||||
if (typeof(money) != "string") {
|
||||
money = money.toString();
|
||||
}
|
||||
|
||||
// 198.4
|
||||
money = money.replace(this.currency.symbol, '').replaceAll(this.currency.thousands_separator, '').replace(this.currency.decimal_mark, '.');
|
||||
|
||||
// "198.40"
|
||||
money = parseFloat(money).toFixed(this.currency.precision);
|
||||
|
||||
// 198.40
|
||||
return parseFloat(money);
|
||||
},
|
||||
|
||||
checkAmount(index, amount) {
|
||||
let max_amount = this.convertMoneyToFloat(this.form.items[index].max_amount);
|
||||
let changed_amount = this.convertMoneyToFloat(amount);
|
||||
|
||||
this.form.items[index].amount = changed_amount.toFixed(this.currency.precision);
|
||||
|
||||
setTimeout(function () {
|
||||
if (changed_amount > max_amount || changed_amount == 0) {
|
||||
this.form.items[index].amount = max_amount.toFixed(this.currency.precision);
|
||||
}
|
||||
}.bind(this), 50);
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
show: function (newValue) {
|
||||
if (newValue) {
|
||||
this.form.items = [];
|
||||
}
|
||||
},
|
||||
transaction: function (transaction) {
|
||||
this.transaction_amount = transaction.amount;
|
||||
},
|
||||
currency: function (currency) {
|
||||
this.money = {
|
||||
decimal: currency.decimal_mark,
|
||||
thousands: currency.thousands_separator,
|
||||
prefix: (currency.symbol_first) ? currency.symbol : '',
|
||||
suffix: (!currency.symbol_first) ? currency.symbol : '',
|
||||
precision: parseInt(currency.precision),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
total_amount: function () {
|
||||
let amount = 0;
|
||||
|
||||
this.form.items.forEach(function(item) {
|
||||
amount += this.convertMoneyToFloat(item.amount);
|
||||
}, this);
|
||||
|
||||
return parseFloat(amount.toFixed(this.currency.precision));
|
||||
},
|
||||
difference_amount: function () {
|
||||
if (!this.transaction_amount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let transaction_amount = this.convertMoneyToFloat(this.transaction_amount);
|
||||
|
||||
return parseFloat((this.total_amount - transaction_amount).toFixed(this.currency.precision));
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
@ -1,122 +1,110 @@
|
||||
<template>
|
||||
<div :id="'select-contact-card-' + _uid" class="document-add-body-form-contact ml-3">
|
||||
<div class="document-contact" :class="[{'fs-exclude': show.contact_selected}]">
|
||||
<div class="document-contact-without-contact">
|
||||
<div v-if="!show.contact_selected" class="document-contact-without-contact-box-contact-select fs-exclude">
|
||||
<div class="aka-select aka-select--medium is-open" tabindex="0">
|
||||
<div>
|
||||
<div class="aka-box aka-box--large" :class="[{'aka-error': error}]">
|
||||
<div class="aka-box-content">
|
||||
<div class="document-contact-without-contact-box">
|
||||
<button type="button" class="btn-aka-link aka-btn--fluid document-contact-without-contact-box-btn" @click="onContactList">
|
||||
<i class="far fa-user fa-2x"></i> <span class="text-add-contact"> {{ addContactText }} </span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :id="'select-contact-card-' + _uid">
|
||||
<div class="relative" :class="[{'fs-exclude': show.contact_selected}]">
|
||||
<div v-if="!show.contact_selected">
|
||||
<div class="aka-select aka-select--medium is-open" tabindex="0">
|
||||
<div class="w-full h-33 bg-white hover:bg-gray-100 rounded-lg border border-light-gray disabled:bg-gray-200 mt-1 text-purple font-medium" :class="[{'border-red': error}]">
|
||||
<div class="text-black h-full">
|
||||
<button type="button" class="w-full h-full flex flex-col items-center justify-center" @click="onContactList">
|
||||
<span class="material-icons-outlined text-7xl text-black-400">person_add</span>
|
||||
<span class="text-add-contact"> {{ addContactText }} </span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="error" class="invalid-feedback d-block mt--2 mb-2"
|
||||
v-html="error">
|
||||
</div>
|
||||
<div v-if="error" class="text-red text-sm mt-1 block mb-2"
|
||||
v-html="error">
|
||||
</div>
|
||||
|
||||
<div class="absolute top-0 left-0 right-0 bg-white border rounded-lg" style="z-index: 999;" v-if="show.contact_list">
|
||||
<div class="relative">
|
||||
<span class="material-icons-round absolute left-4 top-3 text-lg">search</span>
|
||||
<input
|
||||
type="text"
|
||||
data-input="true"
|
||||
class="form-element px-10 border-t-0 border-l-0 border-r-0 border-gray-200 rounded-none"
|
||||
autocapitalize="default" autocorrect="ON"
|
||||
:placeholder="placeholder"
|
||||
:ref="'input-contact-field-' + _uid"
|
||||
v-model="search"
|
||||
@input="onInput"
|
||||
@keyup.enter="onInput"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="aka-select-menu" v-if="show.contact_list">
|
||||
<div class="aka-select-search-container">
|
||||
<span class="aka-prefixed-input aka-prefixed-input--fluid">
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa fa-search"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
data-input="true"
|
||||
class="form-control"
|
||||
autocapitalize="default" autocorrect="ON"
|
||||
:placeholder="placeholder"
|
||||
:ref="'input-contact-field-' + _uid"
|
||||
v-model="search"
|
||||
@input="onInput"
|
||||
@keyup.enter="onInput"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
<ul class="form-element p-0 border-0 mt-0 cursor-pointer">
|
||||
<div class="hover:bg-gray-100 px-4 py-2" v-for="(contact, index) in sortContacts" :key="index" @click="onContactSeleted(index, contact.id)">
|
||||
<span>{{ contact.name }}</span>
|
||||
</div>
|
||||
|
||||
<ul class="aka-select-menu-options">
|
||||
<div class="aka-select-menu-option" v-for="(contact, index) in sortContacts" :key="index" @click="onContactSeleted(index, contact.id)">
|
||||
<div>
|
||||
<strong class="text-strong"><span>{{ contact.name }}</span></strong>
|
||||
</div>
|
||||
<div class="hover:bg-gray-100 px-4 py-2" v-if="!sortContacts.length">
|
||||
<div>
|
||||
<span v-if="!contacts.length && !search">{{ noDataText }}</span>
|
||||
|
||||
<span v-else>{{ noMatchingDataText }}</span>
|
||||
</div>
|
||||
|
||||
<div class="aka-select-menu-option" v-if="!sortContacts.length">
|
||||
<div>
|
||||
<strong class="text-strong" v-if="!contacts.length && !search"><span>{{ noDataText }}</span></strong>
|
||||
|
||||
<strong class="text-strong" v-else><span>{{ noMatchingDataText }}</span></strong>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<div class="aka-select-footer" tabindex="0" @click="onContactCreate">
|
||||
<span>
|
||||
<i class="fas fa-plus"></i> {{ createNewContactText }}
|
||||
</span>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<div class="flex items-center justify-center h-11 text-center text-purple font-bold border border-l-0 border-r-0 border-b-0 rounded-bl-lg rounded-br-lg hover:bg-gray-100 cursor-pointer" tabindex="0" @click="onContactCreate">
|
||||
<span class="text-sm"> {{ createNewContactText }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="document-contact-with-contact-bill-to">
|
||||
<div>
|
||||
<span class="aka-text aka-text--block-label">{{ contactInfoText }}</span>
|
||||
</div>
|
||||
<div v-else class="document-contact-with-contact-bill-to">
|
||||
<div>
|
||||
<span class="text-sm">{{ contactInfoText }}</span>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-borderless p-0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="p-0" style="text-align:left;">
|
||||
<strong class="d-block">{{ contact.name }}</strong>
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.address">
|
||||
<th class="p-0" style="text-align:left; white-space: normal;">
|
||||
<div class="overflow-x-visible mt-0">
|
||||
<table class="table table-borderless p-0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="font-medium text-left text-sm p-0">
|
||||
<span class="block">{{ contact.name }}</span>
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.address">
|
||||
<th class="font-normal text-xs text-left p-0">
|
||||
<div class="w-60 truncate">
|
||||
{{ contact.address }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.location">
|
||||
<th class="p-0" style="text-align:left; white-space: normal;">
|
||||
{{ contact.location }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.tax_number">
|
||||
<th class="p-0" style="text-align:left;">
|
||||
{{ taxNumberText }}: {{ contact.tax_number }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.phone">
|
||||
<th class="p-0" style="text-align:left;">
|
||||
{{ contact.phone }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.email">
|
||||
<th class="p-0" style="text-align:left;">
|
||||
{{ contact.email }}
|
||||
</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.location">
|
||||
<th class="font-normal text-xs text-left p-0">
|
||||
{{ contact.location }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.tax_number">
|
||||
<th class="font-normal text-xs text-left p-0">
|
||||
{{ taxNumberText }}: {{ contact.tax_number }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="contact.phone">
|
||||
<th class="font-normal text-xs text-left p-0">
|
||||
{{ contact.phone }}
|
||||
<span v-if="contact.email">
|
||||
- {{ contact.email }}
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-link p-0" @click="onContactEdit">
|
||||
{{ editContactText.replace(':contact_name', contact.name).replace(':field', contact.name) }}
|
||||
</button> •
|
||||
<button type="button" class="btn btn-link p-0" @click="onContactList">
|
||||
{{ chooseDifferentContactText }}
|
||||
<div class="absolute flex flex-col mt-2">
|
||||
<button type="button" class="p-0 text-xs text-purple ltr:text-left rtl:text-right" @click="onContactEdit">
|
||||
<span class="border-b border-transparent transition-all hover:border-purple">
|
||||
{{ editContactText.replace(':contact_name', contact.name).replace(':field', contact.name) }}
|
||||
</span>
|
||||
</button>
|
||||
<button type="button" class="p-0 text-xs text-purple ltr:text-left rtl:text-right" @click="onContactList">
|
||||
<span class="border-b border-transparent transition-all hover:border-purple">
|
||||
{{ chooseDifferentContactText }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -134,7 +122,7 @@ import { Select, Option, OptionGroup, ColorPicker } from 'element-ui';
|
||||
import AkauntingModalAddNew from './AkauntingModalAddNew';
|
||||
import AkauntingModal from './AkauntingModal';
|
||||
import AkauntingMoney from './AkauntingMoney';
|
||||
import AkauntingRadioGroup from './forms/AkauntingRadioGroup';
|
||||
import AkauntingRadioGroup from './AkauntingRadioGroup';
|
||||
import AkauntingSelect from './AkauntingSelect';
|
||||
import AkauntingDate from './AkauntingDate';
|
||||
|
||||
@ -204,7 +192,7 @@ export default {
|
||||
description: 'List of Contacts'
|
||||
},
|
||||
contacts: {
|
||||
type: Array,
|
||||
type: [Array, Object],
|
||||
default: () => [],
|
||||
description: 'List of Contacts'
|
||||
},
|
||||
@ -539,7 +527,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
@ -556,7 +544,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
},
|
||||
|
||||
closeIfClickedOutside(event) {
|
||||
@ -666,10 +654,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.aka-error, .aka-error:hover {
|
||||
border-color: #ef3232 !important;
|
||||
background-color: #fb634038;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,31 +1,16 @@
|
||||
<template>
|
||||
<div class="countdown">
|
||||
<section class="flex text-6xl justify-center content-center">
|
||||
<div class="days mr-2 relative">
|
||||
{{ displayDays}}
|
||||
<div class="label text-sm absolut bottom-0"> {{ textDays }} </div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<section class="flex text-xl justify-center content-center">
|
||||
<div class="days mr-2 relative"> {{ displayDays}} </div>
|
||||
<span class="leading-snug">:</span>
|
||||
|
||||
<div class="hours mx-2 relative">
|
||||
{{ displayHours }}
|
||||
<div class="label text-sm absolut bottom-0">{{ textHours }} </div>
|
||||
</div>
|
||||
|
||||
<div class="hours mx-2 relative"> {{ displayHours }} </div>
|
||||
<span class="leading-snug">:</span>
|
||||
|
||||
<div class="minutes mx-2 relative">
|
||||
{{ displayMinutes }}
|
||||
<div class="label text-sm absolut bottom-0"> {{ textMinutes }} </div>
|
||||
</div>
|
||||
|
||||
<div class="minutes mx-2 relative"> {{ displayMinutes }} </div>
|
||||
<span class="leading-snug">:</span>
|
||||
|
||||
<div class="seconds ml-2 relative">
|
||||
{{ displaySeconds }}
|
||||
<div class="label text-sm absolut bottom-0"> {{ textSeconds }} </div>
|
||||
</div>
|
||||
<div class="seconds ml-2 relative"> {{ displaySeconds }} </div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@ -42,24 +27,6 @@ export default {
|
||||
description: "Modal header title"
|
||||
},
|
||||
|
||||
textHours: {
|
||||
type: String,
|
||||
default: 'hours',
|
||||
description: "Modal header title"
|
||||
},
|
||||
|
||||
textMinutes: {
|
||||
type: String,
|
||||
default: 'minutes',
|
||||
description: "Modal header title"
|
||||
},
|
||||
|
||||
textSeconds: {
|
||||
type: String,
|
||||
default: 'seconds',
|
||||
description: "Modal header title"
|
||||
},
|
||||
|
||||
year: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
@ -172,30 +139,3 @@ export default {
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.countdown {
|
||||
text-align: justify;
|
||||
}
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
.content-center {
|
||||
align-content: center;
|
||||
}
|
||||
.seconds {
|
||||
max-width: 60px;
|
||||
}
|
||||
.leading-snug {
|
||||
line-height: 1.375;
|
||||
}
|
||||
.days, .hours, .minutes, .seconds {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="d-flex align-items-center justify-content-end mt-3">
|
||||
<div class="flex items-center justify-end text-xs mt-3">
|
||||
<span>{{ texts[0] }}</span>
|
||||
<money v-bind="{
|
||||
decimal: this.currencySymbol.decimal_mark,
|
||||
@ -8,9 +8,9 @@
|
||||
suffix: (!this.currencySymbol.symbol_first) ? this.currencySymbol.symbol : '',
|
||||
precision: parseInt(this.currencySymbol.precision),
|
||||
masked: true
|
||||
}" :value="price" disabled size="5" masked class="disabled-money text-right mr-2 js-conversion-input"></money>
|
||||
}" :value="price" disabled size="5" masked class="disabled-money text-right mr-1 js-conversion-input text-xs px-1"></money>
|
||||
<span class="mr-2">{{ texts[1] }}</span>
|
||||
<input name="currency_rate" v-model="rate" @input="onChange" class="form-control text-right mwpx-100 h-auto js-conversion-input" />
|
||||
<input name="currency_rate" v-model="rate" @input="onChange" class="form-element w-16 h-10 text-right js-conversion-input" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
formClasses
|
||||
]"
|
||||
:footer-error="formError"
|
||||
:prependIcon="icon"
|
||||
:appendIcon="icon"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
@focus="focus"
|
||||
@ -19,7 +19,7 @@
|
||||
@on-open="focus"
|
||||
@on-close="blur"
|
||||
:config="dateConfig"
|
||||
class="form-control datepicker"
|
||||
class="form-element datepicker"
|
||||
v-model="real_model"
|
||||
@input="change"
|
||||
:readonly="readonly"
|
||||
@ -135,6 +135,7 @@ export default {
|
||||
if (this.locale !== 'en') {
|
||||
try {
|
||||
const lang = require(`flatpickr/dist/l10n/${this.locale}.js`).default[this.locale];
|
||||
|
||||
this.dateConfig.locale = lang;
|
||||
}
|
||||
catch (e) {
|
||||
@ -148,6 +149,7 @@ export default {
|
||||
if (this.model) {
|
||||
this.real_model = this.model;
|
||||
}
|
||||
|
||||
this.$emit('interface', this.real_model);
|
||||
},
|
||||
|
||||
|
299
resources/assets/js/components/AkauntingDocumentButton.vue
Normal file
299
resources/assets/js/components/AkauntingDocumentButton.vue
Normal file
@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<div :id="'select-item-button-' + _uid" class="w-full border-b">
|
||||
<button type="button" class="w-full h-10 flex items-center justify-center text-purple font-medium disabled:bg-gray-200 hover:bg-gray-100" @click="showItems">
|
||||
<span class="material-icons-outlined text-base font-bold ltr:mr-1 rtl:ml-1">
|
||||
add
|
||||
</span>
|
||||
{{ addItemText }}
|
||||
</button>
|
||||
|
||||
<div :class="[{'is-open': show.item_list}]" tabindex="-1">
|
||||
<div class="-mt-10.5 left-0 right-0 bg-white border rounded-lg" v-if="show.item_list">
|
||||
<div class="relative">
|
||||
<span class="material-icons-round absolute left-4 top-3 text-lg">search</span>
|
||||
<input
|
||||
type="text"
|
||||
data-input="true"
|
||||
class="form-element px-10 border-t-0 border-l-0 border-r-0 border-gray-200 rounded-none"
|
||||
autocapitalize="default"
|
||||
autocorrect="ON"
|
||||
:placeholder="placeholder"
|
||||
v-model="search"
|
||||
@input="onInput"
|
||||
:ref="'input-item-field-' + _uid"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ul class="form-element p-0 mt-0 border-0 cursor-pointer">
|
||||
<div
|
||||
class="hover:bg-gray-100 px-4"
|
||||
v-for="(item, index) in sortedItems"
|
||||
:key="index"
|
||||
@click="onItemSelected(item)"
|
||||
>
|
||||
<div class="w-full flex items-center justify-between">
|
||||
<span>{{ item.name }}</span>
|
||||
|
||||
<money
|
||||
:name="'item-id-' + item.id"
|
||||
:value="item.amount"
|
||||
v-bind="money"
|
||||
masked
|
||||
disabled
|
||||
class="text-right disabled-money text-gray"
|
||||
></money>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hover:bg-gray-100 text-center py-2 px-4" v-if="!sortedItems.length">
|
||||
<div class="text-center">
|
||||
<span>{{ noDataText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
|
||||
import {Money} from 'v-money';
|
||||
|
||||
export default {
|
||||
name: 'akaunting-document-button',
|
||||
|
||||
components: {
|
||||
Money,
|
||||
},
|
||||
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: 'Type an item name',
|
||||
description: 'Input placeholder'
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
description: 'List of Items'
|
||||
},
|
||||
selectedItems: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
description: 'List of Selected Items'
|
||||
},
|
||||
addItemText: {
|
||||
type: String,
|
||||
default: 'Add an item',
|
||||
description: ""
|
||||
},
|
||||
noDataText: {
|
||||
type: String,
|
||||
default: 'No Data',
|
||||
description: "Selectbox empty options message"
|
||||
},
|
||||
dynamicCurrency: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
decimal_mark: '.',
|
||||
thousands_separator: ',',
|
||||
symbol_first: 1,
|
||||
symbol: '$',
|
||||
precision: 2,
|
||||
};
|
||||
},
|
||||
description: "Dynamic currency"
|
||||
},
|
||||
currency: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
decimal_mark: '.',
|
||||
thousands_separator: ',',
|
||||
symbol_first: 1,
|
||||
symbol: '$',
|
||||
precision: 2,
|
||||
};
|
||||
},
|
||||
description: "Default currency"
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
item_list: [],
|
||||
search: '', // search column model
|
||||
show: {
|
||||
item_list: false,
|
||||
},
|
||||
money: {
|
||||
decimal: this.currency.decimal_mark,
|
||||
thousands: this.currency.thousands_separator,
|
||||
prefix: (this.currency.symbol_first) ? this.currency.symbol : '',
|
||||
suffix: (!this.currency.symbol_first) ? this.currency.symbol : '',
|
||||
precision: parseInt(this.currency.precision),
|
||||
masked: this.masked
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.setItemList(this.items);
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.dynamicCurrency.code != this.currency.code) {
|
||||
if (!this.dynamicCurrency.decimal) {
|
||||
this.money = {
|
||||
decimal: this.dynamicCurrency.decimal_mark,
|
||||
thousands: this.dynamicCurrency.thousands_separator,
|
||||
prefix: (this.dynamicCurrency.symbol_first) ? this.dynamicCurrency.symbol : '',
|
||||
suffix: (!this.dynamicCurrency.symbol_first) ? this.dynamicCurrency.symbol : '',
|
||||
precision: parseInt(this.dynamicCurrency.precision),
|
||||
masked: this.masked
|
||||
};
|
||||
} else {
|
||||
this.money = this.dynamicCurrency;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setItemList(items) {
|
||||
this.item_list = [];
|
||||
|
||||
// Option set sort_option data
|
||||
if (Array.isArray(items)) {
|
||||
items.forEach(function (item, index) {
|
||||
let selected = this.selectedItems.find(function (selected_item) {
|
||||
return selected_item.id === item.id;
|
||||
}, this);
|
||||
|
||||
if (selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.item_list.push({
|
||||
id: item.id,
|
||||
name: item.document_number + ' | ' + item.contact_name + (item.notes ? ' | ' + item.notes : ''),
|
||||
amount: item.amount,
|
||||
});
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
showItems() {
|
||||
this.show.item_list = true;
|
||||
|
||||
setTimeout(function() {
|
||||
this.$refs['input-item-field-' + this._uid].focus();
|
||||
}.bind(this), 100);
|
||||
},
|
||||
|
||||
onInput() {
|
||||
//to optimize performance we kept the condition that checks for if search exists or not
|
||||
if (!this.search) {
|
||||
return;
|
||||
}
|
||||
|
||||
//condition that checks if input is below the given character limit
|
||||
this.setItemList(this.items); //once the user deletes the search input, we show the overall item list
|
||||
this.sortItems(); // we order it as wanted
|
||||
this.$emit('input', this.search); // keep the input binded to v-model
|
||||
},
|
||||
|
||||
onItemSelected(param_item) {
|
||||
let selected_item = this.items.find(function (item) {
|
||||
return item.id === param_item.id
|
||||
}, this);
|
||||
|
||||
this.$emit('document-selected', selected_item);
|
||||
|
||||
this.show.item_list = false;
|
||||
|
||||
this.search = '';
|
||||
|
||||
// Set default item list
|
||||
this.setItemList(this.items);
|
||||
},
|
||||
|
||||
closeIfClickedOutside(event) {
|
||||
if (!document.getElementById('select-item-button-' + this._uid).contains(event.target)) {
|
||||
this.show.item_list = false;
|
||||
this.search = '';
|
||||
|
||||
document.removeEventListener('click', this.closeIfClickedOutside);
|
||||
|
||||
this.setItemList(this.items);
|
||||
}
|
||||
},
|
||||
|
||||
sortItems() {
|
||||
this.item_list.sort(function (a, b) {
|
||||
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
|
||||
|
||||
if (nameA < nameB) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nameA > nameB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// names must be equal
|
||||
return 0;
|
||||
});
|
||||
|
||||
const sortedItemList = this.item_list.filter(item =>
|
||||
item.name.toLowerCase().includes(this.search.toLowerCase())
|
||||
);
|
||||
|
||||
return sortedItemList;
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
sortedItems() {
|
||||
return this.sortItems();
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dynamicCurrency: function (currency) {
|
||||
if (!currency) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.money = {
|
||||
decimal: currency.decimal_mark,
|
||||
thousands: currency.thousands_separator,
|
||||
prefix: (currency.symbol_first) ? currency.symbol : '',
|
||||
suffix: (!currency.symbol_first) ? currency.symbol : '',
|
||||
precision: parseInt(currency.precision),
|
||||
masked: this.masked
|
||||
};
|
||||
},
|
||||
|
||||
show: {
|
||||
handler: function(newValue) {
|
||||
if (newValue) {
|
||||
document.addEventListener('click', this.closeIfClickedOutside);
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
||||
items: function (items) {
|
||||
this.setItemList(items);
|
||||
},
|
||||
|
||||
selectedItems: function () {
|
||||
this.setItemList(this.items);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :id="'dropzone-' + _uid" class="dropzone mb-3 dz-clickable" :class="[preview == 'single' ? 'dropzone-single': 'dropzone-multiple']">
|
||||
<div :id="'dropzone-' + _uid" class="dropzone dz-clickable" :class="[preview == 'single' ? 'dropzone-single': 'dropzone-multiple', singleWidthClasses ? 'w-full': 'w-37']">
|
||||
<div class="fallback">
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" :id="'projectCoverUploads' + _uid" :multiple="multiple">
|
||||
@ -11,39 +11,40 @@
|
||||
<div v-if="preview == 'single'" class="dz-preview dz-preview-single" :class="previewClasses" ref="previewSingle">
|
||||
<div class="dz-preview-cover">
|
||||
<img class="dz-preview-img" data-dz-thumbnail>
|
||||
<i class="fas fa-file-image display-3 fa-2x mt-2 d-none" data-dz-thumbnail-image></i>
|
||||
<i class="far fa-file-pdf display-3 fa-2x mt-2 d-none" data-dz-thumbnail-pdf></i>
|
||||
<i class="far fa-file-word fa-2x mt-2 d-none" data-dz-thumbnail-word></i>
|
||||
<i class="far fa-file-excel fa-2x mt-2 d-none" data-dz-thumbnail-excel></i>
|
||||
<span class="mb-1 d-none" data-dz-name>...</span>
|
||||
<span class="material-icons hidden" data-dz-thumbnail-image>crop_original</span>
|
||||
<span class="material-icons-outlined avatar hidden">file_present</span>
|
||||
<span class="material-icons-outlined avatar hidden" data-dz-thumbnail-pdf>picture_as_pdf</span>
|
||||
<span class="material-icons-outlined avatar hidden" data-dz-thumbnail-word>content_paste</span>
|
||||
<span class="material-icons-outlined avatar hidden" data-dz-thumbnail-excel>table_chart</span>
|
||||
<span class="mb-1 text-sm ml-3 text-gray-500 hidden" data-dz-name>...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul v-else class="dz-preview dz-preview-multiple list-group list-group-lg list-group-flush" :class="previewClasses" ref="previewMultiple">
|
||||
<li class="list-group-item px-0">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<li class="list-group-item border-b py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<div class="avatar">
|
||||
<img class="avatar-img rounded" data-dz-thumbnail>
|
||||
<i class="fas fa-file-image display-3 d-none" data-dz-thumbnail-image></i>
|
||||
<i class="far fa-file-pdf display-3 d-none" data-dz-thumbnail-pdf></i>
|
||||
<i class="far fa-file-word d-none" data-dz-thumbnail-word></i>
|
||||
<i class="far fa-file-excel d-none" data-dz-thumbnail-excel></i>
|
||||
<span class="material-icons hidden" data-dz-thumbnail-image>crop_original</span>
|
||||
<span class="material-icons-outlined display-3 hidden" data-dz-thumbnail-pdf>picture_as_pdf</span>
|
||||
<span class="material-icons-outlined hidden" data-dz-thumbnail-word>content_paste</span>
|
||||
<span class="material-icons-outlined hidden" data-dz-thumbnail-excel>table_chart</span>
|
||||
</div>
|
||||
|
||||
<div class="col text-gray-500 ml-3">
|
||||
<h4 class="text-sm mb-1" data-dz-name>...</h4>
|
||||
|
||||
<p class="text-xs text-muted mb-0" data-dz-size>...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col ml--3">
|
||||
<h4 class="mb-1" data-dz-name>...</h4>
|
||||
|
||||
<p class="small text-muted mb-0" data-dz-size>...</p>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<div class="gap-x-1">
|
||||
<button data-dz-remove="true" class="btn btn-danger btn-sm">
|
||||
<i class="fas fa-trash"></i>
|
||||
<span class="material-icons text-base text-red">delete</span>
|
||||
</button>
|
||||
<a href="#" type="button" class="btn btn-sm btn-info text-white d-none" data-dz-download>
|
||||
<i class="fas fa-file-download"></i>
|
||||
<a href="#" type="button" class="btn btn-sm btn-info hidden" data-dz-download>
|
||||
<span class="material-icons-round text-base">download</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -72,7 +73,7 @@ export default {
|
||||
description: 'Choose file text'
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
type: [Object, Array],
|
||||
default: () => ({})
|
||||
},
|
||||
value: [String, Object, Array, File],
|
||||
@ -86,6 +87,10 @@ export default {
|
||||
description: 'Multiple file Upload'
|
||||
},
|
||||
previewClasses: [String, Object, Array],
|
||||
singleWidthClasses: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
preview: {
|
||||
type: String,
|
||||
default: function () {
|
||||
@ -146,17 +151,17 @@ export default {
|
||||
if (file.type.indexOf("image") == -1) {
|
||||
let ext = file.name.split('.').pop();
|
||||
|
||||
file.previewElement.querySelector("[data-dz-thumbnail]").classList.add("d-none");
|
||||
file.previewElement.querySelector("[data-dz-name]").classList.remove("d-none");
|
||||
file.previewElement.querySelector("[data-dz-thumbnail]").classList.add("hidden");
|
||||
file.previewElement.querySelector("[data-dz-name]").classList.remove("hidden");
|
||||
|
||||
if (ext == "pdf") {
|
||||
file.previewElement.querySelector("[data-dz-thumbnail-pdf]").classList.remove("d-none");
|
||||
file.previewElement.querySelector("[data-dz-thumbnail-pdf]").classList.remove("hidden");
|
||||
} else if ((ext.indexOf("doc") != -1) || (ext.indexOf("docx") != -1)) {
|
||||
file.previewElement.querySelector("[data-dz-thumbnail-word]").classList.remove("d-none");
|
||||
file.previewElement.querySelector("[data-dz-thumbnail-word]").classList.remove("hidden");
|
||||
} else if ((ext.indexOf("xls") != -1) || (ext.indexOf("xlsx") != -1)) {
|
||||
file.previewElement.querySelector("[data-dz-thumbnail-excel]").classList.remove("d-none");
|
||||
file.previewElement.querySelector("[data-dz-thumbnail-excel]").classList.remove("hidden");
|
||||
} else {
|
||||
file.previewElement.querySelector("[data-dz-thumbnail-image]").classList.remove("d-none");
|
||||
file.previewElement.querySelector("[data-dz-thumbnail-image]").classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
}),
|
||||
@ -208,7 +213,7 @@ export default {
|
||||
self.files.forEach(async (attachment) => {
|
||||
if (attachment.download) {
|
||||
attachment.previewElement.querySelector("[data-dz-download]").href = attachment.download;
|
||||
attachment.previewElement.querySelector("[data-dz-download]").classList.remove("d-none");
|
||||
attachment.previewElement.querySelector("[data-dz-download]").classList.remove("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
@ -253,7 +258,7 @@ export default {
|
||||
this.files.forEach(async (attachment) => {
|
||||
if (attachment.download) {
|
||||
attachment.previewElement.querySelector("[data-dz-download]").href = attachment.download;
|
||||
attachment.previewElement.querySelector("[data-dz-download]").classList.remove("d-none");
|
||||
attachment.previewElement.querySelector("[data-dz-download]").classList.remove("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
@ -271,4 +276,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.avatar.hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="item-columns-edit">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
<div class="item-columns-edit group">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-aka-link"
|
||||
@click="onEditItemColumns">
|
||||
{{ editColumn.text }}
|
||||
class="w-6 h-7 flex items-center rounded-lg p-0 group-hover:bg-gray-100"
|
||||
style="color: rgb(136, 152, 170);"
|
||||
@click="onEditItemColumns"
|
||||
>
|
||||
<span class="material-icons-outlined w-full text-lg text-gray-300 group-hover:text-gray-500">edit</span>
|
||||
</button>
|
||||
|
||||
<component v-bind:is="edit_html" @submit="onSubmit" @cancel="onCancel"></component>
|
||||
@ -164,7 +165,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,105 +1,53 @@
|
||||
<template>
|
||||
<div class="quill">
|
||||
<div :id="toolbarId">
|
||||
<div class="ql-formats">
|
||||
<button class="ql-bold"></button>
|
||||
<button class="ql-italic"></button>
|
||||
<button class="ql-underline"></button>
|
||||
<button class="ql-link"></button>
|
||||
<button class="ql-blockquote"></button>
|
||||
<button type="button" class="ql-list" value="ordered"></button>
|
||||
<button type="button" class="ql-list" value="bullet"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :id="editorId" :name="name" class="" ref="editor">
|
||||
</div>
|
||||
<div>
|
||||
<vue-editor :id="editorId" v-model="content" :editorToolbar="customToolbar" :disabled="disabled"></vue-editor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Quill from 'quill';
|
||||
|
||||
//var Block = Quill.import('blots/block');
|
||||
//Block.tagName = 'div';
|
||||
//Quill.register(Block);
|
||||
import { VueEditor } from "vue2-editor";
|
||||
|
||||
export default {
|
||||
name: 'akaunting-html-editor',
|
||||
|
||||
components: {
|
||||
VueEditor
|
||||
},
|
||||
|
||||
props: {
|
||||
name: String,
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'The name of the field',
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
default: 'snow'
|
||||
model: {
|
||||
type: [String, Number, Array, Object],
|
||||
default: '',
|
||||
description: "Selectbox selected model"
|
||||
},
|
||||
readonly: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: false,
|
||||
description: "Selectbox disabled status"
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
editor: null,
|
||||
editorValue: this.value,
|
||||
content: null,
|
||||
lastHtmlValue: '',
|
||||
editorId: null,
|
||||
toolbarId: null
|
||||
customToolbar: [
|
||||
["bold", "italic", "underline"],
|
||||
[{ list: "ordered" }, { list: "bullet" }],
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
initialize (Quill) {
|
||||
let theme = this.theme;
|
||||
|
||||
this.editor = new Quill(`#${this.editorId}`, {
|
||||
theme: theme,
|
||||
modules: {
|
||||
toolbar: `#${this.toolbarId}`
|
||||
},
|
||||
readOnly: this.readonly
|
||||
});
|
||||
|
||||
if (this.editorValue.length > 0) {
|
||||
this.editorValue = this.editorValue.replace(new RegExp('<p><br></p>', 'g'), '<p> </p>');
|
||||
|
||||
this.editor.pasteHTML(this.editorValue);
|
||||
}
|
||||
|
||||
let editorRef = this.$refs.editor;
|
||||
let node = editorRef.children[0];
|
||||
|
||||
this.editor.on('text-change', () => {
|
||||
let html = node.innerHTML;
|
||||
|
||||
if (html === '<p><br></p>') {
|
||||
html = '';
|
||||
} else {
|
||||
html = html.replace(new RegExp('<p><br></p>', 'g'), '<p> </p>');
|
||||
}
|
||||
|
||||
this.content = html;
|
||||
|
||||
this.$emit('input', this.content);
|
||||
});
|
||||
},
|
||||
|
||||
pasteHTML () {
|
||||
if (!this.editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.editorValue = this.editorValue.replace(new RegExp('<p><br></p>', 'g'), '<p> </p>');
|
||||
|
||||
this.editor.pasteHTML(this.editorValue);
|
||||
},
|
||||
|
||||
randomString() {
|
||||
let text = "";
|
||||
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
@ -113,26 +61,21 @@ export default {
|
||||
},
|
||||
|
||||
async mounted () {
|
||||
this.content = this.editorValue;
|
||||
|
||||
this.editorId = this.randomString();
|
||||
this.toolbarId = this.randomString();
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.initialize(Quill)
|
||||
});
|
||||
this.content = this.value;
|
||||
},
|
||||
|
||||
watch: {
|
||||
value (newVal) {
|
||||
if (newVal !== this.content) {
|
||||
this.pasteHTML(newVal);
|
||||
this.content = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
editorValue (newVal) {
|
||||
model (newVal) {
|
||||
if (newVal !== this.content) {
|
||||
this.pasteHTML(newVal);
|
||||
this.content = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1,81 +1,62 @@
|
||||
<template>
|
||||
<div :id="'select-item-button-' + _uid" class="product-select">
|
||||
<div class="item-add-new">
|
||||
<button type="button" class="btn btn-link w-100" @click="showItems">
|
||||
<i class="fas fa-plus-circle"></i> {{ addItemText }}
|
||||
</button>
|
||||
</div>
|
||||
<div :id="'select-item-button-' + _uid" class="w-full border-b">
|
||||
<button type="button" class="w-full h-10 flex items-center justify-center text-purple font-medium disabled:bg-gray-200 hover:bg-gray-100" @click="showItems">
|
||||
<span class="material-icons-outlined text-base font-bold ltr:mr-1 rtl:ml-1">add</span>
|
||||
{{ addItemText }}
|
||||
</button>
|
||||
|
||||
<div class="aka-select aka-select--fluid" :class="[{'is-open': show.item_list}]" tabindex="-1">
|
||||
<div class="aka-select-menu" v-if="show.item_list">
|
||||
<div class="aka-select-search-container">
|
||||
<span class="aka-prefixed-input aka-prefixed-input--fluid">
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa fa-search"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div :class="[{'is-open': show.item_list}]" tabindex="-1">
|
||||
<div class="-mt-10.5 left-0 right-0 bg-white border rounded-lg" v-if="show.item_list">
|
||||
<div class="relative">
|
||||
<span class="material-icons-round absolute left-4 top-3 text-lg">search</span>
|
||||
<input
|
||||
type="text"
|
||||
data-input="true"
|
||||
class="form-element px-10 border-t-0 border-l-0 border-r-0 border-gray-200 rounded-none"
|
||||
autocapitalize="default"
|
||||
autocorrect="ON"
|
||||
:placeholder="placeholder"
|
||||
v-model="search"
|
||||
@input="onInput"
|
||||
:ref="'input-item-field-' + _uid"
|
||||
@keydown.enter="inputEnterEvent"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
data-input="true"
|
||||
class="form-control"
|
||||
autocapitalize="default"
|
||||
autocorrect="ON"
|
||||
:placeholder="placeholder"
|
||||
v-model="search"
|
||||
@input="onInput"
|
||||
:ref="'input-item-field-' + _uid"
|
||||
@keydown.enter="inputEnterEvent"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul class="aka-select-menu-options">
|
||||
<ul class="form-element p-0 mt-0 border-0 cursor-pointer">
|
||||
<div
|
||||
class="aka-select-menu-option"
|
||||
class="hover:bg-gray-100 px-4"
|
||||
v-for="(item, index) in sortedItems"
|
||||
:key="index"
|
||||
:class="isItemMatched ? 'highlightItem' : ''"
|
||||
@click="onItemSelected(item)"
|
||||
>
|
||||
<div class="item-select w-100">
|
||||
<div class="item-select-column item-select-info w-75">
|
||||
<b class="item-select-info-name"><span>{{ item.name }}</span></b>
|
||||
</div>
|
||||
<div class="w-full flex items-center justify-between">
|
||||
<span>{{ item.name }}</span>
|
||||
|
||||
<div class="item-select-column item-select-price w-25">
|
||||
<money
|
||||
:name="'item-id-' + item.id"
|
||||
:value="item.price"
|
||||
v-bind="money"
|
||||
masked
|
||||
disabled
|
||||
class="text-right disabled-money"
|
||||
></money>
|
||||
</div>
|
||||
<money
|
||||
:name="'item-id-' + item.id"
|
||||
:value="item.price"
|
||||
v-bind="money"
|
||||
masked
|
||||
disabled
|
||||
class="text-right disabled-money text-gray"
|
||||
></money>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="aka-select-menu-option" v-if="!sortedItems.length">
|
||||
<div>
|
||||
<strong class="text-strong" v-if="!items.length && !search">
|
||||
<span>{{ noDataText }}</span>
|
||||
</strong>
|
||||
<div class="hover:bg-gray-100 text-center py-2 px-4" v-if="!sortedItems.length">
|
||||
<div class="text-center">
|
||||
<span v-if="!items.length && !search">{{ noDataText }}</span>
|
||||
|
||||
<strong class="text-strong" v-else>
|
||||
<span>{{ noMatchingDataText }}</span>
|
||||
</strong>
|
||||
<span v-else>{{ noMatchingDataText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<div class="aka-select-footer" @click="onItemCreate">
|
||||
<span>
|
||||
<i class="fas fa-plus"></i> {{ createNewItemText }}
|
||||
</span>
|
||||
<div class="flex items-center justify-center h-11 text-center text-purple font-bold border border-l-0 border-r-0 border-b-0 rounded-bl-lg rounded-br-lg hover:bg-gray-100 cursor-pointer" @click="onItemCreate">
|
||||
<span class="material-icons text-lg font-bold mr-1">add</span>
|
||||
{{ createNewItemText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -91,7 +72,7 @@ import {Money} from 'v-money';
|
||||
import AkauntingModalAddNew from './AkauntingModalAddNew';
|
||||
import AkauntingModal from './AkauntingModal';
|
||||
import AkauntingMoney from './AkauntingMoney';
|
||||
import AkauntingRadioGroup from './forms/AkauntingRadioGroup';
|
||||
import AkauntingRadioGroup from './AkauntingRadioGroup';
|
||||
import AkauntingSelect from './AkauntingSelect';
|
||||
import AkauntingDate from './AkauntingDate';
|
||||
|
||||
@ -149,7 +130,7 @@ export default {
|
||||
},
|
||||
addItemText: {
|
||||
type: String,
|
||||
default: 'Add an item',
|
||||
default: 'Add New Item',
|
||||
description: ""
|
||||
},
|
||||
createNewItemText: {
|
||||
@ -204,6 +185,7 @@ export default {
|
||||
return {
|
||||
item_list: [],
|
||||
selected_items: [],
|
||||
changeBackground: true,
|
||||
search: '', // search column model
|
||||
show: {
|
||||
item_selected: false,
|
||||
@ -361,6 +343,7 @@ export default {
|
||||
const indexeditem = { ...item, index: this.currentIndex };
|
||||
|
||||
this.addItem(indexeditem, 'oldItem');
|
||||
this.changeBackground = false;
|
||||
},
|
||||
|
||||
addItem(item, itemType) {
|
||||
@ -390,7 +373,7 @@ export default {
|
||||
price: 0,
|
||||
tax_ids: [],
|
||||
};
|
||||
|
||||
|
||||
this.newItems.push(item);
|
||||
|
||||
this.addItem(item, 'newItem');
|
||||
@ -461,7 +444,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
@ -480,7 +463,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
},
|
||||
|
||||
closeIfClickedOutside(event) {
|
||||
@ -524,7 +507,6 @@ export default {
|
||||
sortedItems() {
|
||||
return this.sortItems();
|
||||
},
|
||||
|
||||
currentIndex() {
|
||||
return this.$root.form.items.length;
|
||||
},
|
||||
@ -560,6 +542,6 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
.highlightItem:first-child {
|
||||
background-color: #F5F7FA;
|
||||
background-color: #F5F7FA;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,37 +1,43 @@
|
||||
<template>
|
||||
<SlideYUpTransition :duration="animationDuration">
|
||||
<div class="modal fade"
|
||||
<div class="modal fade w-full h-full fixed top-0 left-0 right-0 z-50 overflow-y-auto overflow-hidden modal-add-new fade items-center justify-center"
|
||||
@click.self="closeModal"
|
||||
:class="[{'show d-block': show}, {'d-none': !show}]"
|
||||
:class="[{'show flex flex-wrap modal-background': show}, {'hidden': !show}]"
|
||||
v-show="show"
|
||||
tabindex="-1"
|
||||
role="dialog"
|
||||
:aria-hidden="!show">
|
||||
<div class="modal-dialog" :class="modalDialogClass">
|
||||
<div class="w-full my-10 m-auto flex flex-col" :class="modalDialogClass ? modalDialogClass : 'max-w-screen-sm'">
|
||||
<slot name="modal-content">
|
||||
<div class="modal-content">
|
||||
<div class="card-header pb-2">
|
||||
<slot name="card-header">
|
||||
<h4 class="float-left"> {{ title }} </h4>
|
||||
<div class="p-5 bg-body rounded-tl-lg rounded-tr-lg">
|
||||
<div class="flex items-center justify-between border-b pb-5">
|
||||
<slot name="card-header">
|
||||
<h4 class="text-base font-medium">
|
||||
{{ title }}
|
||||
</h4>
|
||||
|
||||
<button type="button" class="close" @click="onCancel" aria-hidden="true">×</button>
|
||||
</slot>
|
||||
<button type="button" class="text-lg" @click="onCancel" aria-hidden="true">
|
||||
<span class="rounded-md border-b-2 px-2 py-1 text-sm bg-gray-100">esc</span>
|
||||
</button>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<slot name="modal-body">
|
||||
<div class="modal-body" v-html="message">
|
||||
</div>
|
||||
<div class="py-1 px-5 bg-body" v-html="message"></div>
|
||||
</slot>
|
||||
|
||||
<div class="card-footer border-top-0 pt-0">
|
||||
<div class="p-5 bg-body rounded-bl-lg rounded-br-lg border-gray-300">
|
||||
<slot name="card-footer">
|
||||
<div class="float-right">
|
||||
<button type="button" class="btn btn-outline-secondary" @click="onCancel">
|
||||
{{ button_cancel }}
|
||||
<div class="flex items-center justify-end">
|
||||
<button type="button" class="px-6 py-1.5 ltr:mr-2 rtl:ml-2 hover:bg-gray-200 rounded-lg" @click="onCancel">
|
||||
{{ button_cancel }}
|
||||
</button>
|
||||
|
||||
<button :disabled="form.loading" type="button" class="btn btn-danger button-submit" @click="onConfirm">
|
||||
<div class="aka-loader"></div><span>{{ button_delete }}</span>
|
||||
<button :disabled="form.loading" type="button" class="relative flex items-center justify-center bg-red hover:bg-red-700 px-6 py-1.5 text-base rounded-lg disabled:opacity-50 text-white" @click="onConfirm">
|
||||
<i v-if="form.loading" class="animate-submit delay-[0.28s] absolute w-2 h-2 rounded-full left-0 right-0 -top-3.5 m-auto before:absolute before:w-2 before:h-2 before:rounded-full before:animate-submit before:delay-[0.14s] after:absolute after:w-2 after:h-2 after:rounded-full after:animate-submit before:-left-3.5 after:-right-3.5 after:delay-[0.42s]"></i>
|
||||
<span :class="[{'opacity-0': form.loading}]">{{ button_delete }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</slot>
|
||||
@ -45,7 +51,7 @@
|
||||
|
||||
<script>
|
||||
import { SlideYUpTransition } from "vue2-transitions";
|
||||
import AkauntingRadioGroup from './forms/AkauntingRadioGroup';
|
||||
import AkauntingRadioGroup from './AkauntingRadioGroup';
|
||||
import AkauntingSelect from './AkauntingSelect';
|
||||
import AkauntingDate from './AkauntingDate';
|
||||
import AkauntingRecurring from './AkauntingRecurring';
|
||||
@ -64,7 +70,9 @@ export default {
|
||||
},
|
||||
|
||||
props: {
|
||||
show: Boolean,
|
||||
show: {
|
||||
type: Boolean,
|
||||
},
|
||||
modalDialogClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
@ -94,7 +102,7 @@ export default {
|
||||
type: Number,
|
||||
default: 800,
|
||||
description: "Modal transition duration"
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
@ -112,8 +120,22 @@ export default {
|
||||
if (this.show) {
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.add("modal-open");
|
||||
documentClasses.add("overflow-hidden");
|
||||
}
|
||||
|
||||
if (this.modalDialogClass) {
|
||||
let modal_size = this.modalDialogClass.replace('modal-', 'max-w-screen-');
|
||||
|
||||
this.modalDialogClass = modal_size;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
window.addEventListener('keyup',(e) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.onCancel();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -131,7 +153,7 @@ export default {
|
||||
onCancel() {
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
|
||||
this.$emit("cancel");
|
||||
}
|
||||
@ -142,21 +164,11 @@ export default {
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
if (val) {
|
||||
documentClasses.add("modal-open");
|
||||
documentClasses.add("overflow-hidden");
|
||||
} else {
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.modal.show {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.modal-md {
|
||||
max-width: 650px;
|
||||
}
|
||||
</style>
|
||||
</script>
|
@ -1,45 +1,52 @@
|
||||
<template>
|
||||
<SlideYUpTransition :duration="animationDuration">
|
||||
<div class="modal modal-add-new fade"
|
||||
<div class="modal w-full h-full fixed top-0 left-0 right-0 z-50 overflow-y-auto overflow-hidden modal-add-new fade items-center justify-center"
|
||||
@click.self="closeModal"
|
||||
:class="[{'show d-block': show}, {'d-none': !show}]"
|
||||
:class="[{'show flex flex-wrap modal-background': show}, {'hidden': !show}]"
|
||||
v-show="show"
|
||||
tabindex="-1"
|
||||
role="dialog"
|
||||
:aria-hidden="!show">
|
||||
<div class="modal-dialog" :class="modalDialogClass">
|
||||
<div class="w-full my-10 m-auto flex flex-col" :class="modalDialogClass ? modalDialogClass : 'max-w-screen-sm'">
|
||||
<slot name="modal-content">
|
||||
<div class="modal-content">
|
||||
<div class="card-header pb-2">
|
||||
<slot name="card-header">
|
||||
<h4 class="float-left"> {{ title }} </h4>
|
||||
<button type="button" class="close" @click="onCancel" aria-hidden="true">×</button>
|
||||
</slot>
|
||||
<div class="p-5 bg-body rounded-tl-lg rounded-tr-lg">
|
||||
<div class="flex items-center justify-between border-b pb-5">
|
||||
<slot name="card-header">
|
||||
<h4 class="text-base font-medium">
|
||||
{{ title }}
|
||||
</h4>
|
||||
|
||||
<button type="button" class="text-lg" @click="onCancel" aria-hidden="true">
|
||||
<span class="rounded-md border-b-2 px-2 py-1 text-sm bg-gray-100">esc</span>
|
||||
</button>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<slot name="modal-body">
|
||||
<div class="modal-body pb-0" v-if="!is_component" v-html="message">
|
||||
</div>
|
||||
<div class="modal-body pb-0" v-else>
|
||||
<div class="py-1 px-5 bg-body" v-if="!is_component" v-html="message"></div>
|
||||
<div class="py-1 px-5 bg-body" v-else>
|
||||
<form id="form-create" method="POST" action="#"/>
|
||||
|
||||
<component v-bind:is="component"></component>
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
<div class="card-footer border-top-0 pt-0">
|
||||
<div class="p-5 bg-body rounded-bl-lg rounded-br-lg border-gray-300">
|
||||
<slot name="card-footer">
|
||||
<div class="float-right">
|
||||
<button type="button" class="btn btn-outline-secondary" :class="buttons.cancel.class" @click="onCancel">
|
||||
<div class="flex items-center justify-end">
|
||||
<button type="button" class="px-6 py-1.5 mr-2 hover:bg-gray-200 rounded-lg" :class="buttons.cancel.class" @click="onCancel">
|
||||
{{ buttons.cancel.text }}
|
||||
</button>
|
||||
|
||||
<a v-if="buttons.payment" :href="buttons.payment.url" class="btn btn-white" :class="buttons.payment.class">
|
||||
<a v-if="buttons.payment" :href="buttons.payment.url" class="px-3 py-1.5 mb-3 sm:mb-0 text-xs bg-transparent hover:bg-transparent font-medium leading-6 ltr:mr-2 rtl:ml-2" :class="buttons.payment.class">
|
||||
{{ buttons.payment.text }}
|
||||
</a>
|
||||
|
||||
<button :disabled="form.loading" type="button" class="btn button-submit" :class="buttons.confirm.class" @click="onSubmit">
|
||||
<div class="aka-loader"></div><span>{{ buttons.confirm.text }}</span>
|
||||
<button :disabled="form.loading" type="button" class="relative px-6 py-1.5 bg-green hover:bg-green-700 text-white rounded-lg" :class="buttons.confirm.class" @click="onSubmit">
|
||||
<i v-if="form.loading" class="animate-submit delay-[0.28s] absolute w-2 h-2 rounded-full left-0 right-0 -top-3.5 m-auto before:absolute before:w-2 before:h-2 before:rounded-full before:animate-submit before:delay-[0.14s] after:absolute after:w-2 after:h-2 after:rounded-full after:animate-submit before:-left-3.5 after:-right-3.5 after:delay-[0.42s]"></i>
|
||||
<span :class="[{'opacity-0': form.loading}]">{{ buttons.confirm.text }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</slot>
|
||||
@ -57,7 +64,7 @@ import Vue from 'vue';
|
||||
import { SlideYUpTransition } from "vue2-transitions";
|
||||
import AkauntingModal from './AkauntingModal';
|
||||
import AkauntingMoney from './AkauntingMoney';
|
||||
import AkauntingRadioGroup from './forms/AkauntingRadioGroup';
|
||||
import AkauntingRadioGroup from './AkauntingRadioGroup';
|
||||
import AkauntingSelect from './AkauntingSelect';
|
||||
import AkauntingSelectRemote from './AkauntingSelectRemote';
|
||||
import AkauntingDate from './AkauntingDate';
|
||||
@ -83,7 +90,6 @@ export default {
|
||||
|
||||
props: {
|
||||
show: Boolean,
|
||||
modalDialogClass: '',
|
||||
is_component: Boolean,
|
||||
|
||||
title: {
|
||||
@ -108,7 +114,7 @@ export default {
|
||||
},
|
||||
confirm: {
|
||||
text: 'Save',
|
||||
class: 'btn-success',
|
||||
class: 'disabled:bg-green-100',
|
||||
}
|
||||
};
|
||||
},
|
||||
@ -119,7 +125,13 @@ export default {
|
||||
type: Number,
|
||||
default: 800,
|
||||
description: "Modal transition duration"
|
||||
}
|
||||
},
|
||||
|
||||
modalDialogClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Modal Body size Class"
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
@ -142,7 +154,13 @@ export default {
|
||||
created: function () {
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.add("modal-open");
|
||||
documentClasses.add("overflow-hidden");
|
||||
|
||||
if (this.modalDialogClass) {
|
||||
let modal_size = this.modalDialogClass.replace('modal-', 'max-w-screen-');
|
||||
|
||||
this.modalDialogClass = modal_size;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
@ -255,6 +273,12 @@ export default {
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('keyup',(e) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.onCancel();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -273,7 +297,7 @@ export default {
|
||||
onCancel() {
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
|
||||
this.$emit("cancel");
|
||||
}
|
||||
@ -284,21 +308,11 @@ export default {
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
if (val) {
|
||||
documentClasses.add("modal-open");
|
||||
documentClasses.add("overflow-hidden");
|
||||
} else {
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.modal.show {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.modal-md {
|
||||
max-width: 650px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,19 +1,19 @@
|
||||
<template>
|
||||
<div v-if="!rowInput" class="form-group"
|
||||
<div v-if="! rowInput" class="form-group"
|
||||
:class="[{'has-error': error}, {'required': required}, {'readonly': readonly}, {'disabled': disabled}, col]">
|
||||
<label v-if="title" :for="name" class="form-control-label">{{ title }}</label>
|
||||
|
||||
<div class="input-group input-group-merge" :class="group_class">
|
||||
<div v-if="icon" class="input-group-prepend">
|
||||
<div class="relative" :class="group_class">
|
||||
<!-- <div class="input-group-prepend absolute left-2 bottom-3 text-light-gray">
|
||||
<span class="input-group-text">
|
||||
<i :class="'fa fa-' + icon"></i>
|
||||
<span class="material-icons w-4 h-5 text-sm">{{ icon }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<money :name="name" @input="input" :placeholder="placeholder" v-bind="money" :value="model" :disabled="disabled" :masked="masked" class="form-control" :class="moneyClass"></money>
|
||||
<money :name="name" @input="input" :placeholder="placeholder" v-bind="money" :value="model" :disabled="disabled" :masked="masked" class="form-element" :class="moneyClass"></money>
|
||||
</div>
|
||||
|
||||
<div class="invalid-feedback d-block" v-if="error" v-html="error"></div>
|
||||
<div class="text-red text-sm mt-1 block" v-if="error" v-html="error"></div>
|
||||
</div>
|
||||
|
||||
<div v-else
|
||||
@ -27,12 +27,12 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<money :name="name" @input="input" :placeholder="placeholder" v-bind="money" :value="model" :disabled="disabled" :masked="masked" class="form-control" :class="moneyClass"></money>
|
||||
<money :name="name" @input="input" :placeholder="placeholder" v-bind="money" :value="model" :disabled="disabled" :masked="masked" class="form-element" :class="moneyClass"></money>
|
||||
</div>
|
||||
|
||||
<money v-else :name="name" @input="input" :placeholder="placeholder" v-bind="money" :value="model" :disabled="disabled" :masked="masked" class="form-control" :class="moneyClass"></money>
|
||||
<money v-else :name="name" @input="input" :placeholder="placeholder" v-bind="money" :value="model" :disabled="disabled" :masked="masked" class="form-element" :class="moneyClass"></money>
|
||||
|
||||
<div class="invalid-feedback d-block" v-if="error" v-html="error"></div>
|
||||
<div class="text-red text-sm mt-1 block" v-if="error" v-html="error"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -134,7 +134,7 @@ export default {
|
||||
description: "Money result value"
|
||||
},
|
||||
rowInput: {
|
||||
type: Boolean,
|
||||
type: [Boolean, Number],
|
||||
default: false,
|
||||
description: "Money result value"
|
||||
},
|
||||
@ -158,12 +158,12 @@ export default {
|
||||
//this.model = this.value;
|
||||
|
||||
if (this.dynamicCurrency.code != this.currency.code) {
|
||||
if (!this.dynamicCurrency.decimal) {
|
||||
if (! this.dynamicCurrency.decimal) {
|
||||
this.money = {
|
||||
decimal: this.dynamicCurrency.decimal_mark,
|
||||
thousands: this.dynamicCurrency.thousands_separator,
|
||||
prefix: (this.dynamicCurrency.symbol_first) ? this.dynamicCurrency.symbol : '',
|
||||
suffix: (!this.dynamicCurrency.symbol_first) ? this.dynamicCurrency.symbol : '',
|
||||
suffix: (! this.dynamicCurrency.symbol_first) ? this.dynamicCurrency.symbol : '',
|
||||
precision: parseInt(this.dynamicCurrency.precision),
|
||||
masked: this.masked
|
||||
};
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<div class="tab-pane tab-example-result fade show active" role="tabpanel" aria-labelledby="-component-tab">
|
||||
<div class="btn-group btn-group-toggle radio-yes-no" data-toggle="buttons" v-on:click="onClick">
|
||||
<label class="btn btn-success"
|
||||
<label class="btn disabled:bg-green-100"
|
||||
:class="[{'active': value === 1}]">
|
||||
<input type="radio"
|
||||
:name="name"
|
@ -1,73 +1,117 @@
|
||||
<template>
|
||||
<div class="row pr-0" :class="formClasses">
|
||||
<base-input :label="title"
|
||||
name="recurring_frequency"
|
||||
:class="frequencyClasses"
|
||||
:error="frequencyError">
|
||||
<template slot="label">
|
||||
<label v-if="title" :class="labelClasses">
|
||||
{{ title }}
|
||||
<el-tooltip class="item" effect="dark" placement="top-start">
|
||||
<div slot="content" v-html="tooltip"></div>
|
||||
<i class="far fa-question-circle fa-xs" style="vertical-align: top;"></i>
|
||||
</el-tooltip>
|
||||
</label>
|
||||
</template>
|
||||
<el-select v-model="recurring_frequency" @input="change" filterable
|
||||
:placeholder="placeholder">
|
||||
<template slot="prefix">
|
||||
<span class="el-input__suffix-inner el-select-icon">
|
||||
<i :class="'el-input__icon el-icon-refresh'"></i>
|
||||
</span>
|
||||
</template>
|
||||
<div class="sm:col-span-6 space-y-8 sm:space-y-2">
|
||||
<div class="flex items-center" :class="{ 'justify-between sm:justify-start': frequency == 'custom' }">
|
||||
<div class="w-60 px-2 text-sm">
|
||||
{{ frequencyText }}
|
||||
</div>
|
||||
|
||||
<el-option v-for="(label, value) in frequencyOptions"
|
||||
:key="label"
|
||||
<el-select class="w-36" v-model="frequency" @input="change">
|
||||
<el-option
|
||||
v-for="(label, value) in frequencies"
|
||||
:key="value"
|
||||
:label="label"
|
||||
:value="value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</base-input>
|
||||
|
||||
<base-input :label="titleInterval"
|
||||
name="recurring_interval"
|
||||
type="number"
|
||||
:value="0"
|
||||
@input="change"
|
||||
:class="invertalClasses"
|
||||
:error="intervalError"
|
||||
v-model="recurring_interval"
|
||||
<div class="w-20 px-2 text-sm text-center" v-if="frequency == 'custom'">
|
||||
{{ frequencyEveryText }}
|
||||
</div>
|
||||
|
||||
<input type="text" class="w-20 form-element" v-model="interval" @input="change" v-if="frequency == 'custom'">
|
||||
|
||||
<el-select class="w-36 ml-2" v-model="customFrequency" @input="change" v-if="frequency == 'custom'">
|
||||
<el-option
|
||||
v-for="(label, value) in customFrequencies"
|
||||
:key="value"
|
||||
:label="label"
|
||||
:value="value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center" :class="{ 'justify-between sm:justify-start': limit !== 'never' }">
|
||||
<div class="w-60 px-2 text-sm">
|
||||
{{ startText }}
|
||||
</div>
|
||||
|
||||
<el-date-picker
|
||||
class="w-36 recurring-invoice-data"
|
||||
v-model="started_at"
|
||||
@input="change"
|
||||
type="date"
|
||||
align="right"
|
||||
:format="formatDate"
|
||||
value-format="yyyy-MM-dd"
|
||||
:picker-options="{
|
||||
disabledDate(time) {
|
||||
return time.getTime() < Date.now();
|
||||
},
|
||||
shortcuts: [
|
||||
{
|
||||
text: dateRangeText['today'],
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', new Date());
|
||||
}
|
||||
},
|
||||
{
|
||||
text: dateRangeText['yesterday'],
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
||||
|
||||
picker.$emit('pick', date);
|
||||
}
|
||||
},
|
||||
{
|
||||
text: dateRangeText['week_ago'],
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
||||
|
||||
picker.$emit('pick', date);
|
||||
}
|
||||
}
|
||||
]
|
||||
}">
|
||||
</el-date-picker>
|
||||
|
||||
<div class="w-20 px-2 text-sm text-center">
|
||||
{{ middleText }}
|
||||
</div>
|
||||
|
||||
<el-select class="w-20" v-model="limit" @input="change">
|
||||
<el-option
|
||||
v-for="(label, value) in limits"
|
||||
:key="value"
|
||||
:label="label"
|
||||
:value="value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<input type="text" class="w-36 form-element ml-2" v-model="limitDate" v-if="limit == 'after'" @input="change">
|
||||
|
||||
<div class="pl-2 text-sm" v-if="limit == 'after'">
|
||||
{{ endText }}
|
||||
</div>
|
||||
|
||||
<el-date-picker
|
||||
class="w-36 ml-2 recurring-invoice-data"
|
||||
v-model="limitDate"
|
||||
type="date"
|
||||
align="right"
|
||||
:format="formatDate"
|
||||
value-format="yyyy-MM-dd"
|
||||
v-if="limit == 'on'"
|
||||
@input="change"
|
||||
>
|
||||
</base-input>
|
||||
|
||||
<base-input :label="titleFrequency"
|
||||
name="recurring_custom_frequency"
|
||||
:class="customFrequencyClasses"
|
||||
:error="customFrequencyError">
|
||||
<el-select v-model="recurring_custom_frequency" @input="change" filterable
|
||||
:placeholder="placeholder">
|
||||
<el-option v-for="(label, value) in customFrequencyOptions"
|
||||
:key="label"
|
||||
:label="label"
|
||||
:value="value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</base-input>
|
||||
|
||||
<base-input :label="titleCount"
|
||||
name="recurring_count"
|
||||
type="number"
|
||||
:value="0"
|
||||
@input="change"
|
||||
:class="countClasses"
|
||||
:error="countError"
|
||||
v-model="recurring_count">
|
||||
</base-input>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Select, Option, Tooltip } from 'element-ui'
|
||||
import { Select, Option, DatePicker } from 'element-ui';
|
||||
|
||||
export default {
|
||||
name: 'akaunting-recurring',
|
||||
@ -75,144 +119,172 @@ export default {
|
||||
components: {
|
||||
[Select.name]: Select,
|
||||
[Option.name]: Option,
|
||||
[Tooltip.name]: Tooltip,
|
||||
[DatePicker.name]: DatePicker,
|
||||
},
|
||||
|
||||
props: {
|
||||
title: {
|
||||
startText: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Modal header title"
|
||||
default: 'Create first invoice on',
|
||||
description: "Default reccuring text"
|
||||
},
|
||||
titleInterval: {
|
||||
dateRangeText: {
|
||||
type: Object,
|
||||
default: {
|
||||
today : 'Today',
|
||||
yesterday : 'Yesterday',
|
||||
week_ago : 'A week ago',
|
||||
},
|
||||
description: "Default reccuring text"
|
||||
},
|
||||
middleText: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Title of interval"
|
||||
default: 'and end',
|
||||
description: "Default reccuring text"
|
||||
},
|
||||
titleFrequency: {
|
||||
endText: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Title of frequency"
|
||||
default: 'invoices',
|
||||
description: "Default reccuring text"
|
||||
},
|
||||
titleCount: {
|
||||
frequencies: null,
|
||||
frequencyText: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Title of count"
|
||||
default: 'Repeat this invoice',
|
||||
description: "Default reccuring text"
|
||||
},
|
||||
tooltip: {
|
||||
frequencyEveryText: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Tooltip message"
|
||||
default: 'every',
|
||||
description: "Default reccuring text"
|
||||
},
|
||||
placeholder: {
|
||||
frequencyValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Modal header title"
|
||||
default: 'monthly',
|
||||
description: "Default reccuring type"
|
||||
},
|
||||
formClasses: {
|
||||
default: 'col-md-6',
|
||||
},
|
||||
formError: null,
|
||||
|
||||
frequencyOptions: null,
|
||||
frequencyValue: null,
|
||||
frequencyError: null,
|
||||
customFrequencies: null,
|
||||
customFrequencyValue: {
|
||||
type: String,
|
||||
default: 'monthly',
|
||||
description: "Default reccuring type"
|
||||
},
|
||||
|
||||
intervalValue: {
|
||||
startedValue: {
|
||||
type: String,
|
||||
default: 'never',
|
||||
description: "Default reccuring limit"
|
||||
},
|
||||
|
||||
limits: null,
|
||||
|
||||
limitValue: {
|
||||
type: String,
|
||||
default: 'never',
|
||||
description: "Default reccuring limit"
|
||||
},
|
||||
|
||||
limitCountValue: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
description: "Default interval value"
|
||||
description: "Default reccuring limit"
|
||||
},
|
||||
intervalError: null,
|
||||
|
||||
customFrequencyOptions: null,
|
||||
customFrequencyValue: null,
|
||||
customFrequencyError: null,
|
||||
|
||||
countValue: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
description: "Default count value"
|
||||
},
|
||||
countError: null,
|
||||
|
||||
icon: {
|
||||
limitDateValue: {
|
||||
type: String,
|
||||
description: "Prepend icon (left)"
|
||||
default: '',
|
||||
description: "Default reccuring limit"
|
||||
},
|
||||
labelClasses: {
|
||||
|
||||
dateFormat: {
|
||||
type: String,
|
||||
description: "Input label css classes",
|
||||
default: "form-control-label"
|
||||
default: 'dd MM yyyy',
|
||||
description: "Default date format"
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
recurring_frequency: null,
|
||||
recurring_interval: null,
|
||||
recurring_custom_frequency: null,
|
||||
recurring_count: null,
|
||||
frequencyClasses: 'col-md-12',
|
||||
invertalClasses: 'col-md-2 d-none',
|
||||
customFrequencyClasses: 'col-md-4 d-none',
|
||||
countClasses: 'col-md-2 d-none'
|
||||
frequency: '',
|
||||
interval: '',
|
||||
customFrequency: '',
|
||||
started_at: '',
|
||||
limit: '',
|
||||
limitCount: '',
|
||||
limitDate: '',
|
||||
formatDate: 'dd MM YYYY',
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.recurring_frequency = this.frequencyValue;
|
||||
this.recurring_interval = this.intervalValue;
|
||||
this.recurring_custom_frequency = this.customFrequencyValue;
|
||||
this.recurring_count = this.countValue;
|
||||
created() {
|
||||
this.formatDate = this.convertToDarteFormat(this.dateFormat);
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.recurring_frequency = this.frequencyValue;
|
||||
this.frequency = this.frequencyValue;
|
||||
this.customFrequency = this.customFrequencyValue;
|
||||
this.started_at = this.startedValue;
|
||||
|
||||
if (this.recurring_frequency != 'custom') {
|
||||
this.recurring_custom_frequency = '';
|
||||
this.recurring_interval = '0';
|
||||
this.limit = this.limitValue;
|
||||
this.limitCount = this.limitCountValue;
|
||||
this.limitDate = this.limitDateValue;
|
||||
|
||||
if (this.limit == 'count') {
|
||||
if (typeof this.limitDate == 'string') {
|
||||
this.limit = 'never';
|
||||
} else {
|
||||
this.limit = 'after';
|
||||
}
|
||||
} else {
|
||||
this.limit = 'on';
|
||||
}
|
||||
|
||||
this.frequencyChanges();
|
||||
|
||||
this.$emit('recurring_frequency', this.recurring_frequency);
|
||||
this.$emit('recurring_interval', this.recurring_interval);
|
||||
this.$emit('recurring_custom_frequency', this.recurring_custom_frequency);
|
||||
this.$emit('recurring_count', this.recurring_count);
|
||||
setTimeout(function() {
|
||||
this.change();
|
||||
}.bind(this), 800);
|
||||
},
|
||||
|
||||
methods: {
|
||||
change() {
|
||||
this.$emit('change', this.recurring_frequency);
|
||||
this.$emit('change', this.frequency);
|
||||
|
||||
this.$emit('recurring_frequency', this.recurring_frequency);
|
||||
this.$emit('recurring_interval', this.recurring_interval);
|
||||
this.$emit('recurring_custom_frequency', this.recurring_custom_frequency);
|
||||
this.$emit('recurring_count', this.recurring_count);
|
||||
this.$emit('frequency', this.frequency);
|
||||
this.$emit('interval', this.interval);
|
||||
this.$emit('custom_frequency', this.customFrequency);
|
||||
this.$emit('started', this.started_at);
|
||||
|
||||
this.frequencyChanges();
|
||||
switch (this.limit) {
|
||||
case 'after':
|
||||
this.$emit('limit', 'count');
|
||||
this.$emit('limit_count', this.limitCount);
|
||||
break;
|
||||
case 'on':
|
||||
this.$emit('limit', 'date');
|
||||
this.$emit('limit_date', this.limitDate);
|
||||
break;
|
||||
case 'never':
|
||||
default:
|
||||
this.$emit('limit', 'count');
|
||||
this.$emit('limit_count', 0);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
frequencyChanges() {
|
||||
if (this.recurring_frequency == 'custom') {
|
||||
this.frequencyClasses = 'col-md-4';
|
||||
this.invertalClasses = 'col-md-2';
|
||||
this.customFrequencyClasses = 'col-md-4';
|
||||
this.countClasses = 'col-md-2 pr-0';
|
||||
} else if (this.recurring_frequency == 'no' || this.recurring_frequency == '') {
|
||||
this.frequencyClasses = 'col-md-12 pr-0';
|
||||
this.invertalClasses = 'col-md-2 d-none';
|
||||
this.customFrequencyClasses = 'col-md-4 d-none';
|
||||
this.countClasses = 'col-md-2 d-none';
|
||||
} else {
|
||||
this.frequencyClasses = 'col-md-10';
|
||||
this.invertalClasses = 'col-md-2 d-none';
|
||||
this.customFrequencyClasses = 'col-md-4 d-none';
|
||||
this.countClasses = 'col-md-2 pr-0';
|
||||
}
|
||||
}
|
||||
convertToDarteFormat(format) {
|
||||
return format.replace('d', 'dd')
|
||||
.replace('M', 'MMM')
|
||||
.replace('m', 'MM')
|
||||
.replace('F', 'MMMM')
|
||||
.replace('y', 'yyyy')
|
||||
.replace('Y', 'yyyy');
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.el-input__inner {
|
||||
height: 42px;
|
||||
}
|
||||
</style>
|
@ -1,45 +1,53 @@
|
||||
<template>
|
||||
<div :id="'search-field-' + _uid" class="searh-field tags-input__wrapper js-search">
|
||||
<div class="tags-group" v-for="(filter, index) in filtered" :index="index">
|
||||
<span v-if="filter.option" class="el-tag el-tag--primary el-tag--small el-tag--light el-tag-option">
|
||||
<div
|
||||
:id="'search-field-' + _uid"
|
||||
class="h-12 my-5 searh-field flex border-b transition-all js-search"
|
||||
:class="input_focus ? 'border-gray-500' : 'border-gray-300'"
|
||||
>
|
||||
<div class="tags-group group items-center" style="display:contents;" v-for="(filter, index) in filtered" :index="index">
|
||||
<span v-if="filter.option" class="flex items-center bg-purple-lighter text-black border-0 mt-3 px-3 py-4 text-sm cursor-pointer el-tag el-tag--small el-tag-option">
|
||||
{{ filter.option }}
|
||||
|
||||
<i v-if="!filter.operator && !filter.value" class="el-tag__close el-icon-close" @click="onFilterDelete(index)"></i>
|
||||
<i v-if="!filter.operator && !filter.value" class="mt-1 ltr:-right-2 rtl:left-0 rtl:right-0 el-tag__close el-icon-close" style="font-size: 16px;" @click="onFilterDelete(index)"></i>
|
||||
</span>
|
||||
|
||||
<span v-if="filter.operator" class="el-tag el-tag--primary el-tag--small el-tag--light el-tag-operator">
|
||||
<i v-if="filter.operator == '='" class="fas fa-equals"></i>
|
||||
<i v-else-if="filter.operator == '><'" class="fas fa-arrows-alt-h"></i>
|
||||
<i v-else class="fas fa-not-equal"></i>
|
||||
<span v-if="filter.operator" class="flex items-center bg-purple-lighter text-black border-2 border-body border-l border-r border-t-0 border-b-0 mt-3 px-3 py-4 text-sm cursor-pointer el-tag el-tag--small el-tag-operator" style="margin-left:0; margin-right:0;">
|
||||
<span v-if="filter.operator == '='" class="material-icons text-2xl">drag_handle</span>
|
||||
<span v-else-if="filter.operator == '><'" class="material-icons text-2xl transform rotate-90">height</span>
|
||||
|
||||
<i v-if="!filter.value" class="el-tag__close el-icon-close" @click="onFilterDelete(index)"></i>
|
||||
<img v-else :src="equal_image" class="w-5 h-5 object-cover block" />
|
||||
|
||||
<i v-if="!filter.value" class="mt-1 ltr:-right-2 rtl:left-0 rtl:right-0 el-tag__close el-icon-close " style="font-size: 16px;" @click="onFilterDelete(index)"></i>
|
||||
</span>
|
||||
|
||||
<span v-if="filter.value" class="el-tag el-tag--primary el-tag--small el-tag--light el-tag-value">
|
||||
<span v-if="filter.value" class="flex items-center bg-purple-lighter text-black border-0 mt-3 px-3 py-4 text-sm cursor-pointer el-tag el-tag--small el-tag-value">
|
||||
{{ filter.value }}
|
||||
|
||||
<i class="el-tag__close el-icon-close" @click="onFilterDelete(index)"></i>
|
||||
<i class="mt-1 ltr:-right-2 rtl:left-0 rtl:right-0 el-tag__close el-icon-close " style="font-size: 16px;" @click="onFilterDelete(index)"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="dropdown input-full">
|
||||
<div class="relative w-full h-full flex">
|
||||
<input
|
||||
v-if="!show_date"
|
||||
type="text"
|
||||
class="form-control"
|
||||
:placeholder="placeholder"
|
||||
:ref="'input-search-field-' + _uid"
|
||||
v-model="search"
|
||||
@focus="onInputFocus"
|
||||
@input="onInput"
|
||||
@keyup.enter="onInputConfirm"
|
||||
v-if="!show_date"
|
||||
type="text"
|
||||
class="w-full bg-transparent text-black text-sm border-0 px-10 pb-0 focus:outline-none focus:ring-transparent focus:border-purple-100"
|
||||
:class="[{'px-4' : !show_icon}]"
|
||||
:placeholder="placeholder"
|
||||
:ref="'input-search-field-' + _uid"
|
||||
v-model="search"
|
||||
@focus="onInputFocus"
|
||||
@input="onInput"
|
||||
@blur="onBlur"
|
||||
@keyup.enter="onInputConfirm"
|
||||
/>
|
||||
|
||||
<flat-picker
|
||||
v-else
|
||||
@on-open="onInputFocus"
|
||||
@blur="onBlur"
|
||||
:config="dateConfig"
|
||||
class="form-control datepicker"
|
||||
class="w-full bg-transparent text-black text-sm border-0 px-10 pb-0 focus:outline-none focus:ring-transparent focus:border-purple-100 datepicker"
|
||||
:placeholder="placeholder"
|
||||
:ref="'input-search-date-field-' + _uid"
|
||||
value=""
|
||||
@ -48,42 +56,53 @@
|
||||
@keyup.enter="onInputConfirm"
|
||||
>
|
||||
</flat-picker>
|
||||
<span class="material-icons absolute bottom-1 ltr:left-3 rtl:right-3 text-lg text-black" style="z-index:-1;">search</span>
|
||||
|
||||
<button type="button" class="btn btn-link clear" @click="onSearchAndFilterClear">
|
||||
<i class="el-tag__close el-icon-close"></i>
|
||||
<button type="button" class="absolute ltr:right-0 rtl:left-0 top-2 clear" v-if="show_close_icon" @click="onSearchAndFilterClear">
|
||||
<span class="material-icons text-sm">close</span>
|
||||
</button>
|
||||
|
||||
<div :id="'search-field-option-' + _uid" class="dropdown-menu" :class="[{'show': visible.options}]">
|
||||
<li ref="" class="dropdown-item" v-for="option in filteredOptions" :data-value="option.key">
|
||||
<button type="button" class="btn btn-link" @click="onOptionSelected(option.key)">{{ option.value }}</button>
|
||||
<div :id="'search-field-option-' + _uid" class="absolute top-12 ltr:left-8 rtl:right-8 py-2 bg-white rounded-md border border-gray-200 shadow-xl z-20 list-none dropdown-menu" :class="[{'show': visible.options}]">
|
||||
<li ref="" class="w-full flex items-center text-purple px-2 h-9 leading-9 whitespace-nowrap" v-for="option in filteredOptions" :data-value="option.key">
|
||||
<button type="button" class="w-full h-full flex items-center rounded-md px-2 text-sm hover:bg-lilac-100" data-btn="btn btn-link" @click="onOptionSelected(option.key)">{{ option.value }}</button>
|
||||
</li>
|
||||
|
||||
<li ref="" v-if="search" class="dropdown-item">
|
||||
<button type="button" class="btn btn-link" @click="onInputConfirm">{{ searchText }}</button>
|
||||
<li ref="" v-if="search" class="p-2 hover:bg-lilac-900 dropdown-item">
|
||||
<button type="button" class="text-left" @click="onInputConfirm">{{ searchText }}</button>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<div :id="'search-field-operator-' + _uid" class="dropdown-menu operator" :class="[{'show': visible.operator}]">
|
||||
<li ref="" class="dropdown-item">
|
||||
<button type="button" class="btn btn-link" @click="onOperatorSelected('=')"><i class="fas fa-equals"></i><span class="btn-helptext d-none">{{ operatorIsText }}</span></button>
|
||||
<div :id="'search-field-operator-' + _uid" class="absolute top-12 ltr:left-8 rtl:right-8 py-2 bg-white rounded-md border border-gray-200 shadow-xl z-20 list-none dropdown-menu operator" :class="[{'show': visible.operator}]">
|
||||
<li ref="" class="w-full flex items-center text-purple px-2 h-9 leading-9 whitespace-nowrap">
|
||||
<button type="button" class="w-full h-full flex items-center rounded-md px-2 text-sm hover:bg-lilac-100" @click="onOperatorSelected('=')">
|
||||
<span class="material-icons text-2xl transform">drag_handle</span>
|
||||
<span class="text-gray hidden">{{ operatorIsText }}
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<li ref="" class="dropdown-item">
|
||||
<button type="button" class="btn btn-link" @click="onOperatorSelected('!=')"><i class="fas fa-not-equal"></i><span class="btn-helptext d-none">{{ operatorIsNotText }}</span></button>
|
||||
<li ref="" class="w-full flex items-center text-purple px-2 h-9 leading-9 whitespace-nowrap">
|
||||
<button type="button" class="w-full h-full flex items-center rounded-md px-2 text-sm hover:bg-lilac-100" @click="onOperatorSelected('!=')">
|
||||
<img :src="equal_image" class="w-6 h-6 block m-auto" />
|
||||
<span class="text-gray hidden">{{ operatorIsNotText }}</span>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<li v-if="range" ref="" class="dropdown-item">
|
||||
<button type="button" class="btn btn-link" @click="onOperatorSelected('><')"><i class="fas fa-arrows-alt-h"></i><span class="btn-helptext d-none">{{ operatorIsNotText }}</span></button>
|
||||
<li v-if="range" ref="" class="w-full flex items-center text-purple px-2 h-9 leading-9 whitespace-nowrap">
|
||||
<button type="button" class="w-full h-full flex items-center rounded-md px-2 text-sm hover:bg-lilac-100" @click="onOperatorSelected('><')">
|
||||
<span class="material-icons text-2xl transform rotate-90">height</span>
|
||||
<span class="text-gray hidden">{{ operatorIsNotText }}</span>
|
||||
</button>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<div :id="'search-field-value-' + _uid" class="dropdown-menu" :class="[{'show': visible.values}]">
|
||||
<li ref="" class="dropdown-item" v-for="(value) in filteredValues" :data-value="value.key">
|
||||
<button type="button" class="btn btn-link" @click="onValueSelected(value.key)">{{ value.value }}</button>
|
||||
<div :id="'search-field-value-' + _uid" class="absolute top-12 ltr:left-8 rtl:right-8 py-2 bg-white rounded-md border border-gray-200 shadow-xl z-20 list-none dropdown-menu" :class="[{'show': visible.values}]">
|
||||
<li ref="" class="w-full flex items-center text-purple px-2 h-9 leading-9 whitespace-nowrap" v-for="(value) in filteredValues" :data-value="value.key">
|
||||
<button type="button" class="w-full h-full flex items-center rounded-md px-2 text-sm hover:bg-lilac-100" @click="onValueSelected(value.key)">{{ value.value }}</button>
|
||||
</li>
|
||||
|
||||
<li ref="" class="dropdown-item" v-if="!filteredValues.length">
|
||||
<button type="button" class="btn btn-link">{{ noMatchingDataText }}</button>
|
||||
<li ref="" class="w-full flex items-center text-purple px-2 h-9 leading-9 whitespace-nowrap" v-if="!filteredValues.length">
|
||||
<button type="button" class="w-full h-full flex items-center rounded-md px-2 text-sm hover:bg-lilac-100">{{ noMatchingDataText }}</button>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
@ -149,7 +168,7 @@ export default {
|
||||
},
|
||||
|
||||
dateConfig: null
|
||||
|
||||
|
||||
},
|
||||
|
||||
model: {
|
||||
@ -178,6 +197,10 @@ export default {
|
||||
values: [],
|
||||
current_value: null,
|
||||
show_date: false,
|
||||
show_close_icon: false,
|
||||
show_icon: true,
|
||||
equal_image: app_url + "/public/img/tailwind_icons/not-equal.svg",
|
||||
input_focus: false
|
||||
};
|
||||
},
|
||||
|
||||
@ -201,7 +224,11 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
//console.log('Focus :' + this.filter_last_step);
|
||||
this.input_focus = true;
|
||||
},
|
||||
|
||||
onBlur() {
|
||||
this.input_focus = false;
|
||||
},
|
||||
|
||||
onInputDateSelected(selectedDates, dateStr, instance) {
|
||||
@ -218,7 +245,7 @@ export default {
|
||||
|
||||
date = dates.join('-to-');
|
||||
}
|
||||
|
||||
|
||||
this.selected_values.push({
|
||||
key: date,
|
||||
value: dateStr,
|
||||
@ -343,6 +370,7 @@ export default {
|
||||
},
|
||||
|
||||
onOptionSelected(value) {
|
||||
this.show_icon = false;
|
||||
this.current_value = value;
|
||||
this.range = false;
|
||||
|
||||
@ -474,6 +502,7 @@ export default {
|
||||
},
|
||||
|
||||
onValueSelected(value) {
|
||||
this.show_close_icon = true;
|
||||
let select_value = false;
|
||||
|
||||
for (let i = 0; i < this.values.length; i++) {
|
||||
@ -517,6 +546,8 @@ export default {
|
||||
},
|
||||
|
||||
onFilterDelete(index) {
|
||||
this.show_icon = true;
|
||||
this.show_close_icon = false;
|
||||
this.filter_list.push(this.selected_options[index]);
|
||||
|
||||
if (this.filter_last_step == 'options') {
|
||||
@ -567,7 +598,7 @@ export default {
|
||||
},
|
||||
|
||||
closeIfClickedOutside(event) {
|
||||
if (!document.getElementById('search-field-' + this._uid).contains(event.target) && event.target.className != 'btn btn-link') {
|
||||
if (!document.getElementById('search-field-' + this._uid).contains(event.target) && event.target.getAttribute('data-btn') != 'btn btn-link') {
|
||||
this.visible.options = false;
|
||||
this.visible.operator = false;
|
||||
this.visible.values = false;
|
||||
@ -592,8 +623,6 @@ export default {
|
||||
|
||||
let search_string = this.value.replace('not ', '').replace(' not ', ' ');
|
||||
|
||||
console.log(search_string);
|
||||
|
||||
search_string = search_string.split(' ');
|
||||
|
||||
search_string.forEach(function (string) {
|
||||
@ -646,7 +675,7 @@ export default {
|
||||
value_assigned = true
|
||||
}
|
||||
}, this);
|
||||
|
||||
|
||||
if (!value_assigned && (cookie != undefined && cookie[_filter.key])) {
|
||||
this.selected_values.push(cookie[_filter.key]);
|
||||
}
|
||||
@ -672,8 +701,6 @@ export default {
|
||||
let filter_values = this.convertOption(_filter.values);
|
||||
|
||||
if (_filter.key == filter.option) {
|
||||
console.log('Filter YES');
|
||||
|
||||
option = _filter.value;
|
||||
operator = filter.operator;
|
||||
|
||||
@ -685,8 +712,6 @@ export default {
|
||||
|
||||
this.selected_options.push(this.filter_list[i]);
|
||||
|
||||
console.log(operator);
|
||||
|
||||
this.selected_operator.push({
|
||||
key: operator,
|
||||
});
|
||||
@ -779,23 +804,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.searh-field {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.searh-field .tags-group {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.searh-field .el-tag.el-tag--primary {
|
||||
background: #f6f9fc;
|
||||
background-color: #f6f9fc;
|
||||
border-color: #f6f9fc;
|
||||
color: #8898aa;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.searh-field .tags-group:hover > span {
|
||||
background:#cbd4de;
|
||||
background-color: #cbd4de;
|
||||
@ -804,64 +812,47 @@ export default {
|
||||
|
||||
.searh-field .el-tag.el-tag--primary .el-tag__close.el-icon-close {
|
||||
color: #8898aa;
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.searh-field .el-tag-option {
|
||||
border-radius: 0.25rem 0 0 0.25rem;
|
||||
.searh-field .el-tag.el-tag--primary .el-tag__close.el-icon-close:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
html[dir='ltr'] .searh-field .el-tag-option {
|
||||
border-radius: 0.50rem 0 0 0.50rem;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
html[dir='rtl'] .searh-field .el-tag-option {
|
||||
border-radius: 0.50rem;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.searh-field .el-tag-operator {
|
||||
border-radius: 0;
|
||||
margin-left: -1px;
|
||||
margin-right: -1px;
|
||||
}
|
||||
|
||||
.searh-field .el-tag-value {
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
html[dir='ltr'] .searh-field .el-tag-value {
|
||||
border-radius: 0 0.50rem 0.50rem 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
html[dir='rtl'] .searh-field .el-tag-value {
|
||||
border-radius: 0.50rem;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
html[dir='rtl'] .searh-field .el-tag-operator {
|
||||
border-radius: 0.50rem;
|
||||
}
|
||||
|
||||
.searh-field .el-select.input-new-tag {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.searh-field .input-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.searh-field .btn.btn-link {
|
||||
width: inherit;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
margin: 0;
|
||||
text-overflow: inherit;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
padding: unset;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.searh-field .btn.btn-link.clear {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
color: #adb5bd;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.searh-field .btn.btn-link.clear:hover {
|
||||
color: #8898aa;
|
||||
}
|
||||
|
||||
.searh-field .btn-helptext {
|
||||
margin-left: auto;
|
||||
color: var(--gray);
|
||||
@ -884,4 +875,30 @@ export default {
|
||||
.searh-field .dropdown-menu.operator .btn i:not(:last-child), .btn svg:not(:last-child) {
|
||||
margin-right: inherit !important;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
min-width: 10rem;
|
||||
}
|
||||
|
||||
.dropdown-menu li {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.dropdown-menu.operator li {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.dropdown-menu li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu > li > button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-menu.show {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
@ -17,23 +17,24 @@
|
||||
:readonly="readonly"
|
||||
:collapse-tags="collapse"
|
||||
:loading="loading"
|
||||
class="forms"
|
||||
>
|
||||
<div v-if="loading" class="el-select-dropdown__wrap" slot="empty">
|
||||
<p class="el-select-dropdown__empty loading">
|
||||
{{ loadingText }}
|
||||
<p class="el-select-dropdown__empty pt-2 pb-0 loading">
|
||||
<span class="material-icons form-spin text-lg animate-spin">data_usage</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="addNew.status && options.length != 0 && sortedOptions.length == 0" class="el-select-dropdown__wrap" slot="empty">
|
||||
<p class="el-select-dropdown__empty">
|
||||
<p class="el-select-dropdown__empty pt-2 pb-0">
|
||||
{{ noMatchingDataText }}
|
||||
</p>
|
||||
|
||||
<ul class="el-scrollbar__view el-select-dropdown__list">
|
||||
<li class="el-select-dropdown__item el-select__footer">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<li class="el-select-dropdown__item el-select__footer bg-purple">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -42,14 +43,14 @@
|
||||
</div>
|
||||
|
||||
<div v-else-if="addNew.status && options.length == 0" slot="empty">
|
||||
<p class="el-select-dropdown__empty">
|
||||
<p class="el-select-dropdown__empty pt-2 pb-0">
|
||||
{{ noDataText }}
|
||||
</p>
|
||||
<ul class="el-scrollbar__view el-select-dropdown__list">
|
||||
<li class="el-select-dropdown__item el-select__footer">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<li class="el-select-dropdown__item el-select__footer bg-purple">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -68,7 +69,7 @@
|
||||
:disabled="disabledOptions.includes(option.key)"
|
||||
:label="option.value"
|
||||
:value="option.key">
|
||||
<span class="float-left">{{ option.value }}</span>
|
||||
<span class="float-left" :style="'padding-left: ' + (10 * option.level).toString() + 'px;'"><i v-if="option.level != 0" class="material-icons align-middle text-lg ltr:mr-2 rtl:ml-2">subdirectory_arrow_right</i>{{ option.value }}</span>
|
||||
<span class="badge badge-pill badge-success float-right mt-2" v-if="new_options[option.key]">{{ addNew.new_text }}</span>
|
||||
</el-option>
|
||||
|
||||
@ -88,10 +89,10 @@
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
|
||||
<el-option v-if="!loading && addNew.status && options.length != 0 && sortedOptions.length > 0" class="el-select__footer select-add-new" disabled value="">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<el-option v-if="!loading && addNew.status && options.length != 0 && sortedOptions.length > 0" class="el-select-dropdown__item el-select__footer select-add-new bg-purple" disabled value="">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -101,12 +102,11 @@
|
||||
|
||||
<component v-bind:is="add_new_html" @submit="onSubmit" @cancel="onCancel"></component>
|
||||
|
||||
<span slot="infoBlock" class="badge badge-success badge-resize float-right" v-if="new_options[selected]">{{ addNew.new_text }}</span>
|
||||
<span slot="infoBlock" class="absolute right-8 top-3 bg-green text-white px-2 py-1 rounded-md text-xs" v-if="new_options[selected]">{{ addNew.new_text }}</span>
|
||||
|
||||
<select :name="name" :id="name" v-model="selected" class="d-none">
|
||||
<option v-for="option in sortedOptions" :key="option.key" :value="option.key">{{ option.value }}</option>
|
||||
</select>
|
||||
|
||||
</base-input>
|
||||
</template>
|
||||
|
||||
@ -118,7 +118,7 @@ import { Select, Option, OptionGroup, ColorPicker } from 'element-ui';
|
||||
import AkauntingModalAddNew from './AkauntingModalAddNew';
|
||||
import AkauntingModal from './AkauntingModal';
|
||||
import AkauntingMoney from './AkauntingMoney';
|
||||
import AkauntingRadioGroup from './forms/AkauntingRadioGroup';
|
||||
import AkauntingRadioGroup from './AkauntingRadioGroup';
|
||||
import AkauntingSelect from './AkauntingSelect';
|
||||
import AkauntingDate from './AkauntingDate';
|
||||
import AkauntingRecurring from './AkauntingRecurring';
|
||||
@ -266,12 +266,6 @@ export default {
|
||||
description: "Selectbox collapse status"
|
||||
},
|
||||
|
||||
loadingText: {
|
||||
type: String,
|
||||
default: 'Loading...',
|
||||
description: "Selectbox loading message"
|
||||
},
|
||||
|
||||
noDataText: {
|
||||
type: String,
|
||||
default: 'No Data',
|
||||
@ -392,7 +386,8 @@ export default {
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
values.push({
|
||||
key: key.toString(),
|
||||
value: value
|
||||
value: value,
|
||||
level: 0
|
||||
});
|
||||
}
|
||||
|
||||
@ -407,13 +402,15 @@ export default {
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: index.toString(),
|
||||
value: option
|
||||
value: option,
|
||||
level: 0
|
||||
});
|
||||
} else {
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
|
||||
level: (option.level) ? option.level : 0
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
@ -424,7 +421,8 @@ export default {
|
||||
for (const [key, value] of Object.entries(created_options)) {
|
||||
this.sorted_options.push({
|
||||
key: key.toString(),
|
||||
value: value
|
||||
value: value,
|
||||
level: 0
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -433,13 +431,15 @@ export default {
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: index.toString(),
|
||||
value: option
|
||||
value: option,
|
||||
level: 0
|
||||
});
|
||||
} else {
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
|
||||
level: (option.level) ? option.level : 0
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
@ -693,7 +693,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
@ -712,7 +712,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
},
|
||||
|
||||
addModal() {
|
||||
@ -812,13 +812,14 @@ export default {
|
||||
|
||||
for (const [key, value] of Object.entries(_options)) {
|
||||
values.push({
|
||||
key: key,
|
||||
value: value
|
||||
key: key.toString(),
|
||||
value: value,
|
||||
level: 0
|
||||
});
|
||||
}
|
||||
|
||||
this.sorted_options.push({
|
||||
key: index,
|
||||
key: index.toString(),
|
||||
value: values
|
||||
});
|
||||
}
|
||||
@ -828,13 +829,15 @@ export default {
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: index.toString(),
|
||||
value: option
|
||||
value: option,
|
||||
level: 0
|
||||
});
|
||||
} else {
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: option.id,
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
|
||||
level: (option.level) ? option.level : 0
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
@ -844,8 +847,9 @@ export default {
|
||||
if (!Array.isArray(options)) {
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
this.sorted_options.push({
|
||||
key: key,
|
||||
value: value
|
||||
key: key.toString(),
|
||||
value: value,
|
||||
level: 0
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -854,13 +858,15 @@ export default {
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: index.toString(),
|
||||
value: option
|
||||
value: option,
|
||||
level: 0
|
||||
});
|
||||
} else {
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: option.id,
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
|
||||
level: (option.level) ? option.level : 0
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
@ -870,57 +876,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-group .modal {
|
||||
z-index: 3050;
|
||||
}
|
||||
|
||||
.el-select-dropdown__empty {
|
||||
padding: 10px 0 0 !important;
|
||||
}
|
||||
|
||||
.el-select-dropdown__empty.loading {
|
||||
padding: 10px 0 !important;
|
||||
}
|
||||
|
||||
.el-select__footer {
|
||||
text-align: center !important;
|
||||
border-top: 1px solid #dee2e6 !important;
|
||||
padding: 0px !important;
|
||||
cursor: pointer !important;
|
||||
color: #3c3f72 !important;
|
||||
font-weight: bold !important;
|
||||
height: 38px !important;
|
||||
line-height: 38px !important;
|
||||
margin-top: 5px !important;
|
||||
margin-bottom: -6px !important;
|
||||
border-bottom-left-radius: 4px !important;
|
||||
border-bottom-right-radius: 4px !important;
|
||||
}
|
||||
|
||||
.el-select__footer.el-select-dropdown__item.hover {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
||||
.el-select__footer.el-select-dropdown__item:hover, .el-select__footer.el-select-dropdown__item:focus {
|
||||
background-color: #3c3f72 !important;
|
||||
color: white !important;
|
||||
border-top-color: #3c3f72;
|
||||
}
|
||||
|
||||
.el-select__footer div span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.badge-resize {
|
||||
float: right;
|
||||
margin-top: -32px;
|
||||
margin-right: 35px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.badge.badge-pill.badge-success {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -20,21 +20,21 @@
|
||||
:loading="loading"
|
||||
>
|
||||
<div v-if="loading" class="el-select-dropdown__wrap" slot="empty">
|
||||
<p class="el-select-dropdown__empty loading">
|
||||
{{ loadingText }}
|
||||
<p class="el-select-dropdown__empty pt-2 pb-0 loading">
|
||||
<span class="material-icons form-spin text-lg animate-spin">data_usage</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && addNew.status && options.length != 0 && sortOptions.length == 0" class="el-select-dropdown__wrap" slot="empty">
|
||||
<p class="el-select-dropdown__empty">
|
||||
<div v-if="!loading && addNew.status && options.length != 0 && sortedOptions.length == 0" class="el-select-dropdown__wrap" slot="empty">
|
||||
<p class="el-select-dropdown__empty pt-2 pb-0">
|
||||
{{ noMatchingDataText }}
|
||||
</p>
|
||||
|
||||
<ul class="el-scrollbar__view el-select-dropdown__list">
|
||||
<li class="el-select-dropdown__item el-select__footer" disabled value="">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<li class="el-select-dropdown__item el-select__footer bg-purple" disabled value="">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -45,10 +45,10 @@
|
||||
<div v-if="!loading && addNew.status && options.length == 0">
|
||||
<el-option class="text-center" disabled :label="noDataText" value="value"></el-option>
|
||||
<ul class="el-scrollbar__view el-select-dropdown__list">
|
||||
<li class="el-select-dropdown__item el-select__footer">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<li class="el-select-dropdown__item el-select__footer bg-purple">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -62,18 +62,18 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<el-option v-if="!group" v-for="(option, index) in sortOptions"
|
||||
<el-option v-if="!group" v-for="(option, index) in sortedOptions"
|
||||
:key="option.key"
|
||||
:disabled="disabledOptions.includes(option.key)"
|
||||
:label="option.value"
|
||||
:value="option.key">
|
||||
<span class="float-left">{{ option.value }}</span>
|
||||
<span class="float-left" :style="'padding-left: ' + (10 * option.level).toString() + 'px;'"><i v-if="option.level != 0" class="material-icons align-middle text-lg ltr:mr-2 rtl:ml-2">subdirectory_arrow_right</i>{{ option.value }}</span>
|
||||
<span class="badge badge-pill badge-success float-right mt-2" v-if="new_options[option.key]">{{ addNew.new_text }}</span>
|
||||
</el-option>
|
||||
|
||||
<el-option-group
|
||||
v-if="group"
|
||||
v-for="(group_options, group_index) in sortOptions"
|
||||
v-for="(group_options, group_index) in sortedOptions"
|
||||
:key="group_index"
|
||||
:label="group_options.key">
|
||||
<el-option
|
||||
@ -82,15 +82,15 @@
|
||||
:disabled="disabledOptions.includes(option.key)"
|
||||
:label="option.value"
|
||||
:value="option.key">
|
||||
<span class="float-left">{{ option.value }}</span>
|
||||
<span class="float-left" :style="'padding-left: ' + (10 * option.level).toString() + 'px;'"><i v-if="option.level != 0" class="material-icons align-middle text-lg ltr:mr-2 rtl:ml-2">subdirectory_arrow_right</i>{{ option.value }}</span>
|
||||
<span class="badge badge-pill badge-success float-right mt-2" v-if="new_options[option.key]">{{ addNew.new_text }}</span>
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
|
||||
<el-option v-if="!loading && addNew.status && options.length != 0 && sortOptions.length > 0" class="el-select__footer" :disabled="disabled" value="">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<el-option v-if="!loading && addNew.status && options.length != 0 && sortedOptions.length > 0" class="el-select__footer bg-purple" :disabled="disabled" value="">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -100,10 +100,10 @@
|
||||
|
||||
<component v-bind:is="add_new_html" @submit="onSubmit" @cancel="onCancel"></component>
|
||||
|
||||
<span slot="infoBlock" class="badge badge-success badge-resize float-right" v-if="new_options[selected]">{{ addNew.new_text }}</span>
|
||||
<span slot="infoBlock" class="absolute right-8 top-3 bg-green text-white px-2 py-1 rounded-md text-xs" v-if="new_options[selected]">{{ addNew.new_text }}</span>
|
||||
|
||||
<select :name="name" :id="name" v-model="selected" class="d-none">
|
||||
<option v-for="option in sortOptions" :key="option.key" :value="option.key">{{ option.value }}</option>
|
||||
<option v-for="option in sortedOptions" :key="option.key" :value="option.key">{{ option.value }}</option>
|
||||
</select>
|
||||
|
||||
</base-input>
|
||||
@ -120,21 +120,21 @@
|
||||
:loading="loading"
|
||||
>
|
||||
<div v-if="loading" class="el-select-dropdown__wrap" slot="empty">
|
||||
<p class="el-select-dropdown__empty loading">
|
||||
{{ loadingText }}
|
||||
<p class="el-select-dropdown__empty pt-2 pb-0 loading">
|
||||
<span class="material-icons form-spin text-lg animate-spin">data_usage</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && addNew.status && options.length != 0 && sortOptions.length == 0" class="el-select-dropdown__wrap" slot="empty">
|
||||
<p class="el-select-dropdown__empty">
|
||||
<div v-if="!loading && addNew.status && options.length != 0 && sortedOptions.length == 0" class="el-select-dropdown__wrap" slot="empty">
|
||||
<p class="el-select-dropdown__empty pt-2 pb-0">
|
||||
{{ noMatchingDataText }}
|
||||
</p>
|
||||
|
||||
<ul class="el-scrollbar__view el-select-dropdown__list">
|
||||
<li class="el-select-dropdown__item el-select__footer" disabled value="">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<li class="el-select-dropdown__item el-select__footer bg-purple" disabled value="">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -145,10 +145,10 @@
|
||||
<div v-if="!loading && addNew.status && options.length == 0">
|
||||
<el-option class="text-center" disabled :label="noDataText" value="value"></el-option>
|
||||
<ul class="el-scrollbar__view el-select-dropdown__list">
|
||||
<li class="el-select-dropdown__item el-select__footer">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<li class="el-select-dropdown__item el-select__footer bg-purple">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -162,18 +162,18 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<el-option v-if="!group" v-for="(option, index) in sortOptions"
|
||||
<el-option v-if="!group" v-for="(option, index) in sortedOptions"
|
||||
:key="option.key"
|
||||
:disabled="disabledOptions.includes(option.key)"
|
||||
:label="option.value"
|
||||
:value="option.key">
|
||||
<span class="float-left">{{ option.value }}</span>
|
||||
<span class="float-left" :style="'padding-left: ' + (10 * option.level).toString() + 'px;'"><i v-if="option.level != 0" class="material-icons align-middle text-lg ltr:mr-2 rtl:ml-2">subdirectory_arrow_right</i>{{ option.value }}</span>
|
||||
<span class="badge badge-pill badge-success float-right mt-2" v-if="new_options[option.key]">{{ addNew.new_text }}</span>
|
||||
</el-option>
|
||||
|
||||
<el-option-group
|
||||
v-if="group"
|
||||
v-for="(group_options, group_index) in sortOptions"
|
||||
v-for="(group_options, group_index) in sortedOptions"
|
||||
:key="group_index"
|
||||
:label="group_options.key">
|
||||
<el-option
|
||||
@ -182,15 +182,15 @@
|
||||
:disabled="disabledOptions.includes(option.key)"
|
||||
:label="option.value"
|
||||
:value="option.key">
|
||||
<span class="float-left">{{ option.value }}</span>
|
||||
<span class="float-left" :style="'padding-left: ' + (10 * option.level).toString() + 'px;'"><i v-if="option.level != 0" class="material-icons align-middle text-lg ltr:mr-2 rtl:ml-2">subdirectory_arrow_right</i>{{ option.value }}</span>
|
||||
<span class="badge badge-pill badge-success float-right mt-2" v-if="new_options[option.key]">{{ addNew.new_text }}</span>
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
|
||||
<el-option v-if="!loading && addNew.status && options.length != 0 && sortOptions.length > 0" class="el-select__footer" disabled value="">
|
||||
<div @click="onAddItem">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>
|
||||
<el-option v-if="!loading && addNew.status && options.length != 0 && sortedOptions.length > 0" class="el-select__footer bg-purple" disabled value="">
|
||||
<div class="w-full flex items-center" @click="onAddItem">
|
||||
<span class="material-icons text-xl text-purple">add</span>
|
||||
<span class="flex-1 font-bold text-purple">
|
||||
{{ addNew.text }}
|
||||
</span>
|
||||
</div>
|
||||
@ -200,10 +200,10 @@
|
||||
|
||||
<component v-bind:is="add_new_html" @submit="onSubmit" @cancel="onCancel"></component>
|
||||
|
||||
<span slot="infoBlock" class="badge badge-success badge-resize float-right" v-if="new_options[selected]">{{ addNew.new_text }}</span>
|
||||
<span slot="infoBlock" class="absolute right-8 top-3 bg-green text-white px-2 py-1 rounded-md text-xs" v-if="new_options[selected]">{{ addNew.new_text }}</span>
|
||||
|
||||
<select :name="name" :id="name" v-model="selected" class="d-none">
|
||||
<option v-for="option in sortOptions" :key="option.key" :value="option.key">{{ option.value }}</option>
|
||||
<option v-for="option in sortedOptions" :key="option.key" :value="option.key">{{ option.value }}</option>
|
||||
</select>
|
||||
</span>
|
||||
</template>
|
||||
@ -216,7 +216,7 @@ import { Select, Option, OptionGroup, ColorPicker } from 'element-ui';
|
||||
import AkauntingModalAddNew from './AkauntingModalAddNew';
|
||||
import AkauntingModal from './AkauntingModal';
|
||||
import AkauntingMoney from './AkauntingMoney';
|
||||
import AkauntingRadioGroup from './forms/AkauntingRadioGroup';
|
||||
import AkauntingRadioGroup from './AkauntingRadioGroup';
|
||||
import AkauntingSelect from './AkauntingSelect';
|
||||
import AkauntingDate from './AkauntingDate';
|
||||
import AkauntingRecurring from './AkauntingRecurring';
|
||||
@ -300,6 +300,12 @@ export default {
|
||||
description: "Option Sortable type (key|value)"
|
||||
},
|
||||
|
||||
sortOptions: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
description: 'Sort options by the option_sortable prop, or sorting is made server-side',
|
||||
},
|
||||
|
||||
model: {
|
||||
type: [String, Number, Array, Object],
|
||||
default: '',
|
||||
@ -358,12 +364,6 @@ export default {
|
||||
description: "Selectbox collapse status"
|
||||
},
|
||||
|
||||
loadingText: {
|
||||
type: String,
|
||||
default: 'Loading...',
|
||||
description: "Selectbox loading message"
|
||||
},
|
||||
|
||||
noDataText: {
|
||||
type: String,
|
||||
default: 'No Data',
|
||||
@ -403,29 +403,33 @@ export default {
|
||||
selected: this.model,
|
||||
|
||||
form: {},
|
||||
sort_options: [],
|
||||
sorted_options: [],
|
||||
new_options: {},
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.setSortOptions();
|
||||
this.setSortedOptions();
|
||||
},
|
||||
|
||||
computed: {
|
||||
sortOptions() {
|
||||
if (this.group) {
|
||||
this.sort_options.sort(this.sortBy("key"));
|
||||
sortedOptions() {
|
||||
if (!this.sortOptions) {
|
||||
return this.sorted_options;
|
||||
}
|
||||
|
||||
for (const [index, options] of Object.entries(this.sort_options)) {
|
||||
if (this.group) {
|
||||
this.sorted_options.sort(this.sortBy("key"));
|
||||
|
||||
for (const [index, options] of Object.entries(this.sorted_options)) {
|
||||
options.value.sort(this.sortBy(this.option_sortable));
|
||||
}
|
||||
} else {
|
||||
this.sort_options.sort(this.sortBy(this.option_sortable));
|
||||
this.sorted_options.sort(this.sortBy(this.option_sortable));
|
||||
}
|
||||
|
||||
return this.sort_options;
|
||||
return this.sorted_options;
|
||||
},
|
||||
},
|
||||
|
||||
@ -476,9 +480,9 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
setSortOptions() {
|
||||
// Reset sort_options
|
||||
this.sort_options = [];
|
||||
setSortedOptions() {
|
||||
// Reset sorted_options
|
||||
this.sorted_options = [];
|
||||
|
||||
let created_options = (this.dynamicOptions) ? this.dynamicOptions : this.options;
|
||||
|
||||
@ -491,11 +495,12 @@ export default {
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
values.push({
|
||||
key: key,
|
||||
value: value
|
||||
value: value,
|
||||
level: 0
|
||||
});
|
||||
}
|
||||
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
key: index,
|
||||
value: values
|
||||
});
|
||||
@ -503,16 +508,18 @@ export default {
|
||||
} else {
|
||||
created_options.forEach(function (option, index) {
|
||||
if (typeof(option) == 'string') {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: index.toString(),
|
||||
value: option
|
||||
value: option,
|
||||
level: 0
|
||||
});
|
||||
} else {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: option.id,
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
|
||||
level: (option.level) ? option.level : 0
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
@ -521,24 +528,27 @@ export default {
|
||||
// Option set sort_option data
|
||||
if (!Array.isArray(created_options)) {
|
||||
for (const [key, value] of Object.entries(created_options)) {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
key: key,
|
||||
value: value
|
||||
value: value,
|
||||
level: 0
|
||||
});
|
||||
}
|
||||
} else {
|
||||
created_options.forEach(function (option, index) {
|
||||
if (typeof(option) == 'string') {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: index.toString(),
|
||||
value: option
|
||||
value: option,
|
||||
level: 0
|
||||
});
|
||||
} else {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: option.id,
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
|
||||
level: (option.level) ? option.level : 0
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
@ -558,7 +568,7 @@ export default {
|
||||
|
||||
// Option changed sort_option data
|
||||
if (this.group) {
|
||||
this.sort_options.forEach(function (option_group, group_index) {
|
||||
this.sorted_options.forEach(function (option_group, group_index) {
|
||||
option_group.value.forEach(function (option, index) {
|
||||
if (this.multiple) {
|
||||
let indexs = [];
|
||||
@ -590,7 +600,7 @@ export default {
|
||||
}, this);
|
||||
}, this);
|
||||
} else {
|
||||
this.sort_options.forEach(function (option, index) {
|
||||
this.sorted_options.forEach(function (option, index) {
|
||||
if (this.multiple) {
|
||||
let indexs = [];
|
||||
let values = [];
|
||||
@ -680,12 +690,12 @@ export default {
|
||||
|
||||
if (response.data.data) {
|
||||
let data = response.data.data;
|
||||
//this.sort_options = [];
|
||||
//this.sorted_options = [];
|
||||
|
||||
data.forEach(function (option) {
|
||||
let check = false;
|
||||
|
||||
this.sort_options.forEach(function (sort_option) {
|
||||
this.sorted_options.forEach(function (sort_option) {
|
||||
if (sort_option.key == option.id) {
|
||||
check = true;
|
||||
return;
|
||||
@ -693,7 +703,7 @@ export default {
|
||||
});
|
||||
|
||||
if (!check) {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
});
|
||||
@ -701,12 +711,12 @@ export default {
|
||||
|
||||
}, this);
|
||||
|
||||
this.sort_options = this.sort_options.filter(item => {
|
||||
this.sorted_options = this.sorted_options.filter(item => {
|
||||
return item.value.toLowerCase()
|
||||
.indexOf(query.toLowerCase()) > -1;
|
||||
});
|
||||
} else {
|
||||
this.sortOptions = [];
|
||||
this.sortedOptions = [];
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
@ -715,7 +725,7 @@ export default {
|
||||
// always executed
|
||||
});
|
||||
} else {
|
||||
this.setSortOptions();
|
||||
this.setSortedOptions();
|
||||
}
|
||||
},
|
||||
|
||||
@ -776,7 +786,7 @@ export default {
|
||||
},
|
||||
|
||||
onModal(value) {
|
||||
this.setSortOptions();
|
||||
this.setSortedOptions();
|
||||
|
||||
let add_new = this.add_new;
|
||||
|
||||
@ -874,7 +884,7 @@ export default {
|
||||
this.form.loading = false;
|
||||
|
||||
if (response.data.success) {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
key: response.data.data[this.add_new.field.key].toString(),
|
||||
value: response.data.data[this.add_new.field.value],
|
||||
});
|
||||
@ -898,7 +908,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
@ -917,7 +927,7 @@ export default {
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
},
|
||||
|
||||
addModal() {
|
||||
@ -1003,7 +1013,7 @@ export default {
|
||||
},
|
||||
|
||||
dynamicOptions: function(options) {
|
||||
this.sort_options = [];
|
||||
this.sorted_options = [];
|
||||
this.selected = [];
|
||||
|
||||
if (this.group) {
|
||||
@ -1015,11 +1025,12 @@ export default {
|
||||
for (const [key, value] of Object.entries(_options)) {
|
||||
values.push({
|
||||
key: key,
|
||||
value: value
|
||||
value: value,
|
||||
level: 0
|
||||
});
|
||||
}
|
||||
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
key: index,
|
||||
value: values
|
||||
});
|
||||
@ -1027,16 +1038,18 @@ export default {
|
||||
} else {
|
||||
options.forEach(function (option, index) {
|
||||
if (typeof(option) == 'string') {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: index.toString(),
|
||||
value: option
|
||||
value: option,
|
||||
level: 0
|
||||
});
|
||||
} else {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: option.id,
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
|
||||
level: (option.level) ? option.level : 0
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
@ -1045,24 +1058,27 @@ export default {
|
||||
// Option set sort_option data
|
||||
if (!Array.isArray(options)) {
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
key: key,
|
||||
value: value
|
||||
value: value,
|
||||
level: 0
|
||||
});
|
||||
}
|
||||
} else {
|
||||
options.forEach(function (option, index) {
|
||||
if (typeof(option) == 'string') {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: index.toString(),
|
||||
value: option
|
||||
value: option,
|
||||
level: 0
|
||||
});
|
||||
} else {
|
||||
this.sort_options.push({
|
||||
this.sorted_options.push({
|
||||
index: index,
|
||||
key: option.id,
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name
|
||||
key: option.id.toString(),
|
||||
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
|
||||
level: (option.level) ? option.level : 0
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
@ -1072,57 +1088,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-group .modal {
|
||||
z-index: 3050;
|
||||
}
|
||||
|
||||
.el-select-dropdown__empty {
|
||||
padding: 10px 0 0 !important;
|
||||
}
|
||||
|
||||
.el-select-dropdown__empty.loading {
|
||||
padding: 10px 0 !important;
|
||||
}
|
||||
|
||||
.el-select__footer {
|
||||
text-align: center !important;
|
||||
border-top: 1px solid #dee2e6 !important;
|
||||
padding: 0px !important;
|
||||
cursor: pointer !important;
|
||||
color: #3c3f72 !important;
|
||||
font-weight: bold !important;
|
||||
height: 38px !important;
|
||||
line-height: 38px !important;
|
||||
margin-top: 5px !important;
|
||||
margin-bottom: -6px !important;
|
||||
border-bottom-left-radius: 4px !important;
|
||||
border-bottom-right-radius: 4px !important;
|
||||
}
|
||||
|
||||
.el-select__footer.el-select-dropdown__item.hover {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
||||
.el-select__footer.el-select-dropdown__item:hover, .el-select__footer.el-select-dropdown__item:focus {
|
||||
background-color: #3c3f72 !important;
|
||||
color: white !important;
|
||||
border-top-color: #3c3f72;
|
||||
}
|
||||
|
||||
.el-select__footer div span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.badge-resize {
|
||||
float: right;
|
||||
margin-top: -32px;
|
||||
margin-right: 35px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.badge.badge-pill.badge-success {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
</style>
|
||||
|
125
resources/assets/js/components/AkauntingSlider.vue
Normal file
125
resources/assets/js/components/AkauntingSlider.vue
Normal file
@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div v-if="video || screenshots">
|
||||
<div class="swiper-carousel overflow-hidden">
|
||||
<div class="swiper-wrapper" style="flex-wrap: nowrap !important;">
|
||||
<div class="swiper-slide" v-for="(screenshot, index) in screenshots" :key="index">
|
||||
<a :href="screenshot.path_string" class="glightbox">
|
||||
<img class="rounded-lg object-cover cursor-pointer" :src="screenshot.path_string" :alt="screenshot.alt_attribute" />
|
||||
<div class="text-gray-700 text-sm my-2">{{ screenshot.description }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="pagination" class="swiper-pagination w-full flex justify-center gap-1"></div>
|
||||
|
||||
<div v-if="arrow" class="swiper-button-next ltr:-right-8 rtl:-left-8 top-12">
|
||||
<span class="material-icons text-5xl">chevron_right</span>
|
||||
</div>
|
||||
|
||||
<div v-if="arrow" class="swiper-button-prev ltr:-left-8 rtl:-right-8 top-12">
|
||||
<span class="material-icons text-5xl">chevron_left</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Swiper, { Navigation, Pagination } from 'swiper';
|
||||
Swiper.use([Navigation, Pagination]);
|
||||
|
||||
import GLightbox from 'glightbox';
|
||||
import 'glightbox/dist/css/glightbox.min.css';
|
||||
|
||||
export default {
|
||||
name: "akaunting-slider",
|
||||
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
default: null,
|
||||
description: "App Name"
|
||||
},
|
||||
video: {
|
||||
type: String,
|
||||
default: null,
|
||||
description: "App Video"
|
||||
},
|
||||
screenshots: {
|
||||
type: Array,
|
||||
default: false,
|
||||
description: "App Screenshots"
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: null,
|
||||
description: "height of the carousel"
|
||||
},
|
||||
arrow: {
|
||||
type: [Boolean, String],
|
||||
default: false,
|
||||
},
|
||||
pagination: {
|
||||
type: [Boolean, String],
|
||||
default: false,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "type of the Carousel (card)"
|
||||
},
|
||||
sliderView: {
|
||||
type: [Number, String],
|
||||
default: 4,
|
||||
},
|
||||
sliderRow: {
|
||||
type: [Number, String],
|
||||
default: 2,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let media = [];
|
||||
if (this.screenshots.length) {
|
||||
this.screenshots.forEach(function(screenshot) {
|
||||
media.push({ // For image
|
||||
thumb: screenshot.path_string,
|
||||
src: screenshot.path_string,
|
||||
});
|
||||
});
|
||||
}
|
||||
this.media = media;
|
||||
new Swiper(".swiper-carousel", {
|
||||
loop: false,
|
||||
grid: {
|
||||
rows: this.sliderRow,
|
||||
},
|
||||
spaceBetween: 30,
|
||||
breakpoints: {
|
||||
640: {
|
||||
slidesPerView: 1
|
||||
},
|
||||
768: {
|
||||
slidesPerView: this.sliderView,
|
||||
}
|
||||
},
|
||||
pagination: {
|
||||
el: ".swiper-pagination",
|
||||
clickable: true
|
||||
},
|
||||
navigation: {
|
||||
nextEl: ".swiper-button-next",
|
||||
prevEl: ".swiper-button-prev",
|
||||
},
|
||||
});
|
||||
GLightbox({
|
||||
touchNavigation: true,
|
||||
loop: false,
|
||||
autoplayVideos: false,
|
||||
selector: ".glightbox"
|
||||
});
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
media: [],
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
68
resources/assets/js/components/AkauntingSwitch.vue
Normal file
68
resources/assets/js/components/AkauntingSwitch.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="lg:absolute w-12 hidden lg:flex items-center lg:ltr:right-0 lg:rtl:left-0 xl:-top-12 cursor-pointer">
|
||||
<input type="radio" :name="name" v-show="selected == '0'" @click="enabled = 1" value="1" id="enabled-1" v-model="selected" class="w-full h-full absolute right-0 z-20 opacity-0 cursor-pointer">
|
||||
<input type="radio" :name="name" v-show="selected == '1'" @click="enabled = 0" value="0" id="enabled-0" v-model="selected" class="w-full h-full absolute left-0 z-20 opacity-0 cursor-pointer">
|
||||
|
||||
<div class="absolute left-1 top-1 bg-white w-5 h-5 rounded-full transition transform" :class="selected == '1' ? 'translate-x-full' : 'translate-x-0'"></div>
|
||||
<div class="block w-full h-7 rounded-full transition transition-color" :class="selected == '1' ? 'bg-green' : 'bg-green-200'"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-switch',
|
||||
|
||||
props: {
|
||||
name: null,
|
||||
|
||||
value: {
|
||||
type: [String, Number, Array, Object, Boolean],
|
||||
default: '1',
|
||||
description: "Selectbox selected value"
|
||||
},
|
||||
|
||||
model: {
|
||||
type: [String, Number, Array, Object, Boolean],
|
||||
default: '',
|
||||
description: "Selectbox selected model"
|
||||
},
|
||||
|
||||
inputData: {
|
||||
type: [String, Number, Array, Object, Boolean],
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
enabled: 1,
|
||||
selected: this.value,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
change() {
|
||||
this.$emit('interface', this.selected);
|
||||
|
||||
this.$emit('change', this.selected);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$emit('interface', this.selected);
|
||||
|
||||
setTimeout(function() {
|
||||
this.change();
|
||||
}.bind(this), 800);
|
||||
},
|
||||
|
||||
watch: {
|
||||
value: function(val) {
|
||||
this.selected = val;
|
||||
},
|
||||
|
||||
selected: function(val) {
|
||||
this.change();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
@ -5,15 +5,14 @@
|
||||
@cancel="onCancel"
|
||||
v-if="display">
|
||||
<template #modal-body>
|
||||
<div class="modal-body text-left">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="py-1 px-5 bg-body">
|
||||
<div class="grid sm:grid-cols-6 gap-x-8 gap-y-6 my-3.5">
|
||||
<div class="form-group sm:col-span-3">
|
||||
<base-input
|
||||
required
|
||||
class="required"
|
||||
v-model="form.name"
|
||||
:label="text.name"
|
||||
prepend-icon="fas fa-font"
|
||||
:placeholder="placeholder.name"
|
||||
:error="form.errors.name[0]"
|
||||
@input="form.errors.name[0] = ''"
|
||||
@ -21,59 +20,44 @@
|
||||
</base-input>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="form-group sm:col-span-3">
|
||||
<base-input
|
||||
required
|
||||
class="required"
|
||||
:error="form.errors.class[0]"
|
||||
:label="text.type">
|
||||
<span class="el-input__prefix">
|
||||
<span class="el-input__suffix-inner el-select-icon">
|
||||
<i class="select-icon-position el-input__icon fa fa-bars"></i>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<el-select
|
||||
class="select-primary"
|
||||
@change="form.errors.class[0] = ''"
|
||||
v-model="form.class" filterable
|
||||
:placeholder="placeholder.type">
|
||||
<el-option v-for="(name, value) in types"
|
||||
class="select-primary"
|
||||
:key="name"
|
||||
:label="name"
|
||||
:value="value">
|
||||
:key="name"
|
||||
:label="name"
|
||||
:value="value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</base-input>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<base-input
|
||||
:label="text.width">
|
||||
<span class="el-input__prefix">
|
||||
<span class="el-input__suffix-inner el-select-icon">
|
||||
<i class="select-icon-position el-input__icon fas fa-ruler-horizontal"></i>
|
||||
</span>
|
||||
</span>
|
||||
<div class="form-group sm:col-span-3">
|
||||
<base-input :label="text.width">
|
||||
<el-select
|
||||
class="select-primary"
|
||||
v-model="form.width" filterable
|
||||
:placeholder="placeholder.width">
|
||||
<el-option v-for="option in widthOptions"
|
||||
class="select-primary"
|
||||
:key="option.label"
|
||||
:label="option.label"
|
||||
:value="option.value">
|
||||
:key="option.label"
|
||||
:label="option.label"
|
||||
:value="option.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</base-input>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="form-group sm:col-span-3">
|
||||
<base-input
|
||||
v-model="form.sort"
|
||||
:label="text.sort"
|
||||
prepend-icon="fas fa-sort"
|
||||
:placeholder="placeholder.sort"
|
||||
:error="form.errors.sort[0]"
|
||||
@input="form.errors.sort[0] = ''"
|
||||
@ -84,33 +68,20 @@
|
||||
</template>
|
||||
|
||||
<template #card-footer>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="float-right">
|
||||
<button type="button" class="btn btn-icon btn-outline-secondary" @click="onCancel">
|
||||
{{ text.cancel }}
|
||||
</button>
|
||||
<div class="flex items-center justify-end">
|
||||
<button type="button" class="flex items-center justify-center px-6 py-1.5 text-base rounded-lg mr-2 bg-transparent hover:bg-gray-300 disabled:bg-gray-200" @click="onCancel">
|
||||
{{ text.cancel }}
|
||||
</button>
|
||||
|
||||
<button :disabled="form.loading" type="button" class="btn btn-icon btn-success button-submit" @click="onSave">
|
||||
<span v-if="form.loading" class="btn-inner--icon"><i class="aka-loader"></i></span>
|
||||
<span :class="[{'ml-0': form.loading}]" class="btn-inner--text">{{ text.save }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button :disabled="form.loading" type="button" class="relative flex items-center justify-center bg-green hover:bg-green-700 text-white px-6 py-1.5 text-base rounded-lg disabled:bg-green-100" @click="onSave">
|
||||
<i v-if="form.loading" class="animate-submit delay-[0.28s] absolute w-2 h-2 rounded-full left-0 right-0 -top-3.5 m-auto before:absolute before:w-2 before:h-2 before:rounded-full before:animate-submit before:delay-[0.14s] after:absolute after:w-2 after:h-2 after:rounded-full after:animate-submit before:-left-3.5 after:-right-3.5 after:delay-[0.42s]"></i>
|
||||
<span :class="[{'opacity-0': form.loading}]">{{ text.save }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</akaunting-modal>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.el-input__prefix
|
||||
{
|
||||
left: 20px;
|
||||
z-index: 999;
|
||||
top: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import { Select, Option } from 'element-ui';
|
||||
@ -197,19 +168,19 @@ export default {
|
||||
widthOptions: [
|
||||
{
|
||||
label: '25%',
|
||||
value: 'col-md-3'
|
||||
value: 'w-full lg:w-1/4 px-6'
|
||||
},
|
||||
{
|
||||
label: '33%',
|
||||
value: 'col-md-4'
|
||||
value: 'w-full lg:w-1/3 px-6'
|
||||
},
|
||||
{
|
||||
label: '50%',
|
||||
value: 'col-md-6'
|
||||
value: 'w-full lg:w-2/4 px-12'
|
||||
},
|
||||
{
|
||||
label: '100%',
|
||||
value: 'col-md-12'
|
||||
value: 'w-full px-12'
|
||||
}
|
||||
],
|
||||
form: {
|
||||
@ -282,7 +253,7 @@ export default {
|
||||
onCancel() {
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
|
||||
this.display = false;
|
||||
this.form.name = '';
|
||||
@ -301,9 +272,9 @@ export default {
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
if (val) {
|
||||
documentClasses.add("modal-open");
|
||||
documentClasses.add("overflow-hidden");
|
||||
} else {
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,4 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
||||
</script>
|
@ -68,14 +68,4 @@ export default {
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
i {
|
||||
padding: 0 3px;
|
||||
}
|
||||
</style>
|
||||
</script>
|
@ -1,100 +0,0 @@
|
||||
<template>
|
||||
<component
|
||||
:is="tag"
|
||||
:class="[{ show: isOpen }, `drop${direction}`]"
|
||||
@click="toggleDropDown"
|
||||
v-click-outside="closeDropDown"
|
||||
>
|
||||
<slot name="title-container" :is-open="isOpen">
|
||||
<component
|
||||
:is="titleTag"
|
||||
class="btn-rotate"
|
||||
:class="[{'dropdown-toggle': hasToggle}, titleClasses]"
|
||||
:aria-expanded="isOpen"
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<slot name="title" :is-open="isOpen">
|
||||
<i :class="icon"></i> {{ title }}
|
||||
</slot>
|
||||
</component>
|
||||
</slot>
|
||||
<ul
|
||||
class="dropdown-menu"
|
||||
:class="[
|
||||
{ show: isOpen },
|
||||
{ 'dropdown-menu-right': menuOnRight },
|
||||
menuClasses
|
||||
]"
|
||||
>
|
||||
<slot></slot>
|
||||
</ul>
|
||||
</component>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-dropdown',
|
||||
props: {
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'div',
|
||||
description: 'Dropdown html tag (e.g div, ul etc)'
|
||||
},
|
||||
titleTag: {
|
||||
type: String,
|
||||
default: 'button',
|
||||
description: 'Dropdown title (toggle) html tag'
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
description: 'Dropdown title'
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'down', // up | down
|
||||
description: 'Dropdown menu direction (up|down)'
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
description: 'Dropdown icon'
|
||||
},
|
||||
titleClasses: {
|
||||
type: [String, Object, Array],
|
||||
description: 'Title css classes'
|
||||
},
|
||||
menuClasses: {
|
||||
type: [String, Object],
|
||||
description: 'Menu css classes'
|
||||
},
|
||||
menuOnRight: {
|
||||
type: Boolean,
|
||||
description: 'Whether menu should appear on the right'
|
||||
},
|
||||
hasToggle: {
|
||||
type: Boolean,
|
||||
description: 'Whether dropdown has arrow icon shown',
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpen: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toggleDropDown() {
|
||||
this.isOpen = !this.isOpen;
|
||||
this.$emit('change', this.isOpen);
|
||||
},
|
||||
closeDropDown() {
|
||||
this.isOpen = false;
|
||||
this.$emit('change', false);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dropdown {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
@ -1,23 +0,0 @@
|
||||
<template>
|
||||
<div class="header" :class="{[`bg-${type}`]: type}">
|
||||
<div class="container-fluid">
|
||||
<div class="header-body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-header',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'success',
|
||||
description: 'Header background type'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
@ -1,134 +0,0 @@
|
||||
<template>
|
||||
<ul class="pagination" :class="[size && `pagination-${size}`, align && `justify-content-${align}`]">
|
||||
<li class="page-item prev-page" :class="{disabled: value === 1}">
|
||||
<a class="page-link" aria-label="Previous" @click="prevPage">
|
||||
<span aria-hidden="true"><i class="fa fa-angle-left" aria-hidden="true"></i></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item" :class="{active: value === item}"
|
||||
:key="item"
|
||||
v-for="item in range(minPage, maxPage)">
|
||||
<a class="page-link" @click="changePage(item)">{{item}}</a>
|
||||
</li>
|
||||
<li class="page-item next-page" :class="{disabled: value === totalPages}">
|
||||
<a class="page-link" aria-label="Next" @click="nextPage">
|
||||
<span aria-hidden="true"><i class="fa fa-angle-right" aria-hidden="true"></i></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "base-pagination",
|
||||
props: {
|
||||
pageCount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
description:
|
||||
"Pagination page count. This should be specified in combination with perPage"
|
||||
},
|
||||
perPage: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
description:
|
||||
"Pagination per page. Should be specified with total or pageCount"
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
description:
|
||||
"Can be specified instead of pageCount. The page count in this case will be total/perPage"
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
description: "Pagination value"
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: "",
|
||||
description: "Pagination size"
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: "",
|
||||
description: "Pagination alignment (e.g center|start|end)"
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalPages() {
|
||||
if (this.pageCount > 0) return this.pageCount;
|
||||
if (this.total > 0) {
|
||||
return Math.ceil(this.total / this.perPage);
|
||||
}
|
||||
return 1;
|
||||
},
|
||||
pagesToDisplay() {
|
||||
if (this.totalPages > 0 && this.totalPages < this.defaultPagesToDisplay) {
|
||||
return this.totalPages;
|
||||
}
|
||||
return this.defaultPagesToDisplay;
|
||||
},
|
||||
minPage() {
|
||||
if (this.value >= this.pagesToDisplay) {
|
||||
const pagesToAdd = Math.floor(this.pagesToDisplay / 2);
|
||||
const newMaxPage = pagesToAdd + this.value;
|
||||
if (newMaxPage > this.totalPages) {
|
||||
return this.totalPages - this.pagesToDisplay + 1;
|
||||
}
|
||||
return this.value - pagesToAdd;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
maxPage() {
|
||||
if (this.value >= this.pagesToDisplay) {
|
||||
const pagesToAdd = Math.floor(this.pagesToDisplay / 2);
|
||||
const newMaxPage = pagesToAdd + this.value;
|
||||
if (newMaxPage < this.totalPages) {
|
||||
return newMaxPage;
|
||||
} else {
|
||||
return this.totalPages;
|
||||
}
|
||||
} else {
|
||||
return this.pagesToDisplay;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultPagesToDisplay: 5
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
range(min, max) {
|
||||
let arr = [];
|
||||
for (let i = min; i <= max; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
changePage(item) {
|
||||
this.$emit("input", item);
|
||||
},
|
||||
nextPage() {
|
||||
if (this.value < this.totalPages) {
|
||||
this.$emit("input", this.value + 1);
|
||||
}
|
||||
},
|
||||
prevPage() {
|
||||
if (this.value > 1) {
|
||||
this.$emit("input", this.value - 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
perPage() {
|
||||
this.$emit("input", 1);
|
||||
},
|
||||
total() {
|
||||
this.$emit("input", 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,90 +0,0 @@
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<div :class="`progress-${type}`" v-if="showLabel">
|
||||
<div class="progress-label">
|
||||
<slot name="label">
|
||||
<span>{{label}}</span>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="progress-percentage">
|
||||
<slot>
|
||||
<span>{{value}}%</span>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress"
|
||||
:class="[{[`progress-${size}`]: size}, progressClasses]"
|
||||
:style="`height: ${height}px`">
|
||||
<div class="progress-bar"
|
||||
:class="computedClasses"
|
||||
role="progressbar"
|
||||
:aria-valuenow="value"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
:style="`width: ${value}%;`">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "base-progress",
|
||||
props: {
|
||||
striped: {
|
||||
type: Boolean,
|
||||
description: "Whether progress is striped"
|
||||
},
|
||||
animated: {
|
||||
type: Boolean,
|
||||
description:
|
||||
"Whether progress is animated (works only with `striped` prop together)"
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
description: "Progress label (shown on the left above progress)"
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 3,
|
||||
description: "Progress line height"
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: "default",
|
||||
description: "Progress type (e.g danger, primary etc)"
|
||||
},
|
||||
showLabel: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
progressClasses: {
|
||||
type: [Array, String],
|
||||
default: '',
|
||||
description: 'Progress css classes'
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
validator: value => {
|
||||
return value >= 0 && value <= 100;
|
||||
},
|
||||
description: "Progress value"
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
computedClasses() {
|
||||
return [
|
||||
{ "progress-bar-striped": this.striped },
|
||||
{ "progress-bar-animated": this.animated },
|
||||
{ [`bg-${this.type}`]: this.type }
|
||||
];
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
@ -1,96 +0,0 @@
|
||||
<template>
|
||||
<div class="slider" :disabled="disabled"></div>
|
||||
</template>
|
||||
<script>
|
||||
import noUiSlider from 'nouislider';
|
||||
|
||||
export default {
|
||||
name: 'base-slider',
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Array, Number],
|
||||
description: 'slider value'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'whether the slider is disabled'
|
||||
},
|
||||
start: {
|
||||
type: [Number, Array],
|
||||
default: 0,
|
||||
description:
|
||||
'[noUi Slider start](https://refreshless.com/nouislider/slider-options/#section-start)'
|
||||
},
|
||||
connect: {
|
||||
type: [Boolean, Array],
|
||||
default: () => [true, false],
|
||||
description:
|
||||
'[noUi Slider connect](https://refreshless.com/nouislider/slider-options/#section-connect)'
|
||||
},
|
||||
range: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
min: 0,
|
||||
max: 100
|
||||
};
|
||||
},
|
||||
description:
|
||||
'[noUi Slider range](https://refreshless.com/nouislider/slider-values/#section-range)'
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
description:
|
||||
'[noUi Slider options](https://refreshless.com/nouislider/slider-options/)'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
slider: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
createSlider() {
|
||||
noUiSlider.create(this.$el, {
|
||||
start: this.value || this.start,
|
||||
connect: Array.isArray(this.value) ? true : this.connect,
|
||||
range: this.range,
|
||||
...this.options
|
||||
});
|
||||
const slider = this.$el.noUiSlider;
|
||||
slider.on('slide', () => {
|
||||
let value = slider.get();
|
||||
if (value !== this.value) {
|
||||
this.$emit('input', value);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.createSlider();
|
||||
},
|
||||
watch: {
|
||||
value(newValue, oldValue) {
|
||||
const slider = this.$el.noUiSlider;
|
||||
const sliderValue = slider.get();
|
||||
if (newValue !== oldValue && sliderValue !== newValue) {
|
||||
if (Array.isArray(sliderValue) && Array.isArray(newValue)) {
|
||||
if (
|
||||
oldValue.length === newValue.length &&
|
||||
oldValue.every((v, i) => v === newValue[i])
|
||||
) {
|
||||
slider.set(newValue);
|
||||
}
|
||||
} else {
|
||||
slider.set(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<label class="custom-toggle" :class="switchClass">
|
||||
<input type="checkbox" v-model="model">
|
||||
<span class="custom-toggle-slider rounded-circle"
|
||||
:data-label-off="offText"
|
||||
:data-label-on="onText">
|
||||
</span>
|
||||
</label>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-switch',
|
||||
props: {
|
||||
value: [Array, Boolean],
|
||||
type: String,
|
||||
onText: {
|
||||
type: String,
|
||||
default: 'Yes'
|
||||
},
|
||||
offText: {
|
||||
type: String,
|
||||
default: 'No'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
switchClass() {
|
||||
let baseClass = 'custom-toggle-';
|
||||
if (this.type) {
|
||||
return baseClass + this.type
|
||||
}
|
||||
return ''
|
||||
},
|
||||
model: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
triggerToggle() {
|
||||
this.model = !this.model;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,70 +0,0 @@
|
||||
<template>
|
||||
<table class="table tablesorter" :class="tableClass">
|
||||
<thead :class="theadClasses">
|
||||
<tr>
|
||||
<slot name="columns" :columns="columns">
|
||||
<th v-for="column in columns" :key="column">{{ column }}</th>
|
||||
</slot>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody :class="tbodyClasses">
|
||||
<tr v-for="(item, index) in data" :key="index">
|
||||
<slot :row="item" :index="index">
|
||||
<td
|
||||
v-for="(column, index) in columns"
|
||||
:key="index"
|
||||
v-if="hasValue(item, column)"
|
||||
>
|
||||
{{ itemValue(item, column) }}
|
||||
</td>
|
||||
</slot>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-table',
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
description: 'Table columns'
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
description: 'Table data'
|
||||
},
|
||||
type: {
|
||||
type: String, // striped | hover
|
||||
default: '',
|
||||
description: 'Whether table is striped or hover type'
|
||||
},
|
||||
theadClasses: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: '<thead> css classes'
|
||||
},
|
||||
tbodyClasses: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: '<tbody> css classes'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tableClass() {
|
||||
return this.type && `table-${this.type}`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hasValue(item, column) {
|
||||
return item[column.toLowerCase()] !== 'undefined';
|
||||
},
|
||||
itemValue(item, column) {
|
||||
return item[column.toLowerCase()];
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb"
|
||||
:class="[{[`bg-${type}`]: type}, listClasses]">
|
||||
<slot></slot>
|
||||
</ol>
|
||||
</nav>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'breadcrumb',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Breadcrumb background type'
|
||||
},
|
||||
listClasses: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
description: 'Breadcrumb list classes'
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,16 +0,0 @@
|
||||
<template>
|
||||
<li class="breadcrumb-item" :class="{ active: active }"><slot></slot></li>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'breadcrumb-item',
|
||||
props: {
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether breadcrumb item is active'
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<bread-crumb list-classes="breadcrumb-links breadcrumb-dark">
|
||||
<BreadCrumbItem>
|
||||
<li class="breadcrumb-item">
|
||||
<router-link to="/">
|
||||
<i class="fas fa-home"></i>
|
||||
</router-link>
|
||||
</li>
|
||||
</BreadCrumbItem>
|
||||
<BreadCrumbItem
|
||||
v-for="(route, index) in $route.matched.slice()"
|
||||
:key="route.name"
|
||||
:active="index === $route.matched.length - 1"
|
||||
style="display:inline-block"
|
||||
>
|
||||
<router-link
|
||||
:to="{ name: route.name }"
|
||||
v-if="index < $route.matched.length - 1"
|
||||
>
|
||||
{{ route.name }}
|
||||
</router-link>
|
||||
<span v-else>{{ route.name }}</span>
|
||||
</BreadCrumbItem>
|
||||
</bread-crumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BreadCrumb from './Breadcrumb';
|
||||
import BreadCrumbItem from './BreadcrumbItem';
|
||||
|
||||
export default {
|
||||
name: 'route-breadcrumb',
|
||||
components: {
|
||||
BreadCrumb,
|
||||
BreadCrumbItem
|
||||
},
|
||||
methods: {
|
||||
getBreadName(route) {
|
||||
return route.name;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -1,39 +0,0 @@
|
||||
<template>
|
||||
<div class="btn-group-toggle" data-toggle="buttons">
|
||||
<label class="btn" :class="[{ active: value }, buttonClasses]">
|
||||
<input v-model="model" type="checkbox" checked="" autocomplete="off">
|
||||
<slot></slot>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'button-checkbox',
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
description: 'Checked value'
|
||||
},
|
||||
buttonClasses: {
|
||||
type: [String, Object],
|
||||
description: 'Inner button css classes'
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('change', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
@ -1,47 +0,0 @@
|
||||
<template>
|
||||
<div class="btn-group-toggle" data-toggle="buttons">
|
||||
<label v-for="(option, index) in options"
|
||||
:key="index"
|
||||
class="btn"
|
||||
:class="[{ active: value === option.value }, buttonClasses]">
|
||||
<input :value="option.value" v-model="model" type="radio" id="option1" autocomplete="off" checked="">
|
||||
{{option.label}}
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'button-radio-group',
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
description: 'Radio options. Should be an array of objects {value: "", label: ""}',
|
||||
default: () => []
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
description: 'Radio value'
|
||||
},
|
||||
buttonClasses: {
|
||||
type: [String, Object],
|
||||
description: 'Inner button css classes'
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('change', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
@ -68,5 +68,3 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
||||
|
@ -45,5 +45,4 @@
|
||||
iconClasses: [String, Array]
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
||||
</script>
|
@ -1,30 +0,0 @@
|
||||
import { Bar, mixins } from 'vue-chartjs';
|
||||
import globalOptionsMixin from "@/components/Charts/globalOptionsMixin";
|
||||
|
||||
export default {
|
||||
name: 'bar-chart',
|
||||
extends: Bar,
|
||||
mixins: [mixins.reactiveProp, globalOptionsMixin],
|
||||
props: {
|
||||
extraOptions: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ctx: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$watch(
|
||||
'chartData',
|
||||
(newVal, oldVal) => {
|
||||
if (!oldVal) {
|
||||
this.renderChart(this.chartData, this.extraOptions);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
}
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
import { Doughnut, mixins } from 'vue-chartjs';
|
||||
import globalOptionsMixin from "./../../components/Charts/globalOptionsMixin";
|
||||
|
||||
export default {
|
||||
name: 'doughnut-chart',
|
||||
extends: Doughnut,
|
||||
mixins: [mixins.reactiveProp, globalOptionsMixin],
|
||||
props: {
|
||||
extraOptions: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ctx: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$watch(
|
||||
'chartData',
|
||||
(newVal, oldVal) => {
|
||||
if (!oldVal) {
|
||||
this.renderChart(this.chartData, this.extraOptions);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
}
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
import { Line, mixins } from 'vue-chartjs';
|
||||
import globalOptionsMixin from "./../../components/Charts/globalOptionsMixin";
|
||||
|
||||
export default {
|
||||
name: 'line-chart',
|
||||
extends: Line,
|
||||
mixins: [mixins.reactiveProp, globalOptionsMixin],
|
||||
props: {
|
||||
extraOptions: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ctx: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$watch(
|
||||
'chartData',
|
||||
(newVal, oldVal) => {
|
||||
if (!oldVal) {
|
||||
this.renderChart(this.chartData, this.extraOptions);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
}
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
import { Pie, mixins } from 'vue-chartjs';
|
||||
import globalOptionsMixin from "@/components/Charts/globalOptionsMixin";
|
||||
|
||||
export default {
|
||||
name: 'pie-chart',
|
||||
extends: Pie,
|
||||
mixins: [mixins.reactiveProp, globalOptionsMixin],
|
||||
props: {
|
||||
extraOptions: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ctx: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$watch(
|
||||
'chartData',
|
||||
(newVal, oldVal) => {
|
||||
if (!oldVal) {
|
||||
this.renderChart(this.chartData, this.extraOptions);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
}
|
||||
};
|
493
resources/assets/js/components/Charts/config.js
vendored
493
resources/assets/js/components/Charts/config.js
vendored
@ -1,493 +0,0 @@
|
||||
import { parseOptions } from "./../../components/Charts/optionHelpers";
|
||||
|
||||
export const Charts = {
|
||||
mode: 'light',//(themeMode) ? themeMode : 'light';
|
||||
fonts: {
|
||||
base: 'Open Sans'
|
||||
},
|
||||
colors: {
|
||||
gray: {
|
||||
100: '#f6f9fc',
|
||||
200: '#e9ecef',
|
||||
300: '#dee2e6',
|
||||
400: '#ced4da',
|
||||
500: '#adb5bd',
|
||||
600: '#8898aa',
|
||||
700: '#525f7f',
|
||||
800: '#32325d',
|
||||
900: '#212529'
|
||||
},
|
||||
theme: {
|
||||
'default': '#172b4d',
|
||||
'primary': '#5e72e4',
|
||||
'secondary': '#f4f5f7',
|
||||
'info': '#11cdef',
|
||||
'success': '#2dce89',
|
||||
'danger': '#f5365c',
|
||||
'warning': '#fb6340'
|
||||
},
|
||||
black: '#12263F',
|
||||
white: '#FFFFFF',
|
||||
transparent: 'transparent',
|
||||
}
|
||||
};
|
||||
|
||||
function chartOptions(Chart) {
|
||||
let { colors, mode, fonts } = Charts;
|
||||
// Options
|
||||
let options = {
|
||||
defaults: {
|
||||
global: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
defaultColor: (mode == 'dark') ? colors.gray[700] : colors.gray[600],
|
||||
defaultFontColor: (mode == 'dark') ? colors.gray[700] : colors.gray[600],
|
||||
defaultFontFamily: fonts.base,
|
||||
defaultFontSize: 13,
|
||||
layout: {
|
||||
padding: 0
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
padding: 16
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
point: {
|
||||
radius: 0,
|
||||
backgroundColor: colors.theme['primary']
|
||||
},
|
||||
line: {
|
||||
tension: .4,
|
||||
borderWidth: 4,
|
||||
borderColor: colors.theme['primary'],
|
||||
backgroundColor: colors.transparent,
|
||||
borderCapStyle: 'rounded'
|
||||
},
|
||||
rectangle: {
|
||||
backgroundColor: colors.theme['warning']
|
||||
},
|
||||
arc: {
|
||||
backgroundColor: colors.theme['primary'],
|
||||
borderColor: (mode == 'dark') ? colors.gray[800] : colors.white,
|
||||
borderWidth: 4
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
}
|
||||
},
|
||||
doughnut: {
|
||||
cutoutPercentage: 83,
|
||||
legendCallback: function (chart) {
|
||||
let data = chart.data;
|
||||
let content = '';
|
||||
|
||||
data.labels.forEach(function (label, index) {
|
||||
let bgColor = data.datasets[0].backgroundColor[index];
|
||||
|
||||
content += '<span class="chart-legend-item">';
|
||||
content += '<i class="chart-legend-indicator" style="background-color: ' + bgColor + '"></i>';
|
||||
content += label;
|
||||
content += '</span>';
|
||||
});
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// yAxes
|
||||
Chart.scaleService.updateScaleDefaults('linear', {
|
||||
gridLines: {
|
||||
borderDash: [2],
|
||||
borderDashOffset: [2],
|
||||
color: (mode == 'dark') ? colors.gray[900] : colors.gray[300],
|
||||
drawBorder: false,
|
||||
drawTicks: false,
|
||||
lineWidth: 0,
|
||||
zeroLineWidth: 0,
|
||||
zeroLineColor: (mode == 'dark') ? colors.gray[900] : colors.gray[300],
|
||||
zeroLineBorderDash: [2],
|
||||
zeroLineBorderDashOffset: [2]
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
padding: 10,
|
||||
callback: function (value) {
|
||||
if (!(value % 10)) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// xAxes
|
||||
Chart.scaleService.updateScaleDefaults('category', {
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
drawOnChartArea: false,
|
||||
drawTicks: false
|
||||
},
|
||||
ticks: {
|
||||
padding: 20
|
||||
},
|
||||
maxBarThickness: 10
|
||||
});
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
export function initGlobalOptions(Chart) {
|
||||
parseOptions(Chart, chartOptions(Chart));
|
||||
}
|
||||
|
||||
export const basicOptions = {
|
||||
maintainAspectRatio: false,
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
responsive: true
|
||||
};
|
||||
|
||||
export let blueChartOptions = {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
gridLines: {
|
||||
color: Charts.colors.gray[700],
|
||||
zeroLineColor: Charts.colors.gray[700]
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
export let lineChartOptionsBlue = {
|
||||
...basicOptions,
|
||||
tooltips: {
|
||||
backgroundColor: '#f5f5f5',
|
||||
titleFontColor: '#333',
|
||||
bodyFontColor: '#666',
|
||||
bodySpacing: 4,
|
||||
xPadding: 12,
|
||||
mode: 'nearest',
|
||||
intersect: 0,
|
||||
position: 'nearest'
|
||||
},
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.0)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
suggestedMin: 60,
|
||||
suggestedMax: 125,
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
xAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export let barChartOptionsGradient = {
|
||||
...basicOptions,
|
||||
tooltips: {
|
||||
backgroundColor: '#f5f5f5',
|
||||
titleFontColor: '#333',
|
||||
bodyFontColor: '#666',
|
||||
bodySpacing: 4,
|
||||
xPadding: 12,
|
||||
mode: 'nearest',
|
||||
intersect: 0,
|
||||
position: 'nearest'
|
||||
},
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(253,93,147,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
suggestedMin: 60,
|
||||
suggestedMax: 125,
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
xAxes: [
|
||||
{
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(253,93,147,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export let pieChartOptions = {
|
||||
...basicOptions,
|
||||
cutoutPercentage: 70,
|
||||
tooltips: {
|
||||
backgroundColor: '#f5f5f5',
|
||||
titleFontColor: '#333',
|
||||
bodyFontColor: '#666',
|
||||
bodySpacing: 4,
|
||||
xPadding: 12,
|
||||
mode: 'nearest',
|
||||
intersect: 0,
|
||||
position: 'nearest'
|
||||
},
|
||||
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
display: 0,
|
||||
ticks: {
|
||||
display: false
|
||||
},
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
zeroLineColor: 'transparent',
|
||||
color: 'rgba(255,255,255,0.05)'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
xAxes: [
|
||||
{
|
||||
display: 0,
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(255,255,255,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export let purpleChartOptions = {
|
||||
...basicOptions,
|
||||
tooltips: {
|
||||
backgroundColor: '#f5f5f5',
|
||||
titleFontColor: '#333',
|
||||
bodyFontColor: '#666',
|
||||
bodySpacing: 4,
|
||||
xPadding: 12,
|
||||
mode: 'nearest',
|
||||
intersect: 0,
|
||||
position: 'nearest'
|
||||
},
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.0)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
suggestedMin: 60,
|
||||
suggestedMax: 125,
|
||||
padding: 20,
|
||||
fontColor: '#9a9a9a'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
xAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(225,78,202,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
padding: 20,
|
||||
fontColor: '#9a9a9a'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export let orangeChartOptions = {
|
||||
...basicOptions,
|
||||
tooltips: {
|
||||
backgroundColor: '#f5f5f5',
|
||||
titleFontColor: '#333',
|
||||
bodyFontColor: '#666',
|
||||
bodySpacing: 4,
|
||||
xPadding: 12,
|
||||
mode: 'nearest',
|
||||
intersect: 0,
|
||||
position: 'nearest'
|
||||
},
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.0)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
suggestedMin: 50,
|
||||
suggestedMax: 110,
|
||||
padding: 20,
|
||||
fontColor: '#ff8a76'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
xAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(220,53,69,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
padding: 20,
|
||||
fontColor: '#ff8a76'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export let greenChartOptions = {
|
||||
...basicOptions,
|
||||
tooltips: {
|
||||
backgroundColor: '#f5f5f5',
|
||||
titleFontColor: '#333',
|
||||
bodyFontColor: '#666',
|
||||
bodySpacing: 4,
|
||||
xPadding: 12,
|
||||
mode: 'nearest',
|
||||
intersect: 0,
|
||||
position: 'nearest'
|
||||
},
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.0)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
suggestedMin: 50,
|
||||
suggestedMax: 125,
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
xAxes: [
|
||||
{
|
||||
barPercentage: 1.6,
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(0,242,195,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export let barChartOptions = {
|
||||
...basicOptions,
|
||||
tooltips: {
|
||||
backgroundColor: '#f5f5f5',
|
||||
titleFontColor: '#333',
|
||||
bodyFontColor: '#666',
|
||||
bodySpacing: 4,
|
||||
xPadding: 12,
|
||||
mode: 'nearest',
|
||||
intersect: 0,
|
||||
position: 'nearest'
|
||||
},
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
suggestedMin: 60,
|
||||
suggestedMax: 120,
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e'
|
||||
}
|
||||
}
|
||||
],
|
||||
xAxes: [
|
||||
{
|
||||
gridLines: {
|
||||
drawBorder: false,
|
||||
color: 'rgba(29,140,248,0.1)',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
padding: 20,
|
||||
fontColor: '#9e9e9e'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
import Chart from 'chart.js';
|
||||
import { initGlobalOptions } from "./../../components/Charts/config";
|
||||
export default {
|
||||
mounted() {
|
||||
initGlobalOptions(Chart);
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
// Parse global options
|
||||
export function parseOptions(parent, options) {
|
||||
for (let item in options) {
|
||||
if (typeof options[item] !== 'object') {
|
||||
parent[item] = options[item];
|
||||
} else {
|
||||
parseOptions(parent[item], options[item]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="navbar-toggler"
|
||||
data-toggle="collapse"
|
||||
@click="handleClick"
|
||||
:data-target="`#${target}`"
|
||||
:aria-controls="target"
|
||||
:aria-expanded="expanded"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span></span> <span></span>
|
||||
</button>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'close-button',
|
||||
props: {
|
||||
target: {
|
||||
type: [String, Number],
|
||||
description: 'Close button target element'
|
||||
},
|
||||
expanded: {
|
||||
type: Boolean,
|
||||
description: 'Whether button is expanded (aria-expanded attribute)'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(evt) {
|
||||
this.$emit('click', evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,84 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
id="accordion"
|
||||
role="tablist"
|
||||
aria-multiselectable="true"
|
||||
class="accordion"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'collapse',
|
||||
props: {
|
||||
animationDuration: {
|
||||
type: Number,
|
||||
default: 250,
|
||||
description: 'Collapse animation duration'
|
||||
},
|
||||
multipleActive: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
description: 'Whether you can have multiple collapse items opened at the same time'
|
||||
},
|
||||
activeIndex: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
description: 'Active collapse item index'
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
animationDuration: this.animationDuration,
|
||||
multipleActive: this.multipleActive,
|
||||
addItem: this.addItem,
|
||||
removeItem: this.removeItem,
|
||||
deactivateAll: this.deactivateAll
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
items: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
addItem(item) {
|
||||
const index = this.$slots.default.indexOf(item.$vnode);
|
||||
if (index !== -1) {
|
||||
this.items.splice(index, 0, item);
|
||||
}
|
||||
},
|
||||
removeItem(item) {
|
||||
const items = this.items;
|
||||
const index = items.indexOf(item);
|
||||
if (index > -1) {
|
||||
items.splice(index, 1);
|
||||
}
|
||||
},
|
||||
deactivateAll() {
|
||||
this.items.forEach(item => {
|
||||
item.active = false;
|
||||
});
|
||||
},
|
||||
activateItem() {
|
||||
if (this.activeIndex !== -1) {
|
||||
this.items[this.activeIndex].active = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.activateItem();
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
activeIndex() {
|
||||
this.activateItem();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -1,91 +0,0 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div role="tab" class="card-header" :aria-expanded="active">
|
||||
<a
|
||||
data-toggle="collapse"
|
||||
data-parent="#accordion"
|
||||
:href="`#${itemId}`"
|
||||
@click.prevent="activate"
|
||||
:aria-controls="`content-${itemId}`"
|
||||
>
|
||||
<slot name="title"> {{ title }} </slot>
|
||||
<i class="tim-icons icon-minimal-down"></i>
|
||||
</a>
|
||||
</div>
|
||||
<collapse-transition :duration="animationDuration">
|
||||
<div
|
||||
v-show="active"
|
||||
:id="`content-${itemId}`"
|
||||
role="tabpanel"
|
||||
:aria-labelledby="title"
|
||||
class="collapsed"
|
||||
>
|
||||
<div class="card-body"><slot></slot></div>
|
||||
</div>
|
||||
</collapse-transition>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { CollapseTransition } from 'vue2-transitions';
|
||||
|
||||
export default {
|
||||
name: 'collapse-item',
|
||||
components: {
|
||||
CollapseTransition
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Collapse item title'
|
||||
},
|
||||
id: String
|
||||
},
|
||||
inject: {
|
||||
animationDuration: {
|
||||
default: 250
|
||||
},
|
||||
multipleActive: {
|
||||
default: false
|
||||
},
|
||||
addItem: {
|
||||
default: () => {}
|
||||
},
|
||||
removeItem: {
|
||||
default: () => {}
|
||||
},
|
||||
deactivateAll: {
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
itemId() {
|
||||
return this.id || this.title;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
active: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
activate() {
|
||||
let wasActive = this.active;
|
||||
if (!this.multipleActive) {
|
||||
this.deactivateAll();
|
||||
}
|
||||
this.active = !wasActive;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.addItem(this);
|
||||
},
|
||||
destroyed() {
|
||||
if (this.$el && this.$el.parentNode) {
|
||||
this.$el.parentNode.removeChild(this.$el);
|
||||
}
|
||||
this.removeItem(this);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,76 +1,58 @@
|
||||
<template>
|
||||
<div class="card-item" :class="{ '-active' : isCardFlipped }">
|
||||
<div class="card-item__side -front">
|
||||
<div class="card-item relative w-2/4 lg:w-3/4 h-48 m-auto" :class="{ '-active' : isCardFlipped }">
|
||||
<div class="card-item__side h-full rounded-lg shadow-lg overflow-hidden" style="transform: perspective(2000px) rotateY(0deg) rotateX(0deg) rotate(0deg);
|
||||
transform-style: preserve-3d;
|
||||
transition: all 0.8s cubic-bezier(0.71, 0.03, 0.56, 0.85);
|
||||
backface-visibility: hidden;">
|
||||
<div
|
||||
class="card-item__focus"
|
||||
:class="{'-active' : focusElementStyle }"
|
||||
class="absolute w-full h-full left-0 right-0 top-0 rounded-sm overflow-hidden z-10 pointer-events-none opacity-0"
|
||||
style="transition: all 0.35s cubic-bezier(0.71, 0.03, 0.56, 0.85);"
|
||||
:class="{'opacity-100' : focusElementStyle }"
|
||||
:style="focusElementStyle"
|
||||
ref="focusElement"
|
||||
></div>
|
||||
<div class="card-item__cover">
|
||||
<div class="absolute w-full h-full bg-black left-0 top-0 rounded-lg overflow-hidden" style="background-image: linear-gradient(147deg, #354fce 0%, #0c296b 74%);">
|
||||
<img
|
||||
v-if="currentCardBackground"
|
||||
:src="currentCardBackground"
|
||||
class="card-item__bg"
|
||||
class="w-full h-full block object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div class="card-item__wrapper">
|
||||
<div class="card-item__top">
|
||||
<div class="relative h-full py-6 px-4 select-none">
|
||||
<div class="flex items-start justify-between px-4">
|
||||
<img
|
||||
src="https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/chip.png"
|
||||
class="card-item__chip"
|
||||
class="w-12"
|
||||
/>
|
||||
<div class="card-item__type">
|
||||
<div class="relative w-full h-12 flex flex-end">
|
||||
<transition name="slide-fade-up">
|
||||
<img
|
||||
:src="'https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/' + cardType + '.png'"
|
||||
v-if="cardType"
|
||||
:key="cardType"
|
||||
alt
|
||||
class="card-item__typeImg"
|
||||
class="w-full h-full object-right-top object-contain"
|
||||
/>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
<label :for="fields.cardNumber" class="card-item__number" :ref="fields.cardNumber">
|
||||
<template>
|
||||
<span v-for="(n, $index) in currentPlaceholder" :key="$index">
|
||||
<transition name="slide-fade-up">
|
||||
<div class="card-item__numberItem" v-if="getIsNumberMasked($index, n)">*</div>
|
||||
<div
|
||||
class="card-item__numberItem"
|
||||
:class="{ '-active' : n.trim() === '' }"
|
||||
:key="currentPlaceholder"
|
||||
v-else-if="labels.cardNumber.length > $index"
|
||||
>{{labels.cardNumber[$index]}}</div>
|
||||
<div
|
||||
class="card-item__numberItem"
|
||||
:class="{ '-active' : n.trim() === '' }"
|
||||
v-else
|
||||
:key="currentPlaceholder + 1"
|
||||
>{{n}}</div>
|
||||
</transition>
|
||||
</span>
|
||||
</template>
|
||||
</label>
|
||||
<div class="card-item__content">
|
||||
<label :for="fields.cardName" class="card-item__info" :ref="fields.cardName">
|
||||
<div class="card-item__holder">Card Holder</div>
|
||||
|
||||
<div class="flex items-start justify-between text-white">
|
||||
<label :for="fields.cardName" class="p-2 block cursor-pointer text-white" :ref="fields.cardName">
|
||||
<transition name="slide-fade-up">
|
||||
<div class="card-item__name" v-if="labels.cardName.length" key="1">
|
||||
<div class="text-lg overflow-hidden" v-if="labels.cardName.length" key="1">
|
||||
<transition-group name="slide-fade-right">
|
||||
<span
|
||||
class="card-item__nameItem"
|
||||
class="text-lg overflow-hidden"
|
||||
v-for="(n, $index) in labels.cardName.replace(/\s\s+/g, ' ')"
|
||||
:key="$index + 1"
|
||||
>{{n}}</span>
|
||||
</transition-group>
|
||||
</div>
|
||||
<div class="card-item__name" v-else key="2">Full Name</div>
|
||||
<div class="text-lg overflow-hidden" v-else key="2">Full Name</div>
|
||||
</transition>
|
||||
</label>
|
||||
<div class="card-item__date" ref="cardDate">
|
||||
<label :for="fields.cardMonth" class="card-item__dateTitle">Expires</label>
|
||||
<div class="flex flex-wrap shrink-0 text-lg p-2 cursor-pointer" ref="cardDate">
|
||||
<label :for="fields.cardMonth" class="card-item__dateItem">
|
||||
<transition name="slide-fade-up">
|
||||
<span v-if="labels.cardMonth" :key="labels.cardMonth">{{labels.cardMonth}}</span>
|
||||
@ -86,27 +68,49 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label :for="fields.cardNumber" class="flex justify-around font-medium text-white text-lg p-3 cursor-pointer" :ref="fields.cardNumber">
|
||||
<template>
|
||||
<span v-for="(n, $index) in currentPlaceholder" :key="$index">
|
||||
<transition name="slide-fade-up">
|
||||
<div class="w-2" v-if="getIsNumberMasked($index, n)">*</div>
|
||||
<div
|
||||
class="w-2"
|
||||
:class="{ '-active' : n.trim() === '' }"
|
||||
:key="currentPlaceholder"
|
||||
v-else-if="labels.cardNumber.length > $index"
|
||||
>{{labels.cardNumber[$index]}}</div>
|
||||
<div
|
||||
class="w-2"
|
||||
:class="{ '-active' : n.trim() === '' }"
|
||||
v-else
|
||||
:key="currentPlaceholder + 1"
|
||||
>{{n}}</div>
|
||||
</transition>
|
||||
</span>
|
||||
</template>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-item__side -back">
|
||||
<div class="card-item__cover">
|
||||
<div class="card-item__side -back absolute top-0 left-0 w-full p-0 h-full">
|
||||
<div class="absolute w-full h-full bg-black left-0 top-0 rounded-lg overflow-hidden" style="background-image: linear-gradient(147deg, #354fce 0%, #0c296b 74%);">
|
||||
<img
|
||||
v-if="currentCardBackground"
|
||||
:src="currentCardBackground"
|
||||
class="card-item__bg"
|
||||
class="w-full h-full block object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div class="card-item__band"></div>
|
||||
<div class="card-item__cvv">
|
||||
<div class="card-item__cvvTitle">CVV</div>
|
||||
<div class="card-item__cvvBand">
|
||||
<div class="absolute w-full h-32 mt-12 bg-black"></div>
|
||||
<div class="relative p-4 text-right">
|
||||
<div class="pr-4 text-white mb-3">CVV</div>
|
||||
<div class="h-12 flex items-center justify-end text-black rounded-sm shadow-lg bg-white text-right">
|
||||
<span v-for="(n, $index) in labels.cardCvv" :key="$index">*</span>
|
||||
</div>
|
||||
<div class="card-item__type">
|
||||
<div class="relative w-24 h-12 flex justify-end">
|
||||
<img
|
||||
:src="'https://raw.githubusercontent.com/muhammederdem/credit-card-form/master/src/assets/images/' + cardType + '.png'"
|
||||
v-if="cardType"
|
||||
class="card-item__typeImg"
|
||||
class="w-full h-full object-right-top object-contain"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -244,3 +248,33 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.card-item.-active .card-item__side.-front {
|
||||
transform: perspective(1000px) rotateY(180deg) rotateX(0deg) rotateZ(0deg);
|
||||
}
|
||||
.card-item.-active .card-item__side.-back {
|
||||
transform: perspective(1000px) rotateY(0) rotateX(0deg) rotateZ(0deg);
|
||||
}
|
||||
|
||||
.card-item__side {
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
transform: perspective(2000px) rotateY(0deg) rotateX(0deg) rotate(0deg);
|
||||
transform-style: preserve-3d;
|
||||
transition: all 0.8s cubic-bezier(0.71, 0.03, 0.56, 0.85);
|
||||
backface-visibility: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card-item__side.-back {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: perspective(2000px) rotateY(-180deg) rotateX(0deg) rotate(0deg);
|
||||
z-index: 2;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,337 +1,195 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row align-items-center" v-if="Object.keys(cards).length">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="item_name" class="form-control-label">{{ textCard }}</label>
|
||||
<div class="input-group-invoice-text" v-for="(name, key, id) in cards">
|
||||
<div class="custom-radio mb-2">
|
||||
<button type="button"
|
||||
:id="'card-'+ key + '-' + id"
|
||||
class="btn btn-outline-default w-100"
|
||||
@click="onSelectedCard(key)"
|
||||
:disabled="loading">
|
||||
<div class="description text-center">
|
||||
<i v-if="loading" class="fa fa-spinner fa-spin fa-1x checkout-spin"></i>
|
||||
|
||||
{{ name }}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-group-invoice-text">
|
||||
<div class="custom-radio mb-2">
|
||||
<button type="button"
|
||||
id="card-new-card"
|
||||
class="btn btn-outline-default w-100"
|
||||
data-toggle="collapse"
|
||||
data-target="#collapseNewCard"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapseNewCard"
|
||||
:disabled="loading">
|
||||
<div class="description text-center">
|
||||
<i v-if="loading" class="fa fa-spinner fa-spin fa-1x checkout-spin"></i>
|
||||
|
||||
{{ textNewCard }}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="collapse w-100" id="collapseNewCard">
|
||||
<div class="row">
|
||||
<div class="col-md-6 p-5">
|
||||
<div class="form-group">
|
||||
<label for="cardName" class="form-control-label">{{ textCardName }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-font"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
:id="fields.cardName"
|
||||
v-letter-only
|
||||
@input="changeName"
|
||||
class="form-control"
|
||||
:placeholder="placeholderCardName"
|
||||
:value="formData.cardName"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="cardNumber" class="form-control-label">{{ textCardNumber }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-credit-card"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="tel"
|
||||
:id="fields.cardNumber"
|
||||
@input="changeNumber"
|
||||
@focus="focusCardNumber"
|
||||
@blur="blurCardNumber"
|
||||
class="form-control"
|
||||
:placeholder="placeholderCardNumber"
|
||||
:value="formData.cardNumber"
|
||||
:maxlength="cardNumberMaxLength"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-7">
|
||||
<label for="cardMonth" class="form-control-label">{{ textExpirationDate }}</label>
|
||||
<div class="card-form__group">
|
||||
<select
|
||||
class="card-input__input -select"
|
||||
:id="fields.cardMonth"
|
||||
v-model="formData.cardMonth"
|
||||
@change="changeMonth"
|
||||
data-card-field
|
||||
>
|
||||
<option value disabled selected>{{ textMonth }}</option>
|
||||
<option
|
||||
v-bind:value="n < 10 ? '0' + n : n"
|
||||
v-for="n in 12"
|
||||
v-bind:disabled="n < minCardMonth"
|
||||
v-bind:key="n"
|
||||
>{{generateMonthValue(n)}}</option>
|
||||
</select>
|
||||
|
||||
<select
|
||||
class="card-input__input -select"
|
||||
:id="fields.cardYear"
|
||||
v-model="formData.cardYear"
|
||||
@change="changeYear"
|
||||
data-card-field
|
||||
>
|
||||
<option value disabled selected>{{ textYear }}</option>
|
||||
<option
|
||||
v-bind:value="$index + minCardYear"
|
||||
v-for="(n, $index) in 12"
|
||||
v-bind:key="n"
|
||||
>{{$index + minCardYear}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<div class="form-group">
|
||||
<label for="cardCvv" class="form-control-label">{{ textCvv }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-key"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="tel"
|
||||
class="form-control"
|
||||
:placeholder="placeholderCvv"
|
||||
v-number-only
|
||||
:id="fields.cardCvv"
|
||||
maxlength="4"
|
||||
:value="formData.cardCvv"
|
||||
@input="changeCvv"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" v-if="storeCard">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input @input="changeStoreCard" :id="'store_card' + _uid" name="store_card" type="checkbox" value="true" class="custom-control-input">
|
||||
<label :for="'store_card' + _uid" class="custom-control-label">
|
||||
<strong>{{ textStoreCard }}</strong>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button class="btn btn-icon btn-success" v-on:click="invaildCard" :disabled="loading">
|
||||
<div v-if="loading" class="aka-loader-frame">
|
||||
<div class="aka-loader"></div>
|
||||
</div>
|
||||
<span v-if="!loading" class="btn-inner--text">{{ textButton }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mt-6">
|
||||
<Card
|
||||
:fields="fields"
|
||||
:labels="formData"
|
||||
:isCardNumberMasked="isCardNumberMasked"
|
||||
:randomBackgrounds="randomBackgrounds"
|
||||
:backgroundImage="backgroundImage"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row align-items-center" v-if="!Object.keys(cards).length">
|
||||
<div class="col-md-6 p-5">
|
||||
<div class="form-group">
|
||||
<label for="cardNumber" class="form-control-label">{{ textCardNumber }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-credit-card"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="tel"
|
||||
:id="fields.cardNumber"
|
||||
@input="changeNumber"
|
||||
@focus="focusCardNumber"
|
||||
@blur="blurCardNumber"
|
||||
class="form-control"
|
||||
:placeholder="placeholderCardNumber"
|
||||
:value="formData.cardNumber"
|
||||
:maxlength="cardNumberMaxLength"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
<div class="invalid-feedback d-block" v-if="validations.card_number" v-html="validations.card_number[0]"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="cardName" class="form-control-label">{{ textCardName }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-font"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
:id="fields.cardName"
|
||||
v-letter-only
|
||||
@input="changeName"
|
||||
class="form-control"
|
||||
:placeholder="placeholderCardName"
|
||||
:value="formData.cardName"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
<div class="invalid-feedback d-block" v-if="validations.card_name" v-html="validations.card_name[0]"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-7">
|
||||
<label for="cardMonth" class="form-control-label">{{ textExpirationDate }}</label>
|
||||
<div class="form-group d-flex">
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</span>
|
||||
</div>
|
||||
<select
|
||||
class="form-control w-50"
|
||||
:id="fields.cardMonth"
|
||||
v-model="formData.cardMonth"
|
||||
@change="changeMonth"
|
||||
data-card-field
|
||||
>
|
||||
<option value="" disabled>{{ textMonth }}</option>
|
||||
<option
|
||||
v-bind:value="n < 10 ? '0' + n : n"
|
||||
v-for="n in 12"
|
||||
v-bind:disabled="n < minCardMonth"
|
||||
v-bind:key="n"
|
||||
>{{generateMonthValue(n)}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group input-group-merge ml-4">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</span>
|
||||
</div>
|
||||
<select
|
||||
class="form-control w-50"
|
||||
:id="fields.cardYear"
|
||||
v-model="formData.cardYear"
|
||||
@change="changeYear"
|
||||
data-card-field
|
||||
>
|
||||
<option value="" disabled>{{ textYear }}</option>
|
||||
<option
|
||||
v-bind:value="$index + minCardYear"
|
||||
v-for="(n, $index) in 12"
|
||||
v-bind:key="n"
|
||||
>{{$index + minCardYear}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<div class="form-group">
|
||||
<label for="cardCvv" class="form-control-label">{{ textCvv }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-key"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="tel"
|
||||
class="form-control"
|
||||
:placeholder="placeholderCvv"
|
||||
v-number-only
|
||||
:id="fields.cardCvv"
|
||||
maxlength="4"
|
||||
:value="formData.cardCvv"
|
||||
@input="changeCvv"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
<div class="invalid-feedback d-block" v-if="validations.card_cvv" v-html="validations.card_cvv[0]"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" v-if="storeCard">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input @input="changeStoreCard" :id="'store_card' + _uid" name="store_card" type="checkbox" value="true" class="custom-control-input">
|
||||
<label :for="'store_card' + _uid" class="custom-control-label">
|
||||
<strong>{{ textStoreCard }}</strong>
|
||||
<div>
|
||||
<div class="flex flex-col" v-if="Object.keys(cards).length">
|
||||
<div class="gap-y-2">
|
||||
<div
|
||||
class="py-2 border-b hover:bg-gray-100 cursor-pointer"
|
||||
v-for="(name, key, id) in cards" :key="key"
|
||||
@click="onRegisterCard(id)"
|
||||
>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
:disabled="loading"
|
||||
:checked="register_card == id"
|
||||
>
|
||||
<span class="ltr:ml-2 rtl:mr-2">{{ name }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button class="btn btn-icon btn-success" v-on:click="invaildCard" :disabled="loading">
|
||||
<div v-if="loading" class="aka-loader-frame">
|
||||
<div class="aka-loader"></div>
|
||||
</div>
|
||||
<span v-if="!loading" class="btn-inner--text">{{ textButton }}</span>
|
||||
<div class="py-2 border-b hover:bg-gray-100 cursor-pointer" @click="onAddNewCard()">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
id="card-new-card"
|
||||
name="new-card"
|
||||
:disabled="loading"
|
||||
:checked="new_card"
|
||||
>
|
||||
<span class="ltr:ml-2 rtl:mr-2">{{ textNewCard }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end" v-for="(name, key, id) in cards" :key="key">
|
||||
<button
|
||||
v-if="register_card == id"
|
||||
type="button"
|
||||
:id="'card-'+ key + '-' + id"
|
||||
@click="onSelectedCard(key)"
|
||||
class="relative flex items-center justify-center px-6 py-1.5 my-2 bg-green hover:bg-green-700 text-white rounded-lg"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i
|
||||
v-if="loading || register_card_loading"
|
||||
class="animate-submit delay-[0.28s] absolute w-2 h-2 rounded-full left-0 right-0 -top-3.5 m-auto before:absolute before:w-2 before:h-2 before:rounded-full before:animate-submit before:delay-[0.14s] after:absolute after:w-2 after:h-2 after:rounded-full after:animate-submit before:-left-3.5 after:-right-3.5 after:delay-[0.42s]"
|
||||
>
|
||||
</i>
|
||||
|
||||
<span :class="[{'opacity-0': loading || register_card_loading}]">
|
||||
{{ textButton }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="new_card" class="w-full mt-3" id="collapseNewCard">
|
||||
<Card
|
||||
:fields="fields"
|
||||
:labels="formData"
|
||||
:isCardNumberMasked="isCardNumberMasked"
|
||||
:randomBackgrounds="randomBackgrounds"
|
||||
:backgroundImage="backgroundImage"
|
||||
/>
|
||||
|
||||
<div class="grid sm:grid-cols-8 gap-x-4 gap-y-6 my-3.5">
|
||||
<div class="sm:col-span-8">
|
||||
<label for="cardName" class="form-control-label text-black text-sm font-medium">
|
||||
{{ textCardName }}
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
:id="fields.cardName"
|
||||
v-letter-only
|
||||
@input="changeName"
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:placeholder="placeholderCardName"
|
||||
:value="formData.cardName"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
|
||||
<div class="text-red text-sm mt-1 block" v-if="validations.card_name" v-html="validations.card_name[0]"></div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-8">
|
||||
<label for="cardNumber" class="form-control-label text-black text-sm font-medium">
|
||||
{{ textCardNumber }}
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="tel"
|
||||
:id="fields.cardNumber"
|
||||
@input="changeNumber"
|
||||
@focus="focusCardNumber"
|
||||
@blur="blurCardNumber"
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:placeholder="placeholderCardNumber"
|
||||
:value="formData.cardNumber"
|
||||
:maxlength="cardNumberMaxLength"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
|
||||
<div class="text-red text-sm mt-1 block" v-if="validations.card_number" v-html="validations.card_number[0]"></div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-3">
|
||||
<label for="cardMonth" class="form-control-label text-black text-sm font-medium">
|
||||
{{ textExpirationDate }}
|
||||
</label>
|
||||
|
||||
<select
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:id="fields.cardMonth"
|
||||
v-model="formData.cardMonth"
|
||||
@change="changeMonth"
|
||||
data-card-field
|
||||
>
|
||||
<option value disabled selected>{{ textMonth }}</option>
|
||||
<option
|
||||
v-bind:value="n < 10 ? '0' + n : n"
|
||||
v-for="n in 12"
|
||||
v-bind:disabled="n < minCardMonth"
|
||||
v-bind:key="n"
|
||||
>{{generateMonthValue(n)}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-3 flex items-end">
|
||||
<select
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:id="fields.cardYear"
|
||||
v-model="formData.cardYear"
|
||||
@change="changeYear"
|
||||
data-card-field
|
||||
>
|
||||
<option value="" disabled>{{ textYear }}</option>
|
||||
<option
|
||||
v-bind:value="$index + minCardYear"
|
||||
v-for="(n, $index) in 12"
|
||||
v-bind:key="n"
|
||||
>{{$index + minCardYear}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label for="cardCvv" class="form-control-label text-black text-sm font-medium">
|
||||
{{ textCvv }}
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="tel"
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:placeholder="placeholderCvv"
|
||||
v-number-only
|
||||
:id="fields.cardCvv"
|
||||
maxlength="4"
|
||||
:value="formData.cardCvv"
|
||||
@input="changeCvv"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
|
||||
<div class="text-red text-sm mt-1 block" v-if="validations.card_cvv" v-html="validations.card_cvv[0]"></div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-8 flex" :class="storeCard ? 'justify-between' : 'justify-end'">
|
||||
<div class="flex items-center" v-if="storeCard">
|
||||
<input @input="changeStoreCard" :id="'store_card' + _uid" name="store_card" type="checkbox" value="true" class="rounded-sm text-purple border-gray-300 cursor-pointer disabled:bg-gray-200 focus:outline-none focus:ring-transparent">
|
||||
|
||||
<label :for="'store_card' + _uid" class="form-control-label ltr:ml-2 rtl:ml-2">
|
||||
<strong>{{ textStoreCard }}</strong>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button class="relative flex items-center justify-center px-6 py-1.5 bg-green hover:bg-green-700 text-white rounded-lg" v-on:click="invaildCard" :disabled="loading">
|
||||
<i
|
||||
v-if="loading"
|
||||
class="animate-submit delay-[0.28s] absolute w-2 h-2 rounded-full left-0 right-0 -top-3.5 m-auto before:absolute before:w-2 before:h-2 before:rounded-full before:animate-submit before:delay-[0.14s] after:absolute after:w-2 after:h-2 after:rounded-full after:animate-submit before:-left-3.5 after:-right-3.5 after:delay-[0.42s]"
|
||||
>
|
||||
</i>
|
||||
|
||||
<span :class="[{'opacity-0': loading}]">
|
||||
{{ textButton }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mt--6">
|
||||
<div class="flex flex-col" v-if="! Object.keys(cards).length">
|
||||
<Card
|
||||
:fields="fields"
|
||||
:labels="formData"
|
||||
@ -339,16 +197,141 @@
|
||||
:randomBackgrounds="randomBackgrounds"
|
||||
:backgroundImage="backgroundImage"
|
||||
/>
|
||||
|
||||
<div class="grid sm:grid-cols-8 gap-x-4 gap-y-6 my-3.5">
|
||||
<div class="sm:col-span-8">
|
||||
<label for="cardName" class="form-control-label text-black text-sm font-medium">
|
||||
{{ textCardName }}
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
:id="fields.cardName"
|
||||
v-letter-only
|
||||
@input="changeName"
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:placeholder="placeholderCardName"
|
||||
:value="formData.cardName"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
|
||||
<div class="text-red text-sm mt-1 block" v-if="validations.card_name" v-html="validations.card_name[0]"></div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-8">
|
||||
<label for="cardNumber" class="form-control-label text-black text-sm font-medium">
|
||||
{{ textCardNumber }}
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="tel"
|
||||
:id="fields.cardNumber"
|
||||
@input="changeNumber"
|
||||
@focus="focusCardNumber"
|
||||
@blur="blurCardNumber"
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:placeholder="placeholderCardNumber"
|
||||
:value="formData.cardNumber"
|
||||
:maxlength="cardNumberMaxLength"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
|
||||
<div class="text-red text-sm mt-1 block" v-if="validations.card_number" v-html="validations.card_number[0]"></div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-3">
|
||||
<label for="cardMonth" class="form-control-label text-black text-sm font-medium">
|
||||
{{ textExpirationDate }}
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<select
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:id="fields.cardMonth"
|
||||
v-model="formData.cardMonth"
|
||||
@change="changeMonth"
|
||||
data-card-field
|
||||
>
|
||||
<option value="" disabled>{{ textMonth }}</option>
|
||||
<option
|
||||
v-bind:value="n < 10 ? '0' + n : n"
|
||||
v-for="n in 12"
|
||||
v-bind:disabled="n < minCardMonth"
|
||||
v-bind:key="n"
|
||||
>{{generateMonthValue(n)}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-3 flex items-end">
|
||||
<select
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:id="fields.cardYear"
|
||||
v-model="formData.cardYear"
|
||||
@change="changeYear"
|
||||
data-card-field
|
||||
>
|
||||
<option value="" disabled>{{ textYear }}</option>
|
||||
<option
|
||||
v-bind:value="$index + minCardYear"
|
||||
v-for="(n, $index) in 12"
|
||||
v-bind:key="n"
|
||||
>{{$index + minCardYear}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label for="cardCvv" class="form-control-label text-black text-sm font-medium">
|
||||
{{ textCvv }}
|
||||
</label>
|
||||
|
||||
<input
|
||||
type="tel"
|
||||
class="w-full text-sm px-3 py-2.5 mt-1 rounded-lg border border-light-gray text-black placeholder-light-gray bg-white disabled:bg-gray-200 focus:outline-none focus:ring-transparent focus:border-purple"
|
||||
:placeholder="placeholderCvv"
|
||||
v-number-only
|
||||
:id="fields.cardCvv"
|
||||
maxlength="4"
|
||||
:value="formData.cardCvv"
|
||||
@input="changeCvv"
|
||||
data-card-field
|
||||
autocomplete="off"
|
||||
/>
|
||||
|
||||
<div class="text-red text-sm mt-1 block" v-if="validations.card_cvv" v-html="validations.card_cvv[0]"></div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-8 flex" :class="storeCard ? 'justify-between' : 'justify-end'">
|
||||
<div class="flex items-center" v-if="storeCard">
|
||||
<input @input="changeStoreCard" :id="'store_card' + _uid" name="store_card" type="checkbox" value="true" class="rounded-sm text-purple border-gray-300 cursor-pointer disabled:bg-gray-200 focus:outline-none focus:ring-transparent">
|
||||
|
||||
<label :for="'store_card' + _uid" class="form-control-label ltr:ml-2 rtl:ml-2">
|
||||
<strong>{{ textStoreCard }}</strong>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button class="relative flex items-center justify-center px-6 py-1.5 bg-green hover:bg-green-700 text-white rounded-lg" v-on:click="invaildCard" :disabled="loading">
|
||||
<i
|
||||
v-if="loading"
|
||||
class="animate-submit delay-[0.28s] absolute w-2 h-2 rounded-full left-0 right-0 -top-3.5 m-auto before:absolute before:w-2 before:h-2 before:rounded-full before:animate-submit before:delay-[0.14s] after:absolute after:w-2 after:h-2 after:rounded-full after:animate-submit before:-left-3.5 after:-right-3.5 after:delay-[0.42s]"
|
||||
>
|
||||
</i>
|
||||
<span :class="[{'opacity-0': loading}]">
|
||||
{{ textButton }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
|
||||
import axios from 'axios';
|
||||
import Card from './Card';
|
||||
import './../../../css/creditcard/style.scss';
|
||||
|
||||
export default {
|
||||
name: 'CardForm',
|
||||
@ -369,6 +352,7 @@ export default {
|
||||
el.addEventListener('keypress', checkValue);
|
||||
}
|
||||
},
|
||||
|
||||
'letter-only': {
|
||||
bind (el) {
|
||||
function checkValue (event) {
|
||||
@ -496,7 +480,9 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
backgroundImage: [String, Object],
|
||||
|
||||
randomBackgrounds: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@ -524,6 +510,9 @@ export default {
|
||||
mainCardNumber: this.cardNumber,
|
||||
cardNumberMaxLength: 19,
|
||||
card_id: 0,
|
||||
new_card: false,
|
||||
register_card: 0,
|
||||
register_card_loading: false
|
||||
}
|
||||
},
|
||||
|
||||
@ -550,6 +539,22 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
onRegisterCard(id) {
|
||||
this.register_card = id;
|
||||
this.new_card = false;
|
||||
this.register_card_loading = true;
|
||||
|
||||
setTimeout(() => {
|
||||
this.register_card_loading = false;
|
||||
}, 800);
|
||||
},
|
||||
|
||||
onAddNewCard() {
|
||||
this.new_card = true;
|
||||
this.register_card = null;
|
||||
},
|
||||
|
||||
|
||||
onSelectedCard(card_id) {
|
||||
this.card_id = card_id;
|
||||
this.formData.card_id = card_id;
|
||||
@ -696,6 +701,9 @@ export default {
|
||||
} else {
|
||||
this.unMaskCardNumber();
|
||||
}
|
||||
},
|
||||
|
||||
showNewCard() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
<template>
|
||||
<date-range-picker
|
||||
:startDate="startDate"
|
||||
:endDate="endDate"
|
||||
@update="console.log(value)"
|
||||
:locale-data="locale"
|
||||
:opens="opens"
|
||||
>
|
||||
<!--Optional scope for the input displaying the dates -->
|
||||
<div slot="input" slot-scope="picker">...</div>
|
||||
</date-range-picker>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: { DateRangePicker },
|
||||
data() {
|
||||
return {
|
||||
startDate: '2017-09-05',
|
||||
endDate: '2017-09-15',
|
||||
opens: "center",//which way the picker opens, default "center", can be "left"/"right"
|
||||
locale: {
|
||||
direction: 'ltr', //direction of text
|
||||
format: 'DD-MM-YYYY', //fomart of the dates displayed
|
||||
separator: ' - ', //separator between the two ranges
|
||||
applyLabel: 'Apply',
|
||||
cancelLabel: 'Cancel',
|
||||
weekLabel: 'W',
|
||||
customRangeLabel: 'Custom Range',
|
||||
daysOfWeek: moment.weekdaysMin(), //array of days - see moment documenations for details
|
||||
monthNames: moment.monthsShort(), //array of month names - see moment documenations for details
|
||||
firstDay: 1 //ISO first day of week - see moment documenations for details
|
||||
showWeekNumbers: true //show week numbers on each row of the calendar
|
||||
},
|
||||
ranges: { //default value for ranges object (if you set this to false ranges will no be rendered)
|
||||
'Today': [moment(), moment()],
|
||||
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
|
||||
'This month': [moment().startOf('month'), moment().endOf('month')],
|
||||
'This year': [moment().startOf('year'), moment().endOf('year')],
|
||||
'Last week': [moment().subtract(1, 'week').startOf('week'), moment().subtract(1, 'week').endOf('week')],
|
||||
'Last month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
//you need to import the CSS manually (in case you want to override it)
|
||||
import 'vue2-daterange-picker/dist/lib/vue-daterange-picker.min.css'
|
@ -1,50 +0,0 @@
|
||||
<template>
|
||||
<div class="media media-comment">
|
||||
<img alt="Image placeholder" class="avatar avatar-lg media-comment-avatar rounded-circle" :src="userImage">
|
||||
<div class="media-body">
|
||||
<div class="media-comment-text">
|
||||
<h6 class="h5 mt-0">{{userName}}</h6>
|
||||
<p class="text-sm lh-160" v-html="text"></p>
|
||||
<div class="icon-actions">
|
||||
<a href="#" class="like active">
|
||||
<i class="ni ni-like-2"></i>
|
||||
<span class="text-muted">{{likeCount}} likes</span>
|
||||
</a>
|
||||
<a href="#">
|
||||
<i class="ni ni-curved-next"></i>
|
||||
<span class="text-muted">{{shareCount}} shares</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'comment',
|
||||
props: {
|
||||
userImage: {
|
||||
type: String,
|
||||
default: 'img/theme/team-1.jpg'
|
||||
},
|
||||
userName: {
|
||||
type: String,
|
||||
default: 'Michael Lewis'
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: 'Cras sit amet nibh libero nulla vel metus scelerisque ante sollicitudin. Cras purus odio vestibulum in vulputate viverra turpis.'
|
||||
},
|
||||
likeCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
shareCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
@ -1,69 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<component v-for="(field, index) in schema"
|
||||
:key="index"
|
||||
:is="field.fieldType"
|
||||
v-bind="field">
|
||||
|
||||
</component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { SlideYUpTransition } from "vue2-transitions";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Modal header title"
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Modal body message"
|
||||
},
|
||||
button_cancel: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Modal footer cancel button text"
|
||||
},
|
||||
button_delete: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: "Modal footer delete button text"
|
||||
},
|
||||
animationDuration: {
|
||||
type: Number,
|
||||
default: 800,
|
||||
description: "Modal transition duration"
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
closeModal() {
|
||||
this.$emit("update:show", false);
|
||||
this.$emit("close");
|
||||
},
|
||||
onConfirm() {
|
||||
this.$emit("confirm");
|
||||
},
|
||||
onCancel() {
|
||||
this.$emit("cancel");
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
show(val) {
|
||||
let documentClasses = document.body.classList;
|
||||
if (val) {
|
||||
documentClasses.add("modal-open");
|
||||
} else {
|
||||
documentClasses.remove("modal-open");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,77 +0,0 @@
|
||||
<template>
|
||||
<div class="custom-control custom-checkbox"
|
||||
:class="[
|
||||
{disabled: disabled},
|
||||
{[`custom-checkbox-${type}`]: type},inlineClass]">
|
||||
<input :id="cbId"
|
||||
class="custom-control-input"
|
||||
:class="inputClasses"
|
||||
type="checkbox"
|
||||
:disabled="disabled"
|
||||
v-model="model"/>
|
||||
<label :for="cbId" class="custom-control-label">
|
||||
<slot>
|
||||
<span v-if="inline"> </span>
|
||||
</slot>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "base-checkbox",
|
||||
model: {
|
||||
prop: "checked"
|
||||
},
|
||||
props: {
|
||||
checked: {
|
||||
type: [Array, Boolean],
|
||||
description: "Whether checkbox is checked"
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
description: "Whether checkbox is disabled"
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
description: "Whether checkbox is inline"
|
||||
},
|
||||
inputClasses: {
|
||||
type: [String, Object, Array],
|
||||
description: "Checkbox input classes"
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
description: 'Checkbox type (e.g info, danger etc)'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cbId: "",
|
||||
touched: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.checked;
|
||||
},
|
||||
set(check) {
|
||||
if (!this.touched) {
|
||||
this.touched = true;
|
||||
}
|
||||
this.$emit("input", check);
|
||||
}
|
||||
},
|
||||
inlineClass() {
|
||||
if (this.inline) {
|
||||
return `form-check-inline`;
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.cbId = Math.random()
|
||||
.toString(16)
|
||||
.slice(2);
|
||||
}
|
||||
};
|
||||
</script>
|
@ -8,17 +8,18 @@
|
||||
{{label}}
|
||||
</label>
|
||||
</slot>
|
||||
<div :class="[
|
||||
<div class="relative" :class="[
|
||||
{'input-group input-group-merge': hasIcon},
|
||||
{'focused': focused},
|
||||
{'input-group-alternative': alternative},
|
||||
{'has-label': label || $slots.label},
|
||||
{'prepend-input-icon': prependIcon},
|
||||
inputGroupClasses
|
||||
]">
|
||||
<div v-if="prependIcon || $slots.prepend" class="input-group-prepend">
|
||||
<div v-if="prependIcon || $slots.prepend" class="input-group-prepend absolute left-2 bottom-3 text-light-gray">
|
||||
<span class="input-group-text">
|
||||
<slot name="prepend">
|
||||
<i :class="prependIcon"></i>
|
||||
<span class="material-icons w-4 h-5 text-sm">{{ prependIcon }}</span>
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
@ -30,30 +31,30 @@
|
||||
v-bind="$attrs"
|
||||
:valid="!error"
|
||||
:required="required"
|
||||
class="form-control"
|
||||
class="form-element"
|
||||
:class="[{'is-valid': valid === true}, {'is-invalid': error}, inputClasses]">
|
||||
</slot>
|
||||
<div v-if="appendIcon || $slots.append" class="input-group-append">
|
||||
<div v-if="appendIcon || $slots.append" class="input-group-append absolute ltr:right-2 rtl:left-2 bottom-2 text-light-gray">
|
||||
<span class="input-group-text">
|
||||
<slot name="append">
|
||||
<i :class="appendIcon"></i>
|
||||
<span class="material-icons w-4 h-5 text-sm">{{ appendIcon }}</span>
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
<slot name="infoBlock"></slot>
|
||||
<slot name="error">
|
||||
<div v-if="error" class="invalid-feedback d-block"
|
||||
<div v-if="error" class="text-red text-sm mt-1 block"
|
||||
v-html="error">
|
||||
</div>
|
||||
</slot>
|
||||
<slot name="success">
|
||||
<div class="valid-feedback" v-if="!error && valid">
|
||||
<div class="text-green text-sm mt-1" v-if="!error && valid">
|
||||
{{successMessage}}
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
<slot name="error">
|
||||
<div v-if="footerError" class="invalid-feedback d-block"
|
||||
<div v-if="footerError" class="text-red text-sm mt-1 block"
|
||||
v-html="footerError">
|
||||
</div>
|
||||
</slot>
|
||||
@ -181,5 +182,3 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
||||
|
@ -1,68 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="custom-control custom-radio"
|
||||
:class="[inlineClass, { disabled: disabled }]">
|
||||
<input
|
||||
:id="cbId"
|
||||
class="custom-control-input"
|
||||
type="radio"
|
||||
:disabled="disabled"
|
||||
:value="name"
|
||||
v-model="model"
|
||||
/>
|
||||
<label :for="cbId" class="custom-control-label">
|
||||
<slot>
|
||||
<span v-if="inline"> </span>
|
||||
</slot>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-radio',
|
||||
props: {
|
||||
name: {
|
||||
type: [String, Number],
|
||||
description: 'Radio label'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
description: 'Whether radio is disabled'
|
||||
},
|
||||
value: {
|
||||
type: [String, Boolean],
|
||||
description: 'Radio value'
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
description: 'Whether radio is inline'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cbId: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
model: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value);
|
||||
}
|
||||
},
|
||||
inlineClass() {
|
||||
if (this.inline) {
|
||||
return `form-check-inline`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.cbId = Math.random()
|
||||
.toString(16)
|
||||
.slice(2);
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,126 +0,0 @@
|
||||
<template>
|
||||
<div class="dropzone mb-3 dz-clickable"
|
||||
:class="[multiple ? 'dropzone-multiple': 'dropzone-single']">
|
||||
<div class="fallback">
|
||||
<div class="custom-file">
|
||||
<input type="file"
|
||||
class="custom-file-input"
|
||||
id="projectCoverUploads"
|
||||
:multiple="multiple">
|
||||
<label class="custom-file-label" for="projectCoverUploads">Choose file</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dz-preview dz-preview-single"
|
||||
v-if="!multiple"
|
||||
:class="previewClasses"
|
||||
ref="previewSingle">
|
||||
<div class="dz-preview-cover">
|
||||
<img class="dz-preview-img" data-dz-thumbnail>
|
||||
</div>
|
||||
</div>
|
||||
<ul v-else
|
||||
class="dz-preview dz-preview-multiple list-group list-group-lg list-group-flush"
|
||||
:class="previewClasses"
|
||||
ref="previewMultiple">
|
||||
<li class="list-group-item px-0">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="avatar">
|
||||
<img class="avatar-img rounded" data-dz-thumbnail>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col ml--3">
|
||||
<h4 class="mb-1" data-dz-name>...</h4>
|
||||
<p class="small text-muted mb-0" data-dz-size>...</p>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button data-dz-remove="true" class="btn btn-danger btn-sm">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Dropzone from 'dropzone';
|
||||
|
||||
Dropzone.autoDiscover = false;
|
||||
|
||||
export default {
|
||||
name: 'dropzone-file-upload',
|
||||
props: {
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
value: [String, Object, Array],
|
||||
url: {
|
||||
type: String,
|
||||
default: 'http://'
|
||||
},
|
||||
multiple: Boolean,
|
||||
previewClasses: [String, Object, Array]
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentFile: null,
|
||||
files: [],
|
||||
showList: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async initDropzone() {
|
||||
let preview = this.multiple ? this.$refs.previewMultiple : this.$refs.previewSingle;
|
||||
let self = this
|
||||
let finalOptions = {
|
||||
...this.options,
|
||||
url: this.url,
|
||||
thumbnailWidth: null,
|
||||
thumbnailHeight: null,
|
||||
previewsContainer: preview,
|
||||
previewTemplate: preview.innerHTML,
|
||||
maxFiles: (!this.multiple) ? 1 : null,
|
||||
acceptedFiles: (!this.multiple) ? 'image/*' : null,
|
||||
init: function () {
|
||||
this.on("addedfile", function (file) {
|
||||
if (!self.multiple && self.currentFile) {
|
||||
// this.removeFile(this.currentFile);
|
||||
}
|
||||
self.currentFile = file;
|
||||
})
|
||||
}
|
||||
}
|
||||
this.dropzone = new Dropzone(this.$el, finalOptions)
|
||||
preview.innerHTML = ''
|
||||
let evtList = ['drop', 'dragstart', 'dragend', 'dragenter', 'dragover', 'addedfile', 'removedfile', 'thumbnail', 'error', 'processing', 'uploadprogress', 'sending', 'success', 'complete', 'canceled', 'maxfilesreached', 'maxfilesexceeded', 'processingmultiple', 'sendingmultiple', 'successmultiple', 'completemultiple', 'canceledmultiple', 'totaluploadprogress', 'reset', 'queuecomplete']
|
||||
evtList.forEach(evt => {
|
||||
this.dropzone.on(evt, (data) => {
|
||||
this.$emit(evt, data);
|
||||
|
||||
if (evt === 'addedfile') {
|
||||
this.files.push(data)
|
||||
this.$emit('change', this.files);
|
||||
} else if (evt === 'removedfile') {
|
||||
let index = this.files.findIndex(f => f.upload.uuid === data.upload.uuid)
|
||||
if (index !== -1) {
|
||||
this.files.splice(index, 1);
|
||||
}
|
||||
this.$emit('change', this.files);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.initDropzone()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
@ -1,54 +0,0 @@
|
||||
<template>
|
||||
<div class="custom-file">
|
||||
<input type="file"
|
||||
class="custom-file-input"
|
||||
id="customFileLang"
|
||||
lang="en"
|
||||
v-bind="$attrs"
|
||||
v-on="listeners"
|
||||
/>
|
||||
<label class="custom-file-label" for="customFileLang">
|
||||
{{label}}
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'file-input',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
initialLabel: {
|
||||
type: String,
|
||||
default: 'Select file'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
files: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
listeners() {
|
||||
return {
|
||||
...this.$listeners,
|
||||
change: this.fileChange
|
||||
}
|
||||
},
|
||||
label() {
|
||||
let fileNames = [];
|
||||
for (let file of this.files) {
|
||||
fileNames.push(file.name)
|
||||
}
|
||||
return fileNames.length ? fileNames.join(', ') : this.initialLabel
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fileChange(evt) {
|
||||
this.files = evt.target.files
|
||||
this.$emit('change', this.files)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
@ -1,96 +0,0 @@
|
||||
<template>
|
||||
<div class="quill">
|
||||
<div :id="toolbarId">
|
||||
<div class="ql-formats">
|
||||
<button class="ql-bold"></button>
|
||||
<button class="ql-italic"></button>
|
||||
<button class="ql-underline"></button>
|
||||
<button class="ql-link"></button>
|
||||
<button class="ql-blockquote"></button>
|
||||
<button class="ql-code"></button>
|
||||
<button class="ql-image"></button>
|
||||
<button type="button" class="ql-list" value="ordered"></button>
|
||||
<button type="button" class="ql-list" value="bullet"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div :id="editorId" :name="name" class="" ref="editor">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'html-editor',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
name: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
editor: null,
|
||||
content: null,
|
||||
lastHtmlValue: '',
|
||||
editorId: null,
|
||||
toolbarId: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initialize (Quill) {
|
||||
this.editor = new Quill(`#${this.editorId}`, {
|
||||
theme: 'snow',
|
||||
modules: {
|
||||
toolbar: `#${this.toolbarId}`
|
||||
}
|
||||
})
|
||||
|
||||
if (this.value.length > 0) {
|
||||
this.editor.pasteHTML(this.value)
|
||||
}
|
||||
|
||||
let editorRef = this.$refs.editor;
|
||||
let node = editorRef.children[0];
|
||||
this.editor.on('text-change', () => {
|
||||
let html = node.innerHTML
|
||||
if (html === '<p><br></p>') {
|
||||
html = '';
|
||||
}
|
||||
this.content = html
|
||||
this.$emit('input', this.content);
|
||||
})
|
||||
},
|
||||
pasteHTML () {
|
||||
if (!this.editor) {
|
||||
return
|
||||
}
|
||||
this.editor.pasteHTML(this.value)
|
||||
},
|
||||
randomString() {
|
||||
let text = "";
|
||||
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
for (let i = 0; i < 5; i++)
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
|
||||
return text;
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
let Quill = await import('quill')
|
||||
Quill = Quill.default || Quill
|
||||
this.editorId = this.randomString();
|
||||
this.toolbarId = this.randomString();
|
||||
this.$nextTick(() => {
|
||||
this.initialize(Quill)
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
value (newVal) {
|
||||
if (newVal !== this.content) {
|
||||
this.pasteHTML(newVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="choice"
|
||||
:class="{ active: checked }"
|
||||
data-toggle="wizard-checkbox"
|
||||
@click="updateValue"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:checked="checked"
|
||||
/>
|
||||
<div class="icon">
|
||||
<slot name="icon"> <i :class="icon"></i> </slot>
|
||||
</div>
|
||||
<slot name="title">
|
||||
<h6>{{ title }}</h6>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'icon-checkbox',
|
||||
model: {
|
||||
prop: 'checked'
|
||||
},
|
||||
props: {
|
||||
checked: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
name: String,
|
||||
title: String,
|
||||
icon: String,
|
||||
disabled: Boolean
|
||||
},
|
||||
methods: {
|
||||
updateValue() {
|
||||
this.$emit('input', !this.checked);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,95 +0,0 @@
|
||||
<template>
|
||||
<div class="tags-input__wrapper">
|
||||
<el-tag
|
||||
v-for="(tag, index) in dynamicTags"
|
||||
:key="tag + index"
|
||||
size="small"
|
||||
:type="tagType"
|
||||
:closable="true"
|
||||
:close-transition="false"
|
||||
@close="handleClose(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Add new tag"
|
||||
class="form-control"
|
||||
v-model="inputValue"
|
||||
ref="saveTagInput"
|
||||
size="mini"
|
||||
@input="onInput"
|
||||
@keyup.enter="handleInputConfirm"
|
||||
@blur="handleInputConfirm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Tag } from 'element-ui';
|
||||
|
||||
export default {
|
||||
name: 'tags-input',
|
||||
components: {
|
||||
[Tag.name]: Tag
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
description: 'List of tags'
|
||||
},
|
||||
tagType: {
|
||||
type: String,
|
||||
default: 'primary',
|
||||
description: 'Tag type (primary|danger etc)'
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dynamicTags: [],
|
||||
inputVisible: false,
|
||||
inputValue: ''
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleClose(tag) {
|
||||
this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
|
||||
this.$emit('change', this.dynamicTags);
|
||||
},
|
||||
showInput() {
|
||||
this.inputVisible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.saveTagInput.$refs.input.focus();
|
||||
});
|
||||
},
|
||||
|
||||
handleInputConfirm() {
|
||||
let inputValue = this.inputValue;
|
||||
if (inputValue) {
|
||||
this.dynamicTags.push(inputValue);
|
||||
this.$emit('change', this.dynamicTags);
|
||||
}
|
||||
this.inputVisible = false;
|
||||
this.inputValue = '';
|
||||
},
|
||||
onInput(evt) {
|
||||
this.$emit('input', evt.target.value);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$watch(
|
||||
'value',
|
||||
newVal => {
|
||||
this.dynamicTags = [...newVal];
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<div class="row" v-loading="true" id="loading"></div>
|
||||
</template>
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import { Loading } from 'element-ui';
|
||||
|
||||
Vue.use(Loading.directive);
|
||||
export default {};
|
||||
</script>
|
||||
<style>
|
||||
#loading {
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.el-loading-spinner .path {
|
||||
stroke: #66615b !important;
|
||||
}
|
||||
|
||||
.el-loading-mask {
|
||||
background: transparent !important;
|
||||
}
|
||||
</style>
|
@ -110,9 +110,9 @@
|
||||
show(val) {
|
||||
let documentClasses = document.body.classList;
|
||||
if (val) {
|
||||
documentClasses.add("modal-open");
|
||||
documentClasses.add("overflow-hidden");
|
||||
} else {
|
||||
documentClasses.remove("modal-open");
|
||||
documentClasses.remove("overflow-hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,120 +0,0 @@
|
||||
<template>
|
||||
<nav :class="classes" class="navbar">
|
||||
<div :class="containerClasses">
|
||||
<slot name="brand"></slot>
|
||||
|
||||
<slot name="toggle-button">
|
||||
<button
|
||||
class="navbar-toggler collapsed"
|
||||
v-if="hasMenu"
|
||||
type="button"
|
||||
@click="toggleMenu"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-bar navbar-kebab"></span>
|
||||
<span class="navbar-toggler-bar navbar-kebab"></span>
|
||||
<span class="navbar-toggler-bar navbar-kebab"></span>
|
||||
</button>
|
||||
</slot>
|
||||
|
||||
<button class="navbar-toggler" @click.stop="toggleMenu">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div
|
||||
class="navbar-collapse navbar-custom-collapse collapse show"
|
||||
:class="menuClasses"
|
||||
v-show="show"
|
||||
v-click-outside="closeMenu">
|
||||
<slot :close-menu="closeMenu"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'base-nav',
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description:
|
||||
'Whether navbar menu is shown (valid for viewports < specified by `expand` prop)'
|
||||
},
|
||||
transparent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether navbar is transparent'
|
||||
},
|
||||
expand: {
|
||||
type: String,
|
||||
default: 'lg',
|
||||
description: 'Breakpoint where nav should expand'
|
||||
},
|
||||
menuClasses: {
|
||||
type: [String, Object, Array],
|
||||
default: '',
|
||||
description:
|
||||
'Navbar menu (items) classes. Can be used to align menu items to the right/left'
|
||||
},
|
||||
containerClasses: {
|
||||
type: [String, Object, Array],
|
||||
default: 'container',
|
||||
description:
|
||||
'Container classes. Can be used to control container classes (contains both navbar brand and menu items)'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'white',
|
||||
validator(value) {
|
||||
return [
|
||||
'',
|
||||
'dark',
|
||||
'success',
|
||||
'danger',
|
||||
'warning',
|
||||
'white',
|
||||
'primary',
|
||||
'light',
|
||||
'info',
|
||||
'vue'
|
||||
].includes(value);
|
||||
},
|
||||
description: 'Navbar color type'
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'show',
|
||||
event: 'change'
|
||||
},
|
||||
computed: {
|
||||
classes() {
|
||||
let color = `bg-${this.type}`;
|
||||
let classes = [
|
||||
{ 'navbar-transparent': this.transparent },
|
||||
{ [`navbar-expand-${this.expand}`]: this.expand }
|
||||
];
|
||||
if (this.position) {
|
||||
classes.push(`navbar-${this.position}`);
|
||||
}
|
||||
if (!this.transparent) {
|
||||
classes.push(color);
|
||||
}
|
||||
return classes;
|
||||
},
|
||||
hasMenu() {
|
||||
return this.$slots.default;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleMenu() {
|
||||
this.$emit('change', !this.show);
|
||||
},
|
||||
closeMenu() {
|
||||
this.$emit('change', false);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="navbar-toggler collapsed"
|
||||
data-toggle="collapse"
|
||||
data-target="#navbar"
|
||||
aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-bar bar1"></span>
|
||||
<span class="navbar-toggler-bar bar2"></span>
|
||||
<span class="navbar-toggler-bar bar3"></span>
|
||||
</button>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'navbar-toggle-button'
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,29 +0,0 @@
|
||||
<template>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-toggle="collapse"
|
||||
:data-target="target"
|
||||
:aria-controls="target"
|
||||
:aria-expanded="toggled"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
target: {
|
||||
type: [String, Number],
|
||||
description: 'Button target element'
|
||||
},
|
||||
toggled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description: 'Whether button is toggled'
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -2,7 +2,8 @@
|
||||
<div
|
||||
@click="tryClose"
|
||||
data-notify="container"
|
||||
class="alert alert-notify alert-dismissible"
|
||||
class="alert alert-notify fixed flex items-center justify-between ltr:right-4 rtl:left-4 p-4 text-black font-bold rounded-lg z-30"
|
||||
style="width: 500px;"
|
||||
:class="[
|
||||
{ 'alert-with-icon': icon },
|
||||
verticalAlign,
|
||||
@ -13,16 +14,16 @@
|
||||
:style="customPosition"
|
||||
data-notify-position="top-center"
|
||||
>
|
||||
<div class="flex items-center ltr:pr-3 rtl:pl-3">
|
||||
<template v-if="icon || $slots.icon">
|
||||
<slot name="icon">
|
||||
<span class="alert-icon" data-notify="icon">
|
||||
<i :class="icon"></i>
|
||||
<span class="alert-icon flex items-center ltr:mr-2 rtl:ml-2" data-notify="icon">
|
||||
<span class="material-icons text-2xl">{{ icon }}</span>
|
||||
</span>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
<span class="alert-text">
|
||||
|
||||
<span v-if="title" class="title">
|
||||
<b>{{ title }}<br/></b>
|
||||
</span>
|
||||
@ -32,10 +33,11 @@
|
||||
:component="component"
|
||||
></content-render>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<slot name="dismiss-icon">
|
||||
<button type="button"
|
||||
class="close"
|
||||
class="close text-2xl"
|
||||
data-dismiss="alert"
|
||||
aria-label="Close"
|
||||
@click="close">
|
||||
@ -95,7 +97,7 @@
|
||||
];
|
||||
return acceptedValues.indexOf(value) !== -1;
|
||||
},
|
||||
description: 'Notification type of notification (default|info|primary|danger|warning|success)'
|
||||
description: 'Notification type of notification (gray-300|blue-300|gray-300|red-300|orange-300|green-300)'
|
||||
},
|
||||
timeout: {
|
||||
type: Number,
|
||||
@ -131,7 +133,23 @@
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
elmHeight: 0
|
||||
elmHeight: 0,
|
||||
typeByClass: {
|
||||
'default': 'black-100',
|
||||
'info': 'blue-100',
|
||||
'primary': 'black-100',
|
||||
'danger': 'red-100',
|
||||
'warning': 'orange-100',
|
||||
'success': 'green-100',
|
||||
},
|
||||
textByClass: {
|
||||
'default': 'black-600',
|
||||
'info': 'blue-600',
|
||||
'primary': 'black-600',
|
||||
'danger': 'red-600',
|
||||
'warning': 'orange-600',
|
||||
'success': 'green-600',
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -139,7 +157,7 @@
|
||||
return this.icon && this.icon.length > 0;
|
||||
},
|
||||
alertType() {
|
||||
return `alert-${this.type}`;
|
||||
return `bg-${this.typeByClass[this.type]} text-${this.textByClass[this.type]}`;
|
||||
},
|
||||
customPosition() {
|
||||
let initialMargin = 20;
|
||||
@ -184,24 +202,4 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.notifications .alert {
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
|
||||
&[data-notify='container'] {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
&.center {
|
||||
margin: 0 auto;
|
||||
}
|
||||
&.left {
|
||||
left: 20px;
|
||||
}
|
||||
&.right {
|
||||
right: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</script>
|
@ -1,123 +0,0 @@
|
||||
<template>
|
||||
<div class="sidenav navbar navbar-vertical fixed-left navbar-expand-xs navbar-light bg-white"
|
||||
@mouseenter="$sidebar.onMouseEnter()"
|
||||
@mouseleave="$sidebar.onMouseLeave()"
|
||||
:data="backgroundColor">
|
||||
<div class="scrollbar-inner" ref="sidebarScrollArea">
|
||||
<div class="sidenav-header d-flex align-items-center">
|
||||
<a class="navbar-brand" href="#">
|
||||
<img :src="logo" class="navbar-brand-img" alt="Sidebar logo">
|
||||
</a>
|
||||
<div class="ml-auto">
|
||||
<!-- Sidenav toggler -->
|
||||
<div class="sidenav-toggler d-none d-xl-block"
|
||||
:class="{'active': !$sidebar.isMinimized }"
|
||||
@click="minimizeSidebar">
|
||||
<div class="sidenav-toggler-inner">
|
||||
<i class="sidenav-toggler-line"></i>
|
||||
<i class="sidenav-toggler-line"></i>
|
||||
<i class="sidenav-toggler-line"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<slot></slot>
|
||||
<div class="navbar-inner">
|
||||
<ul class="navbar-nav">
|
||||
<slot name="links">
|
||||
<sidebar-item
|
||||
v-for="(link, index) in sidebarLinks"
|
||||
:key="link.name + index"
|
||||
:link="link"
|
||||
>
|
||||
<sidebar-item
|
||||
v-for="(subLink, index) in link.children"
|
||||
:key="subLink.name + index"
|
||||
:link="subLink"
|
||||
>
|
||||
</sidebar-item>
|
||||
</sidebar-item>
|
||||
</slot>
|
||||
</ul>
|
||||
<slot name="links-after"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'sidebar',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Creative Tim',
|
||||
description: 'Sidebar title'
|
||||
},
|
||||
shortTitle: {
|
||||
type: String,
|
||||
default: 'CT',
|
||||
description: 'Sidebar short title'
|
||||
},
|
||||
logo: {
|
||||
type: String,
|
||||
default: 'https://demos.creative-tim.com/vue-argon-dashboard-pro/img/brand/green.png',
|
||||
description: 'Sidebar app logo'
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: 'vue',
|
||||
validator: value => {
|
||||
let acceptedValues = [
|
||||
'',
|
||||
'vue',
|
||||
'blue',
|
||||
'green',
|
||||
'orange',
|
||||
'red',
|
||||
'primary'
|
||||
];
|
||||
return acceptedValues.indexOf(value) !== -1;
|
||||
},
|
||||
description:
|
||||
'Sidebar background color (vue|blue|green|orange|red|primary)'
|
||||
},
|
||||
sidebarLinks: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
description:
|
||||
"List of sidebar links as an array if you don't want to use components for these."
|
||||
},
|
||||
autoClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
description:
|
||||
'Whether sidebar should autoclose on mobile when clicking an item'
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
autoClose: this.autoClose
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
minimizeSidebar() {
|
||||
if (this.$sidebar) {
|
||||
this.$sidebar.toggleMinimize();
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.$sidebar.showSidebar) {
|
||||
this.$sidebar.showSidebar = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
@media (min-width: 992px) {
|
||||
.navbar-search-form-mobile,
|
||||
.nav-mobile-menu {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,198 +0,0 @@
|
||||
<template>
|
||||
<component
|
||||
:is="baseComponent"
|
||||
:to="link.path ? link.path : '/'"
|
||||
class="nav-item"
|
||||
:class="{ active: isActive }"
|
||||
tag="li"
|
||||
>
|
||||
<a
|
||||
v-if="isMenu"
|
||||
class="sidebar-menu-item nav-link"
|
||||
:class="{ active: isActive }"
|
||||
:aria-expanded="!collapsed"
|
||||
data-toggle="collapse"
|
||||
@click.prevent="collapseMenu"
|
||||
>
|
||||
<template v-if="addLink">
|
||||
<span class="nav-link-text">
|
||||
{{ link.name }} <b class="caret"></b>
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<i :class="link.icon"></i>
|
||||
<span class="nav-link-text">{{ link.name }} <b class="caret"></b></span>
|
||||
</template>
|
||||
</a>
|
||||
|
||||
<collapse-transition>
|
||||
<div
|
||||
v-if="$slots.default || this.isMenu"
|
||||
v-show="!collapsed"
|
||||
class="collapse show"
|
||||
>
|
||||
<ul class="nav nav-sm flex-column">
|
||||
<slot></slot>
|
||||
</ul>
|
||||
</div>
|
||||
</collapse-transition>
|
||||
|
||||
<slot
|
||||
name="title"
|
||||
v-if="children.length === 0 && !$slots.default && link.path"
|
||||
>
|
||||
<component
|
||||
:to="link.path"
|
||||
@click.native="linkClick"
|
||||
:is="elementType(link, false)"
|
||||
class="nav-link"
|
||||
:class="{ active: link.active }"
|
||||
:target="link.target"
|
||||
:href="link.path"
|
||||
>
|
||||
<template v-if="addLink">
|
||||
<span class="nav-link-text">{{ link.name }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<i :class="link.icon"></i>
|
||||
<span class="nav-link-text">{{ link.name }}</span>
|
||||
</template>
|
||||
</component>
|
||||
</slot>
|
||||
</component>
|
||||
</template>
|
||||
<script>
|
||||
import { CollapseTransition } from 'vue2-transitions';
|
||||
|
||||
export default {
|
||||
name: 'sidebar-item',
|
||||
components: {
|
||||
CollapseTransition
|
||||
},
|
||||
props: {
|
||||
menu: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
description:
|
||||
"Whether the item is a menu. Most of the item it's not used and should be used only if you want to override the default behavior."
|
||||
},
|
||||
link: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
name: '',
|
||||
path: '',
|
||||
children: []
|
||||
};
|
||||
},
|
||||
description:
|
||||
'Sidebar link. Can contain name, path, icon and other attributes. See examples for more info'
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
addLink: this.addChild,
|
||||
removeLink: this.removeChild
|
||||
};
|
||||
},
|
||||
inject: {
|
||||
addLink: { default: null },
|
||||
removeLink: { default: null },
|
||||
autoClose: {
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
children: [],
|
||||
collapsed: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
baseComponent() {
|
||||
return this.isMenu || this.link.isRoute ? 'li' : 'router-link';
|
||||
},
|
||||
linkPrefix() {
|
||||
if (this.link.name) {
|
||||
let words = this.link.name.split(' ');
|
||||
return words.map(word => word.substring(0, 1)).join('');
|
||||
}
|
||||
},
|
||||
isMenu() {
|
||||
return this.children.length > 0 || this.menu === true;
|
||||
},
|
||||
isActive() {
|
||||
if (this.$route && this.$route.path) {
|
||||
let matchingRoute = this.children.find(c =>
|
||||
this.$route.path.startsWith(c.link.path)
|
||||
);
|
||||
if (matchingRoute !== undefined) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addChild(item) {
|
||||
const index = this.$slots.default.indexOf(item.$vnode);
|
||||
this.children.splice(index, 0, item);
|
||||
},
|
||||
removeChild(item) {
|
||||
const tabs = this.children;
|
||||
const index = tabs.indexOf(item);
|
||||
tabs.splice(index, 1);
|
||||
},
|
||||
elementType(link, isParent = true) {
|
||||
if (link.isRoute === false) {
|
||||
return isParent ? 'li' : 'a';
|
||||
} else {
|
||||
return 'router-link';
|
||||
}
|
||||
},
|
||||
linkAbbreviation(name) {
|
||||
const matches = name.match(/\b(\w)/g);
|
||||
return matches.join('');
|
||||
},
|
||||
linkClick() {
|
||||
if (
|
||||
this.autoClose &&
|
||||
this.$sidebar &&
|
||||
this.$sidebar.showSidebar === true
|
||||
) {
|
||||
this.$sidebar.displaySidebar(false);
|
||||
}
|
||||
},
|
||||
collapseMenu() {
|
||||
this.collapsed = !this.collapsed;
|
||||
},
|
||||
collapseSubMenu(link) {
|
||||
link.collapsed = !link.collapsed;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.addLink) {
|
||||
this.addLink(this);
|
||||
}
|
||||
if (this.link.collapsed !== undefined) {
|
||||
this.collapsed = this.link.collapsed;
|
||||
}
|
||||
if (this.isActive && this.isMenu) {
|
||||
this.collapsed = false;
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
if (this.$el && this.$el.parentNode) {
|
||||
this.$el.parentNode.removeChild(this.$el);
|
||||
}
|
||||
if (this.removeLink) {
|
||||
this.removeLink(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.sidebar-menu-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
@ -1,70 +0,0 @@
|
||||
import Sidebar from './SideBar.vue';
|
||||
import SidebarItem from './SidebarItem.vue';
|
||||
|
||||
const SidebarStore = {
|
||||
showSidebar: true,
|
||||
sidebarLinks: [],
|
||||
isMinimized: false,
|
||||
breakpoint: 1200,
|
||||
displaySidebar(value) {
|
||||
if (window.innerWidth > this.breakpoint) {
|
||||
return;
|
||||
}
|
||||
this.showSidebar = value;
|
||||
let docClasses = document.body.classList
|
||||
if (value) {
|
||||
docClasses.add('g-sidenav-pinned')
|
||||
docClasses.add('g-sidenav-show')
|
||||
docClasses.remove('g-sidenav-hidden')
|
||||
} else {
|
||||
docClasses.add('g-sidenav-hidden')
|
||||
docClasses.remove('g-sidenav-pinned')
|
||||
}
|
||||
},
|
||||
toggleMinimize() {
|
||||
this.isMinimized = !this.isMinimized;
|
||||
let docClasses = document.body.classList
|
||||
if (this.isMinimized) {
|
||||
docClasses.add('g-sidenav-hidden')
|
||||
docClasses.remove('g-sidenav-pinned')
|
||||
} else {
|
||||
docClasses.add('g-sidenav-pinned')
|
||||
docClasses.remove('g-sidenav-hidden')
|
||||
}
|
||||
},
|
||||
onMouseEnter() {
|
||||
if (this.isMinimized) {
|
||||
document.body.classList.add('g-sidenav-show')
|
||||
document.body.classList.remove('g-sidenav-hidden')
|
||||
}
|
||||
},
|
||||
onMouseLeave() {
|
||||
if (this.isMinimized) {
|
||||
let docClasses = document.body.classList
|
||||
docClasses.remove('g-sidenav-show')
|
||||
docClasses.add('g-sidenav-hide')
|
||||
setTimeout(() => {
|
||||
docClasses.remove('g-sidenav-hide')
|
||||
docClasses.add('g-sidenav-hidden')
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const SidebarPlugin = {
|
||||
install(Vue, options) {
|
||||
if (options && options.sidebarLinks) {
|
||||
SidebarStore.sidebarLinks = options.sidebarLinks;
|
||||
}
|
||||
let app = new Vue({
|
||||
data: {
|
||||
sidebarStore: SidebarStore
|
||||
}
|
||||
});
|
||||
Vue.prototype.$sidebar = app.sidebarStore;
|
||||
Vue.component('side-bar', Sidebar);
|
||||
Vue.component('sidebar-item', SidebarItem);
|
||||
}
|
||||
};
|
||||
|
||||
export default SidebarPlugin;
|
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="tab-pane"
|
||||
v-show="active"
|
||||
:id="id || title"
|
||||
:class="{ active: active }"
|
||||
:aria-expanded="active"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'tab-pane',
|
||||
props: ['title', 'id'],
|
||||
inject: ['addTab', 'removeTab'],
|
||||
data() {
|
||||
return {
|
||||
active: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.addTab(this);
|
||||
},
|
||||
destroyed() {
|
||||
if (this.$el && this.$el.parentNode) {
|
||||
this.$el.parentNode.removeChild(this.$el);
|
||||
}
|
||||
this.removeTab(this);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,168 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
{ 'col-md-4': vertical && !tabNavWrapperClasses },
|
||||
{ 'col-12': centered && !tabNavWrapperClasses },
|
||||
tabNavWrapperClasses
|
||||
]"
|
||||
>
|
||||
<ul
|
||||
class="nav nav-pills"
|
||||
role="tablist"
|
||||
:class="[
|
||||
`nav-pills-${type}`,
|
||||
{ 'flex-column': vertical },
|
||||
{ 'justify-content-center': centered },
|
||||
tabNavClasses
|
||||
]"
|
||||
>
|
||||
<li
|
||||
v-for="tab in tabs"
|
||||
class="nav-item active"
|
||||
data-toggle="tab"
|
||||
role="tablist"
|
||||
aria-expanded="true"
|
||||
:key="tab.id"
|
||||
>
|
||||
<a
|
||||
data-toggle="tab"
|
||||
role="tablist"
|
||||
:href="`#${tab.id}`"
|
||||
@click.prevent="activateTab(tab)"
|
||||
:aria-expanded="tab.active"
|
||||
class="nav-link"
|
||||
:class="{ active: tab.active }"
|
||||
>
|
||||
<tab-item-content :tab="tab"> </tab-item-content>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="tab-content"
|
||||
:class="[
|
||||
{ 'tab-space': !vertical },
|
||||
{ 'col-md-8': vertical && !tabContentClasses },
|
||||
tabContentClasses
|
||||
]"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'tabs',
|
||||
components: {
|
||||
TabItemContent: {
|
||||
props: ['tab'],
|
||||
render(h) {
|
||||
return h('div', [this.tab.$slots.title || this.tab.title]);
|
||||
}
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
addTab: this.addTab,
|
||||
removeTab: this.removeTab
|
||||
};
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary',
|
||||
validator: value => {
|
||||
let acceptedValues = [
|
||||
'primary',
|
||||
'info',
|
||||
'success',
|
||||
'warning',
|
||||
'danger'
|
||||
];
|
||||
return acceptedValues.indexOf(value) !== -1;
|
||||
}
|
||||
},
|
||||
activeTab: {
|
||||
type: String,
|
||||
default: '',
|
||||
description: 'Active tab name'
|
||||
},
|
||||
tabNavWrapperClasses: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
description: 'ul wrapper css classes'
|
||||
},
|
||||
tabNavClasses: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
description: 'ul css classes'
|
||||
},
|
||||
tabContentClasses: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
description: 'tab content css classes'
|
||||
},
|
||||
vertical: Boolean,
|
||||
centered: Boolean,
|
||||
value: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabs: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
findAndActivateTab(title) {
|
||||
let tabToActivate = this.tabs.find(t => t.title === title);
|
||||
if (tabToActivate) {
|
||||
this.activateTab(tabToActivate);
|
||||
}
|
||||
},
|
||||
activateTab(tab) {
|
||||
if (this.handleClick) {
|
||||
this.handleClick(tab);
|
||||
}
|
||||
this.deactivateTabs();
|
||||
tab.active = true;
|
||||
},
|
||||
deactivateTabs() {
|
||||
this.tabs.forEach(tab => {
|
||||
tab.active = false;
|
||||
});
|
||||
},
|
||||
addTab(tab) {
|
||||
const index = this.$slots.default.indexOf(tab.$vnode);
|
||||
if (!this.activeTab && index === 0) {
|
||||
tab.active = true;
|
||||
}
|
||||
if (this.activeTab === tab.name) {
|
||||
tab.active = true;
|
||||
}
|
||||
this.tabs.splice(index, 0, tab);
|
||||
},
|
||||
removeTab(tab) {
|
||||
const tabs = this.tabs;
|
||||
const index = tabs.indexOf(tab);
|
||||
if (index > -1) {
|
||||
tabs.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
if (this.value) {
|
||||
this.findAndActivateTab(this.value);
|
||||
}
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
value(newVal) {
|
||||
this.findAndActivateTab(newVal);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<div class="timeline" :class="{[`timeline-${type}`]: type}">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'time-line',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,30 +0,0 @@
|
||||
<template>
|
||||
<div class="timeline-block" :class="{ 'timeline-inverted': inverted }">
|
||||
<slot name="badge">
|
||||
<span class="timeline-step" :class="`badge-${badgeType}`">
|
||||
<i :class="badgeIcon"></i>
|
||||
</span>
|
||||
</slot>
|
||||
<div class="timeline-content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'time-line-item',
|
||||
props: {
|
||||
inverted: Boolean,
|
||||
title: String,
|
||||
badgeType: {
|
||||
type: String,
|
||||
default: 'success'
|
||||
},
|
||||
badgeIcon: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,28 +0,0 @@
|
||||
<template>
|
||||
<div class="world-map-container">
|
||||
<world-map v-bind="$attrs" v-on="$listeners"></world-map>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
/* We lazy load (async) the VectorMaps component because it contains 2 big libraries (jquery and jquery vector maps)
|
||||
If the component is not loaded within 200ms, we display a loading component in the meanwhile.
|
||||
This way, we don't bloat the main bundle with 2 unnecessary libs that we only need for this page :)
|
||||
*/
|
||||
import { LoadingPanel } from '@/components';
|
||||
const WorldMap = () => ({
|
||||
component: import('./WorldMap.vue'),
|
||||
loading: LoadingPanel,
|
||||
delay: 200
|
||||
});
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
components: {
|
||||
WorldMap
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.world-map-container {
|
||||
min-height: 500px;
|
||||
}
|
||||
</style>
|
@ -1,127 +0,0 @@
|
||||
<template>
|
||||
<div :id="id" class="world-map"></div>
|
||||
</template>
|
||||
<script>
|
||||
import 'd3';
|
||||
import * as d3 from 'd3';
|
||||
import 'topojson';
|
||||
import { throttle } from '@/util/throttle';
|
||||
|
||||
export default {
|
||||
name: 'world-map',
|
||||
props: {
|
||||
mapData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
points: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
id: this.randomString(),
|
||||
color1: '#f6f9fc',
|
||||
color2: '#adb5bd',
|
||||
highlightFillColor: '#ced4da',
|
||||
borderColor: 'white',
|
||||
highlightBorderColor: 'white',
|
||||
bubbleHighlightFillColor: '#11cdef',
|
||||
bubbleFillColor: '#fb6340'
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
generateColors(length) {
|
||||
return d3
|
||||
.scaleLinear()
|
||||
.domain([0, length])
|
||||
.range([this.color1, this.color2]);
|
||||
},
|
||||
generateMapColors() {
|
||||
let mapDataValues = Object.values(this.mapData);
|
||||
let maxVal = Math.max(...mapDataValues);
|
||||
let colors = this.generateColors(maxVal);
|
||||
let mapData = {};
|
||||
let fills = {
|
||||
defaultFill: '#EDF0F2'
|
||||
};
|
||||
for (let key in this.mapData) {
|
||||
let val = this.mapData[key];
|
||||
fills[key] = colors(val);
|
||||
mapData[key] = {
|
||||
fillKey: key,
|
||||
value: val
|
||||
};
|
||||
}
|
||||
return {
|
||||
mapData,
|
||||
fills
|
||||
};
|
||||
},
|
||||
async initVectorMap() {
|
||||
let DataMap = await import('datamaps');
|
||||
DataMap = DataMap.default || DataMap
|
||||
let { fills, mapData } = this.generateMapColors();
|
||||
let worldMap = new DataMap({
|
||||
scope: 'world',
|
||||
element: document.getElementById(this.id),
|
||||
fills,
|
||||
data: mapData,
|
||||
responsive: true,
|
||||
geographyConfig: {
|
||||
borderColor: this.borderColor,
|
||||
borderWidth: 1,
|
||||
borderOpacity: 1,
|
||||
highlightFillColor: this.highlightFillColor,
|
||||
highlightBorderColor: this.highlightBorderColor,
|
||||
highlightBorderWidth: 1,
|
||||
highlightBorderOpacity: 1
|
||||
}
|
||||
});
|
||||
let bubbleOptions = {
|
||||
radius: 2,
|
||||
borderWidth: 4,
|
||||
highlightBorderWidth: 4,
|
||||
fillKey: this.bubbleFillColor,
|
||||
fillColor: this.bubbleFillColor,
|
||||
borderColor: this.bubbleFillColor,
|
||||
highlightFillColor: this.bubbleHighlightFillColor,
|
||||
highlightBorderColor: this.bubbleHighlightFillColor
|
||||
}
|
||||
let bubblePoints = this.points.map(point => {
|
||||
return {
|
||||
...bubbleOptions,
|
||||
...point
|
||||
}
|
||||
})
|
||||
worldMap.bubbles(bubblePoints, {
|
||||
popupTemplate: function(geo, data) {
|
||||
return '<div class="hoverinfo">' + data.name
|
||||
}
|
||||
});
|
||||
let resizeFunc = worldMap.resize.bind(worldMap);
|
||||
window.addEventListener(
|
||||
'resize',
|
||||
() => {
|
||||
throttle(resizeFunc, 40);
|
||||
},
|
||||
false
|
||||
);
|
||||
},
|
||||
randomString() {
|
||||
let text = "";
|
||||
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
for (let i = 0; i < 5; i++)
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
|
||||
return text;
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.initVectorMap();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="(attributes.required) ? col + ' required' : col">
|
||||
<div class="input-checkbox">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4" v-for="(key, item, index) in items">
|
||||
<div class="input-checkbox">
|
||||
<input type="checkbox" :name="name" :value="key[id]"> <small>{{ key[value] }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-checkbox-group',
|
||||
props: {
|
||||
name: '',
|
||||
text: '',
|
||||
items: [],
|
||||
id: '',
|
||||
value: '',
|
||||
selected: '',
|
||||
attributes: [],
|
||||
col: ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="(attributes.required) ? col + ' required' : col">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa" :class="'fa-' + icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input type="email" :name="name" :value="value" :id="name" class="form-control" v-bind="attributes">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-email-group',
|
||||
props: {
|
||||
name: '',
|
||||
text: '',
|
||||
icon: '',
|
||||
attributes: [],
|
||||
value: '',
|
||||
col: ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,34 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="(attributes.required) ? col + ' required' : col">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
<div class="input-group input-group-merge custom-file">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa" :class="'fa-' + icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input type="file" :name="name" :value="value" :id="name" class="form-control" v-bind="attributes">
|
||||
<label :for="name" class="custom-file-label">{{ text }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-file-group',
|
||||
props: {
|
||||
name: '',
|
||||
text: '',
|
||||
icon: '',
|
||||
attributes: [],
|
||||
value: '',
|
||||
col: ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="col">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa" :class="'fa-' + icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input type="text" :name="input_name" :value="input_value" :id="input_name" class="form-control" v-bind="attributes">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-invoice-text-group',
|
||||
props: {
|
||||
name: '',
|
||||
input_name: '',
|
||||
input_value: '',
|
||||
text: '',
|
||||
icon: '',
|
||||
attributes: [],
|
||||
values: [],
|
||||
selected: '',
|
||||
col: ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="(attributes.required) ? col + ' required' : col">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa" :class="'fa-' + icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input type="number" :name="name" :value="value" :id="name" class="form-control" v-bind="attributes">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-number-group',
|
||||
props: {
|
||||
name: '',
|
||||
text: '',
|
||||
icon: '',
|
||||
attributes: [],
|
||||
value: '',
|
||||
col: ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="(attributes.required) ? col + ' required' : col">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa" :class="'fa-' + icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input type="password" :name="name" :value="value" :id="name" class="form-control" v-bind="attributes">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-password-group',
|
||||
props: {
|
||||
name: '',
|
||||
text: '',
|
||||
icon: '',
|
||||
attributes: [],
|
||||
value: '',
|
||||
col: ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,54 +0,0 @@
|
||||
<template>
|
||||
<div class="col-md-12">
|
||||
<a href="http://localhost/Ak-Dev/Beta/v2.0.0/common/items" class="btn btn-icon btn-outline-secondary">
|
||||
<span class="btn-inner--icon"><i class="fas fa-times"></i></span>
|
||||
<span class="btn-inner--text">Cancel</span>
|
||||
</a>
|
||||
|
||||
<loading :active.sync="isLoading"
|
||||
:can-cancel="false"
|
||||
:on-cancel="onCancel"
|
||||
:is-full-page="fullPage"
|
||||
></loading>
|
||||
|
||||
<button type="button" v-on:click="doLoading" class="btn btn-icon btn-success button-submit">
|
||||
<span class="btn-inner--icon"><i class="fas fa-save"></i></span>
|
||||
<span class="btn-inner--text"> Save</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
// Import component
|
||||
import Loading from 'vue-loading-overlay';
|
||||
// Import stylesheet
|
||||
import 'vue-loading-overlay/dist/vue-loading.css';
|
||||
|
||||
export default {
|
||||
name: 'akaunting-save-buttons',
|
||||
components: {
|
||||
Loading
|
||||
},
|
||||
props: {
|
||||
formSubmit: Function,
|
||||
loading: false
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: loading,
|
||||
fullPage: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doLoading() {
|
||||
this.isLoading = true;
|
||||
|
||||
this.formSubmit();
|
||||
},
|
||||
onCancel() {
|
||||
console.log('User cancelled the loader.')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="(attributes.required) ? col + ' required' : col">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa" :class="'fa-' + icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<select :name="name" :id="name" class="form-control" v-bind="attributes">
|
||||
<option value="" disabled>{{ attributes.placeholder }}</option>
|
||||
<option v-for="(key, value, index) in values" :value="value" :selected="selected == value">{{ key }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-select-group',
|
||||
props: {
|
||||
name: '',
|
||||
text: '',
|
||||
icon: '',
|
||||
values: [],
|
||||
selected: '',
|
||||
attributes: [],
|
||||
col: ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,34 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="(attributes.required) ? col + ' required' : col">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i class="fa" :class="'fa-' + icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<input type="text" :name="name" :value="value" :id="name" class="form-control" v-bind="attributes" v-on:input="onChange" v-model:input="forms.data[name]">
|
||||
<div class="text-danger invalid-feedback d-block" v-text="" v-if="errors[name]">
|
||||
{{ errors[name][0] }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-text-group',
|
||||
props: {
|
||||
name: '',
|
||||
text: '',
|
||||
icon: '',
|
||||
attributes: [],
|
||||
value: '',
|
||||
col: ''
|
||||
},
|
||||
data: {
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group" :class="(attributes.required) ? col + ' required' : col">
|
||||
<label :for="name" class="form-control-label">{{ text }}</label>
|
||||
<textarea :name="name" :id="name" class="form-control" cols="50" v-bind="attributes">{{ value }}</textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'akaunting-textarea-group',
|
||||
props: {
|
||||
name: '',
|
||||
text: '',
|
||||
icon: '',
|
||||
value: '',
|
||||
attributes: [],
|
||||
col: ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
}
|
||||
}
|
||||
</script>
|
70
resources/assets/js/components/index.js
vendored
70
resources/assets/js/components/index.js
vendored
@ -1,70 +0,0 @@
|
||||
import BaseCheckbox from './Inputs/BaseCheckbox.vue';
|
||||
import BaseAlert from './BaseAlert.vue';
|
||||
import IconCheckbox from './Inputs/IconCheckbox.vue';
|
||||
import BaseRadio from './Inputs/BaseRadio.vue';
|
||||
import BaseInput from './Inputs/BaseInput.vue';
|
||||
import TagsInput from './Inputs/TagsInput.vue';
|
||||
import BaseSwitch from './BaseSwitch.vue';
|
||||
import Badge from './Badge';
|
||||
import BaseProgress from './BaseProgress.vue';
|
||||
import BaseButton from './BaseButton.vue';
|
||||
|
||||
import BaseDropdown from './BaseDropdown.vue';
|
||||
import BaseTable from './BaseTable.vue';
|
||||
|
||||
import Card from './Cards/Card.vue';
|
||||
import StatsCard from './Cards/StatsCard.vue';
|
||||
import BaseNav from './Navbar/BaseNav';
|
||||
import NavbarToggleButton from './Navbar/NavbarToggleButton';
|
||||
|
||||
import Breadcrumb from './Breadcrumb/Breadcrumb.vue';
|
||||
import BreadcrumbItem from './Breadcrumb/BreadcrumbItem.vue';
|
||||
import RouteBreadCrumb from './Breadcrumb/RouteBreadcrumb.vue';
|
||||
import TimeLine from './Timeline/TimeLine.vue';
|
||||
import TimeLineItem from './Timeline/TimeLineItem.vue';
|
||||
import TabPane from './Tabs/Tab.vue';
|
||||
import Tabs from './Tabs/Tabs.vue';
|
||||
import Collapse from './Collapse/Collapse.vue';
|
||||
import CollapseItem from './Collapse/CollapseItem.vue';
|
||||
import Modal from './Modal.vue';
|
||||
import BaseSlider from './BaseSlider.vue';
|
||||
import LoadingPanel from './LoadingPanel.vue';
|
||||
import AsyncWorldMap from './WorldMap/AsyncWorldMap.vue';
|
||||
|
||||
import BasePagination from './BasePagination.vue';
|
||||
|
||||
import SidebarPlugin from './SidebarPlugin';
|
||||
|
||||
export {
|
||||
BaseCheckbox,
|
||||
IconCheckbox,
|
||||
BaseSwitch,
|
||||
Badge,
|
||||
BaseAlert,
|
||||
BaseProgress,
|
||||
BasePagination,
|
||||
BaseRadio,
|
||||
BaseInput,
|
||||
TagsInput,
|
||||
Card,
|
||||
StatsCard,
|
||||
BaseTable,
|
||||
BaseDropdown,
|
||||
SidebarPlugin,
|
||||
BaseNav,
|
||||
NavbarToggleButton,
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
RouteBreadCrumb,
|
||||
TimeLine,
|
||||
TimeLineItem,
|
||||
TabPane,
|
||||
Tabs,
|
||||
Modal,
|
||||
BaseSlider,
|
||||
BaseButton,
|
||||
Collapse,
|
||||
CollapseItem,
|
||||
LoadingPanel,
|
||||
AsyncWorldMap
|
||||
};
|
19
resources/assets/js/install.js
vendored
19
resources/assets/js/install.js
vendored
@ -17,6 +17,9 @@ import Language from './views/install/Language';
|
||||
import Database from './views/install/Database';
|
||||
import Settings from './views/install/Settings';
|
||||
|
||||
import Swiper, { Navigation, Pagination, Autoplay } from 'swiper';
|
||||
Swiper.use([Navigation, Pagination, Autoplay]);
|
||||
|
||||
var global_path = new URL(url).protocol + '//' + window.location.host;
|
||||
var base_path = url.replace(global_path, '');
|
||||
|
||||
@ -68,5 +71,19 @@ const router = new VueRouter({
|
||||
new Vue({
|
||||
el : '#app',
|
||||
render: h => h(Install),
|
||||
router
|
||||
router,
|
||||
mounted() {
|
||||
new Swiper(".swiper-container", {
|
||||
loop: true,
|
||||
speed: 1000,
|
||||
allowTouchMove: true,
|
||||
autoplay: {
|
||||
delay: 3000,
|
||||
},
|
||||
pagination: {
|
||||
el: ".swiper-pagination",
|
||||
clickable: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
232
resources/assets/js/mixins/global.js
vendored
232
resources/assets/js/mixins/global.js
vendored
@ -7,11 +7,12 @@ import AkauntingContactCard from './../components/AkauntingContactCard';
|
||||
import AkauntingCompanyEdit from './../components/AkauntingCompanyEdit';
|
||||
import AkauntingEditItemColumns from './../components/AkauntingEditItemColumns';
|
||||
import AkauntingItemButton from './../components/AkauntingItemButton';
|
||||
import AkauntingDocumentButton from './../components/AkauntingDocumentButton';
|
||||
import AkauntingSearch from './../components/AkauntingSearch';
|
||||
import AkauntingModal from './../components/AkauntingModal';
|
||||
import AkauntingMoney from './../components/AkauntingMoney';
|
||||
import AkauntingModalAddNew from './../components/AkauntingModalAddNew';
|
||||
import AkauntingRadioGroup from './../components/forms/AkauntingRadioGroup';
|
||||
import AkauntingRadioGroup from './../components/AkauntingRadioGroup';
|
||||
import AkauntingSelect from './../components/AkauntingSelect';
|
||||
import AkauntingSelectRemote from './../components/AkauntingSelectRemote';
|
||||
import AkauntingDate from './../components/AkauntingDate';
|
||||
@ -19,6 +20,10 @@ import AkauntingRecurring from './../components/AkauntingRecurring';
|
||||
import AkauntingHtmlEditor from './../components/AkauntingHtmlEditor';
|
||||
import AkauntingCountdown from './../components/AkauntingCountdown';
|
||||
import AkauntingCurrencyConversion from './../components/AkauntingCurrencyConversion';
|
||||
import AkauntingConnectTransactions from './../components/AkauntingConnectTransactions';
|
||||
import AkauntingSwitch from './../components/AkauntingSwitch';
|
||||
import AkauntingSlider from './../components/AkauntingSlider';
|
||||
import AkauntingColor from './../components/AkauntingColor';
|
||||
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
@ -27,6 +32,10 @@ import NProgressAxios from './../plugins/nprogress-axios';
|
||||
import { Select, Option, Steps, Step, Button, Link, Tooltip, ColorPicker } from 'element-ui';
|
||||
|
||||
import Form from './../plugins/form';
|
||||
import Swiper, { Navigation, Pagination } from 'swiper';
|
||||
import GLightbox from 'glightbox';
|
||||
|
||||
Swiper.use([Navigation, Pagination]);
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -35,6 +44,7 @@ export default {
|
||||
AkauntingCompanyEdit,
|
||||
AkauntingEditItemColumns,
|
||||
AkauntingItemButton,
|
||||
AkauntingDocumentButton,
|
||||
AkauntingSearch,
|
||||
AkauntingRadioGroup,
|
||||
AkauntingSelect,
|
||||
@ -47,6 +57,10 @@ export default {
|
||||
AkauntingHtmlEditor,
|
||||
AkauntingCountdown,
|
||||
AkauntingCurrencyConversion,
|
||||
AkauntingConnectTransactions,
|
||||
AkauntingSwitch,
|
||||
AkauntingSlider,
|
||||
AkauntingColor,
|
||||
[Select.name]: Select,
|
||||
[Option.name]: Option,
|
||||
[Steps.name]: Steps,
|
||||
@ -71,6 +85,7 @@ export default {
|
||||
"thousands_separator":",",
|
||||
},
|
||||
all_currencies: [],
|
||||
content_loading: true
|
||||
}
|
||||
},
|
||||
|
||||
@ -79,8 +94,32 @@ export default {
|
||||
},
|
||||
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
this.content_loading = false;
|
||||
}, 1500);
|
||||
|
||||
this.checkNotify();
|
||||
|
||||
GLightbox({
|
||||
touchNavigation: true,
|
||||
loop: false,
|
||||
autoplayVideos: false,
|
||||
selector: ".glightbox-video",
|
||||
plyr: {
|
||||
config: {
|
||||
ratio: '16:9', // or '4:3'
|
||||
muted: false,
|
||||
hideControls: true,
|
||||
youtube: {
|
||||
noCookie: true,
|
||||
rel: 0,
|
||||
showinfo: 0,
|
||||
iv_load_policy: 3
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (aka_currency) {
|
||||
this.currency = aka_currency;
|
||||
}
|
||||
@ -88,12 +127,32 @@ export default {
|
||||
if (typeof all_currencies !== 'undefined' && all_currencies) {
|
||||
this.all_currencies = all_currencies;
|
||||
}
|
||||
|
||||
GLightbox({
|
||||
touchNavigation: true,
|
||||
loop: false,
|
||||
autoplayVideos: false,
|
||||
selector: ".glightbox"
|
||||
});
|
||||
|
||||
new Swiper(".swiper-container", {
|
||||
loop: false,
|
||||
slidesPerView: 2,
|
||||
pagination: {
|
||||
el: ".swiper-pagination",
|
||||
clickable: true
|
||||
},
|
||||
navigation: {
|
||||
nextEl: ".swiper-button-next",
|
||||
prevEl: ".swiper-button-prev",
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
// Check Default set notify > store / update action
|
||||
checkNotify: function () {
|
||||
if (!flash_notification) {
|
||||
if (! flash_notification) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -108,7 +167,7 @@ export default {
|
||||
this.$notify({
|
||||
message: notify.message,
|
||||
timeout: timeout,
|
||||
icon: 'fas fa-bell',
|
||||
icon: 'error_outline',
|
||||
type
|
||||
});
|
||||
});
|
||||
@ -130,42 +189,58 @@ export default {
|
||||
},
|
||||
|
||||
// Bulk Action Select all
|
||||
onSelectAll() {
|
||||
onSelectAllBulkAction() {
|
||||
this.bulk_action.selectAll();
|
||||
},
|
||||
|
||||
// Bulk Action Select checked/ unchecked
|
||||
onSelect() {
|
||||
// Bulk Action Checkbox checked/ unchecked
|
||||
onSelectBulkAction() {
|
||||
this.bulk_action.select();
|
||||
},
|
||||
|
||||
// Bulk Action use selected Change
|
||||
onChange(event) {
|
||||
var result = this.bulk_action.change(event);
|
||||
onChangeBulkAction(type) {
|
||||
this.bulk_action.change(type);
|
||||
|
||||
if (this.bulk_action.message.length) {
|
||||
this.bulk_action.modal=true;
|
||||
} else {
|
||||
this.onActionBulkAction();
|
||||
}
|
||||
},
|
||||
|
||||
// Bulk Action use selected Action
|
||||
onAction() {
|
||||
onActionBulkAction() {
|
||||
this.bulk_action.action();
|
||||
},
|
||||
|
||||
// Bulk Action modal cancel
|
||||
onCancel() {
|
||||
onCancelBulkAction() {
|
||||
this.bulk_action.modal = false;
|
||||
},
|
||||
|
||||
// Bulk Action Clear selected items
|
||||
onClear() {
|
||||
onClearBulkAction() {
|
||||
this.bulk_action.modal = false;
|
||||
|
||||
this.bulk_action.clear();
|
||||
},
|
||||
|
||||
// List Enabled column status changes
|
||||
onStatus(item_id, event) {
|
||||
onStatusBulkAction(item_id, event) {
|
||||
this.bulk_action.status(item_id, event, this.$notify);
|
||||
},
|
||||
|
||||
onDeleteViaConfirmation(delete_id) {
|
||||
let action = document.getElementById(delete_id).getAttribute('data-action');
|
||||
let title = document.getElementById(delete_id).getAttribute('data-title');
|
||||
let message = document.getElementById(delete_id).getAttribute('data-message');
|
||||
let button_cancel = document.getElementById(delete_id).getAttribute('data-cancel');
|
||||
let button_delete = document.getElementById(delete_id).getAttribute('data-delete');
|
||||
|
||||
this.confirmDelete(action, title, message, button_cancel, button_delete);
|
||||
},
|
||||
|
||||
// Actions > Delete
|
||||
confirmDelete(url, title, message, button_cancel, button_delete) {
|
||||
let confirm = {
|
||||
@ -222,7 +297,7 @@ export default {
|
||||
|
||||
// Change bank account get money and currency rate
|
||||
onChangeAccount(account_id) {
|
||||
if (!account_id) {
|
||||
if (! account_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -230,7 +305,7 @@ export default {
|
||||
params: {
|
||||
account_id: account_id
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
this.currency = response.data;
|
||||
|
||||
@ -243,31 +318,40 @@ export default {
|
||||
|
||||
// Change currency get money
|
||||
onChangeCurrency(currency_code) {
|
||||
if (!currency_code) {
|
||||
if (! currency_code) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.all_currencies.length) {
|
||||
if (! this.all_currencies.length) {
|
||||
let currency_promise = Promise.resolve(window.axios.get((url + '/settings/currencies')));
|
||||
|
||||
currency_promise.then(response => {
|
||||
if ( response.data.success) {
|
||||
if (response.data.success) {
|
||||
this.all_currencies = response.data.data;
|
||||
}
|
||||
|
||||
this.all_currencies.forEach(function (currency, index) {
|
||||
if (currency_code == currency.code) {
|
||||
this.currency = currency;
|
||||
|
||||
this.form.currency_code = currency.code;
|
||||
this.form.currency_rate = currency.rate;
|
||||
}
|
||||
}, this);
|
||||
})
|
||||
.catch(error => {
|
||||
this.onChangeCurrency(currency_code);
|
||||
});
|
||||
} else {
|
||||
this.all_currencies.forEach(function (currency, index) {
|
||||
if (currency_code == currency.code) {
|
||||
this.currency = currency;
|
||||
|
||||
this.form.currency_code = currency.code;
|
||||
this.form.currency_rate = currency.rate;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
this.all_currencies.forEach(function (currency, index) {
|
||||
if (currency_code == currency.code) {
|
||||
this.currency = currency;
|
||||
|
||||
this.form.currency_code = currency.code;
|
||||
this.form.currency_rate = currency.rate;
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
// Pages limit change
|
||||
@ -294,25 +378,24 @@ export default {
|
||||
}
|
||||
|
||||
if (query_partials[0] == 'limit') {
|
||||
path += 'limit=' + event.target.value;
|
||||
path += 'limit=' + event.target.getAttribute("value");
|
||||
} else {
|
||||
path += query_partials[0] + '=' + query_partials[1];
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
path = window.location.href + '&limit=' + event.target.value;
|
||||
path = window.location.href + '&limit=' + event.target.getAttribute("value");
|
||||
}
|
||||
} else {
|
||||
path = window.location.href + '?limit=' + event.target.value;
|
||||
path = window.location.href + '?limit=' + event.target.getAttribute("value");
|
||||
}
|
||||
|
||||
window.location.href = path;
|
||||
},
|
||||
|
||||
// Dynamic component get path view and show it.
|
||||
onDynamicComponent(path)
|
||||
{
|
||||
onDynamicComponent(path) {
|
||||
axios.get(path)
|
||||
.then(response => {
|
||||
let html = response.data.html;
|
||||
@ -487,5 +570,92 @@ export default {
|
||||
|
||||
this.onChangeCurrency(currency_code);
|
||||
},
|
||||
|
||||
onShareLink(url) {
|
||||
let share = {
|
||||
modal: false,
|
||||
url: url,
|
||||
title: '',
|
||||
html: '',
|
||||
buttons:{}
|
||||
};
|
||||
|
||||
let share_promise = Promise.resolve(window.axios.get(share.url));
|
||||
|
||||
share_promise.then(response => {
|
||||
share.modal = true;
|
||||
share.title = response.data.data.title;
|
||||
share.success_message = response.data.data.success_message;
|
||||
share.html = response.data.html;
|
||||
share.buttons = response.data.data.buttons;
|
||||
|
||||
this.component = Vue.component('add-new-component', (resolve, reject) => {
|
||||
resolve({
|
||||
template: '<div id="dynamic-share-component"><akaunting-modal-add-new modal-dialog-class="max-w-screen-md" :show="share.modal" @submit="onCopyLink" @cancel="onCancel" :buttons="share.buttons" :is_component=true :title="share.title" :message="share.html"></akaunting-modal-add-new></div>',
|
||||
|
||||
components: {
|
||||
AkauntingModalAddNew,
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
share: share,
|
||||
form: {},
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onCopyLink(event) {
|
||||
let type = 'success';
|
||||
let copyText = document.querySelector('#dynamic-share-component #hidden-share');
|
||||
copyText.select();
|
||||
document.execCommand("copy");
|
||||
|
||||
this.$notify({
|
||||
message: this.share.success_message,
|
||||
timeout: 5000,
|
||||
icon: 'error_outline',
|
||||
type
|
||||
});
|
||||
|
||||
this.onCancel();
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.share.modal = false;
|
||||
this.share.html = null;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove("modal-open");
|
||||
},
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
},
|
||||
|
||||
onCopyLink() {
|
||||
let copy_html = document.getElementById('share');
|
||||
let copy_badge = document.querySelector('[data-copied]');
|
||||
|
||||
copy_html.select();
|
||||
document.execCommand('copy');
|
||||
|
||||
copy_badge.classList.remove('hidden');
|
||||
copy_badge.classList.add('flex');
|
||||
copy_html.classList.add('hidden');
|
||||
|
||||
setTimeout(() => {
|
||||
copy_badge.classList.add('hidden');
|
||||
copy_badge.classList.remove('flex');
|
||||
copy_html.classList.remove('hidden');
|
||||
}, 800);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
resources/assets/js/mixins/wizardAction.js
vendored
20
resources/assets/js/mixins/wizardAction.js
vendored
@ -11,6 +11,8 @@ export default {
|
||||
enabled: 1
|
||||
},
|
||||
error_field: {},
|
||||
create_tax_text: true,
|
||||
button_loading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -62,10 +64,12 @@ export default {
|
||||
this.$notify({
|
||||
message: response.data.message,
|
||||
timeout: timeout,
|
||||
icon: "fas fa-bell",
|
||||
icon: "error_outline",
|
||||
type,
|
||||
});
|
||||
|
||||
this.button_loading = false;
|
||||
|
||||
this.onDataChange();
|
||||
},
|
||||
|
||||
@ -80,24 +84,17 @@ export default {
|
||||
this.$notify({
|
||||
message: event.message,
|
||||
timeout: timeout,
|
||||
icon: "fas fa-bell",
|
||||
icon: "",
|
||||
type,
|
||||
});
|
||||
|
||||
this.onDataChange();
|
||||
},
|
||||
|
||||
onStatusControl(status_form, status_item, event) {
|
||||
status_form.forEach((status) => {
|
||||
if (status.id == status_item) {
|
||||
status.enabled = event.target.checked;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onSubmitEvent(form_method, form_url, plus_data, form_list, form_id) {
|
||||
const formData = new FormData(this.$refs["form"]);
|
||||
const data = {};
|
||||
this.button_loading = true;
|
||||
|
||||
for (let [key, val] of formData.entries()) {
|
||||
Object.assign(data, {
|
||||
@ -154,7 +151,7 @@ export default {
|
||||
}, this);
|
||||
|
||||
this.component = "";
|
||||
document.body.classList.remove("modal-open");
|
||||
document.body.classList.remove("overflow-hidden");
|
||||
this.onDeleteItemMessage(event);
|
||||
},
|
||||
|
||||
@ -166,6 +163,7 @@ export default {
|
||||
|
||||
onFailError(error) {
|
||||
this.error_field = error.response.data.errors;
|
||||
this.button_loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
resources/assets/js/plugins/bulk-action.js
vendored
34
resources/assets/js/plugins/bulk-action.js
vendored
@ -37,8 +37,9 @@ export default class BulkAction {
|
||||
this.select_all = true;
|
||||
}
|
||||
|
||||
if (!this.count) {
|
||||
if (! this.count) {
|
||||
this.show = false;
|
||||
|
||||
this.hideSearchHTML();
|
||||
}
|
||||
}
|
||||
@ -49,7 +50,7 @@ export default class BulkAction {
|
||||
this.selected = [];
|
||||
this.hideSearchHTML();
|
||||
|
||||
if (!this.select_all) {
|
||||
if (! this.select_all) {
|
||||
this.show = true;
|
||||
|
||||
for (let input of document.querySelectorAll('[data-bulk-action]')) {
|
||||
@ -60,23 +61,23 @@ export default class BulkAction {
|
||||
this.count = this.selected.length;
|
||||
}
|
||||
|
||||
change(event) {
|
||||
this.message = event.target.options[event.target.options.selectedIndex].dataset.message;
|
||||
change(type) {
|
||||
let action = document.getElementById('button-bulk-action-' + type);
|
||||
|
||||
this.value = type;
|
||||
|
||||
this.message = action.getAttribute('data-message');
|
||||
|
||||
if (typeof(this.message) == "undefined") {
|
||||
this.message = '';
|
||||
}
|
||||
|
||||
this.path = document.getElementsByName("bulk_action_path")[0].getAttribute('value');
|
||||
|
||||
if (event.target.options[event.target.options.selectedIndex].dataset.path) {
|
||||
this.path = event.target.options[event.target.options.selectedIndex].dataset.path;
|
||||
}
|
||||
this.path = action.getAttribute('data-path');
|
||||
|
||||
this.type = '*';
|
||||
|
||||
if (event.target.options[event.target.options.selectedIndex].dataset.type) {
|
||||
this.type = event.target.options[event.target.options.selectedIndex].dataset.type;
|
||||
if (action.getAttribute('data-type')) {
|
||||
this.type = action.getAttribute('data-type');
|
||||
}
|
||||
|
||||
return this.message;
|
||||
@ -146,6 +147,7 @@ export default class BulkAction {
|
||||
|
||||
window.location.reload(false);
|
||||
});
|
||||
|
||||
break;
|
||||
default:
|
||||
let type_promise = Promise.resolve(window.axios.post(this.path, {
|
||||
@ -177,12 +179,14 @@ export default class BulkAction {
|
||||
this.show = false;
|
||||
this.select_all = false;
|
||||
this.selected = [];
|
||||
|
||||
this.hideSearchHTML();
|
||||
}
|
||||
|
||||
hideSearchHTML() {
|
||||
setInterval(() => {
|
||||
const search_box_html = document.querySelector('.js-search-box-hidden');
|
||||
|
||||
if (search_box_html) {
|
||||
search_box_html.classList.add('d-none');
|
||||
}
|
||||
@ -191,14 +195,14 @@ export default class BulkAction {
|
||||
|
||||
// Change enabled status
|
||||
status(item_id, event, notify) {
|
||||
var item = event.target;
|
||||
var status = (event.target.checked) ? 'enable' : 'disable';
|
||||
let item = event.target;
|
||||
let status = (event.target.checked) ? 'enable' : 'disable';
|
||||
|
||||
window.axios.get(this.path + '/' + item_id + '/' + status)
|
||||
.then(response => {
|
||||
var type = (response.data.success) ? 'success' : 'warning';
|
||||
let type = (response.data.success) ? 'success' : 'warning';
|
||||
|
||||
if (!response.data.success) {
|
||||
if (! response.data.success) {
|
||||
if (item.checked) {
|
||||
item.checked = false;
|
||||
} else {
|
||||
|
@ -8,8 +8,6 @@ import VeeValidate from 'vee-validate';
|
||||
import GlobalComponents from './globalComponents';
|
||||
// A plugin file where you could register global directives
|
||||
import GlobalDirectives from './globalDirectives';
|
||||
// Sidebar on the right. Used as a local plugin in DashboardLayout.vue
|
||||
import SideBar from './../components/SidebarPlugin';
|
||||
|
||||
// element ui language configuration
|
||||
import lang from 'element-ui/lib/locale/lang/en';
|
||||
@ -18,13 +16,11 @@ import locale from 'element-ui/lib/locale';
|
||||
locale.use(lang);
|
||||
|
||||
// asset imports
|
||||
import './../../sass/argon.scss';
|
||||
|
||||
export default {
|
||||
install(Vue) {
|
||||
Vue.use(GlobalComponents);
|
||||
Vue.use(GlobalDirectives);
|
||||
Vue.use(SideBar);
|
||||
Vue.use(Notifications);
|
||||
Vue.use(VeeValidate, {
|
||||
fieldsBagName: 'veeFields',
|
||||
|
21
resources/assets/js/plugins/form.js
vendored
21
resources/assets/js/plugins/form.js
vendored
@ -122,7 +122,15 @@ export default class Form {
|
||||
this[form_element.getAttribute('data-field')][name] = form_element.value;
|
||||
}
|
||||
} else {
|
||||
this[form_element.getAttribute('data-field')][name] = [];
|
||||
if (form_element.dataset.type != undefined) {
|
||||
if (form_element.dataset.type == 'multiple') {
|
||||
this[form_element.getAttribute('data-field')][name] = [];
|
||||
} else {
|
||||
this[form_element.getAttribute('data-field')][name] = '';
|
||||
}
|
||||
} else {
|
||||
this[form_element.getAttribute('data-field')][name] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -163,7 +171,16 @@ export default class Form {
|
||||
this[name] = form_element.value;
|
||||
}
|
||||
} else {
|
||||
this[name] = [];
|
||||
|
||||
if (form_element.dataset.type != undefined) {
|
||||
if (form_element.dataset.type == 'multiple') {
|
||||
this[name] = [];
|
||||
} else {
|
||||
this[name] = '';
|
||||
}
|
||||
} else {
|
||||
this[name] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
21
resources/assets/js/plugins/globalComponents.js
vendored
21
resources/assets/js/plugins/globalComponents.js
vendored
@ -1,19 +1,10 @@
|
||||
import BaseInput from './../components/Inputs/BaseInput';
|
||||
import BaseDropdown from './../components/BaseDropdown.vue';
|
||||
import Card from './../components/Cards/Card.vue';
|
||||
import Modal from './../components/Modal.vue';
|
||||
import StatsCard from './../components/Cards/StatsCard.vue';
|
||||
import BaseButton from './../components/BaseButton.vue';
|
||||
import Badge from './../components/Badge.vue';
|
||||
import RouteBreadcrumb from './../components/Breadcrumb/RouteBreadcrumb';
|
||||
import BaseCheckbox from './../components/Inputs/BaseCheckbox.vue';
|
||||
import BaseSwitch from './../components/BaseSwitch.vue';
|
||||
import BaseRadio from "./../components/Inputs/BaseRadio";
|
||||
import BaseProgress from "./../components/BaseProgress";
|
||||
import BasePagination from "./../components/BasePagination";
|
||||
import BaseAlert from "./../components/BaseAlert";
|
||||
import BaseNav from "./../components/Navbar/BaseNav";
|
||||
import BaseHeader from './../components/BaseHeader';
|
||||
import BaseAlert from './../components/BaseAlert';
|
||||
import { Input, Tooltip, Popover } from 'element-ui';
|
||||
/**
|
||||
* You can register global components here and use them as a plugin in your main Vue instance
|
||||
@ -24,19 +15,11 @@ const GlobalComponents = {
|
||||
Vue.component(Badge.name, Badge);
|
||||
Vue.component(BaseAlert.name, BaseAlert);
|
||||
Vue.component(BaseButton.name, BaseButton);
|
||||
Vue.component(BaseCheckbox.name, BaseCheckbox);
|
||||
Vue.component(BaseHeader.name, BaseHeader);
|
||||
Vue.component(Badge.name, Badge);
|
||||
Vue.component(BaseInput.name, BaseInput);
|
||||
Vue.component(BaseDropdown.name, BaseDropdown);
|
||||
Vue.component(BaseNav.name, BaseNav);
|
||||
Vue.component(BasePagination.name, BasePagination);
|
||||
Vue.component(BaseProgress.name, BaseProgress);
|
||||
Vue.component(BaseRadio.name, BaseRadio);
|
||||
Vue.component(BaseSwitch.name, BaseSwitch);
|
||||
Vue.component(Card.name, Card);
|
||||
Vue.component(Modal.name, Modal);
|
||||
Vue.component(StatsCard.name, StatsCard);
|
||||
Vue.component(RouteBreadcrumb.name, RouteBreadcrumb);
|
||||
Vue.component(Input.name, Input);
|
||||
Vue.use(Tooltip);
|
||||
Vue.use(Popover);
|
||||
|
57
resources/assets/js/plugins/selecttwo.js
vendored
57
resources/assets/js/plugins/selecttwo.js
vendored
@ -1,57 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
/*
|
||||
// Initialize the annoying-background directive.
|
||||
export const SelectTwo = {
|
||||
twoWay: true,
|
||||
bind(el, binding, vnode) {
|
||||
var variblee = this;
|
||||
var selectbox = el.getAttribute('id');
|
||||
var binding2 = binding;
|
||||
var vnode2 = vnode;
|
||||
|
||||
$(vnode.elm).select2()
|
||||
.on("select2:select", function(e) {
|
||||
//this.$set($(vnode.elm).val());
|
||||
}.bind($(vnode.elm)));
|
||||
},
|
||||
update: function(nv, ov) {
|
||||
$('#' + nv.id).trigger("change");
|
||||
}
|
||||
}
|
||||
|
||||
// You can also make it available globally.
|
||||
Vue.directive('select-two', SelectTwo);
|
||||
*/
|
||||
|
||||
|
||||
Vue.component('select2', {
|
||||
props: ['options', 'value'],
|
||||
template: '#select2-template',
|
||||
mounted: function () {
|
||||
var vm = this
|
||||
$(this.$el)
|
||||
// init select2
|
||||
.select2({ data: this.options })
|
||||
.val(this.value)
|
||||
.trigger('change')
|
||||
// emit event on change.
|
||||
.on('change', function () {
|
||||
vm.$emit('input', this.value)
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
value: function (value) {
|
||||
// update value
|
||||
$(this.$el)
|
||||
.val(value)
|
||||
.trigger('change')
|
||||
},
|
||||
options: function (options) {
|
||||
// update options
|
||||
$(this.$el).empty().select2({ data: options })
|
||||
}
|
||||
},
|
||||
destroyed: function () {
|
||||
$(this.$el).off().select2('destroy')
|
||||
}
|
||||
})
|
@ -9,24 +9,44 @@ require('./../../bootstrap');
|
||||
import Vue from 'vue';
|
||||
|
||||
import Form from './../../plugins/form';
|
||||
import Swiper, { Navigation, Pagination, Autoplay } from 'swiper';
|
||||
|
||||
const app = new Vue({
|
||||
const login = new Vue({
|
||||
el: '#app',
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
form: new Form('reset')
|
||||
form: new Form('auth'),
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
Swiper.use([Navigation, Pagination, Autoplay]);
|
||||
|
||||
new Swiper(".swiper-container", {
|
||||
loop: true,
|
||||
speed: 1000,
|
||||
allowTouchMove: true,
|
||||
autoplay: {
|
||||
delay: 3000,
|
||||
},
|
||||
pagination: {
|
||||
el: ".swiper-pagination",
|
||||
clickable: true,
|
||||
},
|
||||
});
|
||||
|
||||
this.checkNotify();
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSubmit() {
|
||||
this.form.submit();
|
||||
},
|
||||
|
||||
// Check Default set notify > store / update action
|
||||
checkNotify: function () {
|
||||
if (!flash_notification) {
|
||||
if (! flash_notification) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -36,15 +56,10 @@ const app = new Vue({
|
||||
this.$notify({
|
||||
message: notify.message,
|
||||
timeout: 5000,
|
||||
icon: 'fas fa-bell',
|
||||
icon: '',
|
||||
type
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Form Submit
|
||||
onSubmit() {
|
||||
this.form.submit();
|
||||
},
|
||||
}
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user