mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-31 13:41:09 -04:00 
			
		
		
		
	v5.0.0 update
This commit is contained in:
		| @ -1,29 +0,0 @@ | ||||
| /** | ||||
|  * First we will load all of this project's JavaScript dependencies which | ||||
|  * include Vue and Vue Resource. This gives a great starting point for | ||||
|  * building robust, powerful web applications using Vue and Laravel. | ||||
|  */ | ||||
| import Vue from 'vue' | ||||
| import router from './router.js' | ||||
| import store from './store/index' | ||||
| import utils from './helpers/utilities' | ||||
| import i18n from './plugins/i18n' | ||||
|  | ||||
| require('./bootstrap') | ||||
|  | ||||
| Vue.prototype.$utils = utils | ||||
|  | ||||
| /** | ||||
|  * Next, we will create a fresh Vue application instance and attach it to | ||||
|  * the page. Then, you may begin adding components to this application | ||||
|  * or customize the JavaScript scaffolding to fit your unique needs. | ||||
|  */ | ||||
| window.hub = new Vue() | ||||
|  | ||||
| window.i18n = i18n | ||||
|  | ||||
| new Vue({ | ||||
|   router, | ||||
|   store, | ||||
|   i18n, | ||||
| }).$mount('#app') | ||||
							
								
								
									
										172
									
								
								resources/assets/js/bootstrap.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										172
									
								
								resources/assets/js/bootstrap.js
									
									
									
									
										vendored
									
									
								
							| @ -1,172 +0,0 @@ | ||||
| import VueRouter from 'vue-router' | ||||
| import Vuex from 'vuex' | ||||
| import Ls from './services/ls' | ||||
| import store from './store/index.js' | ||||
| import Vue from 'vue' | ||||
| import Vuelidate from 'vuelidate' | ||||
| import money from 'v-money' | ||||
| import VTooltip from 'v-tooltip' | ||||
| import Transitions from 'vue2-transitions' | ||||
| import SpaceWind from '@bytefury/spacewind' | ||||
| import swal from 'vue-sweetalert2' | ||||
| import 'sweetalert2/dist/sweetalert2.min.css' | ||||
|  | ||||
| /** | ||||
|  * Theme | ||||
|  */ | ||||
| import theme from './components/theme' | ||||
|  | ||||
| /** | ||||
|  * Global css plugins | ||||
|  */ | ||||
|  | ||||
| Vue.use(SpaceWind, { theme }) | ||||
|  | ||||
| Vue.use(Vuelidate) | ||||
|  | ||||
| Vue.use(swal, { | ||||
|   customClass: { | ||||
|     container: | ||||
|       'fixed z-50 inset-0 overflow-y-auto bg-black bg-opacity-25 flex justify-center min-h-screen items-center sm:p-0 swal2-container', | ||||
|     popup: | ||||
|       'flex items-center flex-col justify-center align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6', | ||||
|     header: 'swal2-header', | ||||
|     title: 'swal2-title', | ||||
|     closeButton: '', | ||||
|     icon: 'swal2-icon', | ||||
|     image: '', | ||||
|     content: 'swal2-content', | ||||
|     input: '', | ||||
|     inputLabel: '', | ||||
|     validationMessage: '', | ||||
|     actions: 'swal2-actions', | ||||
|     confirmButton: | ||||
|       'w-full inline-flex py-2 px-4 text-sm leading-5 rounded items-center justify-center text-white font-normal transition duration-150 ease-in-out border border-transparent focus:outline-none bg-primary-500 hover:bg-opacity-75 whitespace-nowrap', | ||||
|     denyButton: '', | ||||
|     cancelButton: | ||||
|       'w-full inline-flex py-2 px-4 text-sm leading-5 rounded justify-center items-center focus:outline-none font-normal transition ease-in-out duration-150 border border-transparent border border-solid border-primary-500 text-primary-500 hover:bg-primary-200 shadow-inner whitespace-nowrap', | ||||
|     loader: '', | ||||
|     footer: '', | ||||
|   }, | ||||
|   buttonsStyling: false, | ||||
| }) | ||||
|  | ||||
| Vue.use(Transitions) | ||||
|  | ||||
| window._ = require('lodash') | ||||
|  | ||||
| /** | ||||
|  * Custom Directives | ||||
|  */ | ||||
| require('./helpers/directives') | ||||
|  | ||||
| /** | ||||
|  * Base Components | ||||
|  */ | ||||
| require('./components/base') | ||||
|  | ||||
| /** | ||||
|  * We'll register a HTTP interceptor to attach the "CSRF" header to each of | ||||
|  * the outgoing requests issued by this application. The CSRF middleware | ||||
|  * included with Laravel will automatically verify the header's value. | ||||
|  */ | ||||
|  | ||||
| window.axios = require('axios') | ||||
| window.axios.defaults.withCredentials = true | ||||
| window.Ls = Ls | ||||
|  | ||||
| window.axios.defaults.headers.common = { | ||||
|   'X-Requested-With': 'XMLHttpRequest', | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Interceptors | ||||
|  */ | ||||
|  | ||||
| window.axios.interceptors.request.use( | ||||
|   function (config) { | ||||
|     if (store.getters['auth/isLoggedOut']) { | ||||
|       let source = window.axios.CancelToken.source() | ||||
|       config.cancelToken = source.token | ||||
|       setTimeout(() => { | ||||
|         store.dispatch('auth/setLogoutFalse') | ||||
|       }, 200) | ||||
|  | ||||
|       return config | ||||
|     } | ||||
|     // Do something before request is sent | ||||
|     const companyId = Ls.get('selectedCompany') | ||||
|  | ||||
|     if (companyId) { | ||||
|       config.headers.common['company'] = companyId | ||||
|     } | ||||
|  | ||||
|     return config | ||||
|   }, | ||||
|   function (error) { | ||||
|     // Do something with request error | ||||
|     return Promise.reject(error) | ||||
|   } | ||||
| ) | ||||
|  | ||||
| /** | ||||
|  * Global Axios Response Interceptor | ||||
|  */ | ||||
| global.axios.interceptors.response.use(undefined, function (err) { | ||||
|   // Do something with request error | ||||
|   if (store.getters['auth/isLoggedOut']) { | ||||
|     return true | ||||
|   } | ||||
|   if (!err.response) { | ||||
|     store.dispatch('notification/showNotification', { | ||||
|       type: 'error', | ||||
|       message: | ||||
|         'Please check your internet connection or wait until servers are back online.', | ||||
|     }) | ||||
|   } else { | ||||
|     if ( | ||||
|       err.response.data && | ||||
|       err.config.url !== '/api/v1/auth/check' && | ||||
|       (err.response.statusText === 'Unauthorized' || | ||||
|         err.response.data === ' Unauthorized.') | ||||
|     ) { | ||||
|       console.log(err.response) | ||||
|       // Unauthorized and log out | ||||
|       store.dispatch('notification/showNotification', { | ||||
|         type: 'error', | ||||
|         message: err.response.data.message | ||||
|           ? err.response.data.message | ||||
|           : 'Unauthorized', | ||||
|       }) | ||||
|       store.dispatch('auth/logout', true) | ||||
|     } else if (err.response.data.errors) { | ||||
|       // Show a notification per error | ||||
|       const errors = JSON.parse(JSON.stringify(err.response.data.errors)) | ||||
|       for (const i in errors) { | ||||
|         store.dispatch('notification/showNotification', { | ||||
|           type: 'error', | ||||
|           message: errors[i], | ||||
|         }) | ||||
|       } | ||||
|     } else { | ||||
|       // Unknown error | ||||
|       store.dispatch('notification/showNotification', { | ||||
|         type: 'error', | ||||
|         message: err.response.data.message | ||||
|           ? err.response.data.message | ||||
|           : err.response.data || 'Unknown error occurred', | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
|   return Promise.reject(err) | ||||
| }) | ||||
|  | ||||
| /** | ||||
|  * Global plugins | ||||
|  */ | ||||
| Vue.use(VueRouter) | ||||
| Vue.use(Vuex) | ||||
| Vue.use(VTooltip) | ||||
|  | ||||
| // register directive v-money and component <money> | ||||
| Vue.use(money, { precision: 2 }) | ||||
| @ -1,157 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-dropdown :is-show="isShow" variant="search-dropdown"> | ||||
|       <sw-input | ||||
|         slot="activator" | ||||
|         v-model="name" | ||||
|         :placeholder="$t('global_search.search')" | ||||
|         variant="search-input" | ||||
|         @input="throttledMethod" | ||||
|       > | ||||
|         <search-icon slot="leftIcon" class="h-5 m-1 text-gray-500" /> | ||||
|         <loading-icon | ||||
|           slot="rightIcon" | ||||
|           v-show="isLoading" | ||||
|           class="absolute right-0 h-5 m-1 animate-spin text-primary-400" | ||||
|         /> | ||||
|       </sw-input> | ||||
|  | ||||
|       <div class="w-64 h-40 overflow-y-scroll box"> | ||||
|         <div v-if="getCustomerList.length > 0 && !isLoading"> | ||||
|           <label class="text-xs text-gray-400 uppercase"> | ||||
|             {{ $t('global_search.customers') }} | ||||
|           </label> | ||||
|           <router-link | ||||
|             v-for="d in getCustomerList" | ||||
|             :key="d.id" | ||||
|             :to="`/admin/customers/${d.id}/view`" | ||||
|           > | ||||
|             <sw-dropdown-item> | ||||
|               <span | ||||
|                 class="flex items-center justify-center w-8 h-8 mr-4 text-xs font-semibold bg-gray-300 rounded-full text-primary-500" | ||||
|               > | ||||
|                 {{ initGenerator(d.name) }} | ||||
|               </span> | ||||
|  | ||||
|               <div v-if="d.contact_name" class="flex flex-col"> | ||||
|                 <span class="text-sm text-black">{{ d.name }}</span> | ||||
|  | ||||
|                 <span class="text-xs text-gray-500">{{ d.contact_name }}</span> | ||||
|               </div> | ||||
|               <div v-else class="flex items-center"> | ||||
|                 <span class="text-sm text-black">{{ d.name }}</span> | ||||
|               </div> | ||||
|             </sw-dropdown-item> | ||||
|           </router-link> | ||||
|         </div> | ||||
|  | ||||
|         <div v-if="getUserList.length > 0 && !isLoading"> | ||||
|           <label class="text-xs text-gray-400 uppercase">{{ | ||||
|             $t('global_search.users') | ||||
|           }}</label> | ||||
|           <router-link | ||||
|             v-for="d in getUserList" | ||||
|             :key="d.id" | ||||
|             :to="`/admin/users/${d.id}/edit`" | ||||
|           > | ||||
|             <sw-dropdown-item> | ||||
|               <span | ||||
|                 class="flex items-center justify-center w-8 h-8 mr-4 text-xs font-semibold bg-gray-300 rounded-full text-primary-500" | ||||
|               > | ||||
|                 {{ initGenerator(d.name) }} | ||||
|               </span> | ||||
|  | ||||
|               <div class="flex items-center"> | ||||
|                 <span class="text-sm text-black">{{ d.name }}</span> | ||||
|               </div> | ||||
|             </sw-dropdown-item> | ||||
|           </router-link> | ||||
|         </div> | ||||
|  | ||||
|         <div | ||||
|           v-if=" | ||||
|             getUserList.length === 0 && | ||||
|             getCustomerList.length === 0 && | ||||
|             !isLoading | ||||
|           " | ||||
|         > | ||||
|           <span | ||||
|             class="flex items-center justify-center text-sm font-normal text-gray-500" | ||||
|           > | ||||
|             {{ $t('global_search.no_results_found') }} | ||||
|           </span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </sw-dropdown> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { SearchIcon } from '@vue-hero-icons/solid' | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import LoadingIcon from '../components/icon/LoadingIcon' | ||||
| import _ from 'lodash' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     SearchIcon, | ||||
|     LoadingIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       isShow: false, | ||||
|       isLoading: false, | ||||
|       name: '', | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('search', ['getCustomerList', 'getUserList']), | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.searchUsers() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('search', ['searchUsers']), | ||||
|  | ||||
|     throttledMethod: _.debounce(async function () { | ||||
|       this.isLoading = true | ||||
|       await this.searchUsers({ search: this.name }).then(() => { | ||||
|         this.isShow = true | ||||
|       }) | ||||
|       if (this.name === '') { | ||||
|         this.isShow = false | ||||
|       } | ||||
|       this.isLoading = false | ||||
|     }, 500), | ||||
|  | ||||
|     initGenerator(name) { | ||||
|       if (name) { | ||||
|         let nameSplit = name.split('') | ||||
|         let initials = | ||||
|           nameSplit[0].charAt(0).toUpperCase() + | ||||
|           nameSplit[1].charAt(0).toUpperCase() | ||||
|         return initials | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .box::-webkit-scrollbar { | ||||
|   width: 4px; | ||||
| } | ||||
|  | ||||
| .box::-webkit-scrollbar-thumb { | ||||
|   background-color: transparent; | ||||
|   outline: 1px solid white; | ||||
|   border-radius: 0.42rem !important; | ||||
| } | ||||
|  | ||||
| .box::-webkit-scrollbar-thumb { | ||||
|   background-color: #e4e6ef; | ||||
| } | ||||
| </style> | ||||
| @ -1,302 +0,0 @@ | ||||
| <template> | ||||
|   <div class="relative"> | ||||
|     <div class="absolute bottom-0 right-0 z-10"> | ||||
|       <sw-dropdown | ||||
|         :close-on-select="true" | ||||
|         max-height="220" | ||||
|         position="bottom-end" | ||||
|         class="mb-2" | ||||
|       > | ||||
|         <sw-button | ||||
|           slot="activator" | ||||
|           variant="primary-outline" | ||||
|           type="button" | ||||
|           class="mr-2" | ||||
|         > | ||||
|           <plus-sm-icon class="h-5 mr-1 -ml-2" /> | ||||
|           {{ $t('settings.customization.addresses.insert_fields') }} | ||||
|         </sw-button> | ||||
|         <div class="flex p-2"> | ||||
|           <ul v-for="(type, index) in fieldList" :key="index" class="list-none"> | ||||
|             <li class="mb-1 ml-2 text-xs font-semibold text-gray-500 uppercase"> | ||||
|               {{ type.label }} | ||||
|             </li> | ||||
|             <li | ||||
|               v-for="(field, index) in type.fields" | ||||
|               :key="index" | ||||
|               class="w-48 text-sm font-normal cursor-pointer hover:bg-gray-200" | ||||
|               @click="insertField(field.value)" | ||||
|             > | ||||
|               <div class="flex"> | ||||
|                 <chevron-double-right-icon class="h-3 mt-1 text-gray-400" />{{ | ||||
|                   field.label | ||||
|                 }} | ||||
|               </div> | ||||
|             </li> | ||||
|           </ul> | ||||
|         </div> | ||||
|       </sw-dropdown> | ||||
|     </div> | ||||
|     <sw-editor | ||||
|       v-model="inputValue" | ||||
|       :set-editor="inputValue" | ||||
|       :disabled="disabled" | ||||
|       :invalid="isFieldValid" | ||||
|       :placeholder="placeholder" | ||||
|       variant="header-editor" | ||||
|       input-class="border-none" | ||||
|       class="text-area-field" | ||||
|       @input="handleInput" | ||||
|       @change="handleChange" | ||||
|       @keyup="handleKeyupEnter" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { PlusSmIcon } from '@vue-hero-icons/outline' | ||||
| import { ChevronDoubleRightIcon } from '@vue-hero-icons/solid' | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import customFields from '../../mixins/customFields' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     PlusSmIcon, | ||||
|     ChevronDoubleRightIcon, | ||||
|   }, | ||||
|   props: { | ||||
|     value: { | ||||
|       type: [String, Number, File], | ||||
|       default: '', | ||||
|     }, | ||||
|     types: { | ||||
|       type: Array, | ||||
|       default: null, | ||||
|     }, | ||||
|     placeholder: { | ||||
|       type: String, | ||||
|       default: '', | ||||
|     }, | ||||
|     rows: { | ||||
|       type: String, | ||||
|       default: '10', | ||||
|     }, | ||||
|     cols: { | ||||
|       type: String, | ||||
|       default: '30', | ||||
|     }, | ||||
|     invalid: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     fields: { | ||||
|       type: Array, | ||||
|       default: null, | ||||
|     }, | ||||
|     disabled: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       fieldList: [], | ||||
|       invoiceFields: [], | ||||
|       estimateFields: [], | ||||
|       paymentFields: [], | ||||
|       customerFields: [], | ||||
|       position: null, | ||||
|       inputValue: this.value, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('customFields', ['getCustomFields']), | ||||
|     isFieldValid() { | ||||
|       return this.invalid | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     value() { | ||||
|       this.inputValue = this.value | ||||
|     }, | ||||
|     fields() { | ||||
|       if (this.fields && this.fields.length > 0) { | ||||
|         this.getFields() | ||||
|       } | ||||
|     }, | ||||
|     getCustomFields(newValue) { | ||||
|       this.invoiceFields = newValue | ||||
|         ? newValue.filter((field) => field.model_type === 'Invoice') | ||||
|         : [] | ||||
|       this.customerFields = newValue | ||||
|         ? newValue.filter((field) => field.model_type === 'Customer') | ||||
|         : [] | ||||
|       this.paymentFields = newValue | ||||
|         ? newValue.filter((field) => field.model_type === 'Payment') | ||||
|         : [] | ||||
|       this.estimateFields = newValue.filter( | ||||
|         (field) => field.model_type === 'Estimate' | ||||
|       ) | ||||
|       this.getFields() | ||||
|     }, | ||||
|   }, | ||||
|   async mounted() { | ||||
|     this.getFields() | ||||
|     await this.fetchNoteCustomFields({ limit: 'all' }) | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('customFields', ['fetchNoteCustomFields']), | ||||
|  | ||||
|     getFields() { | ||||
|       this.fieldList = [] | ||||
|  | ||||
|       if (this.fields && this.fields.length > 0) { | ||||
|         if (this.fields.find((field) => field == 'shipping')) { | ||||
|           this.fieldList.push({ | ||||
|             label: 'Shipping Address', | ||||
|             fields: [ | ||||
|               { label: 'Address name', value: 'SHIPPING_ADDRESS_NAME' }, | ||||
|               { label: 'Country', value: 'SHIPPING_COUNTRY' }, | ||||
|               { label: 'State', value: 'SHIPPING_STATE' }, | ||||
|               { label: 'City', value: 'SHIPPING_CITY' }, | ||||
|               { label: 'Address Street 1', value: 'SHIPPING_ADDRESS_STREET_1' }, | ||||
|               { label: 'Address Street 2', value: 'SHIPPING_ADDRESS_STREET_2' }, | ||||
|               { label: 'Phone', value: 'SHIPPING_PHONE' }, | ||||
|               { label: 'Zip Code', value: 'SHIPPING_ZIP_CODE' }, | ||||
|             ], | ||||
|           }) | ||||
|         } | ||||
|  | ||||
|         if (this.fields.find((field) => field == 'billing')) { | ||||
|           this.fieldList.push({ | ||||
|             label: 'Billing Address', | ||||
|             fields: [ | ||||
|               { label: 'Address name', value: 'BILLING_ADDRESS_NAME' }, | ||||
|               { label: 'Country', value: 'BILLING_COUNTRY' }, | ||||
|               { label: 'State', value: 'BILLING_STATE' }, | ||||
|               { label: 'City', value: 'BILLING_CITY' }, | ||||
|               { label: 'Address Street 1', value: 'BILLING_ADDRESS_STREET_1' }, | ||||
|               { label: 'Address Street 2', value: 'BILLING_ADDRESS_STREET_2' }, | ||||
|               { label: 'Phone', value: 'BILLING_PHONE' }, | ||||
|               { label: 'Zip Code', value: 'BILLING_ZIP_CODE' }, | ||||
|             ], | ||||
|           }) | ||||
|         } | ||||
|  | ||||
|         if (this.fields.find((field) => field == 'customer')) { | ||||
|           this.fieldList.push({ | ||||
|             label: 'Customer', | ||||
|             fields: [ | ||||
|               { label: 'Display Name', value: 'CONTACT_DISPLAY_NAME' }, | ||||
|               { label: 'Contact Name', value: 'PRIMARY_CONTACT_NAME' }, | ||||
|               { label: 'Email', value: 'CONTACT_EMAIL' }, | ||||
|               { label: 'Phone', value: 'CONTACT_PHONE' }, | ||||
|               { label: 'Website', value: 'CONTACT_WEBSITE' }, | ||||
|               ...this.customerFields.map((i) => ({ | ||||
|                 label: i.label, | ||||
|                 value: i.slug, | ||||
|               })), | ||||
|             ], | ||||
|           }) | ||||
|         } | ||||
|  | ||||
|         if (this.fields.find((field) => field == 'invoice')) { | ||||
|           this.fieldList.push({ | ||||
|             label: 'Invoice', | ||||
|             fields: [ | ||||
|               { label: 'Date', value: 'INVOICE_DATE' }, | ||||
|               { label: 'Due Date', value: 'INVOICE_DUE_DATE' }, | ||||
|               { label: 'Number', value: 'INVOICE_NUMBER' }, | ||||
|               { label: 'Ref Number', value: 'INVOICE_REF_NUMBER' }, | ||||
|               { label: 'Invoice Link', value: 'INVOICE_LINK' }, | ||||
|               ...this.invoiceFields.map((i) => ({ | ||||
|                 label: i.label, | ||||
|                 value: i.slug, | ||||
|               })), | ||||
|             ], | ||||
|           }) | ||||
|         } | ||||
|  | ||||
|         if (this.fields.find((field) => field == 'estimate')) { | ||||
|           this.fieldList.push({ | ||||
|             label: 'Estimate', | ||||
|             fields: [ | ||||
|               { label: 'Date', value: 'ESTIMATE_DATE' }, | ||||
|               { label: 'Expiry Date', value: 'ESTIMATE_EXPIRY_DATE' }, | ||||
|               { label: 'Number', value: 'ESTIMATE_NUMBER' }, | ||||
|               { label: 'Ref Number', value: 'ESTIMATE_REF_NUMBER' }, | ||||
|               { label: 'Estimate Link', value: 'ESTIMATE_LINK' }, | ||||
|               ...this.estimateFields.map((i) => ({ | ||||
|                 label: i.label, | ||||
|                 value: i.slug, | ||||
|               })), | ||||
|             ], | ||||
|           }) | ||||
|         } | ||||
|  | ||||
|         if (this.fields.find((field) => field == 'payment')) { | ||||
|           this.fieldList.push({ | ||||
|             label: 'Payment', | ||||
|             fields: [ | ||||
|               { label: 'Date', value: 'PAYMENT_DATE' }, | ||||
|               { label: 'Number', value: 'PAYMENT_NUMBER' }, | ||||
|               { label: 'Mode', value: 'PAYMENT_MODE' }, | ||||
|               { label: 'Amount', value: 'PAYMENT_AMOUNT' }, | ||||
|               { label: 'Payment Link', value: 'PAYMENT_LINK' }, | ||||
|               ...this.paymentFields.map((i) => ({ | ||||
|                 label: i.label, | ||||
|                 value: i.slug, | ||||
|               })), | ||||
|             ], | ||||
|           }) | ||||
|         } | ||||
|  | ||||
|         if (this.fields.find((field) => field == 'company')) { | ||||
|           this.fieldList.push({ | ||||
|             label: 'Company', | ||||
|             fields: [ | ||||
|               { label: 'Company Name', value: 'COMPANY_NAME' }, | ||||
|               { label: 'Country', value: 'COMPANY_COUNTRY' }, | ||||
|               { label: 'State', value: 'COMPANY_STATE' }, | ||||
|               { label: 'City', value: 'COMPANY_CITY' }, | ||||
|               { label: 'Address Street 1', value: 'COMPANY_ADDRESS_STREET_1' }, | ||||
|               { label: 'Address Street 2', value: 'COMPANY_ADDRESS_STREET_2' }, | ||||
|               { label: 'Phone', value: 'COMPANY_PHONE' }, | ||||
|               { label: 'Zip Code', value: 'COMPANY_ZIP_CODE' }, | ||||
|             ], | ||||
|           }) | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     insertField(varName) { | ||||
|       if (this.inputValue) { | ||||
|         this.inputValue += `{${varName}}` | ||||
|       } else { | ||||
|         this.inputValue = `{${varName}}` | ||||
|       } | ||||
|       this.$emit('input', this.inputValue) | ||||
|     }, | ||||
|  | ||||
|     handleInput(e) { | ||||
|       this.$emit('input', this.inputValue) | ||||
|     }, | ||||
|  | ||||
|     handleChange(e) { | ||||
|       this.$emit('change', this.inputValue) | ||||
|     }, | ||||
|  | ||||
|     handleKeyupEnter(e) { | ||||
|       this.$emit('keyup', this.inputValue) | ||||
|     }, | ||||
|  | ||||
|     handleKeyDownEnter(e) { | ||||
|       this.$emit('keydown', e, this.inputValue) | ||||
|     }, | ||||
|  | ||||
|     handleFocusOut(e) { | ||||
|       this.$emit('blur', this.inputValue) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,61 +0,0 @@ | ||||
| <template> | ||||
|   <div class="item-selector"> | ||||
|     <sw-select | ||||
|       ref="baseSelect" | ||||
|       v-model="customerSelect" | ||||
|       :options="customers" | ||||
|       :show-labels="false" | ||||
|       :preserve-search="false" | ||||
|       :placeholder="$t('customers.type_or_click')" | ||||
|       label="name" | ||||
|       class="multi-select-item" | ||||
|       @close="checkCustomers" | ||||
|       @value="onTextChange" | ||||
|       @select="(val) => $emit('select', val)" | ||||
|       @remove="deselectCustomer" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       customerSelect: null, | ||||
|       loading: false, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('customer', ['customers']), | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.fetchCustomers() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('customer', ['fetchCustomers']), | ||||
|     async searchCustomers(search) { | ||||
|       this.loading = true | ||||
|  | ||||
|       await this.fetchCustomers({ search }) | ||||
|  | ||||
|       this.loading = false | ||||
|     }, | ||||
|     onTextChange(val) { | ||||
|       this.searchCustomers(val) | ||||
|     }, | ||||
|     checkCustomers(val) { | ||||
|       if (!this.customers.length) { | ||||
|         this.fetchCustomers() | ||||
|       } | ||||
|     }, | ||||
|     deselectCustomer() { | ||||
|       this.customerSelect = null | ||||
|       this.$emit('deselect') | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,148 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-date-picker | ||||
|       ref="BaseDatepicker" | ||||
|       v-model="date" | ||||
|       :config="config" | ||||
|       :placeholder="placeholder" | ||||
|       :disabled="disabled" | ||||
|       :invalid="invalid" | ||||
|       :name="name" | ||||
|       :tabindex="tabindex" | ||||
|       @input="onDateChange" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapGetters } from 'vuex' | ||||
| import SwDatePicker from '@bytefury/spacewind/src/components/SwDatePicker' | ||||
| import moment from 'moment' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     SwDatePicker, | ||||
|   }, | ||||
|   props: { | ||||
|     placeholder: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|     invalid: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     enableTime: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     time_24hr: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     disabled: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     name: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|     value: { | ||||
|       type: [String, Date], | ||||
|       default: () => moment(new Date()), | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       date: null, | ||||
|       config: { | ||||
|         altInput: true, | ||||
|         enableTime: this.enableTime, | ||||
|         time_24hr: this.time_24hr, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('company', { | ||||
|       carbonFormat: 'getCarbonDateFormat', | ||||
|       momentFormat: 'getMomentDateFormat', | ||||
|     }), | ||||
|   }, | ||||
|   watch: { | ||||
|     // value(val) { | ||||
|     //   console.log(val) | ||||
|  | ||||
|     //   if (val && !this.enableTime) { | ||||
|     //     this.date = moment(new Date(val), 'YYYY-MM-DD').format('YYYY-MM-DD') | ||||
|     //   } else { | ||||
|     //     this.date = moment(new Date(val), 'YYYY-MM-DD').format( | ||||
|     //       'YYYY-MM-DD H:m:s' | ||||
|     //     ) | ||||
|     //   } | ||||
|     // }, | ||||
|     enableTime(val) { | ||||
|       this.$set(this.config, 'enableTime', this.enableTime) | ||||
|     }, | ||||
|     carbonFormat() { | ||||
|       if (!this.enableTime) { | ||||
|         this.$set( | ||||
|           this.config, | ||||
|           'altFormat', | ||||
|           this.carbonFormat ? this.carbonFormat : 'd M Y' | ||||
|         ) | ||||
|       } else { | ||||
|         this.$set( | ||||
|           this.config, | ||||
|           'altFormat', | ||||
|           this.carbonFormat ? `${this.carbonFormat} H:i ` : 'd M Y H:i' | ||||
|         ) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.$set(this.config, 'enableTime', this.enableTime) | ||||
|  | ||||
|     if (!this.enableTime) { | ||||
|       this.$set( | ||||
|         this.config, | ||||
|         'altFormat', | ||||
|         this.carbonFormat ? this.carbonFormat : 'd M Y' | ||||
|       ) | ||||
|     } else { | ||||
|       this.$set( | ||||
|         this.config, | ||||
|         'altFormat', | ||||
|         this.carbonFormat ? `${this.carbonFormat} H:i ` : 'd M Y H:i' | ||||
|       ) | ||||
|     } | ||||
|  | ||||
|     if (this.value && !this.enableTime) { | ||||
|       this.date = moment(new Date(this.value), 'YYYY-MM-DD').format( | ||||
|         'YYYY-MM-DD' | ||||
|       ) | ||||
|       return true | ||||
|     } | ||||
|  | ||||
|     if (this.value) { | ||||
|       this.date = moment(new Date(this.value), 'YYYY-MM-DD').format( | ||||
|         'YYYY-MM-DD HH:mm:SS' | ||||
|       ) | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     onDateChange(date) { | ||||
|       this.$emit('input', date) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| <style lang="scss"> | ||||
| .flatpickr-calendar.open { | ||||
|   z-index: 60 !important; | ||||
| } | ||||
| </style> | ||||
| @ -1,123 +0,0 @@ | ||||
| <template> | ||||
|   <div | ||||
|     :class="{ 'bg-gray-400': showBgOverlay }" | ||||
|     class="absolute top-0 left-0 z-20 flex items-center justify-center w-full h-full bg-opacity-25 base-loader" | ||||
|   > | ||||
|     <div class="absolute top-0 left-0 w-full h-full overlay"> | ||||
|       <div | ||||
|         class="absolute flex items-center justify-center ball-scale-ripple-multiple" | ||||
|       > | ||||
|         <div></div> | ||||
|         <div></div> | ||||
|         <div></div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     showBgOverlay: { | ||||
|       default: false, | ||||
|       type: Boolean, | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| // function.scss | ||||
|  | ||||
| @function delay($interval, $count, $index) { | ||||
|   @return ($index * $interval) - ($interval * $count); | ||||
| } | ||||
|  | ||||
| // mixins.scss | ||||
|  | ||||
| @mixin global-bg() { | ||||
|   background-color: #5851d8; | ||||
| } | ||||
|  | ||||
| @mixin global-animation() { | ||||
|   animation-fill-mode: both; | ||||
| } | ||||
|  | ||||
| @mixin balls() { | ||||
|   @include global-bg(); | ||||
|  | ||||
|   width: 15px; | ||||
|   height: 15px; | ||||
|   border-radius: 100%; | ||||
|   margin: 2px; | ||||
| } | ||||
|  | ||||
| @mixin lines() { | ||||
|   @include global-bg(); | ||||
|  | ||||
|   width: $line-width; | ||||
|   height: $line-height; | ||||
|   border-radius: 2px; | ||||
|   margin: $margin; | ||||
| } | ||||
|  | ||||
| .base-loader { | ||||
|   .overlay { | ||||
|     @keyframes ball-scale-ripple-multiple { | ||||
|       0% { | ||||
|         transform: scale(0.1); | ||||
|         opacity: 1; | ||||
|       } | ||||
|       70% { | ||||
|         transform: scale(1); | ||||
|         opacity: 0.7; | ||||
|       } | ||||
|       100% { | ||||
|         opacity: 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     @mixin ball-scale-ripple-multiple($n: 3, $start: 0) { | ||||
|       @for $i from $start through $n { | ||||
|         > div:nth-child(#{$i}) { | ||||
|           animation-delay: delay(0.2s, $n, $i - 1); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .loader { | ||||
|       width: 100%; | ||||
|       position: relative; | ||||
|       min-height: 500px; | ||||
|     } | ||||
|  | ||||
|     .ball-scale-ripple-multiple { | ||||
|       transform: translateY(-25px); | ||||
|       top: 50%; | ||||
|       left: 50%; | ||||
|       @include ball-scale-ripple-multiple(); | ||||
|       transform: translateY(-50px / 2); | ||||
|  | ||||
|       > div { | ||||
|         @include global-animation(); | ||||
|  | ||||
|         position: absolute; | ||||
|         top: -2px; | ||||
|         left: -26px; | ||||
|         width: 50px; | ||||
|         height: 50px; | ||||
|         border-radius: 100%; | ||||
|         border: 2px solid #5851d8; | ||||
|         animation: ball-scale-ripple-multiple 1.25s 0s infinite | ||||
|           cubic-bezier(0.21, 0.53, 0.56, 0.8); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &.table-loader .overlay { | ||||
|     background: rgba(255, 255, 255, 0.5); | ||||
|     height: calc(100% - 80px); | ||||
|     top: 80px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -1,147 +0,0 @@ | ||||
| <template> | ||||
|   <transition | ||||
|     enter-class="translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2 " | ||||
|     enter-active-class="transition duration-300 ease-out transform" | ||||
|     enter-to-class="duration-300 translate-y-0 opacity-100 sm:translate-x-0" | ||||
|     leave-active-class="transition duration-100 ease-in" | ||||
|     leave-class="duration-200 opacity-100" | ||||
|     leave-to-class="duration-200 opacity-0" | ||||
|   > | ||||
|     <div | ||||
|       v-if="notificationActive" | ||||
|       class="fixed inset-0 z-50 flex items-end justify-center px-4 py-6 pointer-events-none sm:p-6 sm:items-start sm:justify-end" | ||||
|     > | ||||
|       <div | ||||
|         :class="success || info ? 'bg-white' : 'bg-red-50'" | ||||
|         class="w-full max-w-sm rounded-lg shadow-lg cursor-pointer pointer-events-auto" | ||||
|         @click="hideNotification" | ||||
|       > | ||||
|         <div class="overflow-hidden rounded-lg shadow-xs"> | ||||
|           <div class="p-4"> | ||||
|             <div class="flex items-start"> | ||||
|               <div class="flex-shrink-0"> | ||||
|                 <svg | ||||
|                   v-if="success" | ||||
|                   class="w-6 h-6 text-green-400" | ||||
|                   fill="none" | ||||
|                   viewBox="0 0 24 24" | ||||
|                   stroke="currentColor" | ||||
|                 > | ||||
|                   <path | ||||
|                     stroke-linecap="round" | ||||
|                     stroke-linejoin="round" | ||||
|                     stroke-width="2" | ||||
|                     d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" | ||||
|                   /> | ||||
|                 </svg> | ||||
|                 <exclamation-circle-icon | ||||
|                   v-if="info" | ||||
|                   class="w-6 h-6 text-blue-400" | ||||
|                 /> | ||||
|                 <svg | ||||
|                   v-if="error" | ||||
|                   class="w-6 h-6 text-red-400" | ||||
|                   fill="currentColor" | ||||
|                   viewBox="0 0 24 24" | ||||
|                 > | ||||
|                   <path | ||||
|                     fill-rule="evenodd" | ||||
|                     d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" | ||||
|                     clip-rule="evenodd" | ||||
|                   /> | ||||
|                 </svg> | ||||
|               </div> | ||||
|               <div class="flex-1 w-0 ml-3"> | ||||
|                 <p | ||||
|                   :class="`text-sm leading-5 font-medium ${ | ||||
|                     success || info ? 'text-gray-900' : 'text-red-800' | ||||
|                   }`" | ||||
|                 > | ||||
|                   {{ | ||||
|                     notificationTitle ? notificationTitle : success ? 'Success!' : 'Error' | ||||
|                   }} | ||||
|                 </p> | ||||
|                 <p | ||||
|                   :class="`mt-1 text-sm leading-5 ${ | ||||
|                     success || info ? 'text-gray-500' : 'text-red-700' | ||||
|                   }`" | ||||
|                 > | ||||
|                   {{ | ||||
|                     notificationMessage | ||||
|                       ? notificationMessage | ||||
|                       : success | ||||
|                       ? 'Successful' | ||||
|                       : 'Something went wrong' | ||||
|                   }} | ||||
|                 </p> | ||||
|               </div> | ||||
|               <div class="flex flex-shrink-0"> | ||||
|                 <button | ||||
|                   :class=" | ||||
|                     success || info | ||||
|                       ? ' text-gray-400 focus:text-gray-500' | ||||
|                       : 'text-red-400 focus:text-red-500' | ||||
|                   " | ||||
|                   class="inline-flex w-5 h-5 transition duration-150 ease-in-out focus:outline-none" | ||||
|                   @click="hideNotification" | ||||
|                 > | ||||
|                   <x-icon /> | ||||
|                 </button> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </transition> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { XIcon } from '@vue-hero-icons/outline' | ||||
| import { ExclamationCircleIcon } from '@vue-hero-icons/solid' | ||||
| export default { | ||||
|   components: { | ||||
|     XIcon, | ||||
|     ExclamationCircleIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       hasFocus: false, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('notification', [ | ||||
|       'notificationActive', | ||||
|       'notificationTitle', | ||||
|       'notificationType', | ||||
|       'notificationAutoHide', | ||||
|       'notificationMessage', | ||||
|     ]), | ||||
|     success() { | ||||
|       return this.notificationType.toLowerCase() === 'success' | ||||
|     }, | ||||
|     error() { | ||||
|       return this.notificationType.toLowerCase() === 'error' | ||||
|     }, | ||||
|     info() { | ||||
|       return this.notificationType.toLowerCase() === 'info' | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     notificationActive(val) { | ||||
|       if (val && this.notificationAutoHide) { | ||||
|         window.setTimeout(this.hideNotification, 5000) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     if (this.notificationActive && this.notificationAutoHide) { | ||||
|       window.setTimeout(this.hideNotification, 5000) | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('notification', ['showNotification', 'hideNotification']), | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,7 +0,0 @@ | ||||
| <template> | ||||
|   <main | ||||
|     class="flex flex-col flex-1 p-8 overflow-y-auto border-b border-gray-300 border-solid" | ||||
|   > | ||||
|     <slot /> | ||||
|   </main> | ||||
| </template> | ||||
| @ -1,81 +0,0 @@ | ||||
| <template> | ||||
|   <sw-date-picker | ||||
|     ref="BaseDatepicker" | ||||
|     v-model="time" | ||||
|     :config="config" | ||||
|     :placeholder="placeholder" | ||||
|     :disabled="disabled" | ||||
|     :invalid="invalid" | ||||
|     :name="name" | ||||
|     :tabindex="tabindex" | ||||
|     @input="onDateChange" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| import SwDatePicker from '@bytefury/spacewind/src/components/SwDatePicker' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     SwDatePicker, | ||||
|   }, | ||||
|   props: { | ||||
|     invalid: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|       require: false, | ||||
|     }, | ||||
|     defaultTime: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|       require: false, | ||||
|     }, | ||||
|     hideClearButton: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|       require: false, | ||||
|     }, | ||||
|     value: { | ||||
|       type: [String, Object], | ||||
|       default: '', | ||||
|     }, | ||||
|     placeholder: { | ||||
|       type: String, | ||||
|       default: 'HH:mm:ss', | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|     disabled: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     name: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       time: this.value, | ||||
|       config: { | ||||
|         enableTime: true, | ||||
|         noCalendar: true, | ||||
|         dateFormat: 'H:i', | ||||
|         time_24hr: true, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value() { | ||||
|       this.time = this.value | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     onDateChange(date) { | ||||
|       this.$emit('input', date) | ||||
|       this.$emit('change', date) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,881 +0,0 @@ | ||||
| <template> | ||||
|   <div | ||||
|     :tabindex="searchable ? -1 : tabindex" | ||||
|     :class="multiSelectStyle" | ||||
|     :aria-owns="'listbox-' + id" | ||||
|     role="combobox" | ||||
|     @focus="activate()" | ||||
|     @blur="searchable ? false : deactivate()" | ||||
|     @keydown.self.down.prevent="pointerForward()" | ||||
|     @keydown.self.up.prevent="pointerBackward()" | ||||
|     @keypress.enter.tab.stop.self="addPointerElement($event)" | ||||
|     @keyup.esc="deactivate()" | ||||
|   > | ||||
|     <slot :toggle="toggle" name="caret"> | ||||
|       <div :class="multiselectSelectStyle" @mousedown.prevent.stop="toggle()" /> | ||||
|     </slot> | ||||
|     <!-- <slot name="clear" :search="search"></slot> --> | ||||
|     <div ref="tags" :class="multiSelectTagsStyle"> | ||||
|       <slot | ||||
|         :search="search" | ||||
|         :remove="removeElement" | ||||
|         :values="visibleValues" | ||||
|         :is-open="isOpen" | ||||
|         name="selection" | ||||
|       > | ||||
|         <div | ||||
|           v-show="visibleValues.length > 0" | ||||
|           :class="multiselectTagsWrapStyle" | ||||
|         > | ||||
|           <template v-for="(option, index) of visibleValues" @mousedown.prevent> | ||||
|             <slot | ||||
|               :option="option" | ||||
|               :search="search" | ||||
|               :remove="removeElement" | ||||
|               name="tag" | ||||
|             > | ||||
|               <span :key="index" :class="multiselectTagStyle"> | ||||
|                 <span v-text="getOptionLabel(option)" /> | ||||
|                 <i | ||||
|                   :class="multiselectTagIconStyle" | ||||
|                   tabindex="1" | ||||
|                   @keypress.enter.prevent="removeElement(option)" | ||||
|                   @mousedown.prevent="removeElement(option)" | ||||
|                 /> | ||||
|               </span> | ||||
|             </slot> | ||||
|           </template> | ||||
|         </div> | ||||
|         <template v-if="internalValue && internalValue.length > limit"> | ||||
|           <slot name="limit"> | ||||
|             <strong | ||||
|               :class="multiselectStrongStyle" | ||||
|               v-text="limitText(internalValue.length - limit)" | ||||
|             /> | ||||
|           </slot> | ||||
|         </template> | ||||
|       </slot> | ||||
|       <transition name="multiselect__loading"> | ||||
|         <slot name="loading"> | ||||
|           <div v-show="loading" :class="multiselectSpinnerStyle" /> | ||||
|         </slot> | ||||
|       </transition> | ||||
|       <input | ||||
|         ref="search" | ||||
|         :name="name" | ||||
|         :id="id" | ||||
|         :placeholder="placeholder" | ||||
|         :style="inputStyle" | ||||
|         :value="search" | ||||
|         :disabled="disabled" | ||||
|         :tabindex="tabindex" | ||||
|         :aria-controls="'listbox-' + id" | ||||
|         :class="multiselectInputStyle" | ||||
|         type="text" | ||||
|         autocomplete="off" | ||||
|         spellcheck="false" | ||||
|         @input="updateSearch($event.target.value)" | ||||
|         @focus.prevent="activate()" | ||||
|         @blur.prevent="deactivate()" | ||||
|         @keyup.esc="deactivate()" | ||||
|         @keydown.down.prevent="pointerForward()" | ||||
|         @keydown.up.prevent="pointerBackward()" | ||||
|         @keypress.enter.prevent.stop.self="addPointerElement($event)" | ||||
|         @keydown.delete.stop="removeLastElement()" | ||||
|       /> | ||||
|       <span | ||||
|         v-if="isSingleLabelVisible" | ||||
|         :class="multiselectSingleStyle" | ||||
|         @mousedown.prevent="toggle" | ||||
|       > | ||||
|         <slot :option="singleValue" name="singleLabel"> | ||||
|           <template>{{ currentOptionLabel }}</template> | ||||
|         </slot> | ||||
|       </span> | ||||
|     </div> | ||||
|     <transition name="multiselect"> | ||||
|       <div | ||||
|         v-show="isOpen" | ||||
|         ref="list" | ||||
|         :style="{ maxHeight: optimizedHeight + 'px' }" | ||||
|         :class="multiselectContentWrapperStyle" | ||||
|         tabindex="-1" | ||||
|         @focus="activate" | ||||
|         @mousedown.prevent | ||||
|       > | ||||
|         <ul | ||||
|           :style="contentStyle" | ||||
|           :id="'listbox-' + id" | ||||
|           :class="multiselectContentStyle" | ||||
|           role="listbox" | ||||
|         > | ||||
|           <slot name="beforeList" /> | ||||
|           <li v-if="multiple && max === internalValue.length"> | ||||
|             <span :class="multiselectOptionStyle"> | ||||
|               <slot name="maxElements"> | ||||
|                 {{ $t('validation.maximum_options_error', { max: max }) }} | ||||
|               </slot> | ||||
|             </span> | ||||
|           </li> | ||||
|           <template v-if="!max || internalValue.length < max"> | ||||
|             <li | ||||
|               v-for="(option, index) of filteredOptions" | ||||
|               :key="index" | ||||
|               :id="id + '-' + index" | ||||
|               :role=" | ||||
|                 !(option && (option.$isLabel || option.$isDisabled)) | ||||
|                   ? 'option' | ||||
|                   : null | ||||
|               " | ||||
|               :class="multiselectElementStyle" | ||||
|             > | ||||
|               <span | ||||
|                 v-if="!(option && (option.$isLabel || option.$isDisabled))" | ||||
|                 :class="optionHighlight(index, option)" | ||||
|                 :data-select=" | ||||
|                   option && option.isTag ? tagPlaceholder : selectLabelText | ||||
|                 " | ||||
|                 :data-selected="selectedLabelText" | ||||
|                 :data-deselect="deselectLabelText" | ||||
|                 @click.stop="select(option)" | ||||
|                 @mouseenter.self="pointerSet(index)" | ||||
|               > | ||||
|                 <slot :option="option" :search="search" name="option"> | ||||
|                   <span>{{ getOptionLabel(option) }}</span> | ||||
|                 </slot> | ||||
|               </span> | ||||
|               <span | ||||
|                 v-if="option && (option.$isLabel || option.$isDisabled)" | ||||
|                 :data-select="groupSelect && selectGroupLabelText" | ||||
|                 :data-deselect="groupSelect && deselectGroupLabelText" | ||||
|                 :class="groupHighlight(index, option)" | ||||
|                 @mouseenter.self="groupSelect && pointerSet(index)" | ||||
|                 @mousedown.prevent="selectGroup(option)" | ||||
|               > | ||||
|                 <slot :option="option" :search="search" name="option"> | ||||
|                   <span>{{ getOptionLabel(option) }}</span> | ||||
|                 </slot> | ||||
|               </span> | ||||
|             </li> | ||||
|           </template> | ||||
|           <li | ||||
|             v-if="showNoOptions && (options.length === 0 && !search && !loading)" | ||||
|           > | ||||
|             <span :class="multiselectOptionStyle"> | ||||
|               <slot name="noOptions">{{ $t('general.list_is_empty') }}</slot> | ||||
|             </span> | ||||
|           </li> | ||||
|         </ul> | ||||
|         <slot name="afterList" /> | ||||
|       </div> | ||||
|     </transition> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import CraterTheme from '../theme/index' | ||||
| import multiselectMixin from './multiselectMixin' | ||||
| import pointerMixin from './pointerMixin' | ||||
|  | ||||
| const { | ||||
|   activeBaseSelectContainer, | ||||
|   disabledBaseSelectContainer, | ||||
|   baseSelectContainer, | ||||
|   multiSelect, | ||||
|   disabledMultiSelect, | ||||
|   multiSelectTags, | ||||
|   multiSelectTagsInvalid, | ||||
|   multiSelectTagsDefaultColor, | ||||
|   disabledMultiSelectTags, | ||||
|   multiselectTagsWrap, | ||||
|   multiselectTag, | ||||
|   multiselectTagIcon, | ||||
|   multiselectStrong, | ||||
|   multiselectSpinner, | ||||
|   multiselectInput, | ||||
|   multiselectSingle, | ||||
|   multiselectContentWrapper, | ||||
|   multiselectContent, | ||||
|   multiselectOption, | ||||
|   multiselectElement, | ||||
| } = CraterTheme.BaseSelect | ||||
|  | ||||
| export default { | ||||
|   name: 'VueMultiselect', | ||||
|   mixins: [multiselectMixin, pointerMixin], | ||||
|   props: { | ||||
|     /** | ||||
|      * name attribute to match optional label element | ||||
|      * @default '' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     name: { | ||||
|       type: String, | ||||
|       default: '', | ||||
|     }, | ||||
|     /** | ||||
|      * String to show when pointing to an option | ||||
|      * @default 'Press enter to select' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     selectLabel: { | ||||
|       type: String, | ||||
|       default: '', | ||||
|     }, | ||||
|     /** | ||||
|      * String to show when pointing to an option | ||||
|      * @default 'Press enter to select' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     selectGroupLabel: { | ||||
|       type: String, | ||||
|       default: '', | ||||
|     }, | ||||
|     /** | ||||
|      * String to show next to selected option | ||||
|      * @default 'Selected' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     selectedLabel: { | ||||
|       type: String, | ||||
|       default: 'Selected', | ||||
|     }, | ||||
|     /** | ||||
|      * String to show when pointing to an already selected option | ||||
|      * @default 'Press enter to remove' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     deselectLabel: { | ||||
|       type: String, | ||||
|       default: 'Press enter to remove', | ||||
|     }, | ||||
|     /** | ||||
|      * String to show when pointing to an already selected option | ||||
|      * @default 'Press enter to remove' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     deselectGroupLabel: { | ||||
|       type: String, | ||||
|       default: 'Press enter to deselect group', | ||||
|     }, | ||||
|     /** | ||||
|      * Decide whether to show pointer labels | ||||
|      * @default true | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     showLabels: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     /** | ||||
|      * Limit the display of selected options. The rest will be hidden within the limitText string. | ||||
|      * @default 99999 | ||||
|      * @type {Integer} | ||||
|      */ | ||||
|     limit: { | ||||
|       type: Number, | ||||
|       default: 99999, | ||||
|     }, | ||||
|     /** | ||||
|      * Sets maxHeight style value of the dropdown | ||||
|      * @default 300 | ||||
|      * @type {Integer} | ||||
|      */ | ||||
|     maxHeight: { | ||||
|       type: Number, | ||||
|       default: 300, | ||||
|     }, | ||||
|     /** | ||||
|      * Function that process the message shown when selected | ||||
|      * elements pass the defined limit. | ||||
|      * @default 'and * more' | ||||
|      * @param {Int} count Number of elements more than limit | ||||
|      * @type {Function} | ||||
|      */ | ||||
|     limitText: { | ||||
|       type: Function, | ||||
|       default: (count) => `and ${count} more`, | ||||
|     }, | ||||
|     /** | ||||
|      * Set true to trigger the loading spinner. | ||||
|      * @default False | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     loading: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * Disables the multiselect if true. | ||||
|      * @default false | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     disabled: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * Fixed opening direction | ||||
|      * @default '' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     openDirection: { | ||||
|       type: String, | ||||
|       default: '', | ||||
|     }, | ||||
|     /** | ||||
|      * Shows slot with message about empty options | ||||
|      * @default true | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     showNoOptions: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     showNoResults: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: 0, | ||||
|     }, | ||||
|     invalid: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isSingleLabelVisible() { | ||||
|       return ( | ||||
|         (this.singleValue || this.singleValue === 0) && | ||||
|         (!this.isOpen || !this.searchable) && | ||||
|         !this.visibleValues.length | ||||
|       ) | ||||
|     }, | ||||
|     isPlaceholderVisible() { | ||||
|       return !this.internalValue.length && (!this.searchable || !this.isOpen) | ||||
|     }, | ||||
|     visibleValues() { | ||||
|       return this.multiple ? this.internalValue.slice(0, this.limit) : [] | ||||
|     }, | ||||
|     singleValue() { | ||||
|       return this.internalValue[0] | ||||
|     }, | ||||
|     deselectLabelText() { | ||||
|       return this.showLabels ? this.deselectLabel : '' | ||||
|     }, | ||||
|     deselectGroupLabelText() { | ||||
|       return this.showLabels ? this.deselectGroupLabel : '' | ||||
|     }, | ||||
|     selectLabelText() { | ||||
|       return this.showLabels ? this.selectLabel : '' | ||||
|     }, | ||||
|     selectGroupLabelText() { | ||||
|       return this.showLabels ? this.selectGroupLabel : '' | ||||
|     }, | ||||
|     selectedLabelText() { | ||||
|       return this.showLabels ? this.selectedLabel : '' | ||||
|     }, | ||||
|     inputStyle() { | ||||
|       if ( | ||||
|         this.searchable || | ||||
|         (this.multiple && this.value && this.value.length) | ||||
|       ) { | ||||
|         // Hide input by setting the width to 0 allowing it to receive focus | ||||
|  | ||||
|         return this.isOpen | ||||
|           ? { width: '100%' } | ||||
|           : this.value | ||||
|           ? { width: '0', position: 'absolute', padding: '0' } | ||||
|           : '' | ||||
|       } | ||||
|     }, | ||||
|     contentStyle() { | ||||
|       return this.options.length | ||||
|         ? { display: 'inline-block' } | ||||
|         : { display: 'block' } | ||||
|     }, | ||||
|     isAbove() { | ||||
|       if (this.openDirection === 'above' || this.openDirection === 'top') { | ||||
|         return true | ||||
|       } else if ( | ||||
|         this.openDirection === 'below' || | ||||
|         this.openDirection === 'bottom' | ||||
|       ) { | ||||
|         return false | ||||
|       } else { | ||||
|         return this.preferredOpenDirection === 'above' | ||||
|       } | ||||
|     }, | ||||
|     showSearchInput() { | ||||
|       return ( | ||||
|         this.searchable && | ||||
|         (this.hasSingleSelectedSlot && | ||||
|         (this.visibleSingleValue || this.visibleSingleValue === 0) | ||||
|           ? this.isOpen | ||||
|           : true) | ||||
|       ) | ||||
|     }, | ||||
|     multiSelectStyle() { | ||||
|       let style = ['multiselect--active', baseSelectContainer] | ||||
|       if (this.isOpen) { | ||||
|         style.push(activeBaseSelectContainer) | ||||
|       } | ||||
|       if (this.disabled) { | ||||
|         style.push(disabledBaseSelectContainer) | ||||
|       } | ||||
|       if (this.isAbove) { | ||||
|         style.push('multiselect--above') | ||||
|       } | ||||
|       return style | ||||
|     }, | ||||
|     multiselectSelectStyle() { | ||||
|       let style = [multiSelect] | ||||
|  | ||||
|       if (this.disabled) { | ||||
|         style.push(disabledMultiSelect) | ||||
|       } | ||||
|  | ||||
|       return style | ||||
|     }, | ||||
|     multiSelectTagsStyle() { | ||||
|       let style = [multiSelectTags] | ||||
|  | ||||
|       if (this.invalid) { | ||||
|         style.push(multiSelectTagsInvalid) | ||||
|       } else { | ||||
|         style.push(multiSelectTagsDefaultColor) | ||||
|       } | ||||
|  | ||||
|       if (this.disabled) { | ||||
|         style.push(disabledMultiSelectTags) | ||||
|       } | ||||
|  | ||||
|       return style | ||||
|     }, | ||||
|     multiselectTagsWrapStyle() { | ||||
|       return [multiselectTagsWrap] | ||||
|     }, | ||||
|     multiselectTagStyle() { | ||||
|       return [multiselectTag] | ||||
|     }, | ||||
|     multiselectTagIconStyle() { | ||||
|       return [multiselectTagIcon] | ||||
|     }, | ||||
|     multiselectStrongStyle() { | ||||
|       return [multiselectStrong] | ||||
|     }, | ||||
|     multiselectSpinnerStyle() { | ||||
|       return [multiselectSpinner] | ||||
|     }, | ||||
|     multiselectInputStyle() { | ||||
|       return [multiselectInput] | ||||
|     }, | ||||
|     multiselectSingleStyle() { | ||||
|       return [multiselectSingle] | ||||
|     }, | ||||
|     multiselectContentWrapperStyle() { | ||||
|       return [multiselectContentWrapper] | ||||
|     }, | ||||
|     multiselectContentStyle() { | ||||
|       return [multiselectContent] | ||||
|     }, | ||||
|     multiselectOptionStyle() { | ||||
|       return [multiselectOption] | ||||
|     }, | ||||
|     multiselectElementStyle() { | ||||
|       return [multiselectElement] | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| <style lang="scss"> | ||||
| fieldset[disabled] .multiselect { | ||||
|   pointer-events: none; | ||||
| } | ||||
|  | ||||
| .multiselect { | ||||
|   min-height: 40px; | ||||
| } | ||||
|  | ||||
| .multiselect__spinner { | ||||
|   right: 1px; | ||||
|   top: 1px; | ||||
| } | ||||
|  | ||||
| .multiselect__spinner:before, | ||||
| .multiselect__spinner:after { | ||||
|   position: absolute; | ||||
|   content: ''; | ||||
|   top: 50%; | ||||
|   left: 50%; | ||||
|   margin: -8px 0 0 -8px; | ||||
|   z-index: 5; | ||||
|   width: 16px; | ||||
|   height: 16px; | ||||
|   border-radius: 100%; | ||||
|   border-color: #41b883 transparent transparent; | ||||
|   border-style: solid; | ||||
|   border-width: 2px; | ||||
|   box-shadow: 0 0 0 1px transparent; | ||||
| } | ||||
|  | ||||
| .multiselect__spinner:before { | ||||
|   animation: spinning 2.4s cubic-bezier(0.41, 0.26, 0.2, 0.62); | ||||
|   animation-iteration-count: infinite; | ||||
| } | ||||
|  | ||||
| .multiselect__spinner:after { | ||||
|   animation: spinning 2.4s cubic-bezier(0.51, 0.09, 0.21, 0.8); | ||||
|   animation-iteration-count: infinite; | ||||
| } | ||||
|  | ||||
| .multiselect__loading-enter-active, | ||||
| .multiselect__loading-leave-active { | ||||
|   transition: opacity 0.4s ease-in-out; | ||||
|   opacity: 1; | ||||
| } | ||||
|  | ||||
| .multiselect__loading-enter, | ||||
| .multiselect__loading-leave-active { | ||||
|   opacity: 0; | ||||
| } | ||||
|  | ||||
| .multiselect, | ||||
| .multiselect__input, | ||||
| .multiselect__single { | ||||
|   font-family: inherit; | ||||
|   // font-size: 14px; | ||||
|   touch-action: manipulation; | ||||
| } | ||||
|  | ||||
| .multiselect { | ||||
|   box-sizing: content-box; | ||||
|   display: block; | ||||
|   position: relative; | ||||
|   width: 100%; | ||||
|   min-height: 40px; | ||||
|   text-align: left; | ||||
|   color: #35495e; | ||||
| } | ||||
|  | ||||
| .multiselect * { | ||||
|   box-sizing: border-box; | ||||
| } | ||||
|  | ||||
| .multiselect:focus { | ||||
|   border: 1px solid #817ae3 !important; | ||||
| } | ||||
|  | ||||
| .multiselect--disabled { | ||||
|   pointer-events: none; | ||||
|   opacity: 0.6; | ||||
| } | ||||
|  | ||||
| .multiselect--active:not(.multiselect--above) .multiselect__current, | ||||
| .multiselect--active:not(.multiselect--above) .multiselect__input, | ||||
| .multiselect--active:not(.multiselect--above) .multiselect__tags { | ||||
|   border-bottom-left-radius: 0; | ||||
|   border-bottom-right-radius: 0; | ||||
| } | ||||
|  | ||||
| .multiselect--active .multiselect__select { | ||||
|   transform: rotateZ(180deg); | ||||
| } | ||||
| .multiselect--above.multiselect--active .multiselect__current, | ||||
| .multiselect--above.multiselect--active .multiselect__input, | ||||
| .multiselect--above.multiselect--active .multiselect__tags { | ||||
|   border-top-left-radius: 0; | ||||
|   border-top-right-radius: 0; | ||||
| } | ||||
|  | ||||
| .multiselect__input, | ||||
| .multiselect__single { | ||||
|   min-height: 20px; | ||||
|   transition: border 0.1s ease; | ||||
| } | ||||
|  | ||||
| .multiselect__input::placeholder { | ||||
|   color: #b9c1d1; | ||||
| } | ||||
|  | ||||
| .multiselect__tag ~ .multiselect__input, | ||||
| .multiselect__tag ~ .multiselect__single { | ||||
|   width: auto; | ||||
| } | ||||
| .multiselect__input:hover, | ||||
| .multiselect__single:hover { | ||||
|   border-color: #cfcfcf; | ||||
| } | ||||
| .multiselect__input:focus, | ||||
| .multiselect__single:focus { | ||||
|   border-color: #a8a8a8; | ||||
|   outline: none; | ||||
| } | ||||
| .multiselect__tag { | ||||
|   background: #41b883; | ||||
|   text-overflow: ellipsis; | ||||
| } | ||||
| .multiselect__tag-icon { | ||||
|   font-style: initial; | ||||
| } | ||||
| .multiselect__tag-icon:after { | ||||
|   content: '×'; | ||||
|   color: #266d4d; | ||||
|   font-size: 14px; | ||||
| } | ||||
| .multiselect__tag-icon:focus, | ||||
| .multiselect__tag-icon:hover { | ||||
|   background: #369a6e; | ||||
| } | ||||
| .multiselect__tag-icon:focus:after, | ||||
| .multiselect__tag-icon:hover:after { | ||||
|   color: white; | ||||
| } | ||||
| .multiselect__current { | ||||
|   line-height: 16px; | ||||
|   min-height: 40px; | ||||
|   box-sizing: border-box; | ||||
|   display: block; | ||||
|   overflow: hidden; | ||||
|   padding: 8px 12px 0; | ||||
|   padding-right: 30px; | ||||
|   white-space: nowrap; | ||||
|   margin: 0; | ||||
|   text-decoration: none; | ||||
|   border-radius: 5px; | ||||
|   border: 1px solid #ebf1fa; | ||||
|   cursor: pointer; | ||||
| } | ||||
| .multiselect__select { | ||||
|   right: 1px; | ||||
|   top: 1px; | ||||
|   transition: transform 0.2s; | ||||
| } | ||||
| .multiselect__select:before { | ||||
|   position: relative; | ||||
|   right: 0; | ||||
|   top: 65%; | ||||
|   color: #a5acc1; | ||||
|   margin-top: 4px; | ||||
|   border-style: solid; | ||||
|   border-width: 5px 5px 0 5px; | ||||
|   border-color: #a5acc1 transparent transparent transparent; | ||||
|   content: ''; | ||||
| } | ||||
| .multiselect__placeholder { | ||||
|   color: #b9c1d1; | ||||
|   display: inline-block; | ||||
|   margin-bottom: 10px; | ||||
|   padding-top: 2px; | ||||
| } | ||||
| .multiselect--active .multiselect__placeholder { | ||||
|   display: none; | ||||
| } | ||||
| .multiselect__content-wrapper { | ||||
|   max-height: 240px; | ||||
|   -webkit-overflow-scrolling: touch; | ||||
| } | ||||
| .multiselect--above .multiselect__content-wrapper { | ||||
|   bottom: 100%; | ||||
|   border-bottom-left-radius: 0; | ||||
|   border-bottom-right-radius: 0; | ||||
|   border-top-left-radius: 5px; | ||||
|   border-top-right-radius: 5px; | ||||
|   border-bottom: none; | ||||
|   border-top: 1px solid #e8e8e8; | ||||
| } | ||||
| .multiselect__content::webkit-scrollbar { | ||||
|   display: none; | ||||
| } | ||||
| .multiselect__option { | ||||
|   min-height: 40px; | ||||
| } | ||||
| .multiselect__option:after { | ||||
|   top: 0; | ||||
|   right: 0; | ||||
|   position: absolute; | ||||
|   line-height: 40px; | ||||
|   padding-right: 12px; | ||||
|   padding-left: 20px; | ||||
|   font-size: 13px; | ||||
| } | ||||
| .multiselect__option--highlight { | ||||
|   background: #41b883; | ||||
|   outline: none; | ||||
|   color: white; | ||||
| } | ||||
| .multiselect__option--highlight:after { | ||||
|   content: attr(data-select); | ||||
|   background: #41b883; | ||||
|   color: white; | ||||
| } | ||||
| .multiselect__option--selected { | ||||
|   background: #f3f3f3; | ||||
|   color: #35495e; | ||||
|   font-weight: bold; | ||||
| } | ||||
| .multiselect__option--selected:after { | ||||
|   content: attr(data-selected); | ||||
|   color: silver; | ||||
| } | ||||
| .multiselect__option--selected.multiselect__option--highlight { | ||||
|   background: #ff6a6a; | ||||
|   color: #fff; | ||||
| } | ||||
| .multiselect__option--selected.multiselect__option--highlight:after { | ||||
|   background: #ff6a6a; | ||||
|   content: attr(data-deselect); | ||||
|   color: #fff; | ||||
| } | ||||
|  | ||||
| .multiselect--disabled .multiselect__current, | ||||
| .multiselect--disabled .multiselect__select { | ||||
|   background: #ebf1fa; | ||||
|   color: #b9c1d1; | ||||
| } | ||||
|  | ||||
| .multiselect--disabled .multiselect__input, | ||||
| .multiselect--disabled .multiselect__single { | ||||
|   background: #ebf1fa; | ||||
|   color: #b9c1d1; | ||||
| } | ||||
|  | ||||
| .multiselect__option--disabled { | ||||
|   background: transparent !important; | ||||
|   color: #dddddd !important; | ||||
|   cursor: text; | ||||
|   pointer-events: none; | ||||
| } | ||||
|  | ||||
| .multiselect__option--group { | ||||
|   background: #ededed; | ||||
|   color: #35495e; | ||||
| } | ||||
|  | ||||
| .multiselect__option--group.multiselect__option--highlight { | ||||
|   background: #35495e; | ||||
|   color: #fff; | ||||
| } | ||||
|  | ||||
| .multiselect__option--group.multiselect__option--highlight:after { | ||||
|   background: #35495e; | ||||
| } | ||||
|  | ||||
| .multiselect__option--disabled.multiselect__option--highlight { | ||||
|   background: #dedede; | ||||
| } | ||||
|  | ||||
| .multiselect__option--group-selected.multiselect__option--highlight { | ||||
|   background: #ff6a6a; | ||||
|   color: #fff; | ||||
| } | ||||
|  | ||||
| .multiselect__option--group-selected.multiselect__option--highlight:after { | ||||
|   background: #ff6a6a; | ||||
|   content: attr(data-deselect); | ||||
|   color: #fff; | ||||
| } | ||||
|  | ||||
| .multiselect-enter-active, | ||||
| .multiselect-leave-active { | ||||
|   transition: all 0.15s ease; | ||||
| } | ||||
|  | ||||
| .multiselect-enter, | ||||
| .multiselect-leave-active { | ||||
|   opacity: 0; | ||||
| } | ||||
|  | ||||
| *[dir='rtl'] .multiselect { | ||||
|   text-align: right; | ||||
| } | ||||
|  | ||||
| *[dir='rtl'] .multiselect__select { | ||||
|   right: auto; | ||||
|   left: 1px; | ||||
| } | ||||
|  | ||||
| *[dir='rtl'] .multiselect__tags { | ||||
|   padding: 8px 8px 0px 40px; | ||||
| } | ||||
|  | ||||
| *[dir='rtl'] .multiselect__content { | ||||
|   text-align: right; | ||||
| } | ||||
|  | ||||
| *[dir='rtl'] .multiselect__option:after { | ||||
|   right: auto; | ||||
|   left: 0; | ||||
| } | ||||
|  | ||||
| *[dir='rtl'] .multiselect__clear { | ||||
|   right: auto; | ||||
|   left: 12px; | ||||
| } | ||||
|  | ||||
| *[dir='rtl'] .multiselect__spinner { | ||||
|   right: auto; | ||||
|   left: 1px; | ||||
| } | ||||
|  | ||||
| @keyframes spinning { | ||||
|   from { | ||||
|     transform: rotate(0); | ||||
|   } | ||||
|   to { | ||||
|     transform: rotate(2turn); | ||||
|   } | ||||
| } | ||||
|  | ||||
| .multiselect { | ||||
|   .multiselect__option--highlight { | ||||
|     background: #5851d8; | ||||
|     color: #040405; | ||||
|     font-weight: normal !important; | ||||
|  | ||||
|     &.multiselect__option--selected { | ||||
|       background: #ebf1fa; | ||||
|       color: #040405; | ||||
|       font-size: 1rem; | ||||
|       font-weight: normal !important; | ||||
|  | ||||
|       &::after { | ||||
|         background: #040405; | ||||
|         color: #fff; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     &::after { | ||||
|       background: #040405; | ||||
|       color: #fff; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .multiselect__option--selected { | ||||
|     font-weight: normal !important; | ||||
|     background: #ebf1fa; | ||||
|   } | ||||
|  | ||||
|   .multiselect__tags-wrap .multiselect__tag { | ||||
|     background: #5851d8; | ||||
|     color: #040405; | ||||
|  | ||||
|     .multiselect__tag-icon { | ||||
|       &:hover { | ||||
|         background: #5851d8; | ||||
|       } | ||||
|  | ||||
|       &::after { | ||||
|         color: #040405; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &.error { | ||||
|     border: 1px solid #fb7178; | ||||
|     border-radius: 5px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -1,7 +0,0 @@ | ||||
| import Multiselect from './Multiselect' | ||||
| import multiselectMixin from './multiselectMixin' | ||||
| import pointerMixin from './pointerMixin' | ||||
|  | ||||
| export default Multiselect | ||||
|  | ||||
| export { Multiselect, multiselectMixin, pointerMixin } | ||||
| @ -1,775 +0,0 @@ | ||||
| function isEmpty(opt) { | ||||
|   if (opt === 0) return false | ||||
|   if (Array.isArray(opt) && opt.length === 0) return true | ||||
|   return !opt | ||||
| } | ||||
|  | ||||
| function not(fun) { | ||||
|   return (...params) => !fun(...params) | ||||
| } | ||||
|  | ||||
| function includes(str, query) { | ||||
|   /* istanbul ignore else */ | ||||
|   if (str === undefined) str = 'undefined' | ||||
|   if (str === null) str = 'null' | ||||
|   if (str === false) str = 'false' | ||||
|   const text = str.toString().toLowerCase() | ||||
|   return text.indexOf(query.trim()) !== -1 | ||||
| } | ||||
|  | ||||
| function filterOptions(options, search, label, customLabel) { | ||||
|   return options.filter((option) => | ||||
|     includes(customLabel(option, label), search) | ||||
|   ) | ||||
| } | ||||
|  | ||||
| function stripGroups(options) { | ||||
|   return options.filter((option) => !option.$isLabel) | ||||
| } | ||||
|  | ||||
| function flattenOptions(values, label) { | ||||
|   return (options) => | ||||
|     options.reduce((prev, curr) => { | ||||
|       /* istanbul ignore else */ | ||||
|       if (curr[values] && curr[values].length) { | ||||
|         prev.push({ | ||||
|           $groupLabel: curr[label], | ||||
|           $isLabel: true, | ||||
|         }) | ||||
|         return prev.concat(curr[values]) | ||||
|       } | ||||
|       return prev | ||||
|     }, []) | ||||
| } | ||||
|  | ||||
| function filterGroups(search, label, values, groupLabel, customLabel) { | ||||
|   return (groups) => | ||||
|     groups.map((group) => { | ||||
|       /* istanbul ignore else */ | ||||
|       if (!group[values]) { | ||||
|         console.warn( | ||||
|           `Options passed to vue-multiselect do not contain groups, despite the config.` | ||||
|         ) | ||||
|         return [] | ||||
|       } | ||||
|       const groupOptions = filterOptions( | ||||
|         group[values], | ||||
|         search, | ||||
|         label, | ||||
|         customLabel | ||||
|       ) | ||||
|  | ||||
|       return groupOptions.length | ||||
|         ? { | ||||
|             [groupLabel]: group[groupLabel], | ||||
|             [values]: groupOptions, | ||||
|           } | ||||
|         : [] | ||||
|     }) | ||||
| } | ||||
|  | ||||
| const flow = (...fns) => (x) => fns.reduce((v, f) => f(v), x) | ||||
|  | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       search: '', | ||||
|       isOpen: false, | ||||
|       preferredOpenDirection: 'below', | ||||
|       optimizedHeight: this.maxHeight, | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     initialSearch: { | ||||
|       type: String, | ||||
|       default: '', | ||||
|     }, | ||||
|     /** | ||||
|      * Decide whether to filter the results based on search query. | ||||
|      * Useful for async filtering, where we search through more complex data. | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     internalSearch: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     /** | ||||
|      * Array of available options: Objects, Strings or Integers. | ||||
|      * If array of objects, visible label will default to option.label. | ||||
|      * If `labal` prop is passed, label will equal option['label'] | ||||
|      * @type {Array} | ||||
|      */ | ||||
|     options: { | ||||
|       type: Array, | ||||
|       required: true, | ||||
|     }, | ||||
|     /** | ||||
|      * Equivalent to the `multiple` attribute on a `<select>` input. | ||||
|      * @default false | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     multiple: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * Presets the selected options value. | ||||
|      * @type {Object||Array||String||Integer} | ||||
|      */ | ||||
|     value: { | ||||
|       type: null, | ||||
|       default() { | ||||
|         return [] | ||||
|       }, | ||||
|     }, | ||||
|     /** | ||||
|      * Key to compare objects | ||||
|      * @default 'id' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     trackBy: { | ||||
|       type: String, | ||||
|     }, | ||||
|     /** | ||||
|      * Label to look for in option Object | ||||
|      * @default 'label' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     label: { | ||||
|       type: String, | ||||
|     }, | ||||
|     /** | ||||
|      * Enable/disable search in options | ||||
|      * @default true | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     searchable: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     /** | ||||
|      * Clear the search input after `) | ||||
|      * @default true | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     clearOnSelect: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     /** | ||||
|      * Hide already selected options | ||||
|      * @default false | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     hideSelected: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * Equivalent to the `placeholder` attribute on a `<select>` input. | ||||
|      * @default 'Select option' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     placeholder: { | ||||
|       type: String, | ||||
|       default: 'Select option', | ||||
|     }, | ||||
|     /** | ||||
|      * Allow to remove all selected values | ||||
|      * @default true | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     allowEmpty: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     /** | ||||
|      * Reset this.internalValue, this.search after this.internalValue changes. | ||||
|      * Useful if want to create a stateless dropdown. | ||||
|      * @default false | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     resetAfter: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * Enable/disable closing after selecting an option | ||||
|      * @default true | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     closeOnSelect: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     /** | ||||
|      * Function to interpolate the custom label | ||||
|      * @default false | ||||
|      * @type {Function} | ||||
|      */ | ||||
|     customLabel: { | ||||
|       type: Function, | ||||
|       default(option, label) { | ||||
|         if (isEmpty(option)) return '' | ||||
|         return label ? option[label] : option | ||||
|       }, | ||||
|     }, | ||||
|     /** | ||||
|      * Disable / Enable tagging | ||||
|      * @default false | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     taggable: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * String to show when highlighting a potential tag | ||||
|      * @default 'Press enter to create a tag' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     tagPlaceholder: { | ||||
|       type: String, | ||||
|       default: 'Press enter to create a tag', | ||||
|     }, | ||||
|     /** | ||||
|      * By default new tags will appear above the search results. | ||||
|      * Changing to 'bottom' will revert this behaviour | ||||
|      * and will proritize the search results | ||||
|      * @default 'top' | ||||
|      * @type {String} | ||||
|      */ | ||||
|     tagPosition: { | ||||
|       type: String, | ||||
|       default: 'top', | ||||
|     }, | ||||
|     /** | ||||
|      * Number of allowed selected options. No limit if 0. | ||||
|      * @default 0 | ||||
|      * @type {Number} | ||||
|      */ | ||||
|     max: { | ||||
|       type: [Number, Boolean], | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * Will be passed with all events as second param. | ||||
|      * Useful for identifying events origin. | ||||
|      * @default null | ||||
|      * @type {String|Integer} | ||||
|      */ | ||||
|     id: { | ||||
|       default: null, | ||||
|     }, | ||||
|     /** | ||||
|      * Limits the options displayed in the dropdown | ||||
|      * to the first X options. | ||||
|      * @default 1000 | ||||
|      * @type {Integer} | ||||
|      */ | ||||
|     optionsLimit: { | ||||
|       type: Number, | ||||
|       default: 1000, | ||||
|     }, | ||||
|     /** | ||||
|      * Name of the property containing | ||||
|      * the group values | ||||
|      * @default 1000 | ||||
|      * @type {String} | ||||
|      */ | ||||
|     groupValues: { | ||||
|       type: String, | ||||
|     }, | ||||
|     /** | ||||
|      * Name of the property containing | ||||
|      * the group label | ||||
|      * @default 1000 | ||||
|      * @type {String} | ||||
|      */ | ||||
|     groupLabel: { | ||||
|       type: String, | ||||
|     }, | ||||
|     /** | ||||
|      * Allow to select all group values | ||||
|      * by selecting the group label | ||||
|      * @default false | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     groupSelect: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * Array of keyboard keys to block | ||||
|      * when selecting | ||||
|      * @default 1000 | ||||
|      * @type {String} | ||||
|      */ | ||||
|     blockKeys: { | ||||
|       type: Array, | ||||
|       default() { | ||||
|         return [] | ||||
|       }, | ||||
|     }, | ||||
|     /** | ||||
|      * Prevent from wiping up the search value | ||||
|      * @default false | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     preserveSearch: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     /** | ||||
|      * Select 1st options if value is empty | ||||
|      * @default false | ||||
|      * @type {Boolean} | ||||
|      */ | ||||
|     preselectFirst: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     /* istanbul ignore else */ | ||||
|     if (!this.multiple && this.max) { | ||||
|       console.warn( | ||||
|         '[Vue-Multiselect warn]: Max prop should not be used when prop Multiple equals false.' | ||||
|       ) | ||||
|     } | ||||
|     if ( | ||||
|       this.preselectFirst && | ||||
|       !this.internalValue.length && | ||||
|       this.options.length | ||||
|     ) { | ||||
|       this.select(this.filteredOptions[0]) | ||||
|     } | ||||
|  | ||||
|     if (this.initialSearch) { | ||||
|       this.search = this.initialSearch | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     internalValue() { | ||||
|       return this.value || this.value === 0 | ||||
|         ? Array.isArray(this.value) | ||||
|           ? this.value | ||||
|           : [this.value] | ||||
|         : [] | ||||
|     }, | ||||
|     filteredOptions() { | ||||
|       const search = this.search || '' | ||||
|       const normalizedSearch = search.toLowerCase().trim() | ||||
|  | ||||
|       let options = this.options.concat() | ||||
|  | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.internalSearch) { | ||||
|         options = this.groupValues | ||||
|           ? this.filterAndFlat(options, normalizedSearch, this.label) | ||||
|           : filterOptions( | ||||
|               options, | ||||
|               normalizedSearch, | ||||
|               this.label, | ||||
|               this.customLabel | ||||
|             ) | ||||
|       } else { | ||||
|         options = this.groupValues | ||||
|           ? flattenOptions(this.groupValues, this.groupLabel)(options) | ||||
|           : options | ||||
|       } | ||||
|  | ||||
|       options = this.hideSelected | ||||
|         ? options.filter(not(this.isSelected)) | ||||
|         : options | ||||
|  | ||||
|       /* istanbul ignore else */ | ||||
|       if ( | ||||
|         this.taggable && | ||||
|         normalizedSearch.length && | ||||
|         !this.isExistingOption(normalizedSearch) | ||||
|       ) { | ||||
|         if (this.tagPosition === 'bottom') { | ||||
|           options.push({ isTag: true, label: search }) | ||||
|         } else { | ||||
|           options.unshift({ isTag: true, label: search }) | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       return options.slice(0, this.optionsLimit) | ||||
|     }, | ||||
|     valueKeys() { | ||||
|       if (this.trackBy) { | ||||
|         return this.internalValue.map((element) => element[this.trackBy]) | ||||
|       } else { | ||||
|         return this.internalValue | ||||
|       } | ||||
|     }, | ||||
|     optionKeys() { | ||||
|       const options = this.groupValues | ||||
|         ? this.flatAndStrip(this.options) | ||||
|         : this.options | ||||
|       return options.map((element) => | ||||
|         this.customLabel(element, this.label).toString().toLowerCase() | ||||
|       ) | ||||
|     }, | ||||
|     currentOptionLabel() { | ||||
|       return this.multiple | ||||
|         ? this.searchable | ||||
|           ? '' | ||||
|           : this.placeholder | ||||
|         : this.internalValue.length | ||||
|         ? this.getOptionLabel(this.internalValue[0]) | ||||
|         : this.searchable | ||||
|         ? '' | ||||
|         : this.placeholder | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     internalValue() { | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.resetAfter && this.internalValue.length) { | ||||
|         this.search = '' | ||||
|         this.$emit('input', this.multiple ? [] : null) | ||||
|       } | ||||
|     }, | ||||
|     search() { | ||||
|       this.$emit('search-change', this.search, this.id) | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     /** | ||||
|      * Returns the internalValue in a way it can be emitted to the parent | ||||
|      * @returns {Object||Array||String||Integer} | ||||
|      */ | ||||
|     getValue() { | ||||
|       return this.multiple | ||||
|         ? this.internalValue | ||||
|         : this.internalValue.length === 0 | ||||
|         ? null | ||||
|         : this.internalValue[0] | ||||
|     }, | ||||
|     /** | ||||
|      * Filters and then flattens the options list | ||||
|      * @param  {Array} | ||||
|      * @returns {Array} returns a filtered and flat options list | ||||
|      */ | ||||
|     filterAndFlat(options, search, label) { | ||||
|       return flow( | ||||
|         filterGroups( | ||||
|           search, | ||||
|           label, | ||||
|           this.groupValues, | ||||
|           this.groupLabel, | ||||
|           this.customLabel | ||||
|         ), | ||||
|         flattenOptions(this.groupValues, this.groupLabel) | ||||
|       )(options) | ||||
|     }, | ||||
|     /** | ||||
|      * Flattens and then strips the group labels from the options list | ||||
|      * @param  {Array} | ||||
|      * @returns {Array} returns a flat options list without group labels | ||||
|      */ | ||||
|     flatAndStrip(options) { | ||||
|       return flow( | ||||
|         flattenOptions(this.groupValues, this.groupLabel), | ||||
|         stripGroups | ||||
|       )(options) | ||||
|     }, | ||||
|     /** | ||||
|      * Updates the search value | ||||
|      * @param  {String} | ||||
|      */ | ||||
|     updateSearch(query) { | ||||
|       this.search = query | ||||
|       this.$emit('value', this.search) | ||||
|     }, | ||||
|     /** | ||||
|      * Finds out if the given query is already present | ||||
|      * in the available options | ||||
|      * @param  {String} | ||||
|      * @returns {Boolean} returns true if element is available | ||||
|      */ | ||||
|     isExistingOption(query) { | ||||
|       return !this.options ? false : this.optionKeys.indexOf(query) > -1 | ||||
|     }, | ||||
|     /** | ||||
|      * Finds out if the given element is already present | ||||
|      * in the result value | ||||
|      * @param  {Object||String||Integer} option passed element to check | ||||
|      * @returns {Boolean} returns true if element is selected | ||||
|      */ | ||||
|     isSelected(option) { | ||||
|       const opt = this.trackBy ? option[this.trackBy] : option | ||||
|       return this.valueKeys.indexOf(opt) > -1 | ||||
|     }, | ||||
|     /** | ||||
|      * Finds out if the given option is disabled | ||||
|      * @param  {Object||String||Integer} option passed element to check | ||||
|      * @returns {Boolean} returns true if element is disabled | ||||
|      */ | ||||
|     isOptionDisabled(option) { | ||||
|       return !!option.$isDisabled | ||||
|     }, | ||||
|     /** | ||||
|      * Returns empty string when options is null/undefined | ||||
|      * Returns tag query if option is tag. | ||||
|      * Returns the customLabel() results and casts it to string. | ||||
|      * | ||||
|      * @param  {Object||String||Integer} Passed option | ||||
|      * @returns {Object||String} | ||||
|      */ | ||||
|     getOptionLabel(option) { | ||||
|       if (isEmpty(option)) return '' | ||||
|       /* istanbul ignore else */ | ||||
|       if (option.isTag) return option.label | ||||
|       /* istanbul ignore else */ | ||||
|       if (option.$isLabel) return option.$groupLabel | ||||
|  | ||||
|       let label = this.customLabel(option, this.label) | ||||
|       /* istanbul ignore else */ | ||||
|       if (isEmpty(label)) return '' | ||||
|       return label | ||||
|     }, | ||||
|     /** | ||||
|      * Add the given option to the list of selected options | ||||
|      * or sets the option as the selected option. | ||||
|      * If option is already selected -> remove it from the results. | ||||
|      * | ||||
|      * @param  {Object||String||Integer} option to select/deselect | ||||
|      * @param  {Boolean} block removing | ||||
|      */ | ||||
|     select(option, key) { | ||||
|       /* istanbul ignore else */ | ||||
|       if (option.$isLabel && this.groupSelect) { | ||||
|         this.selectGroup(option) | ||||
|         return | ||||
|       } | ||||
|       if ( | ||||
|         this.blockKeys.indexOf(key) !== -1 || | ||||
|         this.disabled || | ||||
|         option.$isDisabled || | ||||
|         option.$isLabel | ||||
|       ) | ||||
|         return | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.max && this.multiple && this.internalValue.length === this.max) | ||||
|         return | ||||
|       /* istanbul ignore else */ | ||||
|       if (key === 'Tab' && !this.pointerDirty) return | ||||
|       if (option.isTag) { | ||||
|         this.$emit('tag', option.label, this.id) | ||||
|         this.search = '' | ||||
|         if (this.closeOnSelect && !this.multiple) this.deactivate() | ||||
|       } else { | ||||
|         const isSelected = this.isSelected(option) | ||||
|  | ||||
|         if (isSelected) { | ||||
|           if (key !== 'Tab') this.removeElement(option) | ||||
|           return | ||||
|         } | ||||
|  | ||||
|         this.$emit('select', option, this.id) | ||||
|  | ||||
|         if (this.multiple) { | ||||
|           this.$emit('input', this.internalValue.concat([option]), this.id) | ||||
|         } else { | ||||
|           this.$emit('input', option, this.id) | ||||
|         } | ||||
|  | ||||
|         /* istanbul ignore else */ | ||||
|         if (this.clearOnSelect) this.search = '' | ||||
|       } | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.closeOnSelect) this.deactivate() | ||||
|     }, | ||||
|     /** | ||||
|      * Add the given group options to the list of selected options | ||||
|      * If all group optiona are already selected -> remove it from the results. | ||||
|      * | ||||
|      * @param  {Object||String||Integer} group to select/deselect | ||||
|      */ | ||||
|     selectGroup(selectedGroup) { | ||||
|       const group = this.options.find((option) => { | ||||
|         return option[this.groupLabel] === selectedGroup.$groupLabel | ||||
|       }) | ||||
|  | ||||
|       if (!group) return | ||||
|  | ||||
|       if (this.wholeGroupSelected(group)) { | ||||
|         this.$emit('remove', group[this.groupValues], this.id) | ||||
|  | ||||
|         const newValue = this.internalValue.filter( | ||||
|           (option) => group[this.groupValues].indexOf(option) === -1 | ||||
|         ) | ||||
|  | ||||
|         this.$emit('input', newValue, this.id) | ||||
|       } else { | ||||
|         const optionsToAdd = group[this.groupValues].filter( | ||||
|           (option) => | ||||
|             !(this.isOptionDisabled(option) || this.isSelected(option)) | ||||
|         ) | ||||
|  | ||||
|         this.$emit('select', optionsToAdd, this.id) | ||||
|         this.$emit('input', this.internalValue.concat(optionsToAdd), this.id) | ||||
|       } | ||||
|     }, | ||||
|     /** | ||||
|      * Helper to identify if all values in a group are selected | ||||
|      * | ||||
|      * @param {Object} group to validated selected values against | ||||
|      */ | ||||
|     wholeGroupSelected(group) { | ||||
|       return group[this.groupValues].every( | ||||
|         (option) => this.isSelected(option) || this.isOptionDisabled(option) | ||||
|       ) | ||||
|     }, | ||||
|     /** | ||||
|      * Helper to identify if all values in a group are disabled | ||||
|      * | ||||
|      * @param {Object} group to check for disabled values | ||||
|      */ | ||||
|     wholeGroupDisabled(group) { | ||||
|       return group[this.groupValues].every(this.isOptionDisabled) | ||||
|     }, | ||||
|     /** | ||||
|      * Removes the given option from the selected options. | ||||
|      * Additionally checks this.allowEmpty prop if option can be removed when | ||||
|      * it is the last selected option. | ||||
|      * | ||||
|      * @param  {type} option description | ||||
|      * @returns {type}        description | ||||
|      */ | ||||
|     removeElement(option, shouldClose = true) { | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.disabled) return | ||||
|       /* istanbul ignore else */ | ||||
|       if (option.$isDisabled) return | ||||
|       /* istanbul ignore else */ | ||||
|       if (!this.allowEmpty && this.internalValue.length <= 1) { | ||||
|         this.deactivate() | ||||
|         return | ||||
|       } | ||||
|  | ||||
|       const index = | ||||
|         typeof option === 'object' | ||||
|           ? this.valueKeys.indexOf(option[this.trackBy]) | ||||
|           : this.valueKeys.indexOf(option) | ||||
|  | ||||
|       this.$emit('remove', option, this.id) | ||||
|       if (this.multiple) { | ||||
|         const newValue = this.internalValue | ||||
|           .slice(0, index) | ||||
|           .concat(this.internalValue.slice(index + 1)) | ||||
|         this.$emit('input', newValue, this.id) | ||||
|       } else { | ||||
|         this.$emit('input', null, this.id) | ||||
|       } | ||||
|  | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.closeOnSelect && shouldClose) this.deactivate() | ||||
|     }, | ||||
|     /** | ||||
|      * Calls this.removeElement() with the last element | ||||
|      * from this.internalValue (selected element Array) | ||||
|      * | ||||
|      * @fires this#removeElement | ||||
|      */ | ||||
|     removeLastElement() { | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.blockKeys.indexOf('Delete') !== -1) return | ||||
|       /* istanbul ignore else */ | ||||
|       if ( | ||||
|         this.search.length === 0 && | ||||
|         Array.isArray(this.internalValue) && | ||||
|         this.internalValue.length | ||||
|       ) { | ||||
|         this.removeElement( | ||||
|           this.internalValue[this.internalValue.length - 1], | ||||
|           false | ||||
|         ) | ||||
|       } | ||||
|     }, | ||||
|     /** | ||||
|      * Opens the multiselect’s dropdown. | ||||
|      * Sets this.isOpen to TRUE | ||||
|      */ | ||||
|     activate() { | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.isOpen || this.disabled) return | ||||
|  | ||||
|       this.adjustPosition() | ||||
|       /* istanbul ignore else  */ | ||||
|       if ( | ||||
|         this.groupValues && | ||||
|         this.pointer === 0 && | ||||
|         this.filteredOptions.length | ||||
|       ) { | ||||
|         this.pointer = 1 | ||||
|       } | ||||
|  | ||||
|       this.isOpen = true | ||||
|       /* istanbul ignore else  */ | ||||
|       if (this.searchable) { | ||||
|         if (!this.preserveSearch) this.search = '' | ||||
|         this.$nextTick(() => this.$refs.search && this.$refs.search.focus()) | ||||
|       } else { | ||||
|         this.$el.focus() | ||||
|       } | ||||
|       this.$emit('open', this.id) | ||||
|     }, | ||||
|     /** | ||||
|      * Closes the multiselect’s dropdown. | ||||
|      * Sets this.isOpen to FALSE | ||||
|      */ | ||||
|     deactivate() { | ||||
|       /* istanbul ignore else */ | ||||
|       if (!this.isOpen) return | ||||
|       this.isOpen = false | ||||
|       /* istanbul ignore else  */ | ||||
|       if (this.searchable) { | ||||
|         this.$refs.search && this.$refs.search.blur() | ||||
|       } else { | ||||
|         this.$el.blur() | ||||
|       } | ||||
|       if (!this.preserveSearch) this.search = '' | ||||
|       this.$emit('close', this.getValue(), this.id) | ||||
|     }, | ||||
|     /** | ||||
|      * Call this.activate() or this.deactivate() | ||||
|      * depending on this.isOpen value. | ||||
|      * | ||||
|      * @fires this#activate || this#deactivate | ||||
|      * @property {Boolean} isOpen indicates if dropdown is open | ||||
|      */ | ||||
|     toggle() { | ||||
|       this.isOpen ? this.deactivate() : this.activate() | ||||
|     }, | ||||
|     /** | ||||
|      * Updates the hasEnoughSpace variable used for | ||||
|      * detecting where to expand the dropdown | ||||
|      */ | ||||
|     adjustPosition() { | ||||
|       if (typeof window === 'undefined') return | ||||
|  | ||||
|       const spaceAbove = this.$el.getBoundingClientRect().top | ||||
|       const spaceBelow = | ||||
|         window.innerHeight - this.$el.getBoundingClientRect().bottom | ||||
|       const hasEnoughSpaceBelow = spaceBelow > this.maxHeight | ||||
|  | ||||
|       if ( | ||||
|         hasEnoughSpaceBelow || | ||||
|         spaceBelow > spaceAbove || | ||||
|         this.openDirection === 'below' || | ||||
|         this.openDirection === 'bottom' | ||||
|       ) { | ||||
|         this.preferredOpenDirection = 'below' | ||||
|         this.optimizedHeight = Math.min(spaceBelow - 40, this.maxHeight) | ||||
|       } else { | ||||
|         this.preferredOpenDirection = 'above' | ||||
|         this.optimizedHeight = Math.min(spaceAbove - 40, this.maxHeight) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,172 +0,0 @@ | ||||
| import CraterTheme from '../theme/index' | ||||
| const { multiselectOption } = CraterTheme.BaseSelect | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       pointer: 0, | ||||
|       pointerDirty: false, | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     /** | ||||
|      * Enable/disable highlighting of the pointed value. | ||||
|      * @type {Boolean} | ||||
|      * @default true | ||||
|      */ | ||||
|     showPointer: { | ||||
|       type: Boolean, | ||||
|       default: true, | ||||
|     }, | ||||
|     optionHeight: { | ||||
|       type: Number, | ||||
|       default: 40, | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     pointerPosition() { | ||||
|       return this.pointer * this.optionHeight | ||||
|     }, | ||||
|     visibleElements() { | ||||
|       return this.optimizedHeight / this.optionHeight | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     filteredOptions() { | ||||
|       this.pointerAdjust() | ||||
|     }, | ||||
|     isOpen() { | ||||
|       this.pointerDirty = false | ||||
|     }, | ||||
|     pointer() { | ||||
|       this.$refs.search.setAttribute( | ||||
|         'aria-activedescendant', | ||||
|         this.id + '-' + this.pointer.toString() | ||||
|       ) | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     optionHighlight(index, option) { | ||||
|       return [ | ||||
|         { | ||||
|           'multiselect__option--highlight': | ||||
|             index === this.pointer && this.showPointer, | ||||
|           'multiselect__option--selected': this.isSelected(option), | ||||
|         }, | ||||
|         multiselectOption, | ||||
|       ] | ||||
|     }, | ||||
|     groupHighlight(index, selectedGroup) { | ||||
|       if (!this.groupSelect) { | ||||
|         return [ | ||||
|           'multiselect__option--group', | ||||
|           'multiselect__option--disabled', | ||||
|           multiselectOption, | ||||
|         ] | ||||
|       } | ||||
|  | ||||
|       const group = this.options.find((option) => { | ||||
|         return option[this.groupLabel] === selectedGroup.$groupLabel | ||||
|       }) | ||||
|  | ||||
|       return group && !this.wholeGroupDisabled(group) | ||||
|         ? [ | ||||
|             'multiselect__option--group', | ||||
|             { | ||||
|               'multiselect__option--highlight': | ||||
|                 index === this.pointer && this.showPointer, | ||||
|             }, | ||||
|             { | ||||
|               'multiselect__option--group-selected': this.wholeGroupSelected( | ||||
|                 group | ||||
|               ), | ||||
|             }, | ||||
|             multiselectOption, | ||||
|           ] | ||||
|         : ['multiselect__option--disabled', multiselectOption] | ||||
|     }, | ||||
|     addPointerElement({ key } = 'Enter') { | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.filteredOptions.length > 0) { | ||||
|         this.select(this.filteredOptions[this.pointer], key) | ||||
|       } | ||||
|       this.pointerReset() | ||||
|     }, | ||||
|     pointerForward() { | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.pointer < this.filteredOptions.length - 1) { | ||||
|         this.pointer++ | ||||
|         /* istanbul ignore next */ | ||||
|         if ( | ||||
|           this.$refs.list.scrollTop <= | ||||
|           this.pointerPosition - (this.visibleElements - 1) * this.optionHeight | ||||
|         ) { | ||||
|           this.$refs.list.scrollTop = | ||||
|             this.pointerPosition - | ||||
|             (this.visibleElements - 1) * this.optionHeight | ||||
|         } | ||||
|         /* istanbul ignore else */ | ||||
|         if ( | ||||
|           this.filteredOptions[this.pointer] && | ||||
|           this.filteredOptions[this.pointer].$isLabel && | ||||
|           !this.groupSelect | ||||
|         ) | ||||
|           this.pointerForward() | ||||
|       } | ||||
|       this.pointerDirty = true | ||||
|     }, | ||||
|     pointerBackward() { | ||||
|       if (this.pointer > 0) { | ||||
|         this.pointer-- | ||||
|         /* istanbul ignore else */ | ||||
|         if (this.$refs.list.scrollTop >= this.pointerPosition) { | ||||
|           this.$refs.list.scrollTop = this.pointerPosition | ||||
|         } | ||||
|         /* istanbul ignore else */ | ||||
|         if ( | ||||
|           this.filteredOptions[this.pointer] && | ||||
|           this.filteredOptions[this.pointer].$isLabel && | ||||
|           !this.groupSelect | ||||
|         ) | ||||
|           this.pointerBackward() | ||||
|       } else { | ||||
|         /* istanbul ignore else */ | ||||
|         if ( | ||||
|           this.filteredOptions[this.pointer] && | ||||
|           this.filteredOptions[0].$isLabel && | ||||
|           !this.groupSelect | ||||
|         ) | ||||
|           this.pointerForward() | ||||
|       } | ||||
|       this.pointerDirty = true | ||||
|     }, | ||||
|     pointerReset() { | ||||
|       /* istanbul ignore else */ | ||||
|       if (!this.closeOnSelect) return | ||||
|       this.pointer = 0 | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.$refs.list) { | ||||
|         this.$refs.list.scrollTop = 0 | ||||
|       } | ||||
|     }, | ||||
|     pointerAdjust() { | ||||
|       /* istanbul ignore else */ | ||||
|       if (this.pointer >= this.filteredOptions.length - 1) { | ||||
|         this.pointer = this.filteredOptions.length | ||||
|           ? this.filteredOptions.length - 1 | ||||
|           : 0 | ||||
|       } | ||||
|  | ||||
|       if ( | ||||
|         this.filteredOptions.length > 0 && | ||||
|         this.filteredOptions[this.pointer].$isLabel && | ||||
|         !this.groupSelect | ||||
|       ) { | ||||
|         this.pointerForward() | ||||
|       } | ||||
|     }, | ||||
|     pointerSet(index) { | ||||
|       this.pointer = index | ||||
|       this.pointerDirty = true | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,46 +0,0 @@ | ||||
| import Vue from 'vue' | ||||
|  | ||||
| import BaseModal from './modal/BaseModal.vue' | ||||
| import BaseLoader from './BaseLoader.vue' | ||||
| import BaseCustomerSelect from './BaseCustomerSelect.vue' | ||||
|  | ||||
| import BaseCustomInput from './BaseCustomInput.vue' | ||||
|  | ||||
| import CustomerSelectPopup from './popup/CustomerSelectPopup.vue' | ||||
| import TaxSelectPopup from './popup/TaxSelectPopup.vue' | ||||
| import NoteSelectPopup from './popup/NoteSelectPopup.vue' | ||||
|  | ||||
| import BaseDatePicker from '../base/BaseDatePicker.vue' | ||||
| import BaseTimePicker from './BaseTimePicker.vue' | ||||
| import BasePage from './BasePage.vue' | ||||
| import BaseNotification from './BaseNotification.vue' | ||||
|  | ||||
| import GlobalSearch from '../GlobalSearch.vue' | ||||
|  | ||||
| import DotIcon from '../../components/icon/DotIcon.vue' | ||||
| import SaveIcon from '../../components/icon/SaveIcon.vue' | ||||
|  | ||||
| import SwSelect from '@bytefury/spacewind/src/components/sw-select' | ||||
|  | ||||
| Vue.component('base-modal', BaseModal) | ||||
| Vue.component('global-search', GlobalSearch) | ||||
|  | ||||
| Vue.component('base-page', BasePage) | ||||
|  | ||||
| Vue.component('base-date-picker', BaseDatePicker) | ||||
|  | ||||
| Vue.component('base-loader', BaseLoader) | ||||
| Vue.component('sw-select', SwSelect) | ||||
|  | ||||
| Vue.component('base-customer-select', BaseCustomerSelect) | ||||
| Vue.component('base-custom-input', BaseCustomInput) | ||||
|  | ||||
| Vue.component('customer-select-popup', CustomerSelectPopup) | ||||
| Vue.component('tax-select-popup', TaxSelectPopup) | ||||
| Vue.component('note-select-popup', NoteSelectPopup) | ||||
|  | ||||
| Vue.component('base-time-picker', BaseTimePicker) | ||||
| Vue.component('base-notification', BaseNotification) | ||||
|  | ||||
| Vue.component('dot-icon', DotIcon) | ||||
| Vue.component('save-icon', SaveIcon) | ||||
| @ -1,187 +0,0 @@ | ||||
| <template> | ||||
|   <div class="relative customer-modal"> | ||||
|     <base-loader | ||||
|       v-if="isRequestOngoing" | ||||
|       :show-bg-overlay="true" | ||||
|       class="h-130" | ||||
|     /> | ||||
|     <form @submit.prevent="createNewBackup"> | ||||
|       <div class="p-6"> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.backup.select_backup_type')" | ||||
|           :error="optionError" | ||||
|           horizontal | ||||
|           required | ||||
|           class="py-2" | ||||
|         > | ||||
|           <sw-select | ||||
|             v-model="formData.option" | ||||
|             :options="options" | ||||
|             :searchable="true" | ||||
|             :show-labels="false" | ||||
|             :placeholder="$t('settings.backup.select_backup_type')" | ||||
|             :allow-empty="false" | ||||
|             :max-height="100" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.select_disk')" | ||||
|           :error="selectDiskError" | ||||
|           horizontal | ||||
|           required | ||||
|           class="py-2" | ||||
|         > | ||||
|           <sw-select | ||||
|             v-model="formData.selected_disk" | ||||
|             :options="getDisks" | ||||
|             :searchable="true" | ||||
|             :show-labels="false" | ||||
|             :placeholder="$t('settings.disk.select_disk')" | ||||
|             :allow-empty="false" | ||||
|             :preselect-first="true" | ||||
|             :custom-label="getCustomLabel" | ||||
|             :max-height="100" | ||||
|             :loading="isLoading" | ||||
|             track-by="id" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3" | ||||
|           variant="primary-outline" | ||||
|           type="button" | ||||
|           @click="cancelBackup" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button | ||||
|           :loading="isCreateLoading" | ||||
|           :disabled="isCreateLoading" | ||||
|           variant="primary" | ||||
|           type="submit" | ||||
|         > | ||||
|           <save-icon v-if="!isCreateLoading" class="mr-2" /> | ||||
|           {{ $t('general.create') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import AddressStub from '../../../stub/address' | ||||
| import _ from 'lodash' | ||||
|  | ||||
| const { required } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       isLoading: false, | ||||
|       isCreateLoading: false, | ||||
|       isRequestOngoing: false, | ||||
|       formData: { | ||||
|         option: 'full', | ||||
|         selected_disk: { driver: 'local' }, | ||||
|       }, | ||||
|       options: ['full', 'only-db', 'only-files'], | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   validations: { | ||||
|     formData: { | ||||
|       option: { | ||||
|         required, | ||||
|       }, | ||||
|       selected_disk: { | ||||
|         required, | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('disks', ['getDisks']), | ||||
|  | ||||
|     ...mapGetters('modal', ['refreshData']), | ||||
|  | ||||
|     optionError() { | ||||
|       if (!this.$v.formData.option.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.option) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     selectDiskError() { | ||||
|       if (!this.$v.formData.selected_disk.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.selected_disk) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.loadData() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('backup', ['createBackup']), | ||||
|  | ||||
|     ...mapActions('disks', ['fetchDisks']), | ||||
|  | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|  | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|  | ||||
|     getCustomLabel({ driver, name }) { | ||||
|       return `${name} — [${driver}]` | ||||
|     }, | ||||
|  | ||||
|     async createNewBackup() { | ||||
|       let data = { | ||||
|         option: this.formData.option, | ||||
|         file_disk_id: this.formData.selected_disk.id, | ||||
|       } | ||||
|  | ||||
|       try { | ||||
|         this.isCreateLoading = true | ||||
|         await this.createBackup(data) | ||||
|         this.isCreateLoading = false | ||||
|         this.showNotification({ | ||||
|           type: 'success', | ||||
|           message: this.$t('settings.backup.created_message'), | ||||
|         }) | ||||
|         this.refreshData ? this.refreshData() : '' | ||||
|         this.cancelBackup() | ||||
|       } catch (e) { | ||||
|         this.isCreateLoading = false | ||||
|         this.showNotification({ | ||||
|           type: 'error', | ||||
|           message: e.response.data.message, | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     async loadData() { | ||||
|       this.isRequestOngoing = true | ||||
|  | ||||
|       let res = await this.fetchDisks({ limit: 'all' }) | ||||
|       this.formData.selected_disk = res.data.disks.data[0] | ||||
|       this.isRequestOngoing = false | ||||
|     }, | ||||
|  | ||||
|     cancelBackup() { | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,96 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-modal ref="baseModal" :variant="variant"> | ||||
|       <template v-slot:header> | ||||
|         <div | ||||
|           class="absolute flex content-center justify-center w-5 cursor-pointer" | ||||
|           style="top: 20px; right: 15px" | ||||
|           @click="closeModal" | ||||
|         > | ||||
|           <x-icon /> | ||||
|         </div> | ||||
|         <span>{{ modalTitle }}</span> | ||||
|       </template> | ||||
|       <component :is="component" /> | ||||
|     </sw-modal> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { XIcon } from '@vue-hero-icons/solid' | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import TaxTypeModal from './TaxTypeModal' | ||||
| import ItemModal from './ItemModal' | ||||
| import EstimateTemplate from './EstimateTemplate' | ||||
| import InvoiceTemplate from './InvoiceTemplate' | ||||
| import CustomerModal from './CustomerModal' | ||||
| import CategoryModal from './CategoryModal' | ||||
| import BackupModal from './BackupModal' | ||||
| import PaymentMode from './PaymentModeModal' | ||||
| import ItemUnit from './ItemUnitModal' | ||||
| import MailTestModal from './MailTestModal' | ||||
| import SendInvoiceModal from './SendInvoiceModal' | ||||
| import SendEstimateModal from './SendEstimateModal' | ||||
| import SendPaymentModal from './SendPaymentModal' | ||||
| import FileDiskModal from './FileDiskModal' | ||||
| import SetDefaultDiskModal from './SetDefaultDiskModal' | ||||
| import CustomFieldModal from './CustomField/Index' | ||||
| import NoteSelectModal from './NoteModal' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     TaxTypeModal, | ||||
|     ItemModal, | ||||
|     EstimateTemplate, | ||||
|     InvoiceTemplate, | ||||
|     CustomerModal, | ||||
|     CategoryModal, | ||||
|     BackupModal, | ||||
|     PaymentMode, | ||||
|     ItemUnit, | ||||
|     MailTestModal, | ||||
|     SendInvoiceModal, | ||||
|     SendEstimateModal, | ||||
|     SendPaymentModal, | ||||
|     XIcon, | ||||
|     FileDiskModal, | ||||
|     SetDefaultDiskModal, | ||||
|     CustomFieldModal, | ||||
|     NoteSelectModal, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       component: '', | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalActive', | ||||
|       'modalTitle', | ||||
|       'componentName', | ||||
|       'modalSize', | ||||
|       'modalData', | ||||
|       'variant', | ||||
|     ]), | ||||
|   }, | ||||
|   watch: { | ||||
|     componentName(component) { | ||||
|       if (!component) { | ||||
|         return | ||||
|       } | ||||
|       this.component = component | ||||
|     }, | ||||
|     modalActive(status) { | ||||
|       if (status) { | ||||
|         this.$refs.baseModal.open() | ||||
|         return true | ||||
|       } | ||||
|       this.$refs.baseModal.close() | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['openModal', 'closeModal']), | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,198 +0,0 @@ | ||||
| <template> | ||||
|   <form action="" @submit.prevent="submitCategoryData"> | ||||
|     <div class="p-8 sm:p-6"> | ||||
|       <sw-input-group | ||||
|         :label="$t('expenses.category')" | ||||
|         :error="nameError" | ||||
|         variant="horizontal" | ||||
|         required | ||||
|       > | ||||
|         <sw-input | ||||
|           ref="name" | ||||
|           :invalid="$v.formData.name.$error" | ||||
|           v-model="formData.name" | ||||
|           type="text" | ||||
|           @input="$v.formData.name.$touch()" | ||||
|         /> | ||||
|       </sw-input-group> | ||||
|  | ||||
|       <sw-input-group | ||||
|         :label="$t('expenses.description')" | ||||
|         :error="descriptionError" | ||||
|         class="mt-5" | ||||
|         variant="horizontal" | ||||
|       > | ||||
|         <sw-textarea | ||||
|           v-model="formData.description" | ||||
|           rows="4" | ||||
|           cols="50" | ||||
|           @input="$v.formData.description.$touch()" | ||||
|         /> | ||||
|       </sw-input-group> | ||||
|     </div> | ||||
|     <div | ||||
|       class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid border-modal-bg" | ||||
|     > | ||||
|       <sw-button | ||||
|         type="button" | ||||
|         variant="primary-outline" | ||||
|         class="mr-3 text-sm" | ||||
|         @click="closeCategoryModal" | ||||
|       > | ||||
|         {{ $t('general.cancel') }} | ||||
|       </sw-button> | ||||
|       <sw-button :loading="isLoading" variant="primary" type="submit"> | ||||
|         <save-icon v-if="!isLoading" class="mr-2" /> | ||||
|         {{ !isEdit ? $t('general.save') : $t('general.update') }} | ||||
|       </sw-button> | ||||
|     </div> | ||||
|   </form> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| const { required, minLength, maxLength } = require('vuelidate/lib/validators') | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       isLoading: false, | ||||
|       formData: { | ||||
|         id: null, | ||||
|         name: null, | ||||
|         description: null, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalDataID', | ||||
|       'modalData', | ||||
|       'modalActive', | ||||
|       'refreshData', | ||||
|     ]), | ||||
|     nameError() { | ||||
|       if (!this.$v.formData.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.minLength) { | ||||
|         return this.$tc( | ||||
|           'validation.name_min_length', | ||||
|           this.$v.formData.name.$params.minLength.min, | ||||
|           { count: this.$v.formData.name.$params.minLength.min } | ||||
|         ) | ||||
|       } | ||||
|     }, | ||||
|     descriptionError() { | ||||
|       if (!this.$v.formData.description.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.name.maxLength) { | ||||
|         return this.$tc('validation.description_maxlength') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   validations: { | ||||
|     formData: { | ||||
|       name: { | ||||
|         required, | ||||
|         minLength: minLength(3), | ||||
|       }, | ||||
|       description: { | ||||
|         maxLength: maxLength(255), | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     modalDataID(val) { | ||||
|       if (val) { | ||||
|         this.isEdit = true | ||||
|         this.setData() | ||||
|       } else { | ||||
|         this.isEdit = false | ||||
|       } | ||||
|     }, | ||||
|     modalActive(val) { | ||||
|       if (!this.modalActive) { | ||||
|         this.resetFormData() | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   mounted() { | ||||
|     this.$refs.name.focus = true | ||||
|     if (this.modalDataID) { | ||||
|       this.isEdit = true | ||||
|       this.setData() | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|     ...mapActions('category', ['addCategory', 'updateCategory']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|  | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         id: null, | ||||
|         name: null, | ||||
|         description: null, | ||||
|       } | ||||
|       this.$v.formData.$reset() | ||||
|     }, | ||||
|     async submitCategoryData() { | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|       this.isLoading = true | ||||
|       let response | ||||
|       if (!this.isEdit) { | ||||
|         response = await this.addCategory(this.formData) | ||||
|       } else { | ||||
|         response = await this.updateCategory(this.formData) | ||||
|       } | ||||
|  | ||||
|       if (response.data) { | ||||
|         if (!this.isEdit) { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$t('settings.expense_category.created_message'), | ||||
|           }) | ||||
|         } else { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$t('settings.expense_category.updated_message'), | ||||
|           }) | ||||
|         } | ||||
|         window.hub.$emit('newCategory', response.data.category) | ||||
|         this.refreshData ? this.refreshData() : '' | ||||
|         this.closeCategoryModal() | ||||
|         this.isLoading = false | ||||
|         return true | ||||
|       } | ||||
|       this.showNotification({ | ||||
|         type: 'error', | ||||
|         message: response.data.error, | ||||
|       }) | ||||
|     }, | ||||
|     async setData() { | ||||
|       this.formData = { | ||||
|         id: this.modalData.id, | ||||
|         name: this.modalData.name, | ||||
|         description: this.modalData.description, | ||||
|       } | ||||
|     }, | ||||
|     closeCategoryModal() { | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,505 +0,0 @@ | ||||
| <template> | ||||
|   <div class="custom-field-modal"> | ||||
|     <form action="" @submit.prevent="submitCustomFieldData"> | ||||
|       <div | ||||
|         class="px-8 py-8 overflow-y-auto sw-scroll sm:p-6" | ||||
|         style="max-height: 600px" | ||||
|       > | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.custom_fields.name')" | ||||
|           :error="nameError" | ||||
|           horizontal | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             ref="name" | ||||
|             :invalid="$v.formData.name.$error" | ||||
|             v-model="formData.name" | ||||
|             type="text" | ||||
|             @input="$v.formData.name.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.custom_fields.model')" | ||||
|           :error="modalTypeError" | ||||
|           class="mt-5" | ||||
|           horizontal | ||||
|           required | ||||
|         > | ||||
|           <sw-select | ||||
|             v-model="formData.model_type" | ||||
|             :options="modelTypes" | ||||
|             :invalid="$v.formData.model_type.$error" | ||||
|             :searchable="true" | ||||
|             :show-labels="false" | ||||
|             :allow-empty="false" | ||||
|             @input="$v.formData.model_type.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.custom_fields.required')" | ||||
|           class="mt-5" | ||||
|           horizontal | ||||
|         > | ||||
|           <sw-switch v-model="formData.is_required" style="margin-top: -20px" /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.custom_fields.type')" | ||||
|           :error="dataTypeError" | ||||
|           class="mt-5" | ||||
|           horizontal | ||||
|           required | ||||
|         > | ||||
|           <sw-select | ||||
|             v-model="selectType" | ||||
|             :options="dataTypes" | ||||
|             :invalid="$v.selectType.$error" | ||||
|             :searchable="true" | ||||
|             :show-labels="false" | ||||
|             :allow-empty="false" | ||||
|             track-by="label" | ||||
|             label="label" | ||||
|             @input="onSelectTypeChange" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.custom_fields.label')" | ||||
|           :error="labelError" | ||||
|           class="mt-5" | ||||
|           horizontal | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             ref="name" | ||||
|             :invalid="$v.formData.label.$error" | ||||
|             v-model="formData.label" | ||||
|             type="text" | ||||
|             @input="$v.formData.label.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           v-if="isDropdownSelected" | ||||
|           :label="$t('settings.custom_fields.options')" | ||||
|           class="mt-5" | ||||
|           horizontal | ||||
|         > | ||||
|           <option-create @onAdd="addNewOptions" /> | ||||
|           <div | ||||
|             v-for="(option, index) in formData.options" | ||||
|             :key="index" | ||||
|             class="flex items-center" | ||||
|             style="margin-top: 5px" | ||||
|           > | ||||
|             <sw-input v-model="option.name" type="text" style="width: 90%" /> | ||||
|             <minus-circle-icon | ||||
|               class="ml-1 cursor-pointer icon text-danger" | ||||
|               @click="removeOption(index)" | ||||
|             /> | ||||
|           </div> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           v-if="formData.type" | ||||
|           :label="$t('settings.custom_fields.default_value')" | ||||
|           horizontal | ||||
|           class="relative mt-5" | ||||
|         > | ||||
|           <component | ||||
|             :value="formData.default_answer" | ||||
|             :is="formData.type + 'Type'" | ||||
|             :options="formData.options" | ||||
|             :default-date-time="formData.dateTimeValue" | ||||
|             v-model="formData.default_answer" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           v-if="!isSwitchTypeSelected" | ||||
|           :label="$t('settings.custom_fields.placeholder')" | ||||
|           class="mt-5" | ||||
|           horizontal | ||||
|         > | ||||
|           <sw-input v-model="formData.placeholder" type="text" /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.custom_fields.order')" | ||||
|           :error="orderError" | ||||
|           class="mt-5" | ||||
|           horizontal | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.order" | ||||
|             :invalid="$v.formData.order.$error" | ||||
|             type="number" | ||||
|             @input="$v.formData.order.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-solid border-gray-light border-modal-bg" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3" | ||||
|           type="button" | ||||
|           variant="primary-outline" | ||||
|           @click="closeCategoryModal" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button | ||||
|           :loading="isLoading" | ||||
|           :disabled="isLoading" | ||||
|           variant="primary" | ||||
|           type="submit" | ||||
|         > | ||||
|           <save-icon v-if="!isLoading" class="mr-2" /> | ||||
|           {{ !isEdit ? $t('general.save') : $t('general.update') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { MinusCircleIcon } from '@vue-hero-icons/solid' | ||||
| import InputType from './types/InputType' | ||||
| import NumberType from './types/NumberType' | ||||
| import SwitchType from './types/SwitchType' | ||||
| import TextAreaType from './types/TextAreaType' | ||||
| import TimeType from './types/TimeType' | ||||
| import UrlType from './types/UrlType' | ||||
| import PhoneType from './types/PhoneType' | ||||
| import DateTimeType from './types/DateTimeType' | ||||
| import DateType from './types/DateType' | ||||
| import DropdownType from './types/DropdownType' | ||||
|  | ||||
| import OptionCreate from './types/OptionsCreate' | ||||
| import moment from 'moment' | ||||
|  | ||||
| const { | ||||
|   required, | ||||
|   requiredIf, | ||||
|   numeric, | ||||
|   minLength, | ||||
| } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     MinusCircleIcon, | ||||
|     OptionCreate, | ||||
|     InputType, | ||||
|     NumberType, | ||||
|     SwitchType, | ||||
|     TextAreaType, | ||||
|     TimeType, | ||||
|     UrlType, | ||||
|     PhoneType, | ||||
|     DateTimeType, | ||||
|     DateType, | ||||
|     DropdownType, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       dateType: 'custom', | ||||
|       isLoading: false, | ||||
|       relativeDateTypes: [ | ||||
|         'Today', | ||||
|         'Tomorrow', | ||||
|         'Yesterday', | ||||
|         'Starting Date of Week', | ||||
|         'Ending Date of Week', | ||||
|         'Starting Date of Next Week', | ||||
|         'Ending Date of Next Week', | ||||
|         'Starting Date of Previous Week', | ||||
|         'Ending Date of Previous Week', | ||||
|         'Starting Date of Month', | ||||
|         'Ending Date of Month', | ||||
|         'Starting Date of Next Month', | ||||
|         'Ending Date of Next Month', | ||||
|         'Starting Date of Previous Month', | ||||
|         'Ending Date of Previous Month', | ||||
|         'Starting Date of Fiscal Month', | ||||
|         'Ending Date of Fiscal Month', | ||||
|       ], | ||||
|       dataTypes: [ | ||||
|         { label: 'Text', value: 'Input' }, | ||||
|         { label: 'Textarea', value: 'TextArea' }, | ||||
|         { label: 'Phone', value: 'Phone' }, | ||||
|         { label: 'URL', value: 'Url' }, | ||||
|         { label: 'Number', value: 'Number' }, | ||||
|         { label: 'Select Field', value: 'Dropdown' }, | ||||
|         { label: 'Switch Toggle', value: 'Switch' }, | ||||
|         { label: 'Date', value: 'Date' }, | ||||
|         { label: 'Time', value: 'Time' }, | ||||
|         { label: 'Date & Time', value: 'DateTime' }, | ||||
|       ], | ||||
|       modelTypes: ['Customer', 'Invoice', 'Estimate', 'Expense', 'Payment'], | ||||
|       selectType: null, | ||||
|       formData: { | ||||
|         label: null, | ||||
|         type: null, | ||||
|         name: null, | ||||
|         default_answer: null, | ||||
|         is_required: false, | ||||
|         placeholder: null, | ||||
|         model_type: null, | ||||
|         order: 1, | ||||
|         options: [], | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     selectType: { | ||||
|       required, | ||||
|     }, | ||||
|     formData: { | ||||
|       name: { | ||||
|         required, | ||||
|       }, | ||||
|       label: { | ||||
|         required, | ||||
|       }, | ||||
|       model_type: { | ||||
|         required, | ||||
|       }, | ||||
|       order: { | ||||
|         required, | ||||
|         numeric, | ||||
|       }, | ||||
|       options: { | ||||
|         required: requiredIf('isDropdownSelected'), | ||||
|         minLength: minLength(1), | ||||
|         $each: { | ||||
|           name: { | ||||
|             required: requiredIf('isDropdownSelected'), | ||||
|             minLength: minLength(1), | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalData', 'modalDataID', 'refreshData']), | ||||
|     isDropdownSelected() { | ||||
|       if (this.selectType && this.selectType.label === 'Select Field') { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isSwitchTypeSelected() { | ||||
|       if (this.selectType && this.selectType.label === 'Switch Toggle') { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     nameError() { | ||||
|       if (!this.$v.formData.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     labelError() { | ||||
|       if (!this.$v.formData.label.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.label.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     modalTypeError() { | ||||
|       if (!this.$v.formData.model_type.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.model_type.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     dataTypeError() { | ||||
|       if (!this.$v.selectType.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.selectType.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     hasPlaceHolder() { | ||||
|       if (this.selectType.label == 'Switch Toggle') { | ||||
|         return false | ||||
|       } | ||||
|       return true | ||||
|     }, | ||||
|     orderError() { | ||||
|       if (!this.$v.formData.order.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.order.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.order.numeric) { | ||||
|         return this.$tc('validation.numbers_only') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     'formData.type'(newValue, oldvalue) { | ||||
|       if (oldvalue != null || oldvalue != undefined) { | ||||
|         this.onChangeReset() | ||||
|       } | ||||
|     }, | ||||
|     dateType(newValue, oldvalue) { | ||||
|       if (oldvalue != null || oldvalue != undefined) { | ||||
|         this.onChangeReset() | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     if (this.modalDataID) { | ||||
|       this.setData() | ||||
|       return true | ||||
|     } | ||||
|     this.formData.model_type = this.modelTypes[0] | ||||
|     this.selectType = this.dataTypes[0] | ||||
|     this.formData.type = this.dataTypes[0].value | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('customFields', [ | ||||
|       'addCustomField', | ||||
|       'updateCustomField', | ||||
|       'fetchCustomField', | ||||
|     ]), | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         label: null, | ||||
|         label: null, | ||||
|         type: null, | ||||
|         dateTimeValue: null, | ||||
|         default_answer: null, | ||||
|         is_required: false, | ||||
|         placeholder: null, | ||||
|         model_type: null, | ||||
|         options: [{ name: '' }], | ||||
|       } | ||||
|       this.$v.$reset() | ||||
|     }, | ||||
|     async submitCustomFieldData() { | ||||
|       this.$v.selectType.$touch() | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return false | ||||
|       } | ||||
|  | ||||
|       let data = { | ||||
|         ...this.formData, | ||||
|         options: this.formData.options.map((option) => option.name), | ||||
|         default_answer: | ||||
|           this.isDropdownSelected && this.formData.default_answer | ||||
|             ? this.formData.default_answer.name | ||||
|             : this.formData.default_answer, | ||||
|       } | ||||
|       if (this.isSwitchTypeSelected && this.formData.default_answer == null) { | ||||
|         data.default_answer = false | ||||
|       } | ||||
|       if (data.type == 'Date') { | ||||
|         data.default_answer = data.default_answer | ||||
|           ? moment(data.default_answer).format('YYYY-MM-DD') | ||||
|           : null | ||||
|       } | ||||
|       if (data.type == 'Time' && typeof data.default_answer == 'object') { | ||||
|         let HH = | ||||
|           data && data.default_answer && data.default_answer.HH | ||||
|             ? data.default_answer.HH | ||||
|             : null | ||||
|         let mm = | ||||
|           data && data.default_answer && data.default_answer.mm | ||||
|             ? data.default_answer.mm | ||||
|             : null | ||||
|         let ss = | ||||
|           data && data.default_answer && data.default_answer.ss | ||||
|             ? data.default_answer.ss | ||||
|             : null | ||||
|         data.default_answer = `${HH}:${mm}:${ss}` | ||||
|       } | ||||
|       let response = null | ||||
|       if (this.isEdit) { | ||||
|         this.isLoading = true | ||||
|         response = await this.updateCustomField(data) | ||||
|         this.showNotification({ | ||||
|           type: 'success', | ||||
|           message: this.$tc('settings.custom_fields.updated_message'), | ||||
|         }) | ||||
|         this.refreshData() | ||||
|         this.closeCategoryModal() | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       this.isLoading = true | ||||
|       response = await this.addCustomField(data) | ||||
|  | ||||
|       this.showNotification({ | ||||
|         type: 'success', | ||||
|         message: this.$tc('settings.custom_fields.added_message'), | ||||
|       }) | ||||
|       this.refreshData() | ||||
|       this.closeCategoryModal() | ||||
|       return true | ||||
|     }, | ||||
|     addNewOptions(option) { | ||||
|       this.formData.options = [{ name: option }, ...this.formData.options] | ||||
|     }, | ||||
|     removeOption(index) { | ||||
|       this.formData.options.splice(index, 1) | ||||
|     }, | ||||
|     async setData() { | ||||
|       let response = await this.fetchCustomField(this.modalDataID) | ||||
|       let fieldData = response.data.customField | ||||
|       this.isEdit = true | ||||
|       let data = { | ||||
|         ...fieldData, | ||||
|         options: [], | ||||
|         dateTimeValue: fieldData.defaultAnswer, | ||||
|         default_answer: fieldData.defaultAnswer, | ||||
|         options: fieldData.options | ||||
|           ? fieldData.options.map((option) => { | ||||
|               return { name: option ? option : '' } | ||||
|             }) | ||||
|           : [], | ||||
|       } | ||||
|       this.selectType = this.dataTypes.find( | ||||
|         (type) => type.value == fieldData.type | ||||
|       ) | ||||
|       if (data.type == 'Dropdown') { | ||||
|         data.default_answer = { name: fieldData.defaultAnswer } | ||||
|       } | ||||
|       this.formData = { ...data } | ||||
|     }, | ||||
|     onChangeReset() { | ||||
|       this.formData = { | ||||
|         ...this.formData, | ||||
|         default_answer: null, | ||||
|         is_required: false, | ||||
|         placeholder: null, | ||||
|         options: [], | ||||
|       } | ||||
|     }, | ||||
|     onSelectTypeChange(data) { | ||||
|       this.formData.type = data.value | ||||
|       this.$v.selectType.$touch() | ||||
|     }, | ||||
|     closeCategoryModal() { | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,35 +0,0 @@ | ||||
| <template> | ||||
|   <base-date-picker | ||||
|     v-model="inputValue" | ||||
|     :enable-time="true" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| import moment from 'moment' | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|     defaultDateTime: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value ? this.value : moment().format('YYYY-MM-DD hh:mm'), | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|     defaultDateTime(data) { | ||||
|       this.dateTimeValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,29 +0,0 @@ | ||||
| <template> | ||||
|   <base-date-picker | ||||
|     :calendar-button="true" | ||||
|     v-model="inputValue" | ||||
|     calendar-button-icon="calendar" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| import moment from 'moment' | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: [String, Date], | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: moment().format('YYYY-MM-DD'), | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,37 +0,0 @@ | ||||
| <template> | ||||
|   <sw-select | ||||
|     v-model="inputValue" | ||||
|     :options="inputOptions" | ||||
|     :taggable="true" | ||||
|     :show-labels="false" | ||||
|     label="name" | ||||
|     track-by="name" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: [String, Object], | ||||
|       default: null, | ||||
|     }, | ||||
|     options: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value, | ||||
|       inputOptions: this.options, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     options(data) { | ||||
|       this.inputOptions = data | ||||
|       this.inputValue = null | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,27 +0,0 @@ | ||||
| <template> | ||||
|   <sw-input | ||||
|     v-model="inputValue" | ||||
|     type="text" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,27 +0,0 @@ | ||||
| <template> | ||||
|   <sw-input | ||||
|     v-model="inputValue" | ||||
|     type="number" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: [String, Number], | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,41 +0,0 @@ | ||||
| <template> | ||||
|   <div class="flex items-center" style="margin-top: 5px"> | ||||
|     <sw-input | ||||
|       v-model="option" | ||||
|       type="text" | ||||
|       style="width: 90%" | ||||
|       @handleEnter.stop="onAddOption" | ||||
|     /> | ||||
|     <plus-circle-icon | ||||
|       class="ml-1 cursor-pointer text-danger" | ||||
|       @click="onAddOption" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import { PlusCircleIcon } from '@vue-hero-icons/solid' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     PlusCircleIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       option: null, | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     onAddOption() { | ||||
|       if ( | ||||
|         this.option == null || | ||||
|         this.option == '' || | ||||
|         this.option == undefined | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       this.$emit('onAdd', this.option) | ||||
|       this.option = null | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,27 +0,0 @@ | ||||
| <template> | ||||
|   <sw-input | ||||
|     v-model="inputValue" | ||||
|     type="text" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: [String, Number], | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,27 +0,0 @@ | ||||
| <template> | ||||
|   <sw-switch | ||||
|     class="-mt-3" | ||||
|     v-model="inputValue" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: [Boolean, Number], | ||||
|       default: false, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,28 +0,0 @@ | ||||
| <template> | ||||
|   <sw-textarea | ||||
|     v-model="inputValue" | ||||
|     rows="2" | ||||
|     name="description" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,28 +0,0 @@ | ||||
| <template> | ||||
|   <base-time-picker | ||||
|     :value="inputValue" | ||||
|     v-model="inputValue" | ||||
|     hide-clear-button | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: [String, Object], | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,27 +0,0 @@ | ||||
| <template> | ||||
|   <sw-input | ||||
|     v-model="inputValue" | ||||
|     type="url" | ||||
|     @input="$emit('input', inputValue)" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     value: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: this.value, | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value(data) { | ||||
|       this.inputValue = data | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,742 +0,0 @@ | ||||
| <template> | ||||
|   <div class="customer-modal"> | ||||
|     <form action="" @submit.prevent="submitCustomerData"> | ||||
|       <div class="flex-1 p-5 sm:p-6"> | ||||
|         <sw-tabs> | ||||
|           <!-- tab1 --> | ||||
|           <sw-tab-item title="Basic Info" class="mt-5"> | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.display_name')" | ||||
|               :error="nameError" | ||||
|               variant="horizontal" | ||||
|               required | ||||
|             > | ||||
|               <sw-input | ||||
|                 ref="name" | ||||
|                 :invalid="$v.formData.name.$error" | ||||
|                 v-model.trim="formData.name" | ||||
|                 type="text" | ||||
|                 name="name" | ||||
|                 class="mt-1 md:mt-0" | ||||
|                 @input="$v.formData.name.$touch()" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.primary_display_name')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="formData.contact_name" | ||||
|                 type="text" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('login.email')" | ||||
|               :error="emailError" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 :invalid="$v.formData.email.$error" | ||||
|                 v-model.trim="formData.email" | ||||
|                 type="text" | ||||
|                 name="email" | ||||
|                 class="mt-1 md:mt-0" | ||||
|                 @input="$v.formData.email.$touch()" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$tc('settings.currencies.currency')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-select | ||||
|                 v-model="currency" | ||||
|                 :options="currencies" | ||||
|                 :searchable="true" | ||||
|                 :allow-empty="false" | ||||
|                 :show-labels="false" | ||||
|                 :placeholder="$t('customers.select_currency')" | ||||
|                 :max-height="200" | ||||
|                 label="name" | ||||
|                 class="mt-1 md:mt-0" | ||||
|                 track-by="id" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.phone')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model.trim="formData.phone" | ||||
|                 type="text" | ||||
|                 name="phone" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.website')" | ||||
|               :error="websiteError" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="formData.website" | ||||
|                 :invalid="$v.formData.website.$error" | ||||
|                 type="url" | ||||
|                 class="mt-1 md:mt-0" | ||||
|                 @input="$v.formData.website.$touch()" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|           </sw-tab-item> | ||||
|  | ||||
|           <!-- tab2 --> | ||||
|           <sw-tab-item title="Billing Address" class="mt-5"> | ||||
|             <sw-input-group :label="$t('customers.name')" variant="horizontal"> | ||||
|               <sw-input | ||||
|                 v-model="billing.name" | ||||
|                 type="text" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.phone')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model.trim="billing.phone" | ||||
|                 type="text" | ||||
|                 name="phone" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.address')" | ||||
|               :error="bill1Error" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-textarea | ||||
|                 v-model="billing.address_street_1" | ||||
|                 :placeholder="$t('general.street_1')" | ||||
|                 rows="2" | ||||
|                 cols="50" | ||||
|                 class="mt-1 md:mt-0" | ||||
|                 @input="$v.billing.address_street_1.$touch()" | ||||
|               /> | ||||
|               <br /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group :error="bill2Error" variant="horizontal"> | ||||
|               <sw-textarea | ||||
|                 v-model="billing.address_street_2" | ||||
|                 :placeholder="$t('general.street_2')" | ||||
|                 rows="2" | ||||
|                 cols="50" | ||||
|                 @input="$v.billing.address_street_2.$touch()" | ||||
|               /> | ||||
|               <br /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.country')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-select | ||||
|                 v-model="billingCountry" | ||||
|                 :options="countries" | ||||
|                 :searchable="true" | ||||
|                 :show-labels="false" | ||||
|                 :placeholder="$t('general.select_country')" | ||||
|                 :allow-empty="false" | ||||
|                 track-by="id" | ||||
|                 label="name" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.state')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="billing.state" | ||||
|                 type="text" | ||||
|                 name="billingState" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.city')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="billing.city" | ||||
|                 type="text" | ||||
|                 name="billingCity" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.zip_code')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="billing.zip" | ||||
|                 type="text" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|           </sw-tab-item> | ||||
|  | ||||
|           <!-- tab3 --> | ||||
|           <sw-tab-item title="Shipping Address" class="mt-5"> | ||||
|             <div class="grid md:grid-cols-12"> | ||||
|               <div class="flex justify-end col-span-12"> | ||||
|                 <sw-button | ||||
|                   ref="sameAddress" | ||||
|                   variant="primary" | ||||
|                   type="button" | ||||
|                   @click="copyAddress(true)" | ||||
|                 > | ||||
|                   {{ $t('customers.copy_billing_address') }} | ||||
|                 </sw-button> | ||||
|               </div> | ||||
|             </div> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.name')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="shipping.name" | ||||
|                 type="text" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.phone')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model.trim="shipping.phone" | ||||
|                 type="text" | ||||
|                 name="phone" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.address')" | ||||
|               :error="ship1Error" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-textarea | ||||
|                 v-model="shipping.address_street_1" | ||||
|                 :placeholder="$t('general.street_1')" | ||||
|                 rows="2" | ||||
|                 cols="50" | ||||
|                 class="mt-1 md:mt-0" | ||||
|                 @input="$v.shipping.address_street_1.$touch()" | ||||
|               /> | ||||
|               <br /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group :error="ship2Error" variant="horizontal"> | ||||
|               <sw-textarea | ||||
|                 v-model="shipping.address_street_2" | ||||
|                 :placeholder="$t('general.street_2')" | ||||
|                 rows="2" | ||||
|                 cols="50" | ||||
|                 @input="$v.shipping.address_street_2.$touch()" | ||||
|               /> | ||||
|               <br /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.country')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-select | ||||
|                 v-model="shippingCountry" | ||||
|                 :options="countries" | ||||
|                 :searchable="true" | ||||
|                 :show-labels="false" | ||||
|                 :allow-empty="false" | ||||
|                 :placeholder="$t('general.select_country')" | ||||
|                 track-by="id" | ||||
|                 label="name" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.state')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="shipping.state" | ||||
|                 type="text" | ||||
|                 name="shippingState" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.city')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="shipping.city" | ||||
|                 type="text" | ||||
|                 name="shippingCity" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|  | ||||
|             <sw-input-group | ||||
|               :label="$t('customers.zip_code')" | ||||
|               class="mt-4" | ||||
|               variant="horizontal" | ||||
|             > | ||||
|               <sw-input | ||||
|                 v-model="shipping.zip" | ||||
|                 type="text" | ||||
|                 class="mt-1 md:mt-0" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|           </sw-tab-item> | ||||
|         </sw-tabs> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3 text-sm" | ||||
|           type="button" | ||||
|           variant="primary-outline" | ||||
|           @click="cancelCustomer" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button :loading="isLoading" variant="primary" type="submit"> | ||||
|           <save-icon v-if="!isLoading" class="mr-2" /> | ||||
|           {{ $t('general.save') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import AddressStub from '../../../stub/address' | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   email, | ||||
|   numeric, | ||||
|   url, | ||||
|   maxLength, | ||||
| } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       isLoading: false, | ||||
|       billingCountry: null, | ||||
|       shippingCountry: null, | ||||
|       isCopyFromBilling: false, | ||||
|       currency: '', | ||||
|       isDisabledBillingState: true, | ||||
|       isDisabledBillingCity: true, | ||||
|       isDisabledShippingState: true, | ||||
|       isDisabledShippingCity: true, | ||||
|       formData: { | ||||
|         id: null, | ||||
|         name: null, | ||||
|         currency_id: null, | ||||
|         phone: null, | ||||
|         website: null, | ||||
|         contact_name: null, | ||||
|         addresses: [], | ||||
|       }, | ||||
|       billing: { | ||||
|         name: null, | ||||
|         country_id: null, | ||||
|         state: null, | ||||
|         city: null, | ||||
|         phone: null, | ||||
|         zip: null, | ||||
|         address_street_1: null, | ||||
|         address_street_2: null, | ||||
|         type: 'billing', | ||||
|       }, | ||||
|       shipping: { | ||||
|         name: null, | ||||
|         country_id: null, | ||||
|         state: null, | ||||
|         city: null, | ||||
|         phone: null, | ||||
|         zip: null, | ||||
|         address_street_1: null, | ||||
|         address_street_2: null, | ||||
|         type: 'shipping', | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     formData: { | ||||
|       name: { | ||||
|         required, | ||||
|         minLength: minLength(3), | ||||
|       }, | ||||
|       email: { | ||||
|         email, | ||||
|       }, | ||||
|       website: { | ||||
|         url, | ||||
|       }, | ||||
|     }, | ||||
|     billing: { | ||||
|       address_street_1: { | ||||
|         maxLength: maxLength(255), | ||||
|       }, | ||||
|       address_street_2: { | ||||
|         maxLength: maxLength(255), | ||||
|       }, | ||||
|     }, | ||||
|     shipping: { | ||||
|       address_street_1: { | ||||
|         maxLength: maxLength(255), | ||||
|       }, | ||||
|       address_street_2: { | ||||
|         maxLength: maxLength(255), | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters(['currencies', 'countries']), | ||||
|     ...mapGetters('company', ['defaultCurrency']), | ||||
|     ...mapGetters('modal', ['modalDataID', 'modalData', 'modalActive']), | ||||
|  | ||||
|     nameError() { | ||||
|       if (!this.$v.formData.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|       if (!this.$v.formData.name.minLength) { | ||||
|         return this.$tc( | ||||
|           'validation.name_min_length', | ||||
|           this.$v.formData.name.$params.minLength.min, | ||||
|           { count: this.$v.formData.name.$params.minLength.min } | ||||
|         ) | ||||
|       } | ||||
|       if (!this.$v.formData.name.alpha) { | ||||
|         return this.$tc('validation.characters_only') | ||||
|       } | ||||
|     }, | ||||
|     emailError() { | ||||
|       if (!this.$v.formData.email.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.email.email) { | ||||
|         return this.$t('validation.email_incorrect') | ||||
|       } | ||||
|     }, | ||||
|     websiteError() { | ||||
|       if (!this.$v.formData.website.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.website.url) { | ||||
|         return this.$tc('validation.invalid_url') | ||||
|       } | ||||
|     }, | ||||
|     bill1Error() { | ||||
|       if (!this.$v.billing.address_street_1.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.billing.address_street_1.maxLength) { | ||||
|         return this.$t('validation.address_maxlength') | ||||
|       } | ||||
|     }, | ||||
|     bill2Error() { | ||||
|       if (!this.$v.billing.address_street_2.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.billing.address_street_2.maxLength) { | ||||
|         return this.$t('validation.address_maxlength') | ||||
|       } | ||||
|     }, | ||||
|     ship1Error() { | ||||
|       if (!this.$v.shipping.address_street_1.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.shipping.address_street_1.maxLength) { | ||||
|         return this.$t('validation.address_maxlength') | ||||
|       } | ||||
|     }, | ||||
|     ship2Error() { | ||||
|       if (!this.$v.shipping.address_street_2.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.shipping.address_street_2.maxLength) { | ||||
|         return this.$t('validation.address_maxlength') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     hasBillingAdd() { | ||||
|       let billing = this.billing | ||||
|       if ( | ||||
|         billing.name || | ||||
|         billing.country_id || | ||||
|         billing.state || | ||||
|         billing.city || | ||||
|         billing.phone || | ||||
|         billing.zip || | ||||
|         billing.address_street_1 || | ||||
|         billing.address_street_2 | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     hasShippingAdd() { | ||||
|       let shipping = this.shipping | ||||
|       if ( | ||||
|         shipping.name || | ||||
|         shipping.country_id || | ||||
|         shipping.state || | ||||
|         shipping.city || | ||||
|         shipping.phone || | ||||
|         shipping.zip || | ||||
|         shipping.address_street_1 || | ||||
|         shipping.address_street_2 | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     modalDataID(val) { | ||||
|       if (val) { | ||||
|         this.isEdit = true | ||||
|         this.setData() | ||||
|       } else { | ||||
|         this.isEdit = false | ||||
|       } | ||||
|     }, | ||||
|     billingCountry() { | ||||
|       if (this.billingCountry) { | ||||
|         this.billing.country_id = this.billingCountry.id | ||||
|         return true | ||||
|       } | ||||
|     }, | ||||
|     shippingCountry() { | ||||
|       if (this.shippingCountry) { | ||||
|         this.shipping.country_id = this.shippingCountry.id | ||||
|         return true | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.$refs.name.focus = true | ||||
|     this.currency = this.defaultCurrency | ||||
|     if (this.modalDataID) { | ||||
|       this.setData() | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('invoice', { | ||||
|       setInvoiceCustomer: 'selectCustomer', | ||||
|     }), | ||||
|     ...mapActions('estimate', { | ||||
|       setEstimateCustomer: 'selectCustomer', | ||||
|     }), | ||||
|     ...mapActions('customer', [ | ||||
|       'fetchCustomer', | ||||
|       'addCustomer', | ||||
|       'updateCustomer', | ||||
|     ]), | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|     resetData() { | ||||
|       this.formData = { | ||||
|         name: null, | ||||
|         currency_id: null, | ||||
|         phone: null, | ||||
|         website: null, | ||||
|         contact_name: null, | ||||
|         addresses: [], | ||||
|       } | ||||
|  | ||||
|       this.billingCountry = null | ||||
|       this.shippingCountry = null | ||||
|  | ||||
|       this.billing = { ...AddressStub } | ||||
|       this.shipping = { ...AddressStub } | ||||
|       this.$v.formData.$reset() | ||||
|     }, | ||||
|     cancelCustomer() { | ||||
|       this.resetData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|     copyAddress(val) { | ||||
|       if (val === true) { | ||||
|         this.isCopyFromBilling = true | ||||
|         this.shipping = { ...this.billing, type: 'shipping' } | ||||
|         this.shippingCountry = this.billingCountry | ||||
|       } else { | ||||
|         this.shipping = { ...AddressStub, type: 'shipping' } | ||||
|         this.shippingCountry = null | ||||
|       } | ||||
|     }, | ||||
|     async loadData() { | ||||
|       let response = await this.fetchCustomer() | ||||
|       this.formData.currency_id = response.data.currency.id | ||||
|       return true | ||||
|     }, | ||||
|     checkAddress() { | ||||
|       const isBillingEmpty = Object.values(this.billing).every( | ||||
|         (val) => val === null || val === '' | ||||
|       ) | ||||
|       const isShippingEmpty = Object.values(this.shipping).every( | ||||
|         (val) => val === null || val === '' | ||||
|       ) | ||||
|       if (isBillingEmpty === true && isBillingEmpty === true) { | ||||
|         this.formData.addresses = [] | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       if (isBillingEmpty === false && isShippingEmpty === false) { | ||||
|         this.formData.addresses = [ | ||||
|           { ...this.billing, type: 'billing' }, | ||||
|           { ...this.shipping, type: 'shipping' }, | ||||
|         ] | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       if (isBillingEmpty === false) { | ||||
|         this.formData.addresses.push({ ...this.billing, type: 'billing' }) | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       this.formData.addresses = [{ ...this.shipping, type: 'shipping' }] | ||||
|       return true | ||||
|     }, | ||||
|     async setData() { | ||||
|       this.formData.id = this.modalData.id | ||||
|       this.formData.name = this.modalData.name | ||||
|       this.formData.email = this.modalData.email | ||||
|       this.formData.contact_name = this.modalData.contact_name | ||||
|       this.formData.phone = this.modalData.phone | ||||
|       this.formData.website = this.modalData.website | ||||
|       this.currency = this.modalData.currency | ||||
|  | ||||
|       if (this.modalData.billing_address) { | ||||
|         this.billing = this.modalData.billing_address | ||||
|         this.billingCountry = this.modalData.billing_address.country | ||||
|       } | ||||
|       if (this.modalData.shipping_address) { | ||||
|         this.shipping = this.modalData.shipping_address | ||||
|         this.shippingCountry = this.modalData.shipping_address.country | ||||
|       } | ||||
|     }, | ||||
|     async submitCustomerData() { | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       // this.checkAddress() | ||||
|       if (this.hasBillingAdd && this.hasShippingAdd) { | ||||
|         this.formData.addresses = [{ ...this.billing }, { ...this.shipping }] | ||||
|       } else if (this.hasBillingAdd) { | ||||
|         this.formData.addresses = [{ ...this.billing }] | ||||
|       } else if (this.hasShippingAdd) { | ||||
|         this.formData.addresses = [{ ...this.shipping }] | ||||
|       } | ||||
|  | ||||
|       this.isLoading = true | ||||
|  | ||||
|       if (this.currency) { | ||||
|         this.formData.currency_id = this.currency.id | ||||
|       } else { | ||||
|         this.formData.currency_id = this.defaultCurrency.id | ||||
|       } | ||||
|       try { | ||||
|         let response = null | ||||
|         if (this.modalDataID) { | ||||
|           response = await this.updateCustomer(this.formData) | ||||
|         } else { | ||||
|           response = await this.addCustomer(this.formData) | ||||
|         } | ||||
|         if (response.data) { | ||||
|           if (this.modalDataID) { | ||||
|             this.showNotification({ | ||||
|               type: 'success', | ||||
|               message: this.$tc('customers.updated_message'), | ||||
|             }) | ||||
|           } else { | ||||
|             this.showNotification({ | ||||
|               type: 'success', | ||||
|               message: this.$tc('customers.created_message'), | ||||
|             }) | ||||
|           } | ||||
|  | ||||
|           this.isLoading = false | ||||
|           if ( | ||||
|             this.$route.name === 'invoices.create' || | ||||
|             this.$route.name === 'invoices.edit' | ||||
|           ) { | ||||
|             this.setInvoiceCustomer(response.data.customer.id) | ||||
|           } | ||||
|           if ( | ||||
|             this.$route.name === 'estimates.create' || | ||||
|             this.$route.name === 'estimates.edit' | ||||
|           ) { | ||||
|             this.setEstimateCustomer(response.data.customer.id) | ||||
|           } | ||||
|           this.resetData() | ||||
|           this.closeModal() | ||||
|           return true | ||||
|         } | ||||
|       } catch (err) { | ||||
|         this.isLoading = false | ||||
|         // if (err.response.data.errors.email) { | ||||
|         //   window.toastr['error'](this.$t('validation.email_already_taken')) | ||||
|         // } | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,91 +0,0 @@ | ||||
| <template> | ||||
|   <div class="template-modal"> | ||||
|     <div class="px-8 py-8 sm:p-6"> | ||||
|       <div class="grid grid-cols-3 gap-2 p-1 overflow-x-auto sw-scroll"> | ||||
|         <div | ||||
|           v-for="(template, index) in modalData" | ||||
|           :key="index" | ||||
|           :class="{ | ||||
|             'border border-solid border-primary-500': | ||||
|               selectedTemplate === template.name, | ||||
|           }" | ||||
|           class="relative flex flex-col m-2 border border-gray-200 border-solid cursor-pointer  hover:border-primary-300" | ||||
|         > | ||||
|           <img | ||||
|             :src="template.path" | ||||
|             :alt="template.name" | ||||
|             class="w-full" | ||||
|             @click="selectedTemplate = template.name" | ||||
|           /> | ||||
|           <img | ||||
|             v-if="selectedTemplate === template.name" | ||||
|             :alt="template.name" | ||||
|             class="absolute z-10 w-5 h-5 text-primary-500" | ||||
|             style="top: -6px; right: -5px" | ||||
|             src="/assets/img/tick.png" | ||||
|           /> | ||||
|           <span | ||||
|             :class="[ | ||||
|               'w-full p-1 bg-gray-200 text-sm text-center absolute bottom-0 left-0', | ||||
|               { | ||||
|                 'text-primary-500 bg-primary-100': | ||||
|                   selectedTemplate === template.name, | ||||
|                 'text-gray-600': selectedTemplate != template.name, | ||||
|               }, | ||||
|             ]" | ||||
|           > | ||||
|             {{ template.name }} | ||||
|           </span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"> | ||||
|       <sw-button | ||||
|         class="mr-3" | ||||
|         variant="primary-outline" | ||||
|         @click="closeEstimateModal" | ||||
|       > | ||||
|         {{ $t('general.cancel') }} | ||||
|       </sw-button> | ||||
|       <sw-button variant="primary" @click="chooseTemplate()"> | ||||
|         {{ $t('general.choose') }} | ||||
|       </sw-button> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       selectedTemplate: null, | ||||
|       isLoading: false, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalData']), | ||||
|     ...mapGetters('estimate', ['getTemplateName']), | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.selectedTemplate = this.getTemplateName | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('estimate', ['setTemplate']), | ||||
|     ...mapActions('modal', ['closeModal', 'resetModalData']), | ||||
|     async chooseTemplate() { | ||||
|       this.isLoading = true | ||||
|       let resp = await this.setTemplate(this.selectedTemplate) | ||||
|       if (resp) { | ||||
|         this.isLoading = false | ||||
|         this.resetModalData() | ||||
|         this.closeModal() | ||||
|       } | ||||
|     }, | ||||
|     closeEstimateModal() { | ||||
|       this.selectedTemplate = this.getTemplateName | ||||
|       this.closeModal() | ||||
|       this.resetModalData() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,160 +0,0 @@ | ||||
| <template> | ||||
|   <div class="file-disk-modal"> | ||||
|     <div v-if="getDiskDrivers.length"> | ||||
|       <component | ||||
|         :is="selected_disk" | ||||
|         :loading="isLoading" | ||||
|         :disks="getDiskDrivers" | ||||
|         :is-edit="isEdit" | ||||
|         @on-change-disk="(disk) => (selected_disk = disk.value)" | ||||
|         @submit="createNewDisk" | ||||
|       > | ||||
|         <template v-slot="slotProps"> | ||||
|           <div | ||||
|             class="z-0 flex justify-end p-4 border-t border-solid border-gray-light" | ||||
|           > | ||||
|             <sw-button | ||||
|               class="mr-3 text-sm" | ||||
|               variant="primary-outline" | ||||
|               type="button" | ||||
|               @click="closeDisk" | ||||
|             > | ||||
|               {{ $t('general.cancel') }} | ||||
|             </sw-button> | ||||
|             <sw-button | ||||
|               :loading="isRequestFire(slotProps)" | ||||
|               :disabled="isRequestFire(slotProps)" | ||||
|               variant="primary" | ||||
|               type="submit" | ||||
|             > | ||||
|               <save-icon v-if="!isRequestFire(slotProps)" class="mr-2" /> | ||||
|               {{ $t('general.save') }} | ||||
|             </sw-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </component> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import Dropbox from './disks/DropboxDisk' | ||||
| import Local from './disks/LocalDisk' | ||||
| import S3 from './disks/S3Disk' | ||||
| import DoSpaces from './disks/DoSpacesDisk' | ||||
|  | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   email, | ||||
|   numeric, | ||||
|   url, | ||||
|   maxLength, | ||||
| } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     Dropbox, | ||||
|     Local, | ||||
|     S3, | ||||
|     DoSpaces, | ||||
|   }, | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       isLoading: false, | ||||
|       isEdit: false, | ||||
|       set_as_default: false, | ||||
|       name: 'local', | ||||
|       formData: {}, | ||||
|       selected_disk: 'local', | ||||
|       diskConfigData: {}, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalDataID', | ||||
|       'modalData', | ||||
|       'modalActive', | ||||
|       'refreshData', | ||||
|     ]), | ||||
|  | ||||
|     ...mapGetters('disks', ['getDiskDrivers']), | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     if (this.modalDataID) { | ||||
|       this.isEdit = true | ||||
|     } | ||||
|     this.loadData() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('disks', ['fetchDiskDrivers', 'createDisk', 'updateDisk']), | ||||
|  | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|  | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|  | ||||
|     isRequestFire(slotProps) { | ||||
|       return slotProps && (slotProps.diskData.isLoading || this.isLoading) | ||||
|     }, | ||||
|  | ||||
|     async loadData() { | ||||
|       this.isLoading = true | ||||
|  | ||||
|       let res = await this.fetchDiskDrivers() | ||||
|       if (this.isEdit) { | ||||
|         this.selected_disk = this.modalData.driver | ||||
|       } else { | ||||
|         this.selected_disk = res.data.drivers[0].value | ||||
|       } | ||||
|  | ||||
|       this.isLoading = false | ||||
|     }, | ||||
|  | ||||
|     async createNewDisk(data) { | ||||
|       this.isLoading = true | ||||
|  | ||||
|       let formData = { | ||||
|         id: this.modalDataID, | ||||
|         ...data, | ||||
|       } | ||||
|       let response | ||||
|       if (this.isEdit) { | ||||
|         response = await this.updateDisk(formData) | ||||
|       } else { | ||||
|         response = await this.createDisk(formData) | ||||
|       } | ||||
|  | ||||
|       if (response.data.success) { | ||||
|         this.refreshData() | ||||
|         this.closeDisk() | ||||
|         if (this.isEdit) { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$t('settings.disk.success_update'), | ||||
|           }) | ||||
|         } else { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$t('settings.disk.success_create'), | ||||
|           }) | ||||
|         } | ||||
|       } else { | ||||
|         this.showNotification({ | ||||
|           type: 'error', | ||||
|           message: this.$t('settings.disk.invalid_disk_credentials'), | ||||
|         }) | ||||
|       } | ||||
|       this.isLoading = false | ||||
|     }, | ||||
|  | ||||
|     closeDisk() { | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,91 +0,0 @@ | ||||
| <template> | ||||
|   <div class="template-modal"> | ||||
|     <div class="px-8 py-8 sm:p-6"> | ||||
|       <div class="grid grid-cols-3 gap-2 p-1 overflow-x-auto sw-scroll"> | ||||
|         <div | ||||
|           v-for="(template, index) in modalData" | ||||
|           :key="index" | ||||
|           :class="{ | ||||
|             'border border-solid border-primary-500': | ||||
|               selectedTemplate === template.name, | ||||
|           }" | ||||
|           class="relative flex flex-col m-2 border border-gray-200 border-solid cursor-pointer  hover:border-primary-300" | ||||
|         > | ||||
|           <img | ||||
|             :src="template.path" | ||||
|             :alt="template.name" | ||||
|             class="w-full" | ||||
|             @click="selectedTemplate = template.name" | ||||
|           /> | ||||
|           <img | ||||
|             v-if="selectedTemplate === template.name" | ||||
|             :alt="template.name" | ||||
|             class="absolute z-10 w-5 h-5 text-primary-500" | ||||
|             style="top: -6px; right: -5px" | ||||
|             src="/assets/img/tick.png" | ||||
|           /> | ||||
|           <span | ||||
|             :class="[ | ||||
|               'w-full p-1 bg-gray-200 text-sm text-center absolute bottom-0 left-0', | ||||
|               { | ||||
|                 'text-primary-500 bg-primary-100': | ||||
|                   selectedTemplate === template.id, | ||||
|                 'text-gray-600': selectedTemplate != template.id, | ||||
|               }, | ||||
|             ]" | ||||
|           > | ||||
|             {{ template.name }} | ||||
|           </span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"> | ||||
|       <sw-button | ||||
|         class="mr-3" | ||||
|         variant="primary-outline" | ||||
|         @click="closeInvoiceModal" | ||||
|       > | ||||
|         {{ $t('general.cancel') }} | ||||
|       </sw-button> | ||||
|       <sw-button variant="primary" @click="chooseTemplate()"> | ||||
|         {{ $t('general.choose') }} | ||||
|       </sw-button> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       selectedTemplate: null, | ||||
|       isLoading: false, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalData']), | ||||
|     ...mapGetters('invoice', ['getTemplateName']), | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.selectedTemplate = this.getTemplateName | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('invoice', ['setTemplate']), | ||||
|     ...mapActions('modal', ['closeModal', 'resetModalData']), | ||||
|     async chooseTemplate() { | ||||
|       this.isLoading = true | ||||
|       let resp = await this.setTemplate(this.selectedTemplate) | ||||
|       if (resp) { | ||||
|         this.isLoading = false | ||||
|         this.resetModalData() | ||||
|         this.closeModal() | ||||
|       } | ||||
|     }, | ||||
|     closeInvoiceModal() { | ||||
|       this.selectedTemplate = this.getTemplateName | ||||
|       this.closeModal() | ||||
|       this.resetModalData() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,334 +0,0 @@ | ||||
| <template> | ||||
|   <div class="item-modal"> | ||||
|     <form action="" @submit.prevent="submitItemData"> | ||||
|       <div class="px-8 py-8 sm:p-6"> | ||||
|         <sw-input-group | ||||
|           :label="$t('items.name')" | ||||
|           :error="nameError" | ||||
|           class="mb-4" | ||||
|           variant="horizontal" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             ref="name" | ||||
|             :invalid="$v.formData.name.$error" | ||||
|             v-model="formData.name" | ||||
|             type="text" | ||||
|             @input="$v.formData.name.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('items.price')" | ||||
|           :error="priceError" | ||||
|           class="mb-4" | ||||
|           variant="horizontal" | ||||
|           required | ||||
|         > | ||||
|           <sw-money | ||||
|             v-model="price" | ||||
|             :currency="defaultCurrencyForInput" | ||||
|             :invalid="$v.formData.price.$error" | ||||
|             class="relative w-full focus:border focus:border-solid focus:border-primary" | ||||
|             @input="$v.formData.price.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('items.unit')" | ||||
|           class="mb-4" | ||||
|           variant="horizontal" | ||||
|         > | ||||
|           <sw-select | ||||
|             v-model="formData.unit" | ||||
|             :options="itemUnits" | ||||
|             :searchable="true" | ||||
|             :show-labels="false" | ||||
|             :max-height="200" | ||||
|             label="name" | ||||
|           > | ||||
|           </sw-select> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           v-if="isTexPerItem" | ||||
|           :label="$t('items.taxes')" | ||||
|           class="mb-4" | ||||
|           variant="horizontal" | ||||
|         > | ||||
|           <sw-select | ||||
|             v-model="formData.taxes" | ||||
|             :options="getTaxTypes" | ||||
|             :searchable="true" | ||||
|             :show-labels="false" | ||||
|             :allow-empty="true" | ||||
|             :multiple="true" | ||||
|             label="tax_name" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('items.description')" | ||||
|           :error="descriptionError" | ||||
|           variant="horizontal" | ||||
|         > | ||||
|           <sw-textarea | ||||
|             v-model="formData.description" | ||||
|             rows="4" | ||||
|             cols="50" | ||||
|             @input="$v.formData.description.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3" | ||||
|           variant="primary-outline" | ||||
|           type="button" | ||||
|           @click="closeItemModal" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button | ||||
|           :loading="isLoading" | ||||
|           :disabled="isLoading" | ||||
|           variant="primary" | ||||
|           type="submit" | ||||
|         > | ||||
|           <save-icon v-if="!isLoading" class="mr-2" /> | ||||
|           {{ isEdit ? $t('general.update') : $t('general.save') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { ShoppingCartIcon } from '@vue-hero-icons/solid' | ||||
|  | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   numeric, | ||||
|   maxLength, | ||||
|   minValue, | ||||
| } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     ShoppingCartIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       isLoading: false, | ||||
|       tempData: null, | ||||
|       taxes: [], | ||||
|       formData: { | ||||
|         name: null, | ||||
|         price: null, | ||||
|         description: null, | ||||
|         unit: null, | ||||
|         taxes: [], | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   validations: { | ||||
|     formData: { | ||||
|       name: { | ||||
|         required, | ||||
|         minLength: minLength(3), | ||||
|       }, | ||||
|       price: { | ||||
|         required, | ||||
|         minValue: minValue(0.1), | ||||
|         maxLength: maxLength(20), | ||||
|       }, | ||||
|       description: { | ||||
|         maxLength: maxLength(255), | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('company', ['defaultCurrencyForInput']), | ||||
|     price: { | ||||
|       get: function () { | ||||
|         return this.formData.price / 100 | ||||
|       }, | ||||
|       set: function (newValue) { | ||||
|         this.formData.price = Math.round(newValue * 100) | ||||
|       }, | ||||
|     }, | ||||
|  | ||||
|     ...mapGetters('modal', ['modalDataID', 'modalData']), | ||||
|     ...mapGetters('item', ['getItemById', 'itemUnits']), | ||||
|     ...mapGetters('taxType', ['taxTypes']), | ||||
|     isTexPerItem() { | ||||
|       return this.modalData.taxPerItem === 'YES' | ||||
|     }, | ||||
|  | ||||
|     getTaxTypes() { | ||||
|       return this.taxTypes.map((tax) => { | ||||
|         return { ...tax, tax_name: tax.name + ' (' + tax.percent + '%)' } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     nameError() { | ||||
|       if (!this.$v.formData.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|       if (!this.$v.formData.name.minLength) { | ||||
|         return this.$tc( | ||||
|           'validation.name_min_length', | ||||
|           this.$v.formData.name.$params.minLength.min, | ||||
|           { count: this.$v.formData.name.$params.minLength.min } | ||||
|         ) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     priceError() { | ||||
|       if (!this.$v.formData.price.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.price.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.price.maxLength) { | ||||
|         return this.$t('validation.price_maxlength') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.price.minValue) { | ||||
|         return this.$t('validation.price_minvalue') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     descriptionError() { | ||||
|       if (!this.$v.formData.description.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.description.maxLength) { | ||||
|         return this.$t('validation.description_maxlength') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   watch: { | ||||
|     modalDataID() { | ||||
|       this.isEdit = true | ||||
|       this.fetchEditData() | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     if (this.modalDataID) { | ||||
|       this.isEdit = true | ||||
|       this.fetchEditData() | ||||
|     } | ||||
|  | ||||
|     if (this.isEdit) { | ||||
|       this.loadEditData() | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   mounted() { | ||||
|     this.$v.formData.$reset() | ||||
|     this.$refs.name.focus = true | ||||
|     this.fetchItemUnits({ limit: 'all' }) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal', 'resetModalData']), | ||||
|     ...mapActions('item', ['addItem', 'updateItem', 'fetchItemUnits']), | ||||
|     ...mapActions('invoice', ['setItem']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|  | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         name: null, | ||||
|         price: null, | ||||
|         description: null, | ||||
|         unit: null, | ||||
|         id: null, | ||||
|       } | ||||
|       this.$v.$reset() | ||||
|     }, | ||||
|  | ||||
|     fetchEditData() { | ||||
|       this.tempData = this.getItemById(this.modalDataID) | ||||
|       if (this.tempData) { | ||||
|         this.formData.name = this.tempData.name | ||||
|         this.formData.price = this.tempData.price | ||||
|         this.formData.description = this.tempData.description | ||||
|         this.formData.unit = this.tempData.unit | ||||
|         this.formData.id = this.tempData.id | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     async submitItemData() { | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|       if (this.formData.unit) { | ||||
|         this.formData.unit_id = this.formData.unit.id | ||||
|       } | ||||
|  | ||||
|       this.isLoading = true | ||||
|       let response | ||||
|       if (this.isEdit) { | ||||
|         response = await this.updateItem(this.formData) | ||||
|       } else { | ||||
|         let data = { | ||||
|           ...this.formData, | ||||
|           taxes: this.formData.taxes.map((tax) => { | ||||
|             return { | ||||
|               tax_type_id: tax.id, | ||||
|               amount: (this.formData.price * tax.percent) / 100, | ||||
|               percent: tax.percent, | ||||
|               name: tax.name, | ||||
|               collective_tax: 0, | ||||
|             } | ||||
|           }), | ||||
|         } | ||||
|         response = await this.addItem(data) | ||||
|       } | ||||
|       if (response.data) { | ||||
|         this.showNotification({ | ||||
|           type: 'success', | ||||
|           message: this.$tc('items.created_message'), | ||||
|         }) | ||||
|         this.setItem(response.data.item) | ||||
|  | ||||
|         window.hub.$emit('newItem', response.data.item) | ||||
|         this.isLoading = false | ||||
|         this.resetModalData() | ||||
|         this.resetFormData() | ||||
|         this.closeModal() | ||||
|         return true | ||||
|       } | ||||
|       this.showNotification({ | ||||
|         type: 'error', | ||||
|         message: response.data.error, | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     closeItemModal() { | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|       this.resetModalData() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,164 +0,0 @@ | ||||
| <template> | ||||
|   <form action="" @submit.prevent="submitItemUnit"> | ||||
|     <div class="p-8 sm:p-6"> | ||||
|       <sw-input-group | ||||
|         :label="$t('settings.customization.items.unit_name')" | ||||
|         :error="nameError" | ||||
|         variant="horizontal" | ||||
|         required | ||||
|       > | ||||
|         <sw-input | ||||
|           ref="name" | ||||
|           :invalid="$v.formData.name.$error" | ||||
|           v-model="formData.name" | ||||
|           type="text" | ||||
|           @input="$v.formData.name.$touch()" | ||||
|         /> | ||||
|       </sw-input-group> | ||||
|     </div> | ||||
|     <div class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"> | ||||
|       <sw-button | ||||
|         class="mr-3" | ||||
|         variant="primary-outline" | ||||
|         type="button" | ||||
|         @click="closeItemUnitModal" | ||||
|       > | ||||
|         {{ $t('general.cancel') }} | ||||
|       </sw-button> | ||||
|       <sw-button | ||||
|         :loading="isLoading" | ||||
|         variant="primary" | ||||
|         icon="save" | ||||
|         type="submit" | ||||
|       > | ||||
|         <save-icon v-if="!isLoading" class="mr-2" /> | ||||
|         {{ !isEdit ? $t('general.save') : $t('general.update') }} | ||||
|       </sw-button> | ||||
|     </div> | ||||
|   </form> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| const { required, minLength } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       isLoading: false, | ||||
|       formData: { | ||||
|         id: null, | ||||
|         name: null, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalDataID', | ||||
|       'modalData', | ||||
|       'modalActive', | ||||
|       'refreshData', | ||||
|     ]), | ||||
|     nameError() { | ||||
|       if (!this.$v.formData.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.minLength) { | ||||
|         return this.$tc( | ||||
|           'validation.name_min_length', | ||||
|           this.$v.formData.name.$params.minLength.min, | ||||
|           { count: this.$v.formData.name.$params.minLength.min } | ||||
|         ) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   validations: { | ||||
|     formData: { | ||||
|       name: { | ||||
|         required, | ||||
|         minLength: minLength(2), | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   async mounted() { | ||||
|     this.$refs.name.focus = true | ||||
|     if (this.modalDataID) { | ||||
|       this.isEdit = true | ||||
|       this.setData() | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal', 'resetModalData']), | ||||
|     ...mapActions('item', ['addItemUnit', 'updateItemUnit', 'fatchItemUnit']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         id: null, | ||||
|         name: null, | ||||
|       } | ||||
|       this.$v.formData.$reset() | ||||
|     }, | ||||
|     async submitItemUnit() { | ||||
|       this.$v.formData.$touch() | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       this.isLoading = true | ||||
|       let response | ||||
|  | ||||
|       try { | ||||
|         if (!this.isEdit) { | ||||
|           response = await this.addItemUnit(this.formData) | ||||
|         } else { | ||||
|           response = await this.updateItemUnit(this.formData) | ||||
|         } | ||||
|  | ||||
|         if (response.data) { | ||||
|           this.isLoading = false | ||||
|           if (!this.isEdit) { | ||||
|             this.showNotification({ | ||||
|               type: 'success', | ||||
|               message: this.$t('settings.customization.items.item_unit_added'), | ||||
|             }) | ||||
|           } else { | ||||
|             this.showNotification({ | ||||
|               type: 'success', | ||||
|               message: this.$t( | ||||
|                 'settings.customization.items.item_unit_updated' | ||||
|               ), | ||||
|             }) | ||||
|           } | ||||
|           this.refreshData ? this.refreshData() : '' | ||||
|           this.closeItemUnitModal() | ||||
|           return true | ||||
|         } | ||||
|       } catch (error) { | ||||
|         this.isLoading = false | ||||
|         this.showNotification({ | ||||
|           type: 'error', | ||||
|           message: response.data.error, | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     async setData() { | ||||
|       this.formData = { | ||||
|         id: this.modalData.id, | ||||
|         name: this.modalData.name, | ||||
|       } | ||||
|     }, | ||||
|     closeItemUnitModal() { | ||||
|       this.resetModalData() | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,201 +0,0 @@ | ||||
| <template> | ||||
|   <div class="mail-config-modal"> | ||||
|     <form action="" @submit.prevent="onTestMailSend"> | ||||
|       <div class="p-4 md:p-8"> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.to')" | ||||
|           :error="emailError" | ||||
|           class="mt-3" | ||||
|           variant="horizontal" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             ref="to" | ||||
|             :invalid="$v.formData.to.$error" | ||||
|             v-model="formData.to" | ||||
|             type="text" | ||||
|             @input="$v.formData.to.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.subject')" | ||||
|           :error="subjectError" | ||||
|           class="mt-3" | ||||
|           variant="horizontal" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             :invalid="$v.formData.subject.$error" | ||||
|             v-model="formData.subject" | ||||
|             type="text" | ||||
|             @input="$v.formData.subject.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.message')" | ||||
|           :error="messageError" | ||||
|           class="mt-3" | ||||
|           variant="horizontal" | ||||
|           required | ||||
|         > | ||||
|           <sw-textarea | ||||
|             v-model="formData.message" | ||||
|             :invalid="$v.formData.message.$error" | ||||
|             rows="4" | ||||
|             cols="50" | ||||
|             @input="$v.formData.message.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid" | ||||
|       > | ||||
|         <sw-button | ||||
|           variant="primary-outline" | ||||
|           class="mr-3" | ||||
|           @click="closeTaxModal" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button :loading="isLoading" variant="primary" type="submit"> | ||||
|           <paper-airplane-icon v-if="!isLoading" class="mr-2" /> | ||||
|           {{ !isEdit ? $t('general.send') : $t('general.update') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { PaperAirplaneIcon } from '@vue-hero-icons/outline' | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   email, | ||||
|   maxLength, | ||||
| } = require('vuelidate/lib/validators') | ||||
| export default { | ||||
|   components: { | ||||
|     PaperAirplaneIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       isLoading: false, | ||||
|       formData: { | ||||
|         to: null, | ||||
|         subject: null, | ||||
|         message: null, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalDataID', 'modalData', 'modalActive']), | ||||
|     emailError() { | ||||
|       if (!this.$v.formData.to.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.to.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|       if (!this.$v.formData.to.email) { | ||||
|         return this.$tc('validation.email_incorrect') | ||||
|       } | ||||
|     }, | ||||
|     subjectError() { | ||||
|       if (!this.$v.formData.subject.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.subject.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.subject.maxLength) { | ||||
|         return this.$tc('validation.subject_maxlength') | ||||
|       } | ||||
|     }, | ||||
|     messageError() { | ||||
|       if (!this.$v.formData.message.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.message.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|       if (!this.$v.formData.message.maxLength) { | ||||
|         return this.$tc('validation.message_maxlength') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   validations: { | ||||
|     formData: { | ||||
|       to: { | ||||
|         required, | ||||
|         email, | ||||
|       }, | ||||
|       subject: { | ||||
|         required, | ||||
|         maxLength: maxLength(100), | ||||
|       }, | ||||
|       message: { | ||||
|         required, | ||||
|         maxLength: maxLength(255), | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   async mounted() { | ||||
|     this.$refs.to.focus = true | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal', 'resetModalData']), | ||||
|     ...mapActions('company', ['sendTestMail']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         to: null, | ||||
|         subject: null, | ||||
|         message: null, | ||||
|       } | ||||
|       this.$v.formData.$reset() | ||||
|     }, | ||||
|     async onTestMailSend() { | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       this.isLoading = true | ||||
|       let response = await this.sendTestMail(this.formData) | ||||
|  | ||||
|       if (response.data) { | ||||
|         if (response.data.success) { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$tc('general.send_mail_successfully'), | ||||
|           }) | ||||
|           this.closeTaxModal() | ||||
|           this.isLoading = false | ||||
|           return true | ||||
|         } | ||||
|         this.showNotification({ | ||||
|           type: 'error', | ||||
|           message: this.$tc('validation.something_went_wrong'), | ||||
|         }) | ||||
|         this.closeTaxModal() | ||||
|         this.isLoading = false | ||||
|         return true | ||||
|       } | ||||
|       this.showNotification({ | ||||
|         type: 'error', | ||||
|         message: response.data.error, | ||||
|       }) | ||||
|     }, | ||||
|     closeTaxModal() { | ||||
|       this.resetModalData() | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,316 +0,0 @@ | ||||
| <template> | ||||
|   <div class="note-modal"> | ||||
|     <form action="" @submit.prevent="submitNote"> | ||||
|       <div class="px-8 py-8 sm:p-6"> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.customization.notes.name')" | ||||
|           :error="nameError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             ref="name" | ||||
|             :invalid="$v.formData.name.$error" | ||||
|             v-model="formData.name" | ||||
|             type="text" | ||||
|             @input="$v.formData.name.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.customization.notes.type')" | ||||
|           :error="typeError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-select | ||||
|             v-model="noteType" | ||||
|             :options="types" | ||||
|             :allow-empty="false" | ||||
|             :show-labels="false" | ||||
|             class="mt-2" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.customization.notes.notes')" | ||||
|           :error="noteError" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <base-custom-input | ||||
|             v-model="formData.notes" | ||||
|             :fields="fields" | ||||
|             class="mt-2" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end px-4 py-4 border-t border-solid border-gray-light" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-2" | ||||
|           variant="primary-outline" | ||||
|           type="button" | ||||
|           @click="closeNoteModal" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button | ||||
|           :loading="isLoading" | ||||
|           variant="primary" | ||||
|           icon="save" | ||||
|           type="submit" | ||||
|         > | ||||
|           <save-icon v-if="!isLoading" class="mr-2" /> | ||||
|           {{ !isEdit ? $t('general.save') : $t('general.update') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| const { required, minLength } = require('vuelidate/lib/validators') | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       isLoading: false, | ||||
|       types: ['Invoice', 'Estimate', 'Payment'], | ||||
|       selectType: null, | ||||
|       formData: { | ||||
|         type: '', | ||||
|         name: '', | ||||
|         notes: '', | ||||
|       }, | ||||
|       noteType: null, | ||||
|       fields: [], | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalDataID', | ||||
|       'modalData', | ||||
|       'modalActive', | ||||
|       'refreshData', | ||||
|     ]), | ||||
|     nameError() { | ||||
|       if (!this.$v.formData.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.minLength) { | ||||
|         return this.$tc( | ||||
|           'validation.name_min_length', | ||||
|           this.$v.formData.name.$params.minLength.min, | ||||
|           { count: this.$v.formData.name.$params.minLength.min } | ||||
|         ) | ||||
|       } | ||||
|     }, | ||||
|     noteError() { | ||||
|       if (!this.$v.formData.notes.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.notes.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     typeError() { | ||||
|       if (!this.$v.noteType.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.noteType.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   validations: { | ||||
|     formData: { | ||||
|       name: { | ||||
|         required, | ||||
|         minLength: minLength(2), | ||||
|       }, | ||||
|       notes: { | ||||
|         required, | ||||
|       }, | ||||
|     }, | ||||
|     noteType: { | ||||
|       required, | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     noteType() { | ||||
|       this.setFields() | ||||
|     }, | ||||
|   }, | ||||
|   async mounted() { | ||||
|     this.setFields() | ||||
|     if (this.modalDataID) { | ||||
|       this.isEdit = true | ||||
|       this.setData() | ||||
|     } else { | ||||
|       this.modalData | ||||
|         ? (this.noteType = this.modalData) | ||||
|         : (this.noteType = 'Invoice') | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal', 'resetModalData']), | ||||
|     ...mapActions('notes', ['addNote', 'updateNote']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|     ...mapActions('invoice', { | ||||
|       setInvoiceNote: 'selectNote', | ||||
|     }), | ||||
|     ...mapActions('estimate', { | ||||
|       setEstimateNote: 'selectNote', | ||||
|     }), | ||||
|     ...mapActions('payment', { | ||||
|       setPaymentNote: 'selectNote', | ||||
|     }), | ||||
|  | ||||
|     setFields() { | ||||
|       this.fields = ['customer', 'customerCustom'] | ||||
|  | ||||
|       if (this.noteType === 'Invoice') { | ||||
|         this.fields.push('invoice', 'invoiceCustom') | ||||
|       } | ||||
|  | ||||
|       if (this.noteType === 'Estimate') { | ||||
|         this.fields.push('estimate', 'estimateCustom') | ||||
|       } | ||||
|  | ||||
|       if (this.noteType === 'Payment') { | ||||
|         this.fields.push('payment', 'paymentCustom') | ||||
|       } | ||||
|  | ||||
|       return true | ||||
|     }, | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         name: null, | ||||
|         notes: null, | ||||
|       } | ||||
|  | ||||
|       this.notetype = null | ||||
|       this.$v.formData.$reset() | ||||
|     }, | ||||
|     async submitNote() { | ||||
|       this.$v.formData.$touch() | ||||
|       this.$v.noteType.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       this.isLoading = true | ||||
|  | ||||
|       if (this.isEdit) { | ||||
|         let data = { | ||||
|           id: this.modalDataID, | ||||
|           type: this.noteType, | ||||
|           name: this.formData.name, | ||||
|           notes: this.formData.notes, | ||||
|         } | ||||
|  | ||||
|         let res = await this.updateNote(data) | ||||
|         if (res.data) { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$t('settings.customization.notes.note_updated'), | ||||
|           }) | ||||
|  | ||||
|           this.refreshData ? this.refreshData() : '' | ||||
|           this.closeNoteModal() | ||||
|           return true | ||||
|         } | ||||
|         this.showNotification({ | ||||
|           type: 'error', | ||||
|           message: res.data.error, | ||||
|         }) | ||||
|       } else { | ||||
|         try { | ||||
|           let data = { | ||||
|             type: this.noteType, | ||||
|             name: this.formData.name, | ||||
|             notes: this.formData.notes, | ||||
|           } | ||||
|  | ||||
|           let response = await this.addNote(data) | ||||
|  | ||||
|           if (response.data && response.data.note) { | ||||
|             this.isLoading = false | ||||
|             this.showNotification({ | ||||
|               type: 'success', | ||||
|               message: this.$t('settings.customization.notes.note_added'), | ||||
|             }) | ||||
|             if ( | ||||
|               (this.$route.name === 'invoices.create' && | ||||
|                 response.data.note.type === 'Invoice') || | ||||
|               (this.$route.name === 'invoices.edit' && | ||||
|                 response.data.note.type === 'Invoice') | ||||
|             ) { | ||||
|               this.setInvoiceNote(response.data.note) | ||||
|             } | ||||
|  | ||||
|             if ( | ||||
|               (this.$route.name === 'estimates.create' && | ||||
|                 response.data.note.type === 'Estimate') || | ||||
|               (this.$route.name === 'estimates.edit' && | ||||
|                 response.data.note.type === 'Estimate') | ||||
|             ) { | ||||
|               this.setEstimateNote(response.data.note) | ||||
|             } | ||||
|  | ||||
|             if ( | ||||
|               (this.$route.name === 'payments.create' && | ||||
|                 response.data.note.type === 'Payment') || | ||||
|               (this.$route.name === 'payments.edit' && | ||||
|                 response.data.note.type === 'Payment') | ||||
|             ) { | ||||
|               this.setPaymentNote(response.data.note) | ||||
|             } | ||||
|  | ||||
|             this.refreshData ? this.refreshData() : '' | ||||
|             this.closeNoteModal() | ||||
|             return true | ||||
|           } | ||||
|           this.showNotification({ | ||||
|             type: 'error', | ||||
|             message: response.data.error, | ||||
|           }) | ||||
|         } catch (err) { | ||||
|           if (err.response.data.errors.name) { | ||||
|             this.isLoading = true | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     async setData() { | ||||
|       this.noteType = this.modalData.type | ||||
|       this.formData.name = this.modalData.name | ||||
|       this.formData.notes = this.modalData.notes | ||||
|     }, | ||||
|     closeNoteModal() { | ||||
|       this.closeModal() | ||||
|       this.resetFormData() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| <style lang="scss"> | ||||
| .note-modal { | ||||
|   .header-editior .editor-menu-bar { | ||||
|     margin-left: 0.5px; | ||||
|     margin-right: 0px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -1,163 +0,0 @@ | ||||
| <template> | ||||
|   <form action="" @submit.prevent="submitPaymentMode"> | ||||
|     <div class="p-8 sm:p-6"> | ||||
|       <sw-input-group | ||||
|         :label="$t('settings.customization.payments.mode_name')" | ||||
|         :error="nameError" | ||||
|         variant="horizontal" | ||||
|         required | ||||
|       > | ||||
|         <sw-input | ||||
|           ref="name" | ||||
|           :invalid="$v.formData.name.$error" | ||||
|           v-model="formData.name" | ||||
|           type="text" | ||||
|           @input="$v.formData.name.$touch()" | ||||
|         /> | ||||
|       </sw-input-group> | ||||
|     </div> | ||||
|     <div class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"> | ||||
|       <sw-button | ||||
|         class="mr-3" | ||||
|         variant="primary-outline" | ||||
|         type="button" | ||||
|         @click="closePaymentModeModal" | ||||
|       > | ||||
|         {{ $t('general.cancel') }} | ||||
|       </sw-button> | ||||
|       <sw-button :loading="isLoading" variant="primary" type="submit"> | ||||
|         <save-icon v-if="!isLoading" class="mr-2" /> | ||||
|         {{ !isEdit ? $t('general.save') : $t('general.update') }} | ||||
|       </sw-button> | ||||
|     </div> | ||||
|   </form> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| const { required, minLength } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       isLoading: false, | ||||
|       formData: { | ||||
|         id: null, | ||||
|         name: null, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalDataID', | ||||
|       'modalData', | ||||
|       'modalActive', | ||||
|       'refreshData', | ||||
|     ]), | ||||
|     nameError() { | ||||
|       if (!this.$v.formData.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.minLength) { | ||||
|         return this.$tc( | ||||
|           'validation.name_min_length', | ||||
|           this.$v.formData.name.$params.minLength.min, | ||||
|           { count: this.$v.formData.name.$params.minLength.min } | ||||
|         ) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   validations: { | ||||
|     formData: { | ||||
|       name: { | ||||
|         required, | ||||
|         minLength: minLength(2), | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   async mounted() { | ||||
|     this.$refs.name.focus = true | ||||
|     if (this.modalDataID) { | ||||
|       this.isEdit = true | ||||
|       this.setData() | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal', 'resetModalData']), | ||||
|     ...mapActions('payment', ['addPaymentMode', 'updatePaymentMode']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         id: null, | ||||
|         name: null, | ||||
|       } | ||||
|       this.$v.formData.$reset() | ||||
|     }, | ||||
|     async submitPaymentMode() { | ||||
|       this.$v.formData.$touch() | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|       this.isLoading = true | ||||
|       let response | ||||
|  | ||||
|       if (this.isEdit) { | ||||
|         response = await this.updatePaymentMode(this.formData) | ||||
|         if (response.data) { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$t( | ||||
|               'settings.customization.payments.payment_mode_updated' | ||||
|             ), | ||||
|           }) | ||||
|           this.refreshData ? this.refreshData() : '' | ||||
|           this.closePaymentModeModal() | ||||
|           return true | ||||
|         } | ||||
|         this.showNotification({ | ||||
|           type: 'error', | ||||
|           message: response.data.error, | ||||
|         }) | ||||
|       } else { | ||||
|         try { | ||||
|           response = await this.addPaymentMode(this.formData) | ||||
|           if (response.data) { | ||||
|             this.isLoading = false | ||||
|             this.showNotification({ | ||||
|               type: 'success', | ||||
|               message: this.$t( | ||||
|                 'settings.customization.payments.payment_mode_added' | ||||
|               ), | ||||
|             }) | ||||
|             this.refreshData ? this.refreshData() : '' | ||||
|             this.closePaymentModeModal() | ||||
|             return true | ||||
|           } | ||||
|           this.showNotification({ | ||||
|             type: 'error', | ||||
|             message: response.data.error, | ||||
|           }) | ||||
|         } catch (err) { | ||||
|           this.isLoading = false | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     async setData() { | ||||
|       this.formData = { | ||||
|         id: this.modalData.id, | ||||
|         name: this.modalData.name, | ||||
|       } | ||||
|     }, | ||||
|     closePaymentModeModal() { | ||||
|       this.resetModalData() | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,293 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <form action="" @submit.prevent="sendEstimateData"> | ||||
|       <div class="px-8 py-8 sm:p-6"> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.from')" | ||||
|           :error="fromError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.from" | ||||
|             :invalid="$v.formData.from.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.from.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.to')" | ||||
|           :error="toError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.to" | ||||
|             :invalid="$v.formData.to.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.to.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.subject')" | ||||
|           :error="subjectError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.subject" | ||||
|             :invalid="$v.formData.subject.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.subject.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.body')" | ||||
|           :error="bodyError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <!-- <sw-editor | ||||
|             v-model="formData.body" | ||||
|             :set-editor="formData.body" | ||||
|             :invalid="$v.formData.body.$error" | ||||
|             @input="$v.formData.body.$touch()" | ||||
|           /> --> | ||||
|           <base-custom-input | ||||
|             v-model="formData.body" | ||||
|             :fields="estimateMailFields" | ||||
|             :invalid="$v.formData.body.$error" | ||||
|             class="mt-2" | ||||
|             @input="$v.formData.body.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3" | ||||
|           variant="primary-outline" | ||||
|           type="button" | ||||
|           @click="closeSendEstimateModal" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button | ||||
|           :loading="isLoading" | ||||
|           :disabled="isLoading" | ||||
|           variant="primary" | ||||
|           type="submit" | ||||
|         > | ||||
|           <paper-airplane-icon v-if="!isLoading" class="h-5 mr-2" /> | ||||
|           {{ $t('general.send') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { PaperAirplaneIcon } from '@vue-hero-icons/solid' | ||||
| const { required, email } = require('vuelidate/lib/validators') | ||||
| const _ = require('lodash') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     PaperAirplaneIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       isLoading: false, | ||||
|       estimateMailFields: [ | ||||
|         'customer', | ||||
|         'customerCustom', | ||||
|         'estimate', | ||||
|         'estimateCustom', | ||||
|         'company', | ||||
|       ], | ||||
|       formData: { | ||||
|         from: null, | ||||
|         to: null, | ||||
|         subject: 'New Estimate', | ||||
|         body: null, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     formData: { | ||||
|       from: { | ||||
|         required, | ||||
|         email, | ||||
|       }, | ||||
|       to: { | ||||
|         required, | ||||
|         email, | ||||
|       }, | ||||
|       subject: { | ||||
|         required, | ||||
|       }, | ||||
|       body: { | ||||
|         required, | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalDataID', 'modalData', 'modalActive']), | ||||
|     ...mapGetters('user', ['currentUser']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|     getEmailUrl() { | ||||
|       return this.url | ||||
|     }, | ||||
|     fromError() { | ||||
|       if (!this.$v.formData.from.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.from.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.from.email) { | ||||
|         return this.$tc('validation.email_incorrect') | ||||
|       } | ||||
|     }, | ||||
|     toError() { | ||||
|       if (!this.$v.formData.to.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.to.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.to.email) { | ||||
|         return this.$tc('validation.email_incorrect') | ||||
|       } | ||||
|     }, | ||||
|     subjectError() { | ||||
|       if (!this.$v.formData.subject.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.subject.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     bodyError() { | ||||
|       if (!this.$v.formData.body.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.body.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.setInitialData() | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|  | ||||
|     ...mapActions('estimate', ['sendEmail']), | ||||
|  | ||||
|     ...mapActions('company', ['fetchCompanySettings', 'fetchMailConfig']), | ||||
|  | ||||
|     async setInitialData() { | ||||
|       let admin = await this.fetchMailConfig() | ||||
|  | ||||
|       if (this.modalData) { | ||||
|         this.formData.from = admin.data.from_mail | ||||
|         this.formData.to = this.modalData.user.email | ||||
|       } | ||||
|  | ||||
|       let res = await this.fetchCompanySettings(['estimate_mail_body']) | ||||
|  | ||||
|       this.formData.body = res.data.estimate_mail_body | ||||
|     }, | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         from: null, | ||||
|         to: null, | ||||
|         subject: null, | ||||
|         body: null, | ||||
|       } | ||||
|     }, | ||||
|     async sendEstimateData() { | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|       this.$swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_send_estimate'), | ||||
|         icon: 'question', | ||||
|         iconHtml: `<svg | ||||
|             aria-hidden="true" | ||||
|             class="w-6 h-6" | ||||
|             focusable="false" | ||||
|             data-prefix="fas" | ||||
|             data-icon="check-circle" | ||||
|             class="svg-inline--fa fa-check-circle fa-w-16" | ||||
|             role="img" | ||||
|             xmlns="http://www.w3.org/2000/svg" | ||||
|             viewBox="0 0 512 512" | ||||
|           > | ||||
|             <path | ||||
|               fill="#55547A" | ||||
|               d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" | ||||
|             ></path> | ||||
|           </svg>`, | ||||
|         showCancelButton: true, | ||||
|         showConfirmButton: true, | ||||
|       }).then(async (result) => { | ||||
|         try { | ||||
|           if (result.value) { | ||||
|             let data = { | ||||
|               ...this.formData, | ||||
|               id: this.modalDataID, | ||||
|               status: 'SENT', | ||||
|             } | ||||
|  | ||||
|             this.isLoading = true | ||||
|             let res = await this.sendEmail(data) | ||||
|             this.closeModal() | ||||
|             if (res.data.success) { | ||||
|               this.isLoading = false | ||||
|               this.showNotification({ | ||||
|                 type: 'success', | ||||
|                 message: this.$tc('estimates.send_estimate_successfully'), | ||||
|               }) | ||||
|               return true | ||||
|             } | ||||
|             if (res.data.error === 'estimates.user_email_does_not_exist') { | ||||
|               this.showNotification({ | ||||
|                 type: 'error', | ||||
|                 message: this.$tc('estimates.user_email_does_not_exist'), | ||||
|               }) | ||||
|               return false | ||||
|             } | ||||
|           } | ||||
|         } catch (error) { | ||||
|           this.isLoading = false | ||||
|           this.showNotification({ | ||||
|             type: 'error', | ||||
|             message: this.$tc('estimates.something_went_wrong'), | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     closeSendEstimateModal() { | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,289 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <form action="" @submit.prevent="sendInvoiceData"> | ||||
|       <div class="gap-4 px-8 py-8 sm:p-6"> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.from')" | ||||
|           :error="fromError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.from" | ||||
|             :invalid="$v.formData.from.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.from.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.to')" | ||||
|           :error="toError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.to" | ||||
|             :invalid="$v.formData.to.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.to.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.subject')" | ||||
|           :error="subjectError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.subject" | ||||
|             :invalid="$v.formData.subject.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.subject.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.body')" | ||||
|           :error="bodyError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <base-custom-input | ||||
|             v-model="formData.body" | ||||
|             :fields="InvoiceMailFields" | ||||
|             :invalid="$v.formData.body.$error" | ||||
|             class="mt-2" | ||||
|             @input="$v.formData.body.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3" | ||||
|           variant="primary-outline" | ||||
|           type="button" | ||||
|           @click="closeSendInvoiceModal" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button | ||||
|           :loading="isLoading" | ||||
|           :disabled="isLoading" | ||||
|           variant="primary" | ||||
|           type="submit" | ||||
|         > | ||||
|           <paper-airplane-icon v-if="!isLoading" class="h-5 mr-2" /> | ||||
|           {{ $t('general.send') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { PaperAirplaneIcon } from '@vue-hero-icons/solid' | ||||
| const { required, email } = require('vuelidate/lib/validators') | ||||
| const _ = require('lodash') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     PaperAirplaneIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       isLoading: false, | ||||
|       InvoiceMailFields: [ | ||||
|         'customer', | ||||
|         'customerCustom', | ||||
|         'invoice', | ||||
|         'invoiceCustom', | ||||
|         'company', | ||||
|       ], | ||||
|       formData: { | ||||
|         from: null, | ||||
|         to: null, | ||||
|         subject: 'New Invoice', | ||||
|         body: null, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   validations: { | ||||
|     formData: { | ||||
|       from: { | ||||
|         required, | ||||
|         email, | ||||
|       }, | ||||
|       to: { | ||||
|         required, | ||||
|         email, | ||||
|       }, | ||||
|       subject: { | ||||
|         required, | ||||
|       }, | ||||
|       body: { | ||||
|         required, | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalDataID', 'modalData', 'modalActive']), | ||||
|  | ||||
|     ...mapGetters('user', ['currentUser']), | ||||
|  | ||||
|     fromError() { | ||||
|       if (!this.$v.formData.from.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.from.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.from.email) { | ||||
|         return this.$tc('validation.email_incorrect') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     toError() { | ||||
|       if (!this.$v.formData.to.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.to.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.from.email) { | ||||
|         return this.$tc('validation.email_incorrect') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     subjectError() { | ||||
|       if (!this.$v.formData.subject.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.subject.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     bodyError() { | ||||
|       if (!this.$v.formData.body.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.body.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.setInitialData() | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|  | ||||
|     ...mapActions('invoice', ['sendEmail']), | ||||
|  | ||||
|     ...mapActions('company', ['fetchCompanySettings', 'fetchMailConfig']), | ||||
|  | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|  | ||||
|     async setInitialData() { | ||||
|       let admin = await this.fetchMailConfig() | ||||
|  | ||||
|       if (this.modalData) { | ||||
|         this.formData.from = admin.data.from_mail | ||||
|         this.formData.to = this.modalData.user.email | ||||
|       } | ||||
|  | ||||
|       let res = await this.fetchCompanySettings(['invoice_mail_body']) | ||||
|  | ||||
|       this.formData.body = res.data.invoice_mail_body | ||||
|     }, | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         from: null, | ||||
|         to: null, | ||||
|         subject: null, | ||||
|         body: null, | ||||
|       } | ||||
|     }, | ||||
|     async sendInvoiceData() { | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|       this.$swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('invoices.confirm_send_invoice'), | ||||
|         icon: 'question', | ||||
|         iconHtml: `<svg | ||||
|             aria-hidden="true" | ||||
|             class="w-6 h-6" | ||||
|             focusable="false" | ||||
|             data-prefix="fas" | ||||
|             data-icon="check-circle" | ||||
|             class="svg-inline--fa fa-check-circle fa-w-16" | ||||
|             role="img" | ||||
|             xmlns="http://www.w3.org/2000/svg" | ||||
|             viewBox="0 0 512 512" | ||||
|           > | ||||
|             <path | ||||
|               fill="#55547A" | ||||
|               d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" | ||||
|             ></path> | ||||
|           </svg>`, | ||||
|         showCancelButton: true, | ||||
|         showConfirmButton: true, | ||||
|       }).then(async (result) => { | ||||
|         try { | ||||
|           if (result.value) { | ||||
|             let data = { | ||||
|               ...this.formData, | ||||
|               id: this.modalDataID, | ||||
|               status: 'SENT', | ||||
|             } | ||||
|             this.isLoading = true | ||||
|             let res = await this.sendEmail(data) | ||||
|             this.closeModal() | ||||
|             if (res.data.success) { | ||||
|               this.isLoading = false | ||||
|               this.showNotification({ | ||||
|                 type: 'success', | ||||
|                 message: this.$tc('invoices.send_invoice_successfully'), | ||||
|               }) | ||||
|               return true | ||||
|             } | ||||
|             if (res.data.error === 'invoices.user_email_does_not_exist') { | ||||
|               this.showNotification({ | ||||
|                 type: 'error', | ||||
|                 message: this.$tc('invoices.user_email_does_not_exist'), | ||||
|               }) | ||||
|               return false | ||||
|             } | ||||
|           } | ||||
|         } catch (error) { | ||||
|           this.isLoading = false | ||||
|           this.showNotification({ | ||||
|             type: 'error', | ||||
|             message: this.$tc('invoices.something_went_wrong'), | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     closeSendInvoiceModal() { | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,286 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <form action="" @submit.prevent="sendPaymentData"> | ||||
|       <div class="px-8 py-8 sm:p-6"> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.from')" | ||||
|           :error="fromError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.from" | ||||
|             :invalid="$v.formData.from.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.from.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.to')" | ||||
|           :error="toError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.to" | ||||
|             :invalid="$v.formData.to.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.to.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.subject')" | ||||
|           :error="subjectError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="formData.subject" | ||||
|             :invalid="$v.formData.subject.$error" | ||||
|             type="text" | ||||
|             @input="$v.formData.subject.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('general.body')" | ||||
|           :error="bodyError" | ||||
|           class="mb-4" | ||||
|           variant="vertical" | ||||
|           required | ||||
|         > | ||||
|           <sw-editor | ||||
|             v-model="formData.body" | ||||
|             :set-editor="formData.body" | ||||
|             :invalid="$v.formData.body.$error" | ||||
|             @input="$v.formData.body.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3" | ||||
|           variant="primary-outline" | ||||
|           type="button" | ||||
|           @click="closeSendPaymentModal" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button | ||||
|           :loading="isLoading" | ||||
|           :disabled="isLoading" | ||||
|           variant="primary" | ||||
|           type="submit" | ||||
|         > | ||||
|           <paper-airplane-icon v-if="!isLoading" class="h-5 mr-2" /> | ||||
|           {{ $t('general.send') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { PaperAirplaneIcon } from '@vue-hero-icons/solid' | ||||
| const { required, email } = require('vuelidate/lib/validators') | ||||
| const _ = require('lodash') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     PaperAirplaneIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       isLoading: false, | ||||
|       formData: { | ||||
|         from: null, | ||||
|         to: null, | ||||
|         subject: null, | ||||
|         body: null, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   validations: { | ||||
|     formData: { | ||||
|       from: { | ||||
|         required, | ||||
|         email, | ||||
|       }, | ||||
|       to: { | ||||
|         required, | ||||
|         email, | ||||
|       }, | ||||
|       subject: { | ||||
|         required, | ||||
|       }, | ||||
|       body: { | ||||
|         required, | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalDataID', 'modalData', 'modalActive']), | ||||
|  | ||||
|     fromError() { | ||||
|       if (!this.$v.formData.from.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.from.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.from.email) { | ||||
|         return this.$tc('validation.email_incorrect') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     toError() { | ||||
|       if (!this.$v.formData.to.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.to.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.to.email) { | ||||
|         return this.$tc('validation.email_incorrect') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     subjectError() { | ||||
|       if (!this.$v.formData.subject.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.subject.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     bodyError() { | ||||
|       if (!this.$v.formData.body.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.body.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   mounted() { | ||||
|     this.setInitialData() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|  | ||||
|     ...mapActions('payment', ['sendEmail']), | ||||
|  | ||||
|     ...mapActions('company', ['fetchCompanySettings', 'fetchMailConfig']), | ||||
|  | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|  | ||||
|     async setInitialData() { | ||||
|       let admin = await this.fetchMailConfig() | ||||
|  | ||||
|       if (this.modalData) { | ||||
|         this.formData.from = admin.data.from_mail | ||||
|         this.formData.to = this.modalData.user.email | ||||
|       } | ||||
|  | ||||
|       let res = await this.fetchCompanySettings(['payment_mail_body']) | ||||
|  | ||||
|       this.formData.body = res.data.payment_mail_body | ||||
|     }, | ||||
|  | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         from: null, | ||||
|         to: null, | ||||
|         subject: null, | ||||
|         body: null, | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     async sendPaymentData() { | ||||
|       this.$v.formData.$touch() | ||||
|  | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|       this.$swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('payments.confirm_send_payment'), | ||||
|         icon: 'question', | ||||
|         iconHtml: `<svg | ||||
|             aria-hidden="true" | ||||
|             class="w-6 h-6" | ||||
|             focusable="false" | ||||
|             data-prefix="fas" | ||||
|             data-icon="check-circle" | ||||
|             class="svg-inline--fa fa-check-circle fa-w-16" | ||||
|             role="img" | ||||
|             xmlns="http://www.w3.org/2000/svg" | ||||
|             viewBox="0 0 512 512" | ||||
|           > | ||||
|             <path | ||||
|               fill="#55547A" | ||||
|               d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" | ||||
|             ></path> | ||||
|           </svg>`, | ||||
|         showCancelButton: true, | ||||
|         showConfirmButton: true, | ||||
|       }).then(async (result) => { | ||||
|         try { | ||||
|           if (result.value) { | ||||
|             let data = { | ||||
|               ...this.formData, | ||||
|               id: this.modalDataID, | ||||
|               status: 'SENT', | ||||
|             } | ||||
|             this.isLoading = true | ||||
|             let res = await this.sendEmail(data) | ||||
|  | ||||
|             this.closeModal() | ||||
|             if (res.data.success) { | ||||
|               this.isLoading = false | ||||
|               this.showNotification({ | ||||
|                 type: 'success', | ||||
|                 message: this.$tc('payments.send_payment_successfully'), | ||||
|               }) | ||||
|               return true | ||||
|             } | ||||
|             if (res.data.error === 'payments.user_email_does_not_exist') { | ||||
|               this.showNotification({ | ||||
|                 type: 'error', | ||||
|                 message: this.$tc('payments.user_email_does_not_exist'), | ||||
|               }) | ||||
|               return false | ||||
|             } | ||||
|           } | ||||
|         } catch (error) { | ||||
|           this.isLoading = false | ||||
|           this.showNotification({ | ||||
|             type: 'error', | ||||
|             message: this.$tc('payments.something_went_wrong'), | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     closeSendPaymentModal() { | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,129 +0,0 @@ | ||||
| <template> | ||||
|   <div class="file-disk-modal"> | ||||
|     <form @submit.prevent="submitData"> | ||||
|       <div class="px-8 py-6"> | ||||
|         <sw-input-group :label="$t('settings.disk.driver')" required> | ||||
|           <sw-select | ||||
|             v-model="selected_disk" | ||||
|             :options="getDisks" | ||||
|             :searchable="true" | ||||
|             :allow-empty="false" | ||||
|             :show-labels="false" | ||||
|             :custom-label="getCustomLabel" | ||||
|             class="mt-2" | ||||
|             track-by="id" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-solid border-gray-light" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3 text-sm" | ||||
|           type="button" | ||||
|           variant="primary-outline" | ||||
|           @click="closeDisk" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button | ||||
|           :loading="isLoading" | ||||
|           icon="save" | ||||
|           type="submit" | ||||
|           variant="primary" | ||||
|           class="text-sm" | ||||
|         > | ||||
|           {{ $t('general.save') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import Dropbox from './disks/DropboxDisk' | ||||
| import Local from './disks/LocalDisk' | ||||
| import S3 from './disks/S3Disk' | ||||
| import DoSpaces from './disks/DoSpacesDisk' | ||||
|  | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   email, | ||||
|   numeric, | ||||
|   url, | ||||
|   maxLength, | ||||
| } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     Dropbox, | ||||
|     Local, | ||||
|     S3, | ||||
|     DoSpaces, | ||||
|   }, | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       isLoading: false, | ||||
|       set_as_default: false, | ||||
|       name: 'local', | ||||
|       formData: null, | ||||
|       selected_disk: null, | ||||
|       diskConfigData: {}, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalData', 'refreshData']), | ||||
|  | ||||
|     ...mapGetters('disks', ['getDisks']), | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.loadData() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('disks', ['fetchDisks', 'setDefaultDisk']), | ||||
|  | ||||
|     ...mapActions('modal', ['closeModal']), | ||||
|  | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|  | ||||
|     async loadData() { | ||||
|       this.loading = true | ||||
|  | ||||
|       let res = await this.fetchDisks() | ||||
|       this.selected_disk = res.data.disks.find((v) => v.set_as_default == true) | ||||
|  | ||||
|       this.loading = false | ||||
|     }, | ||||
|  | ||||
|     async submitData() { | ||||
|       this.isLoading = true | ||||
|  | ||||
|       let response = await this.setDefaultDisk(this.selected_disk) | ||||
|  | ||||
|       if (response.data.success) { | ||||
|         this.refreshData() | ||||
|         this.closeDisk() | ||||
|         this.showNotification({ | ||||
|           type: 'success', | ||||
|           message: this.$t('settings.disk.success'), | ||||
|         }) | ||||
|       } | ||||
|       this.isLoading = true | ||||
|     }, | ||||
|  | ||||
|     closeDisk() { | ||||
|       this.closeModal() | ||||
|     }, | ||||
|  | ||||
|     getCustomLabel({ driver, name }) { | ||||
|       return `${name} — [${driver}]` | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,239 +0,0 @@ | ||||
| <template> | ||||
|   <div class="tax-type-modal"> | ||||
|     <form action="" @submit.prevent="submitTaxTypeData"> | ||||
|       <div class="p-8 sm:p-6"> | ||||
|         <sw-input-group | ||||
|           :label="$t('tax_types.name')" | ||||
|           :error="nameError" | ||||
|           class="mt-3" | ||||
|           variant="horizontal" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             ref="name" | ||||
|             :invalid="$v.formData.name.$error" | ||||
|             v-model="formData.name" | ||||
|             type="text" | ||||
|             @input="$v.formData.name.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('tax_types.percent')" | ||||
|           :error="percentError" | ||||
|           class="mt-3" | ||||
|           variant="horizontal" | ||||
|           required | ||||
|         > | ||||
|           <sw-money | ||||
|             v-model="formData.percent" | ||||
|             :currency="defaultInput" | ||||
|             :invalid="$v.formData.percent.$error" | ||||
|             class="relative w-full focus:border focus:border-solid focus:border-primary" | ||||
|             @input="$v.formData.percent.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('tax_types.description')" | ||||
|           :error="descriptionError" | ||||
|           class="mt-3" | ||||
|           variant="horizontal" | ||||
|         > | ||||
|           <sw-textarea | ||||
|             v-model="formData.description" | ||||
|             rows="4" | ||||
|             cols="50" | ||||
|             @input="$v.formData.description.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('tax_types.compound_tax')" | ||||
|           class="mt-3" | ||||
|           variant="horizontal" | ||||
|         > | ||||
|           <sw-switch | ||||
|             v-model="formData.compound_tax" | ||||
|             class="flex items-center mt-1" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div | ||||
|         class="z-0 flex justify-end p-4 border-t border-solid border--200 border-modal-bg" | ||||
|       > | ||||
|         <sw-button | ||||
|           class="mr-3 text-sm" | ||||
|           variant="primary-outline" | ||||
|           type="button" | ||||
|           @click="closeTaxModal" | ||||
|         > | ||||
|           {{ $t('general.cancel') }} | ||||
|         </sw-button> | ||||
|         <sw-button :loading="isLoading" variant="primary" type="submit"> | ||||
|           <save-icon v-if="!isLoading" class="mr-2" /> | ||||
|           {{ !isEdit ? $t('general.save') : $t('general.update') }} | ||||
|         </sw-button> | ||||
|       </div> | ||||
|     </form> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   between, | ||||
|   maxLength, | ||||
| } = require('vuelidate/lib/validators') | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       isEdit: false, | ||||
|       isLoading: false, | ||||
|       formData: { | ||||
|         id: null, | ||||
|         name: null, | ||||
|         percent: 0, | ||||
|         description: null, | ||||
|         compound_tax: false, | ||||
|         collective_tax: 0, | ||||
|       }, | ||||
|       defaultInput: { | ||||
|         decimal: '.', | ||||
|         thousands: ',', | ||||
|         prefix: '% ', | ||||
|         precision: 2, | ||||
|         masked: false, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('modal', [ | ||||
|       'modalDataID', | ||||
|       'modalData', | ||||
|       'modalActive', | ||||
|       'refreshData', | ||||
|     ]), | ||||
|     descriptionError() { | ||||
|       if (!this.$v.formData.description.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.description.maxLength) { | ||||
|         return this.$t('validation.description_maxlength') | ||||
|       } | ||||
|     }, | ||||
|     nameError() { | ||||
|       if (!this.$v.formData.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } else { | ||||
|         return this.$tc( | ||||
|           'validation.name_min_length', | ||||
|           this.$v.formData.name.$params.minLength.min, | ||||
|           { count: this.$v.formData.name.$params.minLength.min } | ||||
|         ) | ||||
|       } | ||||
|     }, | ||||
|     percentError() { | ||||
|       if (!this.$v.formData.percent.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.percent.required) { | ||||
|         return this.$t('validation.required') | ||||
|       } else { | ||||
|         return this.$t('validation.enter_valid_tax_rate') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   validations: { | ||||
|     formData: { | ||||
|       name: { | ||||
|         required, | ||||
|         minLength: minLength(3), | ||||
|       }, | ||||
|       percent: { | ||||
|         required, | ||||
|         between: between(-100, 100), | ||||
|       }, | ||||
|       description: { | ||||
|         maxLength: maxLength(255), | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   async mounted() { | ||||
|     this.$refs.name.focus = true | ||||
|     if (this.modalDataID) { | ||||
|       this.isEdit = true | ||||
|       this.setData() | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['closeModal', 'resetModalData']), | ||||
|     ...mapActions('taxType', ['addTaxType', 'updateTaxType', 'fetchTaxType']), | ||||
|     ...mapActions('notification', ['showNotification']), | ||||
|     resetFormData() { | ||||
|       this.formData = { | ||||
|         id: null, | ||||
|         name: null, | ||||
|         percent: 0, | ||||
|         description: null, | ||||
|         collective_tax: 0, | ||||
|       } | ||||
|       this.$v.formData.$reset() | ||||
|     }, | ||||
|     async submitTaxTypeData() { | ||||
|       this.$v.formData.$touch() | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|       this.isLoading = true | ||||
|       let response | ||||
|       if (!this.isEdit) { | ||||
|         response = await this.addTaxType(this.formData) | ||||
|       } else { | ||||
|         response = await this.updateTaxType(this.formData) | ||||
|       } | ||||
|       if (response.data) { | ||||
|         if (!this.isEdit) { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$t('settings.tax_types.created_message'), | ||||
|           }) | ||||
|         } else { | ||||
|           this.showNotification({ | ||||
|             type: 'success', | ||||
|             message: this.$t('settings.tax_types.updated_message'), | ||||
|           }) | ||||
|         } | ||||
|         window.hub.$emit('newTax', response.data.taxType) | ||||
|         this.refreshData ? this.refreshData() : '' | ||||
|         this.closeTaxModal() | ||||
|         this.isLoading = false | ||||
|         return true | ||||
|       } | ||||
|       this.showNotification({ | ||||
|         type: 'error', | ||||
|         message: response.data.error, | ||||
|       }) | ||||
|     }, | ||||
|     async setData() { | ||||
|       this.formData = { | ||||
|         id: this.modalData.id, | ||||
|         name: this.modalData.name, | ||||
|         percent: this.modalData.percent, | ||||
|         description: this.modalData.description, | ||||
|         compound_tax: this.modalData.compound_tax ? true : false, | ||||
|       } | ||||
|     }, | ||||
|     closeTaxModal() { | ||||
|       this.resetModalData() | ||||
|       this.resetFormData() | ||||
|       this.closeModal() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,345 +0,0 @@ | ||||
| <template> | ||||
|   <form @submit.prevent="submitData"> | ||||
|     <div class="px-8 py-6"> | ||||
|       <div class="grid gap-6 grid-col-1 md:grid-cols-2"> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.name')" | ||||
|           :error="nameError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="name" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             :invalid="$v.name.$error" | ||||
|             @input="$v.name.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group :label="$t('settings.disk.driver')" required> | ||||
|           <sw-select | ||||
|             v-model="selected_disk" | ||||
|             :invalid="$v.selected_disk.$error" | ||||
|             :options="disks" | ||||
|             :searchable="true" | ||||
|             :allow-empty="false" | ||||
|             :show-labels="false" | ||||
|             class="mt-2" | ||||
|             track-by="value" | ||||
|             label="name" | ||||
|             @input="onChangeDriver" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.do_spaces_root')" | ||||
|           :error="rootError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.root" | ||||
|             :invalid="$v.diskConfigData.root.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             placeholder="Ex. /user/root/" | ||||
|             @input="$v.diskConfigData.root.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.do_spaces_key')" | ||||
|           :error="keyError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.key" | ||||
|             :invalid="$v.diskConfigData.key.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             placeholder="Ex. KEIS4S39SERSDS" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.key.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.do_spaces_secret')" | ||||
|           :error="secretError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.secret" | ||||
|             :invalid="$v.diskConfigData.secret.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             placeholder="Ex. ********" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.secret.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.do_spaces_region')" | ||||
|           :error="regionError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.region" | ||||
|             :invalid="$v.diskConfigData.region.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             placeholder="Ex. nyc3" | ||||
|             @input="$v.diskConfigData.region.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.do_spaces_endpoint')" | ||||
|           :error="endpointError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.endpoint" | ||||
|             :invalid="$v.diskConfigData.endpoint.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             placeholder="Ex. https://nyc3.digitaloceanspaces.com" | ||||
|             @input="$v.diskConfigData.endpoint.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.do_spaces_bucket')" | ||||
|           :error="bucketError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.bucket" | ||||
|             :invalid="$v.diskConfigData.bucket.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             placeholder="Ex. my-new-space" | ||||
|             @input="$v.diskConfigData.bucket.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div class="flex items-center mt-6" v-if="!isDisabled"> | ||||
|         <div class="relative flex items-center w-12"> | ||||
|           <sw-switch class="flex" v-model="set_as_default"/> | ||||
|         </div> | ||||
|         <div class="ml-4 right"> | ||||
|           <p class="p-0 mb-1 text-base leading-snug text-black box-title"> | ||||
|             {{ $t('settings.disk.is_default') }} | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <slot :disk-data="{ isLoading, submitData }" /> | ||||
|   </form> | ||||
| </template> | ||||
| <script> | ||||
| const { required, url } = require('vuelidate/lib/validators') | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     isEdit: { | ||||
|       type: Boolean, | ||||
|       require: true, | ||||
|       default: false, | ||||
|     }, | ||||
|     loading: { | ||||
|       type: Boolean, | ||||
|       require: true, | ||||
|       default: false, | ||||
|     }, | ||||
|     disks: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       diskConfigData: { | ||||
|         selected_driver: 'doSpaces', | ||||
|         key: '', | ||||
|         secret: '', | ||||
|         region: '', | ||||
|         bucket: '', | ||||
|         endpoint: '', | ||||
|         root: '', | ||||
|       }, | ||||
|       name: '', | ||||
|       isLoading: false, | ||||
|       set_as_default: false, | ||||
|       selected_disk: null, | ||||
|       is_current_disk: null, | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     diskConfigData: { | ||||
|       key: { | ||||
|         required, | ||||
|       }, | ||||
|       secret: { | ||||
|         required, | ||||
|       }, | ||||
|       region: { | ||||
|         required, | ||||
|       }, | ||||
|       bucket: { | ||||
|         required, | ||||
|       }, | ||||
|       root: { | ||||
|         required, | ||||
|       }, | ||||
|       endpoint: { | ||||
|         required, | ||||
|         url | ||||
|       }, | ||||
|     }, | ||||
|     name: { | ||||
|       required, | ||||
|     }, | ||||
|     selected_disk: { | ||||
|       required, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalData']), | ||||
|  | ||||
|     nameError() { | ||||
|       if (!this.$v.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     typeError() { | ||||
|       if (!this.$v.diskConfigData.type.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.type.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     keyError() { | ||||
|       if (!this.$v.diskConfigData.key.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.key.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     secretError() { | ||||
|       if (!this.$v.diskConfigData.secret.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.secret.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     regionError() { | ||||
|       if (!this.$v.diskConfigData.region.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.region.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     bucketError() { | ||||
|       if (!this.$v.diskConfigData.bucket.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.bucket.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     rootError() { | ||||
|       if (!this.$v.diskConfigData.root.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.root.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     endpointError() { | ||||
|       if (!this.$v.diskConfigData.endpoint.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.endpoint.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|       if (!this.$v.diskConfigData.endpoint.url) { | ||||
|         return this.$tc('validation.invalid_url') | ||||
|       } | ||||
|     }, | ||||
|     isDisabled() { | ||||
|       return (this.isEdit && this.set_as_default && this.is_current_disk) ? true : false | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.loadData() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('disks', ['fetchDiskEnv', 'updateDisk']), | ||||
|  | ||||
|     async loadData() { | ||||
|       this.isLoading = true | ||||
|       let data = { | ||||
|         disk: 'doSpaces', | ||||
|       } | ||||
|  | ||||
|       if(this.isEdit) { | ||||
|         this.diskConfigData = JSON.parse(this.modalData.credentials) | ||||
|         this.set_as_default = this.modalData.set_as_default | ||||
|         if(this.set_as_default) { | ||||
|           this.is_current_disk = true | ||||
|         } | ||||
|         this.name = this.modalData.name | ||||
|       } else { | ||||
|         let diskData = await this.fetchDiskEnv(data) | ||||
|  | ||||
|         this.diskConfigData = diskData.data | ||||
|       } | ||||
|       this.selected_disk = this.disks.find((v) => v.value == 'doSpaces') | ||||
|  | ||||
|       this.isLoading = false | ||||
|     }, | ||||
|  | ||||
|     async submitData() { | ||||
|       this.$v.$touch() | ||||
|       if (this.$v.$invalid) { | ||||
|         return | ||||
|       } | ||||
|  | ||||
|       let data = { | ||||
|         credentials: this.diskConfigData, | ||||
|         name: this.name, | ||||
|         driver: this.selected_disk.value, | ||||
|         set_as_default: this.set_as_default, | ||||
|       } | ||||
|  | ||||
|       this.$emit('submit', data) | ||||
|  | ||||
|       return false | ||||
|     }, | ||||
|  | ||||
|     onChangeDriver() { | ||||
|       this.$emit('on-change-disk', this.selected_disk) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,311 +0,0 @@ | ||||
| <template> | ||||
|   <form @submit.prevent="submitData"> | ||||
|     <div class="px-8 py-6"> | ||||
|       <div class="grid gap-6 grid-col-1 md:grid-cols-2"> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.name')" | ||||
|           :error="nameError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="name" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             :invalid="$v.name.$error" | ||||
|             @input="$v.name.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group :label="$t('settings.disk.driver')" required> | ||||
|           <sw-select | ||||
|             v-model="selected_disk" | ||||
|             :invalid="$v.selected_disk.$error" | ||||
|             :options="disks" | ||||
|             :searchable="true" | ||||
|             :allow-empty="false" | ||||
|             :show-labels="false" | ||||
|             track-by="value" | ||||
|             label="name" | ||||
|             class="mt-2" | ||||
|             @input="onChangeDriver" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.dropbox_root')" | ||||
|           :error="rootError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.root" | ||||
|             :invalid="$v.diskConfigData.root.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             placeholder="Ex. /user/root/" | ||||
|             @input="$v.diskConfigData.root.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.dropbox_token')" | ||||
|           :error="tokenError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.token" | ||||
|             :invalid="$v.diskConfigData.token.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.token.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.dropbox_key')" | ||||
|           :error="keyError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.key" | ||||
|             :invalid="$v.diskConfigData.key.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             placeholder="Ex. KEIS4S39SERSDS" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.key.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.dropbox_secret')" | ||||
|           :error="secretError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.secret" | ||||
|             :invalid="$v.diskConfigData.secret.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             placeholder="Ex. ********" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.secret.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.dropbox_app')" | ||||
|           :error="appError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.app" | ||||
|             :invalid="$v.diskConfigData.app.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.app.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div class="flex items-center mt-6" v-if="!isDisabled"> | ||||
|         <div class="relative flex items-center w-12"> | ||||
|           <sw-switch class="flex" v-model="set_as_default"/> | ||||
|         </div> | ||||
|         <div class="ml-4 right"> | ||||
|           <p class="p-0 mb-1 text-base leading-snug text-black box-title"> | ||||
|             {{ $t('settings.disk.is_default') }} | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <slot :disk-data="{ isLoading, submitData }" /> | ||||
|   </form> | ||||
| </template> | ||||
| <script> | ||||
| const { required, edisk } = require('vuelidate/lib/validators') | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     isEdit: { | ||||
|       type: Boolean, | ||||
|       require: true, | ||||
|       default: false, | ||||
|     }, | ||||
|     loading: { | ||||
|       type: Boolean, | ||||
|       require: true, | ||||
|       default: false, | ||||
|     }, | ||||
|     disks: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       diskConfigData: { | ||||
|         selected_driver: 'dropbox', | ||||
|         token: '', | ||||
|         key: '', | ||||
|         secret: '', | ||||
|         app: '', | ||||
|       }, | ||||
|       name: '', | ||||
|       set_as_default: false, | ||||
|       isLoading: false, | ||||
|       is_current_disk: null, | ||||
|       selected_disk: 'dropbox', | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   validations: { | ||||
|     diskConfigData: { | ||||
|       token: { | ||||
|         required, | ||||
|       }, | ||||
|       key: { | ||||
|         required, | ||||
|       }, | ||||
|       secret: { | ||||
|         required, | ||||
|       }, | ||||
|       app: { | ||||
|         required, | ||||
|       }, | ||||
|       root: { | ||||
|         required, | ||||
|       }, | ||||
|     }, | ||||
|     name: { | ||||
|       required, | ||||
|     }, | ||||
|     selected_disk: { | ||||
|       required, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalData']), | ||||
|  | ||||
|     nameError() { | ||||
|       if (!this.$v.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     typeError() { | ||||
|       if (!this.$v.diskConfigData.type.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.type.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     tokenError() { | ||||
|       if (!this.$v.diskConfigData.token.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.token.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     keyError() { | ||||
|       if (!this.$v.diskConfigData.key.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.key.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     secretError() { | ||||
|       if (!this.$v.diskConfigData.secret.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.secret.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     appError() { | ||||
|       if (!this.$v.diskConfigData.app.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.app.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     rootError() { | ||||
|       if (!this.$v.diskConfigData.root.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.root.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|      isDisabled() { | ||||
|       return (this.isEdit && this.set_as_default && this.is_current_disk) ? true : false | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.loadData() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('disks', ['fetchDiskEnv', 'updateDisk']), | ||||
|  | ||||
|     async loadData() { | ||||
|       this.isLoading = true | ||||
|       let data = { | ||||
|         disk: this.selected_disk, | ||||
|       } | ||||
|       if(this.isEdit) { | ||||
|         this.diskConfigData = JSON.parse(this.modalData.credentials) | ||||
|         this.set_as_default = this.modalData.set_as_default | ||||
|         if(this.set_as_default) { | ||||
|           this.is_current_disk = true | ||||
|         } | ||||
|         this.name = this.modalData.name | ||||
|       } else { | ||||
|         let diskData = await this.fetchDiskEnv(data) | ||||
|  | ||||
|         this.diskConfigData = diskData.data | ||||
|       } | ||||
|       this.selected_disk = this.disks.find((v) => v.value == 'dropbox') | ||||
|  | ||||
|       this.isLoading = false | ||||
|     }, | ||||
|  | ||||
|     async submitData() { | ||||
|       this.$v.$touch() | ||||
|       if (this.$v.$invalid) { | ||||
|         return | ||||
|       } | ||||
|  | ||||
|       let data = { | ||||
|         credentials: this.diskConfigData, | ||||
|         name: this.name, | ||||
|         driver: this.selected_disk.value, | ||||
|         set_as_default: this.set_as_default, | ||||
|       } | ||||
|  | ||||
|       this.$emit('submit', data) | ||||
|  | ||||
|       return false | ||||
|     }, | ||||
|  | ||||
|     onChangeDriver() { | ||||
|       this.$emit('on-change-disk', this.selected_disk) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,177 +0,0 @@ | ||||
| <template> | ||||
|   <form @submit.prevent="submitData"> | ||||
|     <div class="px-8 py-6"> | ||||
|       <div class="grid gap-6 grid-col-1 md:grid-cols-2"> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.name')" | ||||
|           :error="nameError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="name" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             :invalid="$v.name.$error" | ||||
|             @input="$v.name.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group :label="$tc('settings.disk.driver')" required> | ||||
|           <sw-select | ||||
|             v-model="selected_disk" | ||||
|             :invalid="$v.selected_disk.$error" | ||||
|             :options="disks" | ||||
|             :searchable="true" | ||||
|             :allow-empty="false" | ||||
|             :show-labels="false" | ||||
|             track-by="value" | ||||
|             label="name" | ||||
|             class="mt-2" | ||||
|             @input="onChangeDriver" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group :label="$t('settings.disk.local_root')" required> | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.root" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             placeholder="Ex. /user/root/" | ||||
|             class="mt-2" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div class="flex items-center mt-6" v-if="!isDisabled"> | ||||
|         <div class="relative flex items-center w-12"> | ||||
|           <sw-switch class="flex" v-model="set_as_default"/> | ||||
|         </div> | ||||
|         <div class="ml-4 right"> | ||||
|           <p class="p-0 mb-1 text-base leading-snug text-black box-title"> | ||||
|             {{ $t('settings.disk.is_default') }} | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <slot :disk-data="{ isLoading, submitData }" /> | ||||
|   </form> | ||||
| </template> | ||||
| <script> | ||||
| const { required, edisk } = require('vuelidate/lib/validators') | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     isEdit: { | ||||
|       type: Boolean, | ||||
|       require: true, | ||||
|       default: false, | ||||
|     }, | ||||
|     loading: { | ||||
|       type: Boolean, | ||||
|       require: true, | ||||
|       default: false, | ||||
|     }, | ||||
|     disks: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       diskConfigData: { | ||||
|         selected_driver: 'local', | ||||
|         root: '', | ||||
|       }, | ||||
|       name: '', | ||||
|       isLoading: false, | ||||
|       set_as_default: false, | ||||
|       selected_disk: null, | ||||
|       is_current_disk: null, | ||||
|       is_current_disk: null, | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     diskConfigData: { | ||||
|       root: { | ||||
|         required, | ||||
|       }, | ||||
|     }, | ||||
|     name: { | ||||
|       required, | ||||
|     }, | ||||
|     selected_disk: { | ||||
|       required, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalData']), | ||||
|  | ||||
|     nameError() { | ||||
|       if (!this.$v.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     isDisabled() { | ||||
|       return (this.isEdit && this.set_as_default && this.is_current_disk) ? true : false | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.loadData() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('disks', ['fetchDiskEnv', 'updateDisk']), | ||||
|  | ||||
|     async loadData() { | ||||
|       this.isLoading = true | ||||
|       let data = { | ||||
|         disk: 'local', | ||||
|       } | ||||
|  | ||||
|       if(this.isEdit) { | ||||
|         this.diskConfigData = JSON.parse(this.modalData.credentials) | ||||
|         this.set_as_default = this.modalData.set_as_default | ||||
|         if(this.set_as_default) { | ||||
|           this.is_current_disk = true | ||||
|         } | ||||
|         this.name = this.modalData.name | ||||
|       } else { | ||||
|         let diskData = await this.fetchDiskEnv(data) | ||||
|  | ||||
|         this.diskConfigData = diskData.data | ||||
|       } | ||||
|       this.selected_disk = this.disks.find((v) => v.value == 'local') | ||||
|  | ||||
|       this.isLoading = false | ||||
|     }, | ||||
|  | ||||
|     async submitData() { | ||||
|       this.$v.$touch() | ||||
|       if (this.$v.$invalid) { | ||||
|         return | ||||
|       } | ||||
|       let data = { | ||||
|         credentials: this.diskConfigData, | ||||
|         name: this.name, | ||||
|         driver: this.selected_disk.value, | ||||
|         set_as_default: this.set_as_default, | ||||
|       } | ||||
|  | ||||
|       this.$emit('submit', data) | ||||
|  | ||||
|       return false | ||||
|     }, | ||||
|  | ||||
|     onChangeDriver() { | ||||
|       this.$emit('on-change-disk', this.selected_disk) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,313 +0,0 @@ | ||||
| <template> | ||||
|   <form @submit.prevent="submitData"> | ||||
|     <div class="px-8 py-6"> | ||||
|       <div class="grid gap-6 grid-col-1 md:grid-cols-2"> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.name')" | ||||
|           :error="nameError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="name" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             :invalid="$v.name.$error" | ||||
|             @input="$v.name.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group :label="$tc('settings.disk.driver')" required> | ||||
|           <sw-select | ||||
|             v-model="selected_disk" | ||||
|             :invalid="$v.selected_disk.$error" | ||||
|             :options="disks" | ||||
|             :searchable="true" | ||||
|             :allow-empty="false" | ||||
|             :show-labels="false" | ||||
|             track-by="value" | ||||
|             label="name" | ||||
|             class="mt-2" | ||||
|             @input="onChangeDriver" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.aws_root')" | ||||
|           :error="rootError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.root" | ||||
|             :invalid="$v.diskConfigData.root.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             placeholder="Ex. /user/root/" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.root.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.aws_key')" | ||||
|           :error="keyError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.key" | ||||
|             :invalid="$v.diskConfigData.key.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             placeholder="Ex. KEIS4S39SERSDS" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.key.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.aws_secret')" | ||||
|           :error="secretError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.secret" | ||||
|             :invalid="$v.diskConfigData.secret.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             placeholder="Ex. ********" | ||||
|             class="mt-2" | ||||
|             @input="$v.diskConfigData.secret.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.aws_region')" | ||||
|           :error="regionError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.region" | ||||
|             :invalid="$v.diskConfigData.region.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             placeholder="Ex. us-west" | ||||
|             @input="$v.diskConfigData.region.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|         <sw-input-group | ||||
|           :label="$t('settings.disk.aws_bucket')" | ||||
|           :error="bucketError" | ||||
|           required | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model.trim="diskConfigData.bucket" | ||||
|             :invalid="$v.diskConfigData.bucket.$error" | ||||
|             type="text" | ||||
|             name="name" | ||||
|             class="mt-2" | ||||
|             placeholder="Ex. AppName" | ||||
|             @input="$v.diskConfigData.bucket.$touch()" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|       </div> | ||||
|       <div class="flex items-center mt-6" v-if="!isDisabled"> | ||||
|         <div class="relative flex items-center w-12"> | ||||
|           <sw-switch class="flex" v-model="set_as_default"/> | ||||
|         </div> | ||||
|         <div class="ml-4 right"> | ||||
|           <p class="p-0 mb-1 text-base leading-snug text-black box-title"> | ||||
|             {{ $t('settings.disk.is_default') }} | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <slot :disk-data="{ isLoading, submitData }" /> | ||||
|   </form> | ||||
| </template> | ||||
| <script> | ||||
| const { required, edisk } = require('vuelidate/lib/validators') | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     isEdit: { | ||||
|       type: Boolean, | ||||
|       require: true, | ||||
|       default: false, | ||||
|     }, | ||||
|     loading: { | ||||
|       type: Boolean, | ||||
|       require: true, | ||||
|       default: false, | ||||
|     }, | ||||
|     disks: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       diskConfigData: { | ||||
|         selected_driver: 's3', | ||||
|         key: '', | ||||
|         secret: '', | ||||
|         region: '', | ||||
|         bucket: '', | ||||
|         root: '', | ||||
|       }, | ||||
|       name: '', | ||||
|       set_as_default: false, | ||||
|       isLoading: false, | ||||
|       selected_disk: null, | ||||
|       is_current_disk: null, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   validations: { | ||||
|     diskConfigData: { | ||||
|       key: { | ||||
|         required, | ||||
|       }, | ||||
|       secret: { | ||||
|         required, | ||||
|       }, | ||||
|       region: { | ||||
|         required, | ||||
|       }, | ||||
|       bucket: { | ||||
|         required, | ||||
|       }, | ||||
|       root: { | ||||
|         required, | ||||
|       }, | ||||
|     }, | ||||
|     name: { | ||||
|       required, | ||||
|     }, | ||||
|     selected_disk: { | ||||
|       required, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('modal', ['modalData']), | ||||
|  | ||||
|     nameError() { | ||||
|       if (!this.$v.name.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.name.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     driverError() { | ||||
|       if (!this.$v.diskConfigData.driver.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.driver.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     keyError() { | ||||
|       if (!this.$v.diskConfigData.key.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.key.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     secretError() { | ||||
|       if (!this.$v.diskConfigData.secret.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.secret.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     regionError() { | ||||
|       if (!this.$v.diskConfigData.region.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.region.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     bucketError() { | ||||
|       if (!this.$v.diskConfigData.bucket.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.bucket.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     rootError() { | ||||
|       if (!this.$v.diskConfigData.root.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.diskConfigData.root.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     isDisabled() { | ||||
|       return (this.isEdit && this.set_as_default && this.is_current_disk) ? true : false | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.loadData() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('disks', ['fetchDiskEnv', 'updateDisk']), | ||||
|  | ||||
|     async loadData() { | ||||
|       this.isLoading = true | ||||
|       let data = { | ||||
|         disk: 's3', | ||||
|       } | ||||
|      if(this.isEdit) { | ||||
|         this.diskConfigData = JSON.parse(this.modalData.credentials) | ||||
|         this.set_as_default = this.modalData.set_as_default | ||||
|         if(this.set_as_default) { | ||||
|           this.is_current_disk = true | ||||
|         } | ||||
|         this.name = this.modalData.name | ||||
|       } else { | ||||
|         let diskData = await this.fetchDiskEnv(data) | ||||
|  | ||||
|         this.diskConfigData = diskData.data | ||||
|       } | ||||
|       this.selected_disk = this.disks.find((v) => v.value == 's3') | ||||
|  | ||||
|       this.isLoading = false | ||||
|     }, | ||||
|  | ||||
|     async submitData() { | ||||
|       this.$v.$touch() | ||||
|       if (this.$v.$invalid) { | ||||
|         return | ||||
|       } | ||||
|  | ||||
|       let data = { | ||||
|         credentials: this.diskConfigData, | ||||
|         name: this.name, | ||||
|         driver: this.selected_disk.value, | ||||
|         set_as_default: this.set_as_default, | ||||
|       } | ||||
|  | ||||
|       this.$emit('submit', data) | ||||
|  | ||||
|       return false | ||||
|     }, | ||||
|  | ||||
|     onChangeDriver() { | ||||
|       this.$emit('on-change-disk', this.selected_disk) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,176 +0,0 @@ | ||||
| <template> | ||||
|   <div class="customer-select"> | ||||
|     <div class="flex flex-col w-full pb-4"> | ||||
|       <div class="flex px-4 pt-4 pb-2"> | ||||
|         <sw-input | ||||
|           v-model="search" | ||||
|           :placeholder="$t('general.search')" | ||||
|           focus | ||||
|           type="text" | ||||
|           icon="search" | ||||
|           @input="searchCustomer" | ||||
|         > | ||||
|           <template v-slot:leftIcon> | ||||
|             <search-icon class="h-5 m-2 text-gray-500" /> | ||||
|           </template> | ||||
|         </sw-input> | ||||
|       </div> | ||||
|  | ||||
|       <div | ||||
|         v-if="customers.length > 0 && !loading" | ||||
|         class="relative flex flex-col overflow-auto sw-scroll list" | ||||
|       > | ||||
|         <div | ||||
|           v-for="(customer, index) in customers" | ||||
|           :key="index" | ||||
|           class="flex px-6 py-2 border-b border-gray-200 border-solid cursor-pointer hover:cursor-pointer hover:bg-gray-100 last:border-b-0" | ||||
|           @click="selectNewCustomer(customer.id)" | ||||
|         > | ||||
|           <span | ||||
|             class="flex items-center content-center justify-center w-10 h-10 mr-4 text-xl font-semibold leading-9 text-white bg-gray-400 rounded-full avatar" | ||||
|             >{{ initGenerator(customer.name) }}</span | ||||
|           > | ||||
|           <div class="flex flex-col justify-center"> | ||||
|             <label class="m-0 leading-tight cursor-pointer font-base">{{ | ||||
|               customer.name | ||||
|             }}</label> | ||||
|             <label | ||||
|               class="m-0 text-sm font-medium text-gray-500 cursor-pointer font-base" | ||||
|               >{{ customer.contact_name }}</label | ||||
|             > | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|       <div v-if="loading" class="flex items-center justify-center list"> | ||||
|         <refresh-icon class="animate-spin" /> | ||||
|       </div> | ||||
|  | ||||
|       <div | ||||
|         v-if="customers.length === 0" | ||||
|         class="flex justify-center p-5 text-gray-400" | ||||
|       > | ||||
|         <label class="cursor-pointer"> | ||||
|           {{ $t('customers.no_customers_found') }} | ||||
|         </label> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|     <button | ||||
|       type="button" | ||||
|       class="flex items-center justify-center w-full px-2 py-3 bg-gray-200 border-none outline-none" | ||||
|       @click="openCustomerModal" | ||||
|     > | ||||
|       <user-add-icon class="text-primary-400" /> | ||||
|  | ||||
|       <label | ||||
|         class="m-0 ml-3 text-sm leading-none cursor-pointer font-base text-primary-400" | ||||
|         >{{ $t('customers.add_new_customer') }}</label | ||||
|       > | ||||
|     </button> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { UserAddIcon, SearchIcon, RefreshIcon } from '@vue-hero-icons/solid' | ||||
|  | ||||
| export default { | ||||
|   components: { UserAddIcon, SearchIcon, RefreshIcon }, | ||||
|  | ||||
|   props: { | ||||
|     type: { | ||||
|       type: String, | ||||
|       required: true, | ||||
|     }, | ||||
|     userId: { | ||||
|       type: Number, | ||||
|       required: false, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       search: null, | ||||
|       loading: false, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('customer', ['customers']), | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.fetchInitialCustomers() | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['openModal']), | ||||
|     ...mapActions('customer', ['fetchCustomers']), | ||||
|     ...mapActions('invoice', { | ||||
|       setInvoiceCustomer: 'selectCustomer', | ||||
|     }), | ||||
|     ...mapActions('estimate', { | ||||
|       setEstimateCustomer: 'selectCustomer', | ||||
|     }), | ||||
|  | ||||
|     async fetchInitialCustomers() { | ||||
|       await this.fetchCustomers({ | ||||
|         filter: {}, | ||||
|         orderByField: '', | ||||
|         orderBy: '', | ||||
|         customer_id: this.userId, | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     async searchCustomer() { | ||||
|       let data = { | ||||
|         display_name: this.search, | ||||
|         email: '', | ||||
|         phone: '', | ||||
|         orderByField: '', | ||||
|         orderBy: '', | ||||
|         page: 1, | ||||
|       } | ||||
|  | ||||
|       this.loading = true | ||||
|  | ||||
|       await this.fetchCustomers(data) | ||||
|  | ||||
|       this.loading = false | ||||
|     }, | ||||
|  | ||||
|     openCustomerModal() { | ||||
|       this.openModal({ | ||||
|         title: this.$t('customers.add_customer'), | ||||
|         componentName: 'CustomerModal', | ||||
|         variant: 'lg', | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     initGenerator(name) { | ||||
|       if (name) { | ||||
|         let nameSplit = name.split(' ') | ||||
|         let initials = nameSplit[0].charAt(0).toUpperCase() | ||||
|         return initials | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     selectNewCustomer(id) { | ||||
|       if (this.type === 'estimate') { | ||||
|         this.setEstimateCustomer(id) | ||||
|       } else { | ||||
|         this.setInvoiceCustomer(id) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| <style lang="scss"> | ||||
| .customer-select { | ||||
|   .list { | ||||
|     max-height: 173px; | ||||
|     min-height: 173px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -1,114 +0,0 @@ | ||||
| <template> | ||||
|   <div class="tax-select"> | ||||
|     <div class="flex flex-col w-full px-4 py-4"> | ||||
|       <div class="relative flex w-full mb-2"> | ||||
|         <sw-input | ||||
|           v-model="textSearch" | ||||
|           :placeholder="$t('general.search')" | ||||
|           focus | ||||
|           class="text-black" | ||||
|           icon="search" | ||||
|           type="text" | ||||
|         /> | ||||
|       </div> | ||||
|       <div | ||||
|         v-if="filteredNotes.length > 0" | ||||
|         class="relative flex flex-col overflow-auto sw-scroll list" | ||||
|         style="max-height: 112px" | ||||
|       > | ||||
|         <div | ||||
|           v-for="(note, index) in filteredNotes" | ||||
|           :key="index" | ||||
|           class="flex justify-between p-4 border-b border-gray-200 border-solid cursor-pointer list-item last:border-b-0 hover:bg-gray-100" | ||||
|           @click="selectNote(index)" | ||||
|         > | ||||
|           <label | ||||
|             class="inline-block m-0 text-base font-normal leading-tight text-black font-base" | ||||
|           > | ||||
|             {{ note.name }} | ||||
|           </label> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div v-else class="flex justify-center p-5 text-gray-400"> | ||||
|         <label class="m-0">{{ $t('general.no_note_found') }}</label> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|     <button | ||||
|       type="button" | ||||
|       class="flex items-center justify-center w-full px-2 py-3 bg-gray-200 border-none outline-none hover:bg-gray-300" | ||||
|       @click="openNoteModal" | ||||
|     > | ||||
|       <check-circle-icon class="h-5" /> | ||||
|       <label | ||||
|         class="m-0 ml-1 text-sm leading-none cursor-pointer font-base text-primary-400" | ||||
|       > | ||||
|         {{ $t('settings.customization.notes.add_new_note') }} | ||||
|       </label> | ||||
|     </button> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { CheckCircleIcon } from '@vue-hero-icons/solid' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     CheckCircleIcon, | ||||
|   }, | ||||
|   props: { | ||||
|     type: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       textSearch: null, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('notes', ['notes']), | ||||
|  | ||||
|     filteredNotes() { | ||||
|       if (this.textSearch) { | ||||
|         var textSearch = this.textSearch | ||||
|         return this.notes.filter(function (el) { | ||||
|           return el.name.toLowerCase().indexOf(textSearch.toLowerCase()) !== -1 | ||||
|         }) | ||||
|       } else { | ||||
|         return this.notes | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.fetchInitialData() | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['openModal']), | ||||
|     ...mapActions('notes', ['fetchNotes']), | ||||
|     selectNote(index) { | ||||
|       this.$emit('select', { ...this.notes[index] }) | ||||
|     }, | ||||
|  | ||||
|     async fetchInitialData() { | ||||
|       await this.fetchNotes({ | ||||
|         filter: {}, | ||||
|         orderByField: '', | ||||
|         orderBy: '', | ||||
|         type: this.type ? this.type : '', | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     openNoteModal() { | ||||
|       this.openModal({ | ||||
|         title: this.$t('settings.customization.notes.add_note'), | ||||
|         componentName: 'NoteSelectModal', | ||||
|         variant: 'lg', | ||||
|         data: this.type, | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,110 +0,0 @@ | ||||
| <template> | ||||
|   <div class="tax-select"> | ||||
|     <div class="flex flex-col w-full p-4"> | ||||
|       <div class="relative flex w-full mb-2"> | ||||
|         <sw-input | ||||
|           v-model="textSearch" | ||||
|           :placeholder="$t('general.search')" | ||||
|           focus | ||||
|           class="text-black" | ||||
|           icon="search" | ||||
|           type="text" | ||||
|         /> | ||||
|       </div> | ||||
|       <div | ||||
|         v-if="filteredTaxType.length > 0" | ||||
|         class="relative flex flex-col overflow-auto sw-scroll list" | ||||
|         style="max-height: 112px" | ||||
|       > | ||||
|         <div | ||||
|           v-for="(taxType, index) in filteredTaxType" | ||||
|           :key="index" | ||||
|           :class="{ | ||||
|             'bg-gray-100 cursor-not-allowed opacity-50 pointer-events-none': taxes.find( | ||||
|               (val) => { | ||||
|                 return val.tax_type_id === taxType.id | ||||
|               } | ||||
|             ), | ||||
|           }" | ||||
|           class="flex justify-between p-4 border-b border-gray-200 border-solid cursor-pointer list-item last:border-b-0 hover:bg-gray-100" | ||||
|           @click="selectTaxType(index)" | ||||
|         > | ||||
|           <label | ||||
|             class="inline-block m-0 text-base font-normal leading-tight text-black font-base" | ||||
|           > | ||||
|             {{ taxType.name }} | ||||
|           </label> | ||||
|           <label | ||||
|             class="inline-block m-0 text-base font-normal leading-tight text-black font-base" | ||||
|           > | ||||
|             {{ taxType.percent }} % | ||||
|           </label> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div v-else class="flex justify-center p-5 text-gray-400"> | ||||
|         <label class="m-0">{{ $t('general.no_tax_found') }}</label> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|     <button | ||||
|       type="button" | ||||
|       class="flex items-center justify-center w-full px-2 py-3 bg-gray-200 border-none outline-none" | ||||
|       @click="openTaxModal" | ||||
|     > | ||||
|       <check-circle-icon class="h-5" /> | ||||
|       <label | ||||
|         class="m-0 ml-3 text-sm leading-none cursor-pointer font-base text-primary-400" | ||||
|       > | ||||
|         {{ $t('invoices.add_new_tax') }} | ||||
|       </label> | ||||
|     </button> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { CheckCircleIcon } from '@vue-hero-icons/solid' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     CheckCircleIcon, | ||||
|   }, | ||||
|   props: { | ||||
|     taxes: { | ||||
|       type: Array, | ||||
|       required: false, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       textSearch: null, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('taxType', ['taxTypes']), | ||||
|     filteredTaxType() { | ||||
|       if (this.textSearch) { | ||||
|         var textSearch = this.textSearch | ||||
|         return this.taxTypes.filter(function (el) { | ||||
|           return el.name.toLowerCase().indexOf(textSearch.toLowerCase()) !== -1 | ||||
|         }) | ||||
|       } else { | ||||
|         return this.taxTypes | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('modal', ['openModal']), | ||||
|     selectTaxType(index) { | ||||
|       this.$emit('select', { ...this.taxTypes[index] }) | ||||
|     }, | ||||
|     openTaxModal() { | ||||
|       this.openModal({ | ||||
|         title: this.$t('settings.tax_types.add_tax'), | ||||
|         componentName: 'TaxTypeModal', | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,31 +0,0 @@ | ||||
| export default { | ||||
|   activeBaseSelectContainer: 'z-50', | ||||
|   disabledBaseSelectContainer: 'pointer-events-none opacity-50', | ||||
|   baseSelectContainer: 'base-select multiselect min-h-10 z-40', | ||||
|   multiSelect: | ||||
|     'multiselect__select h-10 m-0 py-1 px-2 no-underline text-center cursor-pointer leading-5 block absolute box-border w-8', | ||||
|   disabledMultiSelect: 'bg-gray-200 text-gray-400', | ||||
|   multiSelectTags: | ||||
|     'multiselect__tags min-h-10 block pt-2 pr-10 pb-0 pl-2 rounded border border-solid text-sm', | ||||
|   multiSelectTagsDefaultColor: 'border-gray-200 bg-white', | ||||
|   multiSelectTagsInvalid: 'border-danger bg-white', | ||||
|   disabledMultiSelectTags: 'bg-gray-200 text-gray-400', | ||||
|   multiselectTagsWrap: 'multiselect__tags-wrap inline', | ||||
|   multiselectTag: | ||||
|     'multiselect__tag relative inline-block pt-1 pr-6 pb-1 pl-2 rounded mr-2 text-white leading-none mb-1 whitespace-nowrap overflow-hidden max-w-full', | ||||
|   multiselectTagIcon: | ||||
|     'multiselect__tag-icon cursor-pointer ml-2 absolute right-0 top-0 bottom-0 font-bold w-5 text-center leading-5 delay-200 transition-all ease-linear rounded', | ||||
|   multiselectStrong: 'mb-2 leading-5 inline-block align-top', | ||||
|   multiselectSpinner: 'multiselect__spinner absolute w-12 h-8 bg-white block', | ||||
|   multiselectInput: | ||||
|     'multiselect__input relative inline-block border-none leading-5 rounded pl-1 w-full box-border align-top text-sm', | ||||
|   multiselectSingle: | ||||
|     'multiselect__single relative inline-block border-none leading-5 rounded bg-white pl-1 w-full box-border align-top pl-1 mb-2 text-sm', | ||||
|   multiselectContentWrapper: | ||||
|     'multiselect__content-wrapper absolute block bg-white w-full overflow-auto border border-solid border-gray-200 border-t-0 rounded-bl rounded-br z-50', | ||||
|   multiselectContent: | ||||
|     'multiselect__content list-none inline-block p-0 m-0 min-w-full align-top', | ||||
|   multiselectOption: | ||||
|     'multiselect__option block p-3 no-underline leading-4 normal-case align-middle relative cursor-pointer whitespace-nowrap text-sm', | ||||
|   multiselectElement: 'multiselect__element block', | ||||
| } | ||||
| @ -1,11 +0,0 @@ | ||||
| export default { | ||||
|   baseClass: | ||||
|     'not-italic font-normal leading-tight text-left border border-solid rounded-md input-field box-border-2 base-date-picker-input', | ||||
|   baseSize: 'w-full h-10 px-3 py-3 text-sm', | ||||
|   baseColorClass: | ||||
|     'placeholder-gray-400 border-gray-200 focus:border-primary-500', | ||||
|   invalidClass: 'border-red', | ||||
|   disabledClass: 'bg-gray-200 text-gray-500', | ||||
|   calendarIconStyle: | ||||
|     'absolute w-4 h-5 text-sm not-italic font-black cursor-pointer text-gray-400', | ||||
| } | ||||
| @ -1,15 +0,0 @@ | ||||
| /* | ||||
|  |-------------------------------------------------------------------------- | ||||
|  | Crater Base Components Theme | ||||
|  |--------------------------------------------------------------------------| | ||||
|  */ | ||||
|  | ||||
| import BaseSelect from './BaseSelect' | ||||
| import DatePicker from './DatePicker' | ||||
|  | ||||
| const CraterTheme = { | ||||
|   BaseSelect, | ||||
|   DatePicker, | ||||
| } | ||||
|  | ||||
| export default CraterTheme | ||||
| @ -1,212 +0,0 @@ | ||||
| <template> | ||||
|   <div class="graph-container"> | ||||
|     <canvas id="graph" ref="graph" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import Chart from 'chart.js' | ||||
| import { mapGetters } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     labels: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|     values: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|     invoices: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|     expenses: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|     receipts: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|     income: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|     formatMoney: { | ||||
|       type: Function, | ||||
|       require: false, | ||||
|       default: Function, | ||||
|     }, | ||||
|     FormatGraphMoney: { | ||||
|       type: Function, | ||||
|       require: false, | ||||
|       default: Function, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('company', ['defaultCurrency']), | ||||
|   }, | ||||
|  | ||||
|   watch: { | ||||
|     labels(val) { | ||||
|       this.update() | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   mounted() { | ||||
|     let self = this | ||||
|     let context = this.$refs.graph.getContext('2d') | ||||
|     let options = { | ||||
|       responsive: true, | ||||
|       maintainAspectRatio: false, | ||||
|       tooltips: { | ||||
|         enabled: true, | ||||
|         callbacks: { | ||||
|           label: function (tooltipItem, data) { | ||||
|             return self.FormatGraphMoney( | ||||
|               Math.round(tooltipItem.value * 100), | ||||
|               self.defaultCurrency | ||||
|             ) | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|       legend: { | ||||
|         display: false, | ||||
|       }, | ||||
|     } | ||||
|     let data = { | ||||
|       labels: this.labels, | ||||
|       datasets: [ | ||||
|         { | ||||
|           label: 'Sales', | ||||
|           fill: false, | ||||
|           lineTension: 0.3, | ||||
|           backgroundColor: 'rgba(230, 254, 249)', | ||||
|           borderColor: '#040405', | ||||
|           borderCapStyle: 'butt', | ||||
|           borderDash: [], | ||||
|           borderDashOffset: 0.0, | ||||
|           borderJoinStyle: 'miter', | ||||
|           pointBorderColor: '#040405', | ||||
|           pointBackgroundColor: '#fff', | ||||
|           pointBorderWidth: 1, | ||||
|           pointHoverRadius: 5, | ||||
|           pointHoverBackgroundColor: '#040405', | ||||
|           pointHoverBorderColor: 'rgba(220,220,220,1)', | ||||
|           pointHoverBorderWidth: 2, | ||||
|           pointRadius: 4, | ||||
|           pointHitRadius: 10, | ||||
|           data: this.invoices.map((invoice) => invoice / 100), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Receipts', | ||||
|           fill: false, | ||||
|           lineTension: 0.3, | ||||
|           backgroundColor: 'rgba(230, 254, 249)', | ||||
|           borderColor: 'rgb(2, 201, 156)', | ||||
|           borderCapStyle: 'butt', | ||||
|           borderDash: [], | ||||
|           borderDashOffset: 0.0, | ||||
|           borderJoinStyle: 'miter', | ||||
|           pointBorderColor: 'rgb(2, 201, 156)', | ||||
|           pointBackgroundColor: '#fff', | ||||
|           pointBorderWidth: 1, | ||||
|           pointHoverRadius: 5, | ||||
|           pointHoverBackgroundColor: 'rgb(2, 201, 156)', | ||||
|           pointHoverBorderColor: 'rgba(220,220,220,1)', | ||||
|           pointHoverBorderWidth: 2, | ||||
|           pointRadius: 4, | ||||
|           pointHitRadius: 10, | ||||
|           data: this.receipts.map((receipt) => receipt / 100), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Expenses', | ||||
|           fill: false, | ||||
|           lineTension: 0.3, | ||||
|           backgroundColor: 'rgba(245, 235, 242)', | ||||
|           borderColor: 'rgb(255,0,0)', | ||||
|           borderCapStyle: 'butt', | ||||
|           borderDash: [], | ||||
|           borderDashOffset: 0.0, | ||||
|           borderJoinStyle: 'miter', | ||||
|           pointBorderColor: 'rgb(255,0,0)', | ||||
|           pointBackgroundColor: '#fff', | ||||
|           pointBorderWidth: 1, | ||||
|           pointHoverRadius: 5, | ||||
|           pointHoverBackgroundColor: 'rgb(255,0,0)', | ||||
|           pointHoverBorderColor: 'rgba(220,220,220,1)', | ||||
|           pointHoverBorderWidth: 2, | ||||
|           pointRadius: 4, | ||||
|           pointHitRadius: 10, | ||||
|           data: this.expenses.map((expense) => expense / 100), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Net Income', | ||||
|           fill: false, | ||||
|           lineTension: 0.3, | ||||
|           backgroundColor: 'rgba(236, 235, 249)', | ||||
|           borderColor: 'rgba(88, 81, 216, 1)', | ||||
|           borderCapStyle: 'butt', | ||||
|           borderDash: [], | ||||
|           borderDashOffset: 0.0, | ||||
|           borderJoinStyle: 'miter', | ||||
|           pointBorderColor: 'rgba(88, 81, 216, 1)', | ||||
|           pointBackgroundColor: '#fff', | ||||
|           pointBorderWidth: 1, | ||||
|           pointHoverRadius: 5, | ||||
|           pointHoverBackgroundColor: 'rgba(88, 81, 216, 1)', | ||||
|           pointHoverBorderColor: 'rgba(220,220,220,1)', | ||||
|           pointHoverBorderWidth: 2, | ||||
|           pointRadius: 4, | ||||
|           pointHitRadius: 10, | ||||
|           data: this.income.map((_i) => _i / 100), | ||||
|         }, | ||||
|       ], | ||||
|     } | ||||
|  | ||||
|     this.myLineChart = new Chart(context, { | ||||
|       type: 'line', | ||||
|       data: data, | ||||
|       options: options, | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     update() { | ||||
|       this.myLineChart.data.labels = this.labels | ||||
|       this.myLineChart.data.datasets[0].data = this.invoices.map( | ||||
|         (invoice) => invoice / 100 | ||||
|       ) | ||||
|       this.myLineChart.data.datasets[1].data = this.receipts.map( | ||||
|         (receipt) => receipt / 100 | ||||
|       ) | ||||
|       this.myLineChart.data.datasets[2].data = this.expenses.map( | ||||
|         (expense) => expense / 100 | ||||
|       ) | ||||
|       this.myLineChart.data.datasets[3].data = this.income.map((_i) => _i / 100) | ||||
|       this.myLineChart.update({ | ||||
|         lazy: true, | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     beforeDestroy() { | ||||
|       this.myLineChart.destroy() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .graph-container { | ||||
|   height: 300px; | ||||
| } | ||||
| </style> | ||||
| @ -1,102 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <base-date-picker | ||||
|       v-model="date" | ||||
|       :calendar-button="true" | ||||
|       :invalid="isInvalid" | ||||
|       :placeholder="placeholder" | ||||
|       calendar-button-icon="calendar" | ||||
|       @input="onDateChanged" | ||||
|     /> | ||||
|     <span v-if="isInvalid" class="text-sm text-danger"> | ||||
|       {{ $t('validation.required') }} | ||||
|     </span> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| import moment from 'moment' | ||||
| const { required, requiredIf } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     isEdit: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       date: null, | ||||
|       placeholder: '', | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     date: { | ||||
|       required: requiredIf('isRequired'), | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.date.$error && !this.$v.date.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|     field: { | ||||
|       handler: 'handleData', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.date = | ||||
|       this.field && this.field.defaultAnswer && this.field.defaultAnswer | ||||
|     this.placeholder = | ||||
|       this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|   }, | ||||
|   methods: { | ||||
|     handleData() { | ||||
|       this.date = | ||||
|         this.field && this.field.defaultAnswer | ||||
|           ? this.field.defaultAnswer | ||||
|           : new Date() | ||||
|       this.placeholder = | ||||
|         this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|     }, | ||||
|     onDateChanged(date) { | ||||
|       this.$v.date.$touch() | ||||
|       this.$emit('update', { | ||||
|         field: this.field, | ||||
|         value: moment(date).format('YYYY-MM-DD'), | ||||
|       }) | ||||
|     }, | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,85 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <base-date-picker | ||||
|       v-model="dateTime" | ||||
|       :invalid="isInvalid" | ||||
|       :enable-time="true" | ||||
|       :placeholder="placeholder" | ||||
|       @input="onChanged" | ||||
|     /> | ||||
|     <span v-if="isInvalid" class="text-sm text-danger"> | ||||
|       {{ $t('validation.required') }} | ||||
|     </span> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| const { required, requiredIf } = require('vuelidate/lib/validators') | ||||
| import moment from 'moment' | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       dateTime: null, | ||||
|       placeholder: '', | ||||
|       defaultValue: null, | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     dateTime: { | ||||
|       required: requiredIf('isRequired'), | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.dateTime.$error && !this.$v.dateTime.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.dateTime = | ||||
|       this.field && this.field.defaultAnswer | ||||
|         ? moment(this.field.defaultAnswer).format('YYYY-MM-DD H:m') | ||||
|         : moment().format('YYYY-MM-DD H:m') | ||||
|     this.placeholder = | ||||
|       this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|   }, | ||||
|   methods: { | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|     onChanged() { | ||||
|       this.$v.dateTime.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.dateTime }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,89 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-select | ||||
|       v-model="selectedValue" | ||||
|       :options="options" | ||||
|       :searchable="true" | ||||
|       :show-labels="false" | ||||
|       :allow-empty="true" | ||||
|       :invalid="isInvalid" | ||||
|       :placeholder="placeholder" | ||||
|       :tabindex="tabindex" | ||||
|       @select="onSelectedValueChanged" | ||||
|     /> | ||||
|     <span v-if="isInvalid" class="text-sm text-danger"> | ||||
|       {{ $t('validation.required') }} | ||||
|     </span> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| const { required, requiredIf } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       require: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       selectedValue: null, | ||||
|       options: [], | ||||
|       placeholder: '', | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     selectedValue: { | ||||
|       required: requiredIf('isRequired'), | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.selectedValue.$error && !this.$v.selectedValue.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.options = this.field && this.field.options ? this.field.options : [] | ||||
|     this.selectedValue = this.field && this.field.defaultAnswer | ||||
|     this.placeholder = this.field && this.field.placeholder | ||||
|   }, | ||||
|   methods: { | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|     onSelectedValueChanged(data) { | ||||
|       this.$v.selectedValue.$touch() | ||||
|       this.$emit('update', { field: this.field, value: data }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,111 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-input | ||||
|       :type="type" | ||||
|       :invalid="isInvalid" | ||||
|       :placeholder="placeholder" | ||||
|       v-model="inputValue" | ||||
|       :tabindex="tabindex" | ||||
|       @input="handleInput" | ||||
|       @change="handleChange" | ||||
|     /> | ||||
|     <span v-if="isInvalid" class="text-sm text-danger"> | ||||
|       {{ $t('validation.required') }} | ||||
|     </span> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   numeric, | ||||
|   minValue, | ||||
|   maxLength, | ||||
|   requiredIf, | ||||
| } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     type: { | ||||
|       type: String, | ||||
|       default: 'text', | ||||
|       required: false, | ||||
|     }, | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: null, | ||||
|       placeholder: '', | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     inputValue: { | ||||
|       required: requiredIf('isRequired'), | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.inputValue.$error && !this.$v.inputValue.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     field: { | ||||
|       handler: 'handleData', | ||||
|       deep: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.inputValue = this.field && this.field.defaultAnswer | ||||
|     this.placeholder = | ||||
|       this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|   }, | ||||
|   methods: { | ||||
|     handleData() { | ||||
|       this.inputValue = this.field && this.field.defaultAnswer | ||||
|       this.placeholder = | ||||
|         this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|     }, | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|     handleInput() { | ||||
|       this.$emit('update', { field: this.field, value: this.inputValue }) | ||||
|       this.$v.inputValue.$touch() | ||||
|     }, | ||||
|     handleChange() { | ||||
|       this.$v.inputValue.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.inputValue }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,114 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-input | ||||
|       :invalid="$v.inputValue.$error || isInvalid" | ||||
|       :placeholder="placeholder" | ||||
|       :tabindex="tabindex" | ||||
|       v-model="inputValue" | ||||
|       type="number" | ||||
|       @input="handleInput" | ||||
|       @change="handleChange" | ||||
|     /> | ||||
|     <div v-if="$v.inputValue.$error || isInvalid"> | ||||
|       <span v-if="isInvalid" class="text-sm text-danger"> | ||||
|         {{ $t('validation.required') }} | ||||
|       </span> | ||||
|       <span | ||||
|         v-if="!isInvalid && $v.inputValue.numeric" | ||||
|         class="text-sm text-danger" | ||||
|       > | ||||
|         {{ $t('validation.required') }} | ||||
|       </span> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| const { required, numeric, requiredIf } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     type: { | ||||
|       type: String, | ||||
|       default: 'text', | ||||
|       required: false, | ||||
|     }, | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: null, | ||||
|       placeholder: '', | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     inputValue: { | ||||
|       required: requiredIf('isRequired'), | ||||
|       numeric, | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.inputValue.$error && !this.$v.inputValue.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     field: { | ||||
|       handler: 'handleData', | ||||
|       deep: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.inputValue = this.field && this.field.defaultAnswer | ||||
|     this.placeholder = | ||||
|       this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|   }, | ||||
|   methods: { | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|     handleData() { | ||||
|       this.inputValue = this.field && this.field.defaultAnswer | ||||
|       this.placeholder = | ||||
|         this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|     }, | ||||
|     handleInput() { | ||||
|       this.$v.inputValue.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.inputValue }) | ||||
|     }, | ||||
|     handleChange() { | ||||
|       this.$v.inputValue.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.inputValue }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,113 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-input | ||||
|       :invalid="$v.inputValue.$error || isInvalid" | ||||
|       :placeholder="placeholder" | ||||
|       :tabindex="tabindex" | ||||
|       v-model="inputValue" | ||||
|       type="text" | ||||
|       @input="handleInput" | ||||
|       @change="handleChange" | ||||
|     /> | ||||
|     <div v-if="$v.inputValue.$error || isInvalid"> | ||||
|       <span | ||||
|         v-if="!isInvalid && !$v.inputValue.phone" | ||||
|         class="text-sm text-danger" | ||||
|       > | ||||
|         {{ $t('validation.invalid_phone') }} | ||||
|       </span> | ||||
|       <span v-if="isInvalid" class="text-sm text-danger"> | ||||
|         {{ $t('validation.required') }} | ||||
|       </span> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   numeric, | ||||
|   minValue, | ||||
|   maxLength, | ||||
|   requiredIf, | ||||
| } = require('vuelidate/lib/validators') | ||||
| const isPhone = (value) => /^\+?[0-9]+$/.test(value) | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     type: { | ||||
|       type: String, | ||||
|       default: 'text', | ||||
|       required: false, | ||||
|     }, | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: null, | ||||
|       placeholder: '', | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     inputValue: { | ||||
|       phone: isPhone, | ||||
|       required: requiredIf('isRequired'), | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.inputValue.$error && !this.$v.inputValue.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.inputValue = this.field && this.field.defaultAnswer | ||||
|     this.placeholder = | ||||
|       this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|   }, | ||||
|   methods: { | ||||
|     handleInput() { | ||||
|       this.$v.inputValue.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.inputValue }) | ||||
|     }, | ||||
|     handleChange() { | ||||
|       this.$v.inputValue.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.inputValue }) | ||||
|     }, | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,37 +0,0 @@ | ||||
| <template> | ||||
|   <sw-switch | ||||
|     v-model="switchData" | ||||
|     class="btn-switch" | ||||
|     @change="onChange" | ||||
|     style="margin-top: -15px" | ||||
|   /> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   props: { | ||||
|     type: { | ||||
|       type: String, | ||||
|       default: 'text', | ||||
|       required: false, | ||||
|     }, | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       switchData: false, | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.switchData = this.field && this.field.defaultAnswer ? true : false | ||||
|   }, | ||||
|   methods: { | ||||
|     onChange() { | ||||
|       this.$emit('update', { field: this.field, value: this.switchData }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,96 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-textarea | ||||
|       v-model="text" | ||||
|       :invalid="isInvalid" | ||||
|       :placeholder="placeholder" | ||||
|       :tabindex="tabindex" | ||||
|       @input="handleInput" | ||||
|       @change="handleChange" | ||||
|     /> | ||||
|     <span v-if="isInvalid" class="text-sm text-danger"> | ||||
|       {{ $t('validation.required') }} | ||||
|     </span> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| const { | ||||
|   required, | ||||
|   minLength, | ||||
|   numeric, | ||||
|   minValue, | ||||
|   maxLength, | ||||
|   requiredIf, | ||||
| } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       text: null, | ||||
|       placeholder: '', | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     text: { | ||||
|       required: requiredIf('isRequired'), | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.text.$error && !this.$v.text.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.text = this.field && this.field.defaultAnswer | ||||
|     this.placeholder = | ||||
|       this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|   }, | ||||
|   methods: { | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|     handleInput() { | ||||
|       this.$v.text.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.text }) | ||||
|     }, | ||||
|     handleChange() { | ||||
|       this.$v.text.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.text }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,103 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <base-time-picker | ||||
|       v-model="time" | ||||
|       :set-value="defaultValue" | ||||
|       :invalid="$v.time.$error" | ||||
|       :placeholder="placeholder" | ||||
|       :tabindex="tabindex" | ||||
|       hide-clear-button | ||||
|       @input="onTimeSelect" | ||||
|     /> | ||||
|     <div v-if="$v.time.$error"> | ||||
|       <span v-if="!$v.time.required" class="text-sm text-danger"> | ||||
|         {{ $t('validation.required') }} | ||||
|       </span> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| const { required, requiredIf } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       time: null, | ||||
|       defaultValue: '00:00:00', | ||||
|       placeholder: '', | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     time: { | ||||
|       required: requiredIf('isRequired'), | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.inputValue.$error && !this.$v.inputValue.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     field: { | ||||
|       handler: 'handleData', | ||||
|       deep: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.placeholder = | ||||
|       this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|     this.handleData() | ||||
|   }, | ||||
|   methods: { | ||||
|     handleData() { | ||||
|       this.defaultValue = | ||||
|         this.field && this.field.defaultAnswer | ||||
|           ? this.field.defaultAnswer | ||||
|           : '00-00-00' | ||||
|       this.time = | ||||
|         this.field && this.field.defaultAnswer | ||||
|           ? this.field.defaultAnswer | ||||
|           : '00-00-00' | ||||
|     }, | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|     onTimeSelect() { | ||||
|       this.$v.time.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.time }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,101 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <sw-input | ||||
|       :invalid="$v.inputValue.$error || isInvalid" | ||||
|       :placeholder="placeholder" | ||||
|       :tabindex="tabindex" | ||||
|       v-model="inputValue" | ||||
|       type="url" | ||||
|       @input="handleInput" | ||||
|       @change="handleChange" | ||||
|     /> | ||||
|     <div v-if="$v.inputValue.$error || isInvalid"> | ||||
|       <span v-if="!$v.inputValue.url" class="text-sm text-danger"> | ||||
|         {{ $t('validation.invalid_url') }} | ||||
|       </span> | ||||
|       <span v-if="isInvalid" class="text-sm text-danger"> | ||||
|         {{ $t('validation.required') }} | ||||
|       </span> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| const { required, url, requiredIf } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   props: { | ||||
|     type: { | ||||
|       type: String, | ||||
|       default: 'text', | ||||
|       required: false, | ||||
|     }, | ||||
|     field: { | ||||
|       type: Object, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     invalidFields: { | ||||
|       type: Array, | ||||
|       default: () => [], | ||||
|     }, | ||||
|     tabindex: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       inputValue: null, | ||||
|       placeholder: '', | ||||
|       invalidFieldIds: [], | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     inputValue: { | ||||
|       url, | ||||
|       required: requiredIf('isRequired'), | ||||
|     }, | ||||
|   }, | ||||
|   computed: { | ||||
|     isRequired() { | ||||
|       if (this.field && this.field.is_required) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     isInvalid() { | ||||
|       if ( | ||||
|         this.invalidFieldIds.indexOf(this.field.cfid) >= 0 || | ||||
|         (this.$v.inputValue.$error && !this.$v.inputValue.required) | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     invalidFields: { | ||||
|       handler: 'setInvalidFieldIds', | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.inputValue = this.field && this.field.defaultAnswer | ||||
|     this.placeholder = | ||||
|       this.field && this.field.placeholder ? this.field.placeholder : '' | ||||
|   }, | ||||
|   methods: { | ||||
|     setInvalidFieldIds() { | ||||
|       this.invalidFieldIds = this.invalidFields.map((field) => field.id) | ||||
|     }, | ||||
|     handleInput() { | ||||
|       this.$v.inputValue.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.inputValue }) | ||||
|     }, | ||||
|     handleChange() { | ||||
|       this.$v.inputValue.$touch() | ||||
|       this.$emit('update', { field: this.field, value: this.inputValue }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,84 +0,0 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <div class="dot-icon" @click="checktoggle"> | ||||
|       <span :class="{ 'move-right': toggle }" class="dot dot1" /> | ||||
|  | ||||
|       <span class="dot dot2" /> | ||||
|  | ||||
|       <span :class="{ 'move-left': toggle }" class="dot dot3" /> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| export default { | ||||
|   data() { | ||||
|     return { | ||||
|       toggle: false, | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     checktoggle: function () { | ||||
|       var v = this | ||||
|       v.toggle = true | ||||
|       setTimeout(function () { | ||||
|         v.toggle = false | ||||
|       }, 300) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style> | ||||
| .dot-icon { | ||||
|   display: flex; | ||||
|   cursor: pointer; | ||||
|   padding: 8px 5px 5px 5px; | ||||
|   justify-content: flex-end; | ||||
| } | ||||
|  | ||||
| .dot { | ||||
|   display: inline-block; | ||||
|   background: #a5acc1; | ||||
|   display: block; | ||||
|   width: 6px; | ||||
|   height: 6px; | ||||
|   border-radius: 50%; | ||||
|   position: relative; | ||||
| } | ||||
|  | ||||
| .dot1 { | ||||
|   margin-right: 3px; | ||||
| } | ||||
|  | ||||
| .dot2 { | ||||
|   margin-right: 3px; | ||||
| } | ||||
|  | ||||
| .move-right { | ||||
|   animation: moveright 0.2s; | ||||
|   animation-fill-mode: forwards; | ||||
| } | ||||
|  | ||||
| .move-left { | ||||
|   animation: moveleft 0.2s; | ||||
|   animation-fill-mode: forwards; | ||||
| } | ||||
|  | ||||
| @keyframes moveleft { | ||||
|   from { | ||||
|     left: 0px; | ||||
|   } | ||||
|   to { | ||||
|     left: -18px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @keyframes moveright { | ||||
|   from { | ||||
|     left: 0px; | ||||
|   } | ||||
|   to { | ||||
|     left: 18px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -1,18 +0,0 @@ | ||||
| <template> | ||||
|   <svg | ||||
|     width="39" | ||||
|     height="39" | ||||
|     viewBox="0 0 39 39" | ||||
|     fill="none" | ||||
|     xmlns="http://www.w3.org/2000/svg" | ||||
|   > | ||||
|     <path | ||||
|       d="M19.22 38.44C29.8349 38.44 38.44 29.8349 38.44 19.22C38.44 8.60509 29.8349 0 19.22 0C8.60509 0 0 8.60509 0 19.22C0 29.8349 8.60509 38.44 19.22 38.44Z" | ||||
|       fill="#3B5998" | ||||
|     /> | ||||
|     <path | ||||
|       d="M23.442 18.5216H20.833V28.08H16.88V18.5216H15V15.1624H16.88V12.9887C16.88 11.4342 17.6184 9 20.8682 9L23.7962 9.01225V12.2729H21.6717C21.3232 12.2729 20.8332 12.447 20.8332 13.1886V15.1656H23.7874L23.442 18.5216Z" | ||||
|       fill="white" | ||||
|     /> | ||||
|   </svg> | ||||
| </template> | ||||
| @ -1,34 +0,0 @@ | ||||
| <template> | ||||
|   <svg | ||||
|     width="40" | ||||
|     height="39" | ||||
|     viewBox="0 0 40 39" | ||||
|     fill="none" | ||||
|     xmlns="http://www.w3.org/2000/svg" | ||||
|   > | ||||
|     <circle | ||||
|       cx="20.0078" | ||||
|       cy="19.7782" | ||||
|       r="18.7188" | ||||
|       fill="#F2F2F2" | ||||
|       stroke="#F2F2F2" | ||||
|       stroke-width="1.00639" | ||||
|     /> | ||||
|     <path | ||||
|       d="M13.744 21.9871L12.9733 24.8641L10.1565 24.9237C9.31465 23.3623 8.83716 21.5759 8.83716 19.6775C8.83716 17.8418 9.2836 16.1107 10.075 14.5864H10.0756L12.5833 15.0462L13.6819 17.5389C13.4519 18.2092 13.3266 18.9288 13.3266 19.6775C13.3267 20.4902 13.4739 21.2688 13.744 21.9871Z" | ||||
|       fill="#FBBB00" | ||||
|     /> | ||||
|     <path | ||||
|       d="M30.7842 17.6089C30.9114 18.2786 30.9777 18.9701 30.9777 19.677C30.9777 20.4695 30.8943 21.2426 30.7356 21.9883C30.1967 24.526 28.7886 26.7419 26.8379 28.3099L26.8373 28.3093L23.6786 28.1482L23.2316 25.3575C24.5259 24.5984 25.5375 23.4104 26.0703 21.9883H20.1508V17.6089H26.1567H30.7842Z" | ||||
|       fill="#518EF8" | ||||
|     /> | ||||
|     <path | ||||
|       d="M26.8374 28.3096L26.838 28.3102C24.9409 29.8351 22.531 30.7475 19.9076 30.7475C15.6918 30.7475 12.0264 28.3911 10.1566 24.9235L13.7441 21.9868C14.679 24.4819 17.0859 26.258 19.9076 26.258C21.1204 26.258 22.2567 25.9301 23.2317 25.3578L26.8374 28.3096Z" | ||||
|       fill="#28B446" | ||||
|     /> | ||||
|     <path | ||||
|       d="M26.9737 11.1555L23.3874 14.0916C22.3783 13.4608 21.1855 13.0964 19.9075 13.0964C17.022 13.0964 14.5701 14.954 13.682 17.5386L10.0757 14.5861H10.0751C11.9175 11.0339 15.6291 8.60693 19.9075 8.60693C22.5936 8.60693 25.0564 9.56373 26.9737 11.1555Z" | ||||
|       fill="#F14336" | ||||
|     /> | ||||
|   </svg> | ||||
| </template> | ||||
| @ -1,113 +0,0 @@ | ||||
| <template> | ||||
|   <svg | ||||
|     width="125" | ||||
|     height="110" | ||||
|     viewBox="0 0 125 110" | ||||
|     fill="none" | ||||
|     xmlns="http://www.w3.org/2000/svg" | ||||
|   > | ||||
|     <g clip-path="url(#clip0)"> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M46.8031 84.4643C46.8031 88.8034 43.3104 92.3215 39.0026 92.3215C34.6948 92.3215 31.2021 88.8034 31.2021 84.4643C31.2021 80.1252 34.6948 76.6072 39.0026 76.6072C43.3104 76.6072 46.8031 80.1252 46.8031 84.4643Z" | ||||
|         fill="#817AE3" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M60.4536 110H64.3539V72.6785H60.4536V110Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M85.8055 76.6072H70.2045C69.1319 76.6072 68.2544 77.4911 68.2544 78.5715V82.5C68.2544 83.5804 69.1319 84.4643 70.2045 84.4643H85.8055C86.878 84.4643 87.7556 83.5804 87.7556 82.5V78.5715C87.7556 77.4911 86.878 76.6072 85.8055 76.6072ZM70.2045 82.5H85.8055V78.5715H70.2045V82.5Z" | ||||
|         fill="#817AE3" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M91.6556 1.96429C94.8811 1.96429 97.506 4.60821 97.506 7.85714V19.6429H83.8181L85.308 21.6071H99.4561V7.85714C99.4561 3.53571 95.9459 0 91.6556 0H33.152C28.8618 0 25.3516 3.53571 25.3516 7.85714V21.6071H39.3203L40.8745 19.6429H27.3017V7.85714C27.3017 4.60821 29.9265 1.96429 33.152 1.96429H91.6556Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M122.858 92.3213H117.007C115.935 92.3213 115.057 93.2052 115.057 94.2856V102.143C115.057 103.223 115.935 104.107 117.007 104.107H122.858C123.93 104.107 124.808 103.223 124.808 102.143V94.2856C124.808 93.2052 123.93 92.3213 122.858 92.3213ZM117.007 102.143H122.858V94.2856H117.007V102.143Z" | ||||
|         fill="#817AE3" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M103.356 43.2142V70.7142H21.4511V43.2142H26.1821V41.2498H19.501V72.6783H105.306V41.2498H98.3541L98.2839 43.2142H103.356Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M101.406 21.6071C104.632 21.6071 107.257 24.251 107.257 27.5V41.25H98.2257L98.0853 43.2142H109.207V27.5C109.207 23.1609 105.714 19.6428 101.406 19.6428H83.8182L85.0878 21.6071H101.406ZM40.8746 19.6428H23.4016C19.0937 19.6428 15.6011 23.1609 15.6011 27.5V43.2142H26.1961L26.3365 41.25H17.5512V27.5C17.5512 24.251 20.1761 21.6071 23.4016 21.6071H39.3204L40.8746 19.6428Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M62.4041 9.82153C45.1709 9.82153 31.2021 23.8917 31.2021 41.2501C31.2021 58.6085 45.1709 72.6787 62.4041 72.6787C79.6373 72.6787 93.606 58.6085 93.606 41.2501C93.606 23.8917 79.6373 9.82153 62.4041 9.82153ZM62.4041 11.7858C78.5335 11.7858 91.6559 25.0035 91.6559 41.2501C91.6559 57.4967 78.5335 70.7144 62.4041 70.7144C46.2746 70.7144 33.1523 57.4967 33.1523 41.2501C33.1523 25.0035 46.2746 11.7858 62.4041 11.7858Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M62.4041 19.6428C45.1709 19.6428 31.2021 23.8916 31.2021 41.25C31.2021 58.6084 45.1709 66.7857 62.4041 66.7857C79.6373 66.7857 93.606 58.6084 93.606 41.25C93.606 23.8916 79.6373 19.6428 62.4041 19.6428ZM62.4041 21.6071C82.6346 21.6071 91.6559 27.665 91.6559 41.25C91.6559 56.0096 80.7216 64.8214 62.4041 64.8214C44.0866 64.8214 33.1523 56.0096 33.1523 41.25C33.1523 27.665 42.1735 21.6071 62.4041 21.6071Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M101.406 70.7144H23.4014C10.478 70.7144 0 81.2685 0 94.2858V110H124.808V94.2858C124.808 81.2685 114.33 70.7144 101.406 70.7144ZM101.406 72.6786C113.234 72.6786 122.858 82.3724 122.858 94.2858V108.036H1.95012V94.2858C1.95012 82.3724 11.574 72.6786 23.4014 72.6786H101.406Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M33.152 33.3928H29.2518C27.0969 33.3928 25.3516 35.1509 25.3516 37.3214V45.1785C25.3516 47.3491 27.0969 49.1071 29.2518 49.1071H33.152V33.3928ZM31.2019 35.3571V47.1428H29.2518C28.1773 47.1428 27.3017 46.2609 27.3017 45.1785V37.3214C27.3017 36.2391 28.1773 35.3571 29.2518 35.3571H31.2019Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M95.556 33.3928H91.6558V49.1071H95.556C97.7109 49.1071 99.4562 47.3491 99.4562 45.1785V37.3214C99.4562 35.1509 97.7109 33.3928 95.556 33.3928ZM95.556 35.3571C96.6305 35.3571 97.5061 36.2391 97.5061 37.3214V45.1785C97.5061 46.2609 96.6305 47.1428 95.556 47.1428H93.6059V35.3571H95.556Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M94.581 15.7144C94.0447 15.7144 93.606 16.1563 93.606 16.6965V34.3751C93.606 34.9152 94.0447 35.3572 94.581 35.3572C95.1173 35.3572 95.5561 34.9152 95.5561 34.3751V16.6965C95.5561 16.1563 95.1173 15.7144 94.581 15.7144Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M38.0273 41.2499C37.4891 41.2499 37.0522 40.8099 37.0522 40.2678C37.0522 33.3142 44.1409 25.5356 53.6283 25.5356C54.1665 25.5356 54.6033 25.9756 54.6033 26.5178C54.6033 27.0599 54.1665 27.4999 53.6283 27.4999C45.2564 27.4999 39.0024 34.2414 39.0024 40.2678C39.0024 40.8099 38.5655 41.2499 38.0273 41.2499Z" | ||||
|         fill="#817AE3" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M97.5059 110H99.456V72.6785H97.5059V110Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|       <path | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|         d="M25.3516 110H27.3017V72.6785H25.3516V110Z" | ||||
|         fill="#55547A" | ||||
|       /> | ||||
|     </g> | ||||
|     <defs> | ||||
|       <clipPath id="clip0"> | ||||
|         <rect width="124.808" height="110" fill="white" /> | ||||
|       </clipPath> | ||||
|     </defs> | ||||
|   </svg> | ||||
| </template> | ||||
| @ -1,18 +0,0 @@ | ||||
| <template> | ||||
|   <svg | ||||
|     width="39" | ||||
|     height="39" | ||||
|     viewBox="0 0 39 39" | ||||
|     fill="none" | ||||
|     xmlns="http://www.w3.org/2000/svg" | ||||
|   > | ||||
|     <path | ||||
|       d="M19.4104 39.0002C30.0264 39.0002 38.6324 30.3942 38.6324 19.7782C38.6324 9.16215 30.0264 0.556152 19.4104 0.556152C8.79435 0.556152 0.188354 9.16215 0.188354 19.7782C0.188354 30.3942 8.79435 39.0002 19.4104 39.0002Z" | ||||
|       fill="#55ACEE" | ||||
|     /> | ||||
|     <path | ||||
|       d="M31.1843 14.3704C30.3605 14.7357 29.4744 14.9827 28.5452 15.0931C29.494 14.5246 30.2221 13.6251 30.5658 12.5516C29.678 13.0783 28.6942 13.4603 27.6481 13.6663C26.81 12.7737 25.6159 12.2158 24.2936 12.2158C21.7566 12.2158 19.699 14.2734 19.699 16.8104C19.699 17.1706 19.7397 17.5211 19.8185 17.8576C16 17.666 12.6143 15.837 10.348 13.0563C9.95261 13.7348 9.72577 14.5246 9.72577 15.3665C9.72577 16.9602 10.5375 18.3671 11.7697 19.1908C11.0169 19.1672 10.3079 18.9606 9.68876 18.6155C9.68842 18.635 9.68842 18.6546 9.68842 18.6738C9.68842 20.9 11.2728 22.7568 13.3743 23.1786C12.9892 23.2841 12.5825 23.34 12.1641 23.34C11.8673 23.34 11.5799 23.3115 11.2996 23.2581C11.8841 25.083 13.5806 26.4115 15.5916 26.4489C14.0188 27.6814 12.038 28.4157 9.88476 28.4157C9.5147 28.4157 9.14806 28.3941 8.78931 28.3512C10.8216 29.6554 13.2373 30.4157 15.8318 30.4157C24.2829 30.4157 28.9046 23.4147 28.9046 17.3426C28.9046 17.1435 28.9002 16.9451 28.8913 16.7484C29.7897 16.1008 30.5685 15.2918 31.1843 14.3704Z" | ||||
|       fill="#F1F2F2" | ||||
|     /> | ||||
|   </svg> | ||||
| </template> | ||||
| @ -1,14 +0,0 @@ | ||||
| <template> | ||||
|   <svg | ||||
|     width="25" | ||||
|     height="19" | ||||
|     viewBox="0 0 25 19" | ||||
|     fill="none" | ||||
|     xmlns="http://www.w3.org/2000/svg" | ||||
|   > | ||||
|     <path | ||||
|       d="M21.0156 8.36719C21.7708 8.4974 22.4479 8.79688 23.0469 9.26562C23.6458 9.73438 24.1146 10.3203 24.4531 11.0234C24.8177 11.7266 25 12.4688 25 13.25C25 14.6302 24.5052 15.8151 23.5156 16.8047C22.5521 17.7682 21.3802 18.25 20 18.25H5.625C4.0625 18.25 2.73438 17.7031 1.64062 16.6094C0.546875 15.5156 0 14.1875 0 12.625C0 11.401 0.351562 10.3073 1.05469 9.34375C1.75781 8.38021 2.65625 7.70312 3.75 7.3125C3.75 7.18229 3.75 7.07812 3.75 7C3.75 5.28125 4.36198 3.8099 5.58594 2.58594C6.8099 1.36198 8.28125 0.75 10 0.75C11.1458 0.75 12.2005 1.03646 13.1641 1.60938C14.1276 2.18229 14.8828 2.9375 15.4297 3.875C16.0547 3.45833 16.7448 3.25 17.5 3.25C18.5417 3.25 19.4271 3.61458 20.1562 4.34375C20.8854 5.07292 21.25 5.95833 21.25 7C21.25 7.46875 21.1719 7.92448 21.0156 8.36719ZM15.3516 10.75C15.638 10.75 15.8333 10.6198 15.9375 10.3594C16.0417 10.099 16.0026 9.8776 15.8203 9.69531L11.6797 5.55469C11.3932 5.26823 11.1068 5.26823 10.8203 5.55469L6.67969 9.69531C6.4974 9.8776 6.45833 10.099 6.5625 10.3594C6.66667 10.6198 6.86198 10.75 7.14844 10.75H9.6875V15.125C9.6875 15.3073 9.73958 15.4635 9.84375 15.5938C9.97396 15.6979 10.1302 15.75 10.3125 15.75H12.1875C12.3698 15.75 12.513 15.6979 12.6172 15.5938C12.7474 15.4635 12.8125 15.3073 12.8125 15.125V10.75H15.3516Z" | ||||
|       fill="#B9C1D1" | ||||
|     /> | ||||
|   </svg> | ||||
| </template> | ||||
| @ -1,45 +0,0 @@ | ||||
| <script> | ||||
| let mailgunComponent = { | ||||
|   template: '#mailgun-template', | ||||
| } | ||||
|  | ||||
| let sendgridComponent = { | ||||
|   template: '#sendgrid-template', | ||||
| } | ||||
|  | ||||
| let sparkPostComponent = { | ||||
|   template: '#sparkpost-template', | ||||
| } | ||||
|  | ||||
| let smtpComponent = { | ||||
|   template: '#smtp-template', | ||||
| } | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     mailgun: mailgunComponent, | ||||
|     sendgrid: sendgridComponent, | ||||
|     sparkpost: sparkPostComponent, | ||||
|     smtp: smtpComponent, | ||||
|   }, | ||||
|   props: { | ||||
|     view: { | ||||
|       type: Array, | ||||
|       require: true, | ||||
|       default: Array, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       currentView: 'mailgun', | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     let views = ['mailgun', 'sendgrid', 'sparkpost', 'smtp'] | ||||
|  | ||||
|     if (this.view && views.indexOf(this.view) > -1) { | ||||
|       this.currentView = this.view | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| @ -1,17 +0,0 @@ | ||||
| export default { | ||||
|   classes: | ||||
|     'px-2 py-1 text-xs bg-success text-green-800 uppercase font-normal text-center', | ||||
|   variants: { | ||||
|     success: | ||||
|       'px-2 py-1 text-xs bg-success text-green-800 uppercase font-normal text-center', | ||||
|  | ||||
|     info: | ||||
|       'px-2 py-1 text-xs bg-info text-blue-800 uppercase text-center font-normal', | ||||
|  | ||||
|     danger: | ||||
|       'px-2 py-1 text-xs bg-danger text-red-700 uppercase font-normal text-center', | ||||
|  | ||||
|     warning: | ||||
|       'px-2 py-1 text-xs bg-warning text-indigo-900 uppercase font-normal text-center', | ||||
|   }, | ||||
| } | ||||
| @ -1,22 +0,0 @@ | ||||
| export default { | ||||
|   variants: { | ||||
|     grayLight: { | ||||
|       button: | ||||
|         'inline-flex items-center justify-center text-gray-400 transition duration-150 ease-in-out border border-transparent focus:outline-none bg-gray-100 border border-gray-200 hover:bg-gray-200 hover:border-gray-400 hover:text-gray-600', | ||||
|     }, | ||||
|     gray: { | ||||
|       button: | ||||
|         'inline-flex items-center justify-center text-gray-400 transition duration-150 ease-in-out border border-transparent focus:outline-none bg-gray-300 border border-gray-200', | ||||
|     }, | ||||
|     white: { | ||||
|       button: | ||||
|         'inline-flex items-center justify-center text-black transition px-2 duration-150 ease-in-out border border-gray-300 border-solid focus:outline-none bg-white', | ||||
|     }, | ||||
|   }, | ||||
|   sizes: { | ||||
|     discount: { | ||||
|       button: 'py-2 px-2 text-sm leading-5 rounded', | ||||
|       loadingIcon: 'w-4 h-4 -ml-2', | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,18 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     container: 'bg-white rounded shadow', | ||||
|     header: 'px-5 py-4 text-black border-b border-solid border-gray-300', | ||||
|     body: 'px-4 py-5 sm:p-8', | ||||
|     footer: 'px-5 py-4 border-t border-solid sm:px-6 border-gray-300', | ||||
|   }, | ||||
|  | ||||
|   variants: { | ||||
|     customerCard: { | ||||
|       body: 'px-4 py-5 sm:p-8', | ||||
|     }, | ||||
|     settingCard: { | ||||
|       header: 'px-4 pt-5 sm:px-8 sm:pt-8', | ||||
|       footer: 'px-5 border-t-none py-4 sm:px-6', | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,25 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     container: 'relative sw-dropdown', | ||||
|     activator: 'cursor-pointer', | ||||
|     divider: 'border-t border-solid border-gray-200 my-2 mx-0 overflow-hidden', | ||||
|     itemContainer: | ||||
|       'z-10 p-2 max-h-60 text-base text-left list-none rounded border-0 shadow bg-white text-black overflow-auto sw-scroll', | ||||
|     item: | ||||
|       'flex p-2 text-sm font-light text-left text-black bg-transparent rounded cursor-pointer none hover:bg-gray-200 whitespace-nowrap', | ||||
|     itemIcon: 'w-5 h-5 mr-3 text-secondary', | ||||
|   }, | ||||
|   variants: { | ||||
|     searchDropdown: { | ||||
|       activator: 'cursor-pointer', | ||||
|       container: 'relative', | ||||
|       divider: | ||||
|         'border-t border-solid border-gray-200 my-2 mx-0 overflow-hidden', | ||||
|       item: | ||||
|         'flex p-0 text-sm font-light text-left text-black bg-transparent rounded cursor-pointer none hover:bg-gray-200 whitespace-nowrap', | ||||
|       itemContainer: | ||||
|         'z-10 p-2 text-base text-left list-none rounded border-0 shadow bg-white text-black', | ||||
|       itemIcon: 'w-5 h-5 mr-3 text-secondary', | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,7 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     container: 'relative p-8 mt-5 rounded bg-gray-200', | ||||
|     body: 'lg:flex block flex-col md:flex-row', | ||||
|   }, | ||||
|   variants: {}, | ||||
| } | ||||
| @ -1,31 +0,0 @@ | ||||
| export default { | ||||
|   variants: { | ||||
|     gray: { | ||||
|       container: | ||||
|         'relative flex items-center w-full border border-solid rounded-md bg-gray-100 hover:border-gray-400', | ||||
|       baseInput: | ||||
|         'not-italic font-normal leading-tight text-left outline-none rounded-md input-field box-border-2 placeholder-gray-400 text-black w-full h-8 px-0 py-0 text-xs bg-gray-100', | ||||
|       rightIconInput: | ||||
|         'not-italic font-normal leading-tight text-left outline-none min-w-0 rounded-md input-field box-border-2 placeholder-gray-400 text-black w-full pl-3 pr-1 py-2 text-sm bg-gray-100', | ||||
|       rightIconContainer: | ||||
|         'flex flex-col justify-center align-middle pr-2 text-gray-400 min-w-0', | ||||
|       containerFocusIn: 'border-primary-500 ', | ||||
|       containerFocusOut: 'border-gray-300 focus:border-transparent', | ||||
|     }, | ||||
|  | ||||
|     searchInput: { | ||||
|       container: | ||||
|         'relative flex items-center w-full border border-solid rounded-md bg-white', | ||||
|       baseInput: | ||||
|         'not-italic font-normal leading-tight text-left outline-none rounded-md input-field box-border-2 placeholder-gray-400 text-black w-full h-8 px-0 py-0 text-xs', | ||||
|       rightIconInput: | ||||
|         'not-italic font-normal leading-tight text-left outline-none rounded-md input-field box-border-2 placeholder-gray-400 text-black w-full pl-3 pr-1 py-2 text-sm', | ||||
|       leftIconInput: | ||||
|         'not-italic font-normal leading-tight text-left outline-none rounded-md input-field box-border-2 placeholder-gray-400 text-black w-full pl-1 pr-3 py-2 text-sm', | ||||
|       rightIconContainer: 'flex flex-col justify-center align-middle pr-2', | ||||
|       leftIconContainer: 'flex flex-col justify-center align-middle', | ||||
|       containerFocusIn: 'border-primary-500', | ||||
|       containerFocusOut: 'border-gray-300 focus:border-transparent', | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,33 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     container: 'pr-4 pl-0 list-none', | ||||
|     itemContainer: | ||||
|       'cursor-pointer pb-2 pr-0 text-sm font-medium leading-5 text-gray-500 flex items-center', | ||||
|     title: '', | ||||
|     iconContainer: 'mr-3', | ||||
|     listGroup: { | ||||
|       container: 'p-0 list-none', | ||||
|       titleContainer: | ||||
|         'flex items-center justify-between pb-2 pr-0 text-sm font-medium leading-5 text-gray-500 cursor-pointer', | ||||
|       title: 'text-sm', | ||||
|       icon: 'w-5 h-5 leading-4 transform rotate-90', | ||||
|       itemsContainer: 'pl-4 list-none', | ||||
|       itemContainer: | ||||
|         'cursor-pointer pb-2 pr-0 text-sm font-medium leading-5 text-gray-500 flex items-center', | ||||
|     }, | ||||
|     active: { | ||||
|       itemContainer: | ||||
|         'cursor-pointer pb-2 pr-0 text-sm font-medium flex items-center leading-5 text-primary-500', | ||||
|       listGroup: { | ||||
|         container: 'p-0 list-none', | ||||
|         titleContainer: | ||||
|           'flex items-center justify-between pb-2 pr-0 text-sm font-medium leading-5 text-primary-500 cursor-pointer', | ||||
|         title: 'text-sm', | ||||
|         icon: 'w-5 h-5 leading-4 ', | ||||
|         itemsContainer: 'pl-4 list-none', | ||||
|         itemContainer: | ||||
|           'cursor-pointer pb-2 pr-0 text-sm font-medium leading-5 text-gray-500 flex items-center', | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,20 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     overlayContainer: | ||||
|       'fixed z-50 inset-0 overflow-y-auto sw-scroll bg-opacity-25 bg-gray-700 flex justify-center min-h-screen items-center text-center sm:p-0', | ||||
|     centering: 'hidden sm:inline-block sm:align-middle sm:h-screen', | ||||
|     base: | ||||
|       'inline-block border-t-8 border-solid border-primary-500 w-full align-bottom bg-white rounded text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-xl sm:w-full m-6 sm:m-0', | ||||
|     header: | ||||
|       'py-4 px-6 h-16 text-black font-medium text-lg border-b border-solid border-gray-light flex justify-between items-center', | ||||
|     body: 'modal body text-sm', | ||||
|     footer: | ||||
|       'border-t border-solid border-gray-light py-4 px-6 flex justify-end', | ||||
|   }, | ||||
|   variants: { | ||||
|     lg: { | ||||
|       base: | ||||
|         'inline-block border-t-8 border-solid border-primary-500 w-full align-bottom bg-white rounded text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full m-6 sm:m-0', | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     container: 'relative w-full', | ||||
|     activator: 'relative w-full cursor-pointer', | ||||
|     base: 'flex flex-col absolute w-full top-0 bg-white rounded z-20 shadow-xl', | ||||
|     above: 'bottom-full top-unset', | ||||
|   }, | ||||
| } | ||||
| @ -1,34 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     container: 'radio', | ||||
|     label: 'cursor-pointer', | ||||
|     input: | ||||
|       'cursor-pointer flex-shrink-0 inline-block text-primary-500 align-middle bg-white border border-gray-300 rounded-full outline-none appearance-none select-none transition duration-200 ease-in-out', | ||||
|   }, | ||||
|   variants: { | ||||
|     success: { | ||||
|       input: | ||||
|         'cursor-pointer flex-shrink-0 inline-block text-success align-middle bg-white border border-gray-300 rounded-full outline-none appearance-none select-none transition duration-200 ease-in-out', | ||||
|       label: 'cursor-pointer', | ||||
|     }, | ||||
|     danger: { | ||||
|       input: | ||||
|         'cursor-pointer flex-shrink-0 inline-block text-danger align-middle bg-white border border-gray-300 rounded-full outline-none appearance-none select-none transition duration-200 ease-in-out', | ||||
|       label: 'cursor-pointer', | ||||
|     }, | ||||
|   }, | ||||
|   sizes: { | ||||
|     sm: { | ||||
|       input: 'w-4 h-4', | ||||
|       label: 'ml-2', | ||||
|     }, | ||||
|     default: { | ||||
|       input: 'w-6 h-6', | ||||
|       label: 'ml-3 text-lg', | ||||
|     }, | ||||
|     lg: { | ||||
|       input: 'w-8 h-8', | ||||
|       label: 'ml-4 text-xl', | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     container: 'switch-container focus:outline-none', | ||||
|     switch: 'switch', | ||||
|     label: | ||||
|       'relative block h-4 bg-white border border-solid cursor-pointer border-gray switch-label', | ||||
|   }, | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| export default { | ||||
|   variants: { | ||||
|     gray: { | ||||
|       tdStyles: | ||||
|         'text-left text-base h-20 px-3 py-6 align-middle bg-gray-100 first:rounded-bl-md first:rounded-tl-md last:rounded-br-md last:rounded-tr-md', | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| @ -1,6 +0,0 @@ | ||||
| export default { | ||||
|   variants: { | ||||
|     invDesc: | ||||
|       'text-left border border-solid box-border rounded not-italic leading-snug placeholder-gray-400 bg-white border-gray-300 focus:border-primary-400 outline-none w-full py-2 px-3 font-normal text-xs text-black', | ||||
|   }, | ||||
| } | ||||
| @ -1,25 +0,0 @@ | ||||
| export default { | ||||
|   classes: { | ||||
|     wizardContainer: 'wizard w-full', | ||||
|     wizardStepsContainer: 'relative flex items-center justify-center', | ||||
|     navigationContainer: | ||||
|       'flex flex-col items-center justify-between h-32 step-indicator', | ||||
|     progressesContainer: | ||||
|       'box-border relative flex justify-around mt-16 border-4 border-gray-200 border-solid rounded-md indicator-line', | ||||
|     progressesSubContainer: 'absolute flex justify-between center', | ||||
|     progress: 'rounded-full steps cursor-pointer', | ||||
|     currentStep: 'bg-white border-primary-500', | ||||
|     previousStep: | ||||
|       'bg-primary-500 border-primary-500 flex justify-center items-center', | ||||
|     nextStep: 'border-gray-200 bg-white', | ||||
|     icon: | ||||
|       'flex items-center justify-center w-full h-full text-sm font-black text-center text-white', | ||||
|     stepContainer: | ||||
|       'w-full mb-8 bg-white border border-gray-200 border-solid rounded p-8 lg:w-9/12 md:w-full relative', | ||||
|     stepHeadingContainer: 'heading-section', | ||||
|     stepTitle: 'text-2xl not-italic font-semibold leading-7 text-black', | ||||
|     stepDescription: | ||||
|       'w-full mt-2.5 mb-8 text-sm not-italic text-gray-600 lg:w-7/12 md:w-7/12 sm:w-7/12', | ||||
|   }, | ||||
|   variants: {}, | ||||
| } | ||||
| @ -1,29 +0,0 @@ | ||||
| import SwModal from './SwModal' | ||||
| import SwInput from './SwInput' | ||||
| import SwTable from './SwTable' | ||||
| import SwButton from './SwButton' | ||||
| import SwDropdown from './SwDropdown' | ||||
| import SwCard from './SwCard' | ||||
| import SwList from './SwList' | ||||
| import SwWizard from './SwWizard' | ||||
| import SwTextarea from './SwTextarea' | ||||
| import SwPopup from './SwPopup' | ||||
| import SwBadge from './SwBadge' | ||||
| import SwFilterWrapper from './SwFilterWrapper' | ||||
| import SwSwitch from './SwSwitch' | ||||
|  | ||||
| export default { | ||||
|   SwModal, | ||||
|   SwInput, | ||||
|   SwTable, | ||||
|   SwButton, | ||||
|   SwCard, | ||||
|   SwList, | ||||
|   SwWizard, | ||||
|   SwTextarea, | ||||
|   SwPopup, | ||||
|   SwDropdown, | ||||
|   SwBadge, | ||||
|   SwFilterWrapper, | ||||
|   SwSwitch, | ||||
| } | ||||
| @ -1,34 +0,0 @@ | ||||
| import Vue from 'vue' | ||||
|  | ||||
| Vue.directive('click-outside', { | ||||
|   bind: function (el, binding, vnode) { | ||||
|     el.event = function (event) { | ||||
|       // here I check that click was outside the el and his childrens | ||||
|       if (!(el === event.target || el.contains(event.target))) { | ||||
|         // and if it did, call method provided in attribute value | ||||
|         vnode.context[binding.expression](event) | ||||
|       } | ||||
|     } | ||||
|     document.body.addEventListener('click', el.event) | ||||
|   }, | ||||
|   unbind: function (el) { | ||||
|     document.body.removeEventListener('click', el.event) | ||||
|   }, | ||||
| }) | ||||
|  | ||||
| Vue.directive('autoresize', { | ||||
|   inserted: function (el) { | ||||
|     el.style.height = el.scrollHeight + 'px' | ||||
|     if (el.style.overflow && el.style.overflow.y) { | ||||
|       el.style.overflow.y = 'hidden' | ||||
|     } | ||||
|     el.style.resize = 'none' | ||||
|     function OnInput() { | ||||
|       this.style.height = 'auto' | ||||
|       this.style.height = this.scrollHeight + 'px' | ||||
|       this.scrollTop = this.scrollHeight | ||||
|       window.scrollTo(window.scrollLeft, this.scrollTop + this.scrollHeight) | ||||
|     } | ||||
|     el.addEventListener('input', OnInput, false) | ||||
|   }, | ||||
| }) | ||||
| @ -1,133 +0,0 @@ | ||||
| import InputField from '../components/custom-fields/InputField.vue' | ||||
| import SwitchField from '../components/custom-fields/SwitchField' | ||||
| import TimeField from '../components/custom-fields/TimeField' | ||||
| import DropdownField from '../components/custom-fields/DropdownField' | ||||
| import DateTimeField from '../components/custom-fields/DateTimeField' | ||||
| import DateField from '../components/custom-fields/DateField' | ||||
| import TextAreaField from '../components/custom-fields/TextAreaField' | ||||
| import UrlField from '../components/custom-fields/UrlField.vue' | ||||
| import PhoneField from '../components/custom-fields/PhoneField.vue' | ||||
| import NumberField from '../components/custom-fields/NumberField.vue' | ||||
|  | ||||
| import { mapActions } from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     InputField, | ||||
|     SwitchField, | ||||
|     TimeField, | ||||
|     DropdownField, | ||||
|     DateTimeField, | ||||
|     DateField, | ||||
|     TextAreaField, | ||||
|     UrlField, | ||||
|     PhoneField, | ||||
|     NumberField, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       formData: { | ||||
|         customFields: [], | ||||
|       }, | ||||
|       invalidFields: [], | ||||
|       customFields: [], | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('customFields', ['fetchCustomFields']), | ||||
|     async setInitialCustomFields(type = null) { | ||||
|       let response = await this.fetchCustomFields({ type: type, limit: 'all' }) | ||||
|       this.customFields = response.data.customFields.data.map((_f) => { | ||||
|         return { ..._f, cfid: _f.id } | ||||
|       }) | ||||
|       this.setRemainingCustomFieldsValue() | ||||
|     }, | ||||
|     setEditCustomFields(fields, customFields) { | ||||
|       this.customFields = fields.map((field) => { | ||||
|         field.label = field.custom_field.label | ||||
|         field.cfid = field.custom_field.id | ||||
|         field.options = field.custom_field.options | ||||
|         field.placeholder = field.custom_field.placeholder | ||||
|         field.is_required = field.custom_field.is_required | ||||
|         field.order = field.custom_field.order | ||||
|         return field | ||||
|       }) | ||||
|  | ||||
|       let currentCustomFieldIds = customFields.map((field) => field.id) | ||||
|       let editCustomFieldIds = fields.map((field) => field.custom_field_id) | ||||
|       let remainingCustomFieldIds = this.$utils.arrayDifference( | ||||
|         currentCustomFieldIds, | ||||
|         editCustomFieldIds | ||||
|       ) | ||||
|       remainingCustomFieldIds.forEach((id) => { | ||||
|         let data = customFields.find((field) => field.id == id) | ||||
|         this.customFields.push({ ...data, cfid: data.id }) | ||||
|       }) | ||||
|  | ||||
|       this.setRemainingCustomFieldsValue(true) | ||||
|     }, | ||||
|     setCustomFieldValue(data) { | ||||
|       let position = this.formData.customFields.findIndex( | ||||
|         (field) => field.id == data.field.cfid | ||||
|       ) | ||||
|  | ||||
|       // check field has value so removed in invalidFields array | ||||
|       let indexInInvalidField = this.invalidFields.findIndex( | ||||
|         (field) => field.id == data.field.cfid | ||||
|       ) | ||||
|       if (indexInInvalidField >= 0) { | ||||
|         if (data.value) { | ||||
|           this.invalidFields.splice(indexInInvalidField, 1) | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // set data in formData.customFields | ||||
|       if (position >= 0) { | ||||
|         this.formData.customFields[position].value = data.value | ||||
|         return true | ||||
|       } | ||||
|       this.formData.customFields.push({ | ||||
|         id: data.field.cfid, | ||||
|         value: data.value, | ||||
|       }) | ||||
|       return true | ||||
|     }, | ||||
|     setRemainingCustomFieldsValue() { | ||||
|       let existingCustomFieldIds = this.formData.customFields.map((_f) => _f.id) | ||||
|       let customFieldIds = this.customFields.map((_f) => _f.cfid) | ||||
|       let remainingCustomFieldIds = this.$utils.arrayDifference( | ||||
|         customFieldIds, | ||||
|         existingCustomFieldIds | ||||
|       ) | ||||
|       remainingCustomFieldIds.forEach((id) => { | ||||
|         let field = this.customFields.find((field) => field.cfid == id) | ||||
|         this.formData.customFields.push({ | ||||
|           id: field.cfid, | ||||
|           isRequired: field.is_required, | ||||
|           value: field.defaultAnswer, | ||||
|         }) | ||||
|       }) | ||||
|       this.customFields = _.sortBy(this.customFields, (_cf) => _cf.order) | ||||
|     }, | ||||
|     getInvalidFields() { | ||||
|       return this.formData.customFields.filter( | ||||
|         (field) => | ||||
|           field.isRequired && | ||||
|           (field.value == null || field.value == undefined || field.value == '') | ||||
|       ) | ||||
|     }, | ||||
|     touchCustomField() { | ||||
|       return new Promise((resolve, reject) => { | ||||
|         try { | ||||
|           if (this.getInvalidFields() <= 0) { | ||||
|             resolve({ error: false }) | ||||
|           } | ||||
|           this.invalidFields = this.getInvalidFields() | ||||
|           resolve({ error: true }) | ||||
|         } catch (error) { | ||||
|           reject(error) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,417 +0,0 @@ | ||||
| import Vue from 'vue' | ||||
| import VueRouter from 'vue-router' | ||||
|  | ||||
| /* | ||||
|  |-------------------------------------------------------------------------- | ||||
|  | Views | ||||
|  |--------------------------------------------------------------------------| | ||||
|  */ | ||||
|  | ||||
| // Layouts | ||||
| import LayoutBasic from './views/layouts/LayoutBasic.vue' | ||||
| import LayoutLogin from './views/layouts/LayoutLogin.vue' | ||||
| import LayoutWizard from './views/layouts/LayoutWizard.vue' | ||||
|  | ||||
| // Auth | ||||
| import Login from './views/auth/Login.vue' | ||||
| import ForgotPassword from './views/auth/ForgotPassword.vue' | ||||
| import ResetPassword from './views/auth/ResetPassword.vue' | ||||
| import Register from './views/auth/Register.vue' | ||||
|  | ||||
| import NotFoundPage from './views/errors/404.vue' | ||||
|  | ||||
| // Dashboard | ||||
| import Dashboard from './views/dashboard/Dashboard.vue' | ||||
|  | ||||
| // Customers | ||||
| import CustomerIndex from './views/customers/Index.vue' | ||||
| import CustomerCreate from './views/customers/Create.vue' | ||||
| import CustomerView from './views/customers/View.vue' | ||||
|  | ||||
| // Items | ||||
| import ItemsIndex from './views/items/Index.vue' | ||||
| import ItemCreate from './views/items/Create.vue' | ||||
|  | ||||
| // Invoices | ||||
| import InvoiceIndex from './views/invoices/Index.vue' | ||||
| import InvoiceCreate from './views/invoices/Create.vue' | ||||
| import InvoiceView from './views/invoices/View.vue' | ||||
|  | ||||
| // Payments | ||||
| import PaymentsIndex from './views/payments/Index.vue' | ||||
| import PaymentCreate from './views/payments/Create.vue' | ||||
| import PaymentView from './views/payments/View.vue' | ||||
|  | ||||
| // Estimates | ||||
| import EstimateIndex from './views/estimates/Index.vue' | ||||
| import EstimateCreate from './views/estimates/Create.vue' | ||||
| import EstimateView from './views/estimates/View.vue' | ||||
|  | ||||
| // Expenses | ||||
| import ExpensesIndex from './views/expenses/Index' | ||||
| import ExpenseCreate from './views/expenses/Create.vue' | ||||
|  | ||||
| //User | ||||
| import UserIndex from './views/users/Index.vue' | ||||
| import UserCreate from './views/users/Create.vue' | ||||
|  | ||||
| // Report | ||||
| import SalesReports from './views/reports/SalesReports' | ||||
| import ExpensesReport from './views/reports/ExpensesReport' | ||||
| import ProfitLossReport from './views/reports/ProfitLossReport' | ||||
| import TaxReport from './views/reports/TaxReport.vue' | ||||
| import ReportLayout from './views/reports/layout/Index.vue' | ||||
|  | ||||
| // Settings | ||||
| import SettingsLayout from './views/settings/SettingsIndex.vue' | ||||
| import CompanyInfo from './views/settings/CompanyInfoSetting.vue' | ||||
| import Customization from './views/settings/CustomizationSetting.vue' | ||||
| import Notifications from './views/settings/NotificationsSetting.vue' | ||||
| import Preferences from './views/settings/PreferencesSetting.vue' | ||||
| import UserProfile from './views/settings/UserProfileSetting.vue' | ||||
| import TaxTypes from './views/settings/TaxTypesSetting.vue' | ||||
| import NotesSetting from './views/settings/NotesSetting.vue' | ||||
| import ExpenseCategory from './views/settings/ExpenseCategorySetting.vue' | ||||
| import MailConfig from './views/settings/MailConfigSetting.vue' | ||||
| import UpdateApp from './views/settings/UpdateAppSetting.vue' | ||||
| import Backup from './views/settings/BackupSetting.vue' | ||||
| import FileDisk from './views/settings/FileDiskSetting.vue' | ||||
| import CustomFieldsIndex from './views/settings/CustomFieldsSetting.vue' | ||||
| import PaymentMode from './views/settings/PaymentsModeSetting.vue' | ||||
| import Wizard from './views/wizard/Wizard.vue' | ||||
|  | ||||
| Vue.use(VueRouter) | ||||
|  | ||||
| const routes = [ | ||||
|   /* | ||||
|    |-------------------------------------------------------------------------- | ||||
|    | Auth & Registration | ||||
|    |--------------------------------------------------------------------------| | ||||
|    */ | ||||
|  | ||||
|   { | ||||
|     path: '/', | ||||
|     component: LayoutLogin, | ||||
|     meta: { redirectIfAuthenticated: true }, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/', | ||||
|         component: Login, | ||||
|       }, | ||||
|       { | ||||
|         path: 'login', | ||||
|         component: Login, | ||||
|         name: 'login', | ||||
|       }, | ||||
|       { | ||||
|         path: '/forgot-password', | ||||
|         component: ForgotPassword, | ||||
|         name: 'forgot-password', | ||||
|       }, | ||||
|       { | ||||
|         path: '/reset-password/:token', | ||||
|         component: ResetPassword, | ||||
|         name: 'reset-password', | ||||
|       }, | ||||
|       { | ||||
|         path: 'register', | ||||
|         component: Register, | ||||
|         name: 'register', | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|  | ||||
|   /* | ||||
|    |-------------------------------------------------------------------------- | ||||
|    | Onboarding | ||||
|    |--------------------------------------------------------------------------| | ||||
|    */ | ||||
|   { | ||||
|     path: '/on-boarding', | ||||
|     component: LayoutWizard, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/', | ||||
|         component: Wizard, | ||||
|         name: 'wizard', | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|  | ||||
|   /* | ||||
|    |-------------------------------------------------------------------------- | ||||
|    | Admin | ||||
|    |--------------------------------------------------------------------------| | ||||
|    */ | ||||
|   { | ||||
|     path: '/admin', | ||||
|     component: LayoutBasic, | ||||
|     meta: { requiresAuth: true }, | ||||
|     children: [ | ||||
|       // Dashboard | ||||
|       { | ||||
|         path: '/', | ||||
|         component: Dashboard, | ||||
|         name: 'dashboard', | ||||
|       }, | ||||
|       { | ||||
|         path: 'dashboard', | ||||
|         component: Dashboard, | ||||
|       }, | ||||
|  | ||||
|       // Customers | ||||
|       { | ||||
|         path: 'customers', | ||||
|         component: CustomerIndex, | ||||
|       }, | ||||
|       { | ||||
|         path: 'customers/create', | ||||
|         name: 'customers.create', | ||||
|         component: CustomerCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'customers/:id/edit', | ||||
|         name: 'customers.edit', | ||||
|         component: CustomerCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'customers/:id/view', | ||||
|         name: 'customers.view', | ||||
|         component: CustomerView, | ||||
|       }, | ||||
|  | ||||
|       // Items | ||||
|       { | ||||
|         path: 'items', | ||||
|         component: ItemsIndex, | ||||
|       }, | ||||
|       { | ||||
|         path: 'items/create', | ||||
|         name: 'items.create', | ||||
|         component: ItemCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'items/:id/edit', | ||||
|         name: 'items.edit', | ||||
|         component: ItemCreate, | ||||
|       }, | ||||
|  | ||||
|       // Estimates | ||||
|       { | ||||
|         path: 'estimates', | ||||
|         name: 'estimates.index', | ||||
|         component: EstimateIndex, | ||||
|       }, | ||||
|       { | ||||
|         path: 'estimates/create', | ||||
|         name: 'estimates.create', | ||||
|         component: EstimateCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'estimates/:id/view', | ||||
|         name: 'estimates.view', | ||||
|         component: EstimateView, | ||||
|       }, | ||||
|       { | ||||
|         path: 'estimates/:id/edit', | ||||
|         name: 'estimates.edit', | ||||
|         component: EstimateCreate, | ||||
|       }, | ||||
|  | ||||
|       // Invoices | ||||
|       { | ||||
|         path: 'invoices', | ||||
|         name: 'invoices.index', | ||||
|         component: InvoiceIndex, | ||||
|       }, | ||||
|       { | ||||
|         path: 'invoices/create', | ||||
|         name: 'invoices.create', | ||||
|         component: InvoiceCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'invoices/:id/view', | ||||
|         name: 'invoices.view', | ||||
|         component: InvoiceView, | ||||
|       }, | ||||
|       { | ||||
|         path: 'invoices/:id/edit', | ||||
|         name: 'invoices.edit', | ||||
|         component: InvoiceCreate, | ||||
|       }, | ||||
|  | ||||
|       // Payments | ||||
|       { | ||||
|         path: 'payments', | ||||
|         name: 'payments.index', | ||||
|         component: PaymentsIndex, | ||||
|       }, | ||||
|       { | ||||
|         path: 'payments/create', | ||||
|         name: 'payments.create', | ||||
|         component: PaymentCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'payments/:id/create', | ||||
|         name: 'invoice.payments.create', | ||||
|         component: PaymentCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'payments/:id/edit', | ||||
|         name: 'payments.edit', | ||||
|         component: PaymentCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'payments/:id/view', | ||||
|         name: 'payments.view', | ||||
|         component: PaymentView, | ||||
|       }, | ||||
|  | ||||
|       // Expenses | ||||
|       { | ||||
|         path: 'expenses', | ||||
|         component: ExpensesIndex, | ||||
|       }, | ||||
|       { | ||||
|         path: 'expenses/create', | ||||
|         name: 'expenses.create', | ||||
|         component: ExpenseCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'expenses/:id/edit', | ||||
|         name: 'expenses.edit', | ||||
|         component: ExpenseCreate, | ||||
|       }, | ||||
|  | ||||
|       // User | ||||
|       { | ||||
|         path: 'users', | ||||
|         component: UserIndex, | ||||
|       }, | ||||
|       { | ||||
|         path: 'users/create', | ||||
|         name: 'users.create', | ||||
|         component: UserCreate, | ||||
|       }, | ||||
|       { | ||||
|         path: 'users/:id/edit', | ||||
|         name: 'users.edit', | ||||
|         component: UserCreate, | ||||
|       }, | ||||
|  | ||||
|       // Reports | ||||
|       { | ||||
|         path: 'reports', | ||||
|         component: ReportLayout, | ||||
|         children: [ | ||||
|           { | ||||
|             path: 'sales', | ||||
|             component: SalesReports, | ||||
|           }, | ||||
|           { | ||||
|             path: 'expenses', | ||||
|             component: ExpensesReport, | ||||
|           }, | ||||
|           { | ||||
|             path: 'profit-loss', | ||||
|             component: ProfitLossReport, | ||||
|           }, | ||||
|           { | ||||
|             path: 'taxes', | ||||
|             component: TaxReport, | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|  | ||||
|       // Settings | ||||
|       { | ||||
|         path: 'settings', | ||||
|         component: SettingsLayout, | ||||
|         children: [ | ||||
|           { | ||||
|             path: 'company-info', | ||||
|             name: 'company.info', | ||||
|             component: CompanyInfo, | ||||
|           }, | ||||
|           { | ||||
|             path: 'customization', | ||||
|             name: 'customization', | ||||
|             component: Customization, | ||||
|           }, | ||||
|           { | ||||
|             path: 'payment-mode', | ||||
|             name: 'payment.mode', | ||||
|             component: PaymentMode, | ||||
|           }, | ||||
|  | ||||
|           { | ||||
|             path: 'custom-fields', | ||||
|             name: 'custom.fields', | ||||
|             component: CustomFieldsIndex, | ||||
|           }, | ||||
|           { | ||||
|             path: 'user-profile', | ||||
|             name: 'user.profile', | ||||
|             component: UserProfile, | ||||
|           }, | ||||
|           { | ||||
|             path: 'preferences', | ||||
|             name: 'preferences', | ||||
|             component: Preferences, | ||||
|           }, | ||||
|           { | ||||
|             path: 'tax-types', | ||||
|             name: 'tax.types', | ||||
|             component: TaxTypes, | ||||
|           }, | ||||
|           { | ||||
|             path: 'notes', | ||||
|             name: 'notes', | ||||
|             component: NotesSetting, | ||||
|           }, | ||||
|           { | ||||
|             path: 'expense-category', | ||||
|             name: 'expense.category', | ||||
|             component: ExpenseCategory, | ||||
|           }, | ||||
|           { | ||||
|             path: 'mail-configuration', | ||||
|             name: 'mailconfig', | ||||
|             component: MailConfig, | ||||
|           }, | ||||
|           { | ||||
|             path: 'notifications', | ||||
|             name: 'notifications', | ||||
|             component: Notifications, | ||||
|           }, | ||||
|           { | ||||
|             path: 'update-app', | ||||
|             name: 'updateapp', | ||||
|             component: UpdateApp, | ||||
|           }, | ||||
|           { | ||||
|             path: 'backup', | ||||
|             name: 'backup', | ||||
|             component: Backup, | ||||
|           }, | ||||
|           { | ||||
|             path: 'file-disk', | ||||
|             name: 'file-disk', | ||||
|             component: FileDisk, | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|  | ||||
|   //  DEFAULT ROUTE | ||||
|   { path: '*', component: NotFoundPage }, | ||||
| ] | ||||
|  | ||||
| const router = new VueRouter({ | ||||
|   routes, | ||||
|   mode: 'history', | ||||
|   linkActiveClass: 'active', | ||||
| }) | ||||
|  | ||||
| export default router | ||||
| @ -1,146 +0,0 @@ | ||||
| import * as types from './mutation-types' | ||||
| import * as userTypes from './modules/user/mutation-types' | ||||
| import * as companyTypes from './modules/company/mutation-types' | ||||
|  | ||||
| export default { | ||||
|   bootstrap({ commit, dispatch, state }) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       window.axios | ||||
|         .get('/api/v1/bootstrap') | ||||
|         .then((response) => { | ||||
|           commit('user/' + userTypes.BOOTSTRAP_CURRENT_USER, response.data.user) | ||||
|  | ||||
|           commit( | ||||
|             'company/' + companyTypes.SET_SELECTED_COMPANY, | ||||
|             response.data.company | ||||
|           ) | ||||
|  | ||||
|           commit('company/' + companyTypes.SET_DEFAULT_CURRENCY, response.data) | ||||
|  | ||||
|           commit( | ||||
|             'user/' + userTypes.SET_DEFAULT_LANGUAGE, | ||||
|             response.data.default_language | ||||
|           ) | ||||
|  | ||||
|           commit( | ||||
|             'company/' + companyTypes.SET_MOMENT_DATE_FORMAT, | ||||
|             response.data.moment_date_format | ||||
|           ) | ||||
|  | ||||
|           commit( | ||||
|             'company/' + companyTypes.SET_CARBON_DATE_FORMAT, | ||||
|             response.data.carbon_date_format | ||||
|           ) | ||||
|  | ||||
|           commit( | ||||
|             'company/' + companyTypes.SET_DEFAULT_FISCAL_YEAR, | ||||
|             response.data.fiscal_year | ||||
|           ) | ||||
|  | ||||
|           commit( | ||||
|             'company/' + companyTypes.SET_DEFAULT_TIME_ZONE, | ||||
|             response.data.time_zone | ||||
|           ) | ||||
|  | ||||
|           commit(types.SET_CURRENCIES, response.data.currencies) | ||||
|  | ||||
|           commit(types.SET_COUNTRIES, response.data.countries) | ||||
|  | ||||
|           commit(types.UPDATE_APP_LOADING_STATUS, true) | ||||
|  | ||||
|           resolve(response) | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           reject(err) | ||||
|         }) | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   fetchLanguages({ commit, dispatch, state }) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       window.axios | ||||
|         .get('/api/v1/languages') | ||||
|         .then((response) => { | ||||
|           commit(types.SET_LANGUAGES, response.data.languages) | ||||
|           resolve(response) | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           reject(err) | ||||
|         }) | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   fetchCurrencies({ commit, dispatch, state }) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       window.axios | ||||
|         .get('/api/v1/currencies') | ||||
|         .then((response) => { | ||||
|           commit(types.SET_CURRENCIES, response.data.currencies) | ||||
|           resolve(response) | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           reject(err) | ||||
|         }) | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   fetchDateFormats({ commit, dispatch, state }) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       window.axios | ||||
|         .get('/api/v1/date/formats') | ||||
|         .then((response) => { | ||||
|           commit(types.SET_DATE_FORMATS, response.data.date_formats) | ||||
|           resolve(response) | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           reject(err) | ||||
|         }) | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   fetchFiscalYears({ commit, dispatch, state }) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       window.axios | ||||
|         .get('/api/v1/fiscal/years') | ||||
|         .then((response) => { | ||||
|           commit(types.SET_FISCAL_YEARS, response.data.fiscal_years) | ||||
|           resolve(response) | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           reject(err) | ||||
|         }) | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   fetchTimeZones({ commit, dispatch, state }) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       window.axios | ||||
|         .get('/api/v1/timezones') | ||||
|         .then((response) => { | ||||
|           commit(types.SET_TIMEZONES, response.data.time_zones) | ||||
|           resolve(response) | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           reject(err) | ||||
|         }) | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   fetchCountries({ commit, dispatch, state }) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       window.axios | ||||
|         .get('/api/v1/countries') | ||||
|         .then((response) => { | ||||
|           commit(types.SET_COUNTRIES, response.data.countries) | ||||
|           resolve(response) | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           reject(err) | ||||
|         }) | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   toggleSidebar({ commit }) { | ||||
|     commit(types.TOGGLE_SIDEBAR) | ||||
|   }, | ||||
| } | ||||
| @ -1,15 +0,0 @@ | ||||
| export const isAppLoaded = (state) => state.isAppLoaded | ||||
|  | ||||
| export const languages = (state) => state.languages | ||||
|  | ||||
| export const currencies = (state) => state.currencies | ||||
|  | ||||
| export const timeZones = (state) => state.timeZones | ||||
|  | ||||
| export const dateFormats = (state) => state.dateFormats | ||||
|  | ||||
| export const fiscalYears = (state) => state.fiscalYears | ||||
|  | ||||
| export const countries = (state) => state.countries | ||||
|  | ||||
| export const isSidebarOpen = (state) => state.isSidebarOpen | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user