mirror of
https://github.com/crater-invoice/crater.git
synced 2025-12-17 02:42:54 -05:00
build version 400
This commit is contained in:
179
resources/assets/js/components/base/modal/BackupModal.vue
Normal file
179
resources/assets/js/components/base/modal/BackupModal.vue
Normal file
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<div class="relative customer-modal">
|
||||
<base-loader
|
||||
v-if="isRequestOngoing"
|
||||
class="h-130"
|
||||
:show-bg-overlay="true"
|
||||
/>
|
||||
<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"
|
||||
:maxHeight="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"
|
||||
track-by="id"
|
||||
:preselect-first="true"
|
||||
:custom-label="getCustomLabel"
|
||||
:maxHeight="100"
|
||||
:loading="isLoading"
|
||||
/>
|
||||
</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"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
:disabled="isCreateLoading"
|
||||
>
|
||||
<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']),
|
||||
|
||||
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
|
||||
window.toastr['success'](this.$t('settings.backup.created_message'))
|
||||
this.refreshData ? this.refreshData() : ''
|
||||
this.cancelBackup()
|
||||
} catch (e) {
|
||||
this.isCreateLoading = false
|
||||
window.toastr['error'](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,19 +1,22 @@
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div v-if="modalActive" :class="'size-' + modalSize" class="base-modal">
|
||||
<div class="modal-body">
|
||||
<div class="close-icon" @click="closeModal">
|
||||
<font-awesome-icon icon="times" />
|
||||
<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>
|
||||
<div class="modal-header p-3">
|
||||
<h5 class="modal-heading">{{ modalTitle }}</h5>
|
||||
</div>
|
||||
<component :is="component" />
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<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'
|
||||
@@ -21,9 +24,17 @@ 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: {
|
||||
@@ -33,14 +44,22 @@ export default {
|
||||
InvoiceTemplate,
|
||||
CustomerModal,
|
||||
CategoryModal,
|
||||
BackupModal,
|
||||
PaymentMode,
|
||||
ItemUnit,
|
||||
MailTestModal
|
||||
MailTestModal,
|
||||
SendInvoiceModal,
|
||||
SendEstimateModal,
|
||||
SendPaymentModal,
|
||||
XIcon,
|
||||
FileDiskModal,
|
||||
SetDefaultDiskModal,
|
||||
CustomFieldModal,
|
||||
NoteSelectModal,
|
||||
},
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
component: '',
|
||||
hasFocus: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -49,31 +68,28 @@ export default {
|
||||
'modalTitle',
|
||||
'componentName',
|
||||
'modalSize',
|
||||
'modalData'
|
||||
])
|
||||
'modalData',
|
||||
'variant',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
componentName (component) {
|
||||
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'
|
||||
])
|
||||
}
|
||||
...mapActions('modal', ['openModal', 'closeModal']),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .5s;
|
||||
}
|
||||
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,98 +1,115 @@
|
||||
<template>
|
||||
<div class="category-modal">
|
||||
<form action="" @submit.prevent="submitCategoryData">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('expenses.category') }}<span class="required text-danger">*</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="name"
|
||||
:invalid="$v.formData.name.$error"
|
||||
v-model="formData.name"
|
||||
type="text"
|
||||
@input="$v.formData.name.$touch()"
|
||||
/>
|
||||
<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>
|
||||
|
||||
<div v-if="$v.formData.name.$error">
|
||||
<span v-if="!$v.formData.name.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.name.minLength" class="text-danger"> {{ $tc('validation.name_min_length', $v.formData.name.$params.minLength.min, { count: $v.formData.name.$params.minLength.min }) }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('expenses.description') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-text-area
|
||||
v-model="formData.description"
|
||||
rows="4"
|
||||
cols="50"
|
||||
@input="$v.formData.description.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.description.$error">
|
||||
<span v-if="!$v.formData.name.maxLength" class="text-danger"> {{ $tc('validation.description_maxlength') }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
@click="closeCategoryModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<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 variant="primary" type="submit" :loading="isLoading">
|
||||
<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'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength, maxLength } = require('vuelidate/lib/validators')
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
formData: {
|
||||
id: null,
|
||||
name: null,
|
||||
description: null
|
||||
}
|
||||
description: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
'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)
|
||||
minLength: minLength(3),
|
||||
},
|
||||
description: {
|
||||
maxLength: maxLength(255)
|
||||
}
|
||||
}
|
||||
maxLength: maxLength(255),
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'modalDataID' (val) {
|
||||
modalDataID(val) {
|
||||
if (val) {
|
||||
this.isEdit = true
|
||||
this.setData()
|
||||
@@ -100,40 +117,33 @@ export default {
|
||||
this.isEdit = false
|
||||
}
|
||||
},
|
||||
'modalActive' (val) {
|
||||
modalActive(val) {
|
||||
if (!this.modalActive) {
|
||||
this.resetFormData()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
|
||||
mounted() {
|
||||
this.$refs.name.focus = true
|
||||
if (this.modalDataID) {
|
||||
this.isEdit = true
|
||||
this.setData()
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
...mapActions('category', [
|
||||
'addCategory',
|
||||
'updateCategory'
|
||||
]),
|
||||
resetFormData () {
|
||||
...mapActions('modal', ['closeModal']),
|
||||
...mapActions('category', ['addCategory', 'updateCategory']),
|
||||
resetFormData() {
|
||||
this.formData = {
|
||||
id: null,
|
||||
name: null,
|
||||
description: null
|
||||
description: null,
|
||||
}
|
||||
this.$v.formData.$reset()
|
||||
},
|
||||
async submitCategoryData () {
|
||||
async submitCategoryData() {
|
||||
this.$v.formData.$touch()
|
||||
|
||||
if (this.$v.$invalid) {
|
||||
@@ -149,28 +159,33 @@ export default {
|
||||
|
||||
if (response.data) {
|
||||
if (!this.isEdit) {
|
||||
window.toastr['success'](this.$t('settings.expense_category.created_message'))
|
||||
window.toastr['success'](
|
||||
this.$t('settings.expense_category.created_message')
|
||||
)
|
||||
} else {
|
||||
window.toastr['success'](this.$t('settings.expense_category.updated_message'))
|
||||
window.toastr['success'](
|
||||
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
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
},
|
||||
async setData () {
|
||||
async setData() {
|
||||
this.formData = {
|
||||
id: this.modalData.id,
|
||||
name: this.modalData.name,
|
||||
description: this.modalData.description
|
||||
description: this.modalData.description,
|
||||
}
|
||||
},
|
||||
closeCategoryModal () {
|
||||
closeCategoryModal() {
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
500
resources/assets/js/components/base/modal/CustomField/Index.vue
Normal file
500
resources/assets/js/components/base/modal/CustomField/Index.vue
Normal file
@@ -0,0 +1,500 @@
|
||||
<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
|
||||
:label="$t('settings.custom_fields.options')"
|
||||
class="mt-5"
|
||||
v-if="isDropdownSelected"
|
||||
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
|
||||
@click="removeOption(index)"
|
||||
class="ml-1 cursor-pointer icon text-danger"
|
||||
/>
|
||||
</div>
|
||||
</sw-input-group>
|
||||
<sw-input-group
|
||||
:label="$t('settings.custom_fields.default_value')"
|
||||
horizontal
|
||||
class="relative mt-5"
|
||||
v-if="formData.type"
|
||||
>
|
||||
<component
|
||||
:value="formData.default_answer"
|
||||
:is="formData.type + 'Type'"
|
||||
:options="formData.options"
|
||||
:defaultDateTime="formData.dateTimeValue"
|
||||
v-model="formData.default_answer"
|
||||
/>
|
||||
</sw-input-group>
|
||||
<sw-input-group
|
||||
:label="$t('settings.custom_fields.placeholder')"
|
||||
v-if="!isSwitchTypeSelected"
|
||||
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']),
|
||||
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)
|
||||
window.toastr['success'](
|
||||
this.$tc('settings.custom_fields.updated_message')
|
||||
)
|
||||
this.refreshData()
|
||||
this.closeCategoryModal()
|
||||
return true
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
response = await this.addCustomField(data)
|
||||
|
||||
window.toastr['success'](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>
|
||||
@@ -0,0 +1,35 @@
|
||||
<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>
|
||||
@@ -0,0 +1,29 @@
|
||||
<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>
|
||||
@@ -0,0 +1,37 @@
|
||||
<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>
|
||||
@@ -0,0 +1,27 @@
|
||||
<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>
|
||||
@@ -0,0 +1,27 @@
|
||||
<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>
|
||||
@@ -0,0 +1,41 @@
|
||||
<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>
|
||||
@@ -0,0 +1,27 @@
|
||||
<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>
|
||||
@@ -0,0 +1,27 @@
|
||||
<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>
|
||||
@@ -0,0 +1,28 @@
|
||||
<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>
|
||||
@@ -0,0 +1,28 @@
|
||||
<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>
|
||||
@@ -0,0 +1,27 @@
|
||||
<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>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,70 +1,66 @@
|
||||
<template>
|
||||
<div class="template-modal">
|
||||
<div class="card-body">
|
||||
<div class="template-container">
|
||||
<div class="px-8 py-8 sm:p-6">
|
||||
<div class="flex flex-wrap justify-start p-1 overflow-x-auto sw-scroll">
|
||||
<div
|
||||
v-for="(template,index) in modalData"
|
||||
v-for="(template, index) in modalData"
|
||||
:key="index"
|
||||
:class="{'selected-template': selectedTemplate === template.id}"
|
||||
class="template-img"
|
||||
:class="{
|
||||
'border border-solid border-primary-500':
|
||||
selectedTemplate === template.id,
|
||||
}"
|
||||
class="relative m-2 border border-gray-200 border-solid"
|
||||
>
|
||||
<img
|
||||
:src="template.path"
|
||||
alt="template-image"
|
||||
height="200" width="140"
|
||||
height="200"
|
||||
width="140"
|
||||
@click="selectedTemplate = template.id"
|
||||
>
|
||||
/>
|
||||
<img
|
||||
v-if="selectedTemplate === template.id"
|
||||
class="check-icon"
|
||||
class="absolute z-10 w-5 h-5 text-primary-500"
|
||||
style="top: -6px; right: -5px"
|
||||
src="/assets/img/tick.png"
|
||||
>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<base-button outline class="mr-3" color="theme" @click="closeEstimateModal">
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
@click="chooseTemplate()"
|
||||
<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') }}
|
||||
</base-button>
|
||||
</sw-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
export default {
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
selectedTemplate: 1,
|
||||
isLoading: false
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalData'
|
||||
]),
|
||||
...mapGetters('estimate', [
|
||||
'getTemplateId'
|
||||
])
|
||||
...mapGetters('modal', ['modalData']),
|
||||
...mapGetters('estimate', ['getTemplateId']),
|
||||
},
|
||||
mounted () {
|
||||
mounted() {
|
||||
this.selectedTemplate = this.getTemplateId
|
||||
},
|
||||
methods: {
|
||||
...mapActions('estimate', [
|
||||
'setTemplate'
|
||||
]),
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
async chooseTemplate () {
|
||||
...mapActions('estimate', ['setTemplate']),
|
||||
...mapActions('modal', ['closeModal', 'resetModalData']),
|
||||
async chooseTemplate() {
|
||||
this.isLoading = true
|
||||
let resp = await this.setTemplate(this.selectedTemplate)
|
||||
if (resp) {
|
||||
@@ -73,11 +69,11 @@ export default {
|
||||
this.closeModal()
|
||||
}
|
||||
},
|
||||
closeEstimateModal () {
|
||||
closeEstimateModal() {
|
||||
this.selectedTemplate = this.getTemplateId
|
||||
this.closeModal()
|
||||
this.resetModalData()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
151
resources/assets/js/components/base/modal/FileDiskModal.vue
Normal file
151
resources/assets/js/components/base/modal/FileDiskModal.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<div class="file-disk-modal">
|
||||
<div v-if="getDiskDrivers.length">
|
||||
<component
|
||||
:is="selected_disk"
|
||||
:loading="isLoading"
|
||||
:disks="getDiskDrivers"
|
||||
@on-change-disk="(disk) => (selected_disk = disk.value)"
|
||||
@submit="createNewDisk"
|
||||
:is-edit="isEdit"
|
||||
>
|
||||
<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"
|
||||
@click="closeDisk"
|
||||
type="button"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</sw-button>
|
||||
<sw-button
|
||||
:loading="isRequestFire(slotProps)"
|
||||
variant="primary"
|
||||
:disabled="isRequestFire(slotProps)"
|
||||
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']),
|
||||
|
||||
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) {
|
||||
window.toastr['success'](this.$t('settings.disk.success_update'))
|
||||
} else {
|
||||
window.toastr['success'](this.$t('settings.disk.success_create'))
|
||||
}
|
||||
} else {
|
||||
window.toastr['error'](
|
||||
this.$t('settings.disk.invalid_disk_credentials')
|
||||
)
|
||||
}
|
||||
this.isLoading = false
|
||||
},
|
||||
|
||||
closeDisk() {
|
||||
this.closeModal()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,71 +1,67 @@
|
||||
<template>
|
||||
<div class="template-modal">
|
||||
<div class="card-body">
|
||||
<div class="template-container">
|
||||
<div class="px-8 py-8 sm:p-6">
|
||||
<div class="flex flex-wrap justify-start p-1 overflow-x-auto sw-scroll">
|
||||
<div
|
||||
v-for="(template,index) in modalData"
|
||||
v-for="(template, index) in modalData"
|
||||
:key="index"
|
||||
:class="{'selected-template': selectedTemplate === template.id}"
|
||||
class="template-img"
|
||||
:class="{
|
||||
'border border-solid border-primary-500':
|
||||
selectedTemplate === template.id,
|
||||
}"
|
||||
class="relative m-2 border border-gray-200 border-solid"
|
||||
>
|
||||
<img
|
||||
:src="template.path"
|
||||
alt="template-image"
|
||||
height="200" width="140"
|
||||
height="200"
|
||||
width="140"
|
||||
@click="selectedTemplate = template.id"
|
||||
>
|
||||
/>
|
||||
<img
|
||||
v-if="selectedTemplate === template.id"
|
||||
class="check-icon"
|
||||
class="absolute z-10 w-5 h-5 text-primary-500"
|
||||
style="top: -6px; right: -5px"
|
||||
src="/assets/img/tick.png"
|
||||
>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<base-button outline class="mr-3" color="theme" @click="closeInvoiceModal">
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
@click="chooseTemplate()"
|
||||
<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') }}
|
||||
</base-button>
|
||||
</sw-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
export default {
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
selectedTemplate: 1,
|
||||
isLoading: false
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalData'
|
||||
]),
|
||||
...mapGetters('invoice', [
|
||||
'getTemplateId'
|
||||
])
|
||||
...mapGetters('modal', ['modalData']),
|
||||
...mapGetters('invoice', ['getTemplateId']),
|
||||
},
|
||||
mounted () {
|
||||
mounted() {
|
||||
this.selectedTemplate = this.getTemplateId
|
||||
},
|
||||
methods: {
|
||||
...mapActions('invoice', [
|
||||
'setTemplate'
|
||||
]),
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
async chooseTemplate () {
|
||||
this.isLoading = true;
|
||||
...mapActions('invoice', ['setTemplate']),
|
||||
...mapActions('modal', ['closeModal', 'resetModalData']),
|
||||
async chooseTemplate() {
|
||||
this.isLoading = true
|
||||
let resp = await this.setTemplate(this.selectedTemplate)
|
||||
if (resp) {
|
||||
this.isLoading = false
|
||||
@@ -73,11 +69,11 @@ export default {
|
||||
this.closeModal()
|
||||
}
|
||||
},
|
||||
closeInvoiceModal () {
|
||||
closeInvoiceModal() {
|
||||
this.selectedTemplate = this.getTemplateId
|
||||
this.closeModal()
|
||||
this.resetModalData()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,120 +1,104 @@
|
||||
<template>
|
||||
<div class="item-modal">
|
||||
<form action="" @submit.prevent="submitItemData">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">
|
||||
{{ $t('items.name') }}<span class="required">*</span>
|
||||
</label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="name"
|
||||
:invalid="$v.formData.name.$error"
|
||||
v-model="formData.name"
|
||||
type="text"
|
||||
@input="$v.formData.name.$touch()"
|
||||
/>
|
||||
<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>
|
||||
|
||||
<div v-if="$v.formData.name.$error">
|
||||
<span v-if="!$v.formData.name.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.name.minLength" class="text-danger"> {{ $tc('validation.name_min_length', $v.formData.name.$params.minLength.min, { count: $v.formData.name.$params.minLength.min }) }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('items.price') }}<span class="required">*</span></label>
|
||||
<div class="col-sm-7">
|
||||
<div class="base-input">
|
||||
<money
|
||||
:class="{'invalid' : $v.formData.price.$error}"
|
||||
v-model="price"
|
||||
v-bind="defaultCurrencyForInput"
|
||||
class="input-field"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="$v.formData.price.$error">
|
||||
<span v-if="!$v.formData.price.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.price.numeric" class="text-danger">{{ $tc('validation.numbers_only') }}</span>
|
||||
<span v-if="!$v.formData.price.maxLength" class="text-danger">{{ $t('validation.price_maxlength') }}</span>
|
||||
<span v-if="!$v.formData.price.minValue" class="text-danger">{{ $t('validation.price_minvalue') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('items.unit') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="formData.unit"
|
||||
:options="itemUnits"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
label="name"
|
||||
>
|
||||
<div slot="afterList">
|
||||
<button type="button" class="list-add-button" @click="addItemUnit">
|
||||
<font-awesome-icon class="icon" icon="cart-plus" />
|
||||
<label>{{ $t('settings.customization.items.add_item_unit') }}</label>
|
||||
</button>
|
||||
</div>
|
||||
</base-select>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isTexPerItem" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('items.taxes') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="formData.taxes"
|
||||
:options="getTaxTypes"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="true"
|
||||
:multiple="true"
|
||||
label="tax_name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('items.description') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-text-area
|
||||
v-model="formData.description"
|
||||
rows="4"
|
||||
cols="50"
|
||||
@input="$v.formData.description.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.description.$error">
|
||||
<span v-if="!$v.formData.description.maxLength" class="text-danger">{{ $t('validation.description_maxlength') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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"
|
||||
:maxHeight="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="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
<div
|
||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
||||
>
|
||||
<sw-button
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
variant="primary-outline"
|
||||
type="button"
|
||||
@click="closeItemModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
v-if="isEdit"
|
||||
</sw-button>
|
||||
<sw-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
@click="submitItemData"
|
||||
>
|
||||
{{ $t('general.update') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
v-else
|
||||
:loading="isLoading"
|
||||
icon="save"
|
||||
color="theme"
|
||||
:disabled="isLoading"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<save-icon v-if="!isLoading" class="mr-2" />
|
||||
{{ isEdit ? $t('general.update') : $t('general.save') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -122,97 +106,131 @@
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength, numeric, maxLength, minValue } = require('vuelidate/lib/validators')
|
||||
import { ShoppingCartIcon } from '@vue-hero-icons/solid'
|
||||
|
||||
const {
|
||||
required,
|
||||
minLength,
|
||||
numeric,
|
||||
maxLength,
|
||||
minValue,
|
||||
} = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
components: {
|
||||
ShoppingCartIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
tempData: null,
|
||||
units: [
|
||||
{ name: 'box', value: 'box' },
|
||||
{ name: 'cm', value: 'cm' },
|
||||
{ name: 'dz', value: 'dz' },
|
||||
{ name: 'ft', value: 'ft' },
|
||||
{ name: 'g', value: 'g' },
|
||||
{ name: 'in', value: 'in' },
|
||||
{ name: 'kg', value: 'kg' },
|
||||
{ name: 'km', value: 'km' },
|
||||
{ name: 'lb', value: 'lb' },
|
||||
{ name: 'mg', value: 'mg' },
|
||||
{ name: 'pc', value: 'pc' }
|
||||
],
|
||||
taxes: [],
|
||||
formData: {
|
||||
name: null,
|
||||
price: null,
|
||||
description: null,
|
||||
unit: null,
|
||||
taxes: []
|
||||
}
|
||||
taxes: [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
validations: {
|
||||
formData: {
|
||||
name: {
|
||||
required,
|
||||
minLength: minLength(3)
|
||||
minLength: minLength(3),
|
||||
},
|
||||
price: {
|
||||
required,
|
||||
numeric,
|
||||
minValue: minValue(0.1),
|
||||
maxLength: maxLength(20)
|
||||
maxLength: maxLength(20),
|
||||
},
|
||||
description: {
|
||||
maxLength: maxLength(255)
|
||||
}
|
||||
}
|
||||
maxLength: maxLength(255),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters('currency', [
|
||||
'defaultCurrencyForInput'
|
||||
]),
|
||||
...mapGetters('company', ['defaultCurrencyForInput']),
|
||||
price: {
|
||||
get: function () {
|
||||
return this.formData.price / 100
|
||||
},
|
||||
set: function (newValue) {
|
||||
this.formData.price = newValue * 100
|
||||
}
|
||||
},
|
||||
},
|
||||
// itemUnits () {
|
||||
// return this.units
|
||||
// },
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData'
|
||||
]),
|
||||
...mapGetters('item', [
|
||||
'getItemById',
|
||||
'itemUnits'
|
||||
]),
|
||||
...mapGetters('taxType', [
|
||||
'taxTypes'
|
||||
]),
|
||||
isTexPerItem () {
|
||||
|
||||
...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 + '%)'}
|
||||
|
||||
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 () {
|
||||
modalDataID() {
|
||||
this.isEdit = true
|
||||
this.fetchEditData()
|
||||
}
|
||||
},
|
||||
},
|
||||
created () {
|
||||
|
||||
created() {
|
||||
if (this.modalDataID) {
|
||||
this.isEdit = true
|
||||
this.fetchEditData()
|
||||
@@ -222,33 +240,30 @@ export default {
|
||||
this.loadEditData()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
mounted() {
|
||||
this.$v.formData.$reset()
|
||||
this.$refs.name.focus = true
|
||||
this.fetchItemUnits({ limit: 'all' })
|
||||
},
|
||||
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'openModal',
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
...mapActions('item', [
|
||||
'addItem',
|
||||
'updateItem'
|
||||
]),
|
||||
...mapActions('invoice', [
|
||||
'setItem'
|
||||
]),
|
||||
resetFormData () {
|
||||
...mapActions('modal', ['closeModal', 'resetModalData']),
|
||||
...mapActions('item', ['addItem', 'updateItem', 'fetchItemUnits']),
|
||||
...mapActions('invoice', ['setItem']),
|
||||
|
||||
resetFormData() {
|
||||
this.formData = {
|
||||
name: null,
|
||||
price: null,
|
||||
description: null,
|
||||
unit: null,
|
||||
id: null
|
||||
id: null,
|
||||
}
|
||||
this.$v.$reset()
|
||||
},
|
||||
fetchEditData () {
|
||||
|
||||
fetchEditData() {
|
||||
this.tempData = this.getItemById(this.modalDataID)
|
||||
if (this.tempData) {
|
||||
this.formData.name = this.tempData.name
|
||||
@@ -258,15 +273,17 @@ export default {
|
||||
this.formData.id = this.tempData.id
|
||||
}
|
||||
},
|
||||
async submitItemData () {
|
||||
|
||||
async submitItemData() {
|
||||
this.$v.formData.$touch()
|
||||
|
||||
if (this.$v.$invalid) {
|
||||
return true
|
||||
}
|
||||
if (this.formData.unit) {
|
||||
this.formData.unit = this.formData.unit.name
|
||||
this.formData.unit_id = this.formData.unit.id
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
let response
|
||||
if (this.isEdit) {
|
||||
@@ -274,21 +291,22 @@ export default {
|
||||
} else {
|
||||
let data = {
|
||||
...this.formData,
|
||||
taxes: this.formData.taxes.map(tax => {
|
||||
taxes: this.formData.taxes.map((tax) => {
|
||||
return {
|
||||
tax_type_id: tax.id,
|
||||
amount: ((this.formData.price * tax.percent) / 100),
|
||||
amount: (this.formData.price * tax.percent) / 100,
|
||||
percent: tax.percent,
|
||||
name: tax.name,
|
||||
collective_tax: 0
|
||||
collective_tax: 0,
|
||||
}
|
||||
})
|
||||
}),
|
||||
}
|
||||
response = await this.addItem(data)
|
||||
}
|
||||
if (response.data) {
|
||||
window.toastr['success'](this.$tc('items.created_message'))
|
||||
this.setItem(response.data.item)
|
||||
|
||||
window.hub.$emit('newItem', response.data.item)
|
||||
this.isLoading = false
|
||||
this.resetModalData()
|
||||
@@ -298,17 +316,12 @@ export default {
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
},
|
||||
async addItemUnit () {
|
||||
this.openModal({
|
||||
'title': 'Add Item Unit',
|
||||
'componentName': 'ItemUnit'
|
||||
})
|
||||
},
|
||||
closeItemModal () {
|
||||
|
||||
closeItemModal() {
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
this.resetModalData()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,78 +1,85 @@
|
||||
<template>
|
||||
<div class="item-unit-modal">
|
||||
<form action="" @submit.prevent="submitItemUnit">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('settings.customization.items.unit_name') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="name"
|
||||
:invalid="$v.formData.name.$error"
|
||||
v-model="formData.name"
|
||||
type="text"
|
||||
@input="$v.formData.name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.name.$error">
|
||||
<span v-if="!$v.formData.name.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
type="button"
|
||||
@click="closePaymentModeModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
icon="save"
|
||||
type="submit"
|
||||
>
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<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'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
formData: {
|
||||
id: null,
|
||||
name: null
|
||||
}
|
||||
name: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
'modalActive',
|
||||
'refreshData',
|
||||
]),
|
||||
nameError() {
|
||||
if (!this.$v.formData.name.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.formData.name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
},
|
||||
validations: {
|
||||
formData: {
|
||||
name: {
|
||||
required,
|
||||
minLength: minLength(2)
|
||||
}
|
||||
}
|
||||
minLength: minLength(2),
|
||||
},
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
|
||||
async mounted() {
|
||||
this.$refs.name.focus = true
|
||||
if (this.modalDataID) {
|
||||
this.isEdit = true
|
||||
@@ -80,69 +87,62 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
...mapActions('item', [
|
||||
'addItemUnit',
|
||||
'updateItemUnit',
|
||||
'fatchItemUnit'
|
||||
]),
|
||||
resetFormData () {
|
||||
...mapActions('modal', ['closeModal', 'resetModalData']),
|
||||
...mapActions('item', ['addItemUnit', 'updateItemUnit', 'fatchItemUnit']),
|
||||
resetFormData() {
|
||||
this.formData = {
|
||||
id: null,
|
||||
name: null
|
||||
name: null,
|
||||
}
|
||||
this.$v.formData.$reset()
|
||||
},
|
||||
async submitItemUnit () {
|
||||
async submitItemUnit() {
|
||||
this.$v.formData.$touch()
|
||||
if (this.$v.$invalid) {
|
||||
return true
|
||||
}
|
||||
this.isLoading = true
|
||||
|
||||
this.isLoading = true
|
||||
let response
|
||||
|
||||
if (this.isEdit) {
|
||||
response = await this.updateItemUnit(this.formData)
|
||||
try {
|
||||
if (!this.isEdit) {
|
||||
response = await this.addItemUnit(this.formData)
|
||||
} else {
|
||||
response = await this.updateItemUnit(this.formData)
|
||||
}
|
||||
|
||||
if (response.data) {
|
||||
window.toastr['success'](this.$t('settings.customization.items.item_unit_updated'))
|
||||
this.closePaymentModeModal()
|
||||
this.isLoading = false
|
||||
if (!this.isEdit) {
|
||||
window.toastr['success'](
|
||||
this.$t('settings.customization.items.item_unit_added')
|
||||
)
|
||||
} else {
|
||||
window.toastr['success'](
|
||||
this.$t('settings.customization.items.item_unit_updated')
|
||||
)
|
||||
}
|
||||
this.refreshData ? this.refreshData() : ''
|
||||
this.closeItemUnitModal()
|
||||
return true
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
this.isLoading = false
|
||||
window.toastr['error'](response.data.error)
|
||||
} else {
|
||||
try {
|
||||
response = await this.addItemUnit(this.formData)
|
||||
if (response.data) {
|
||||
this.isLoading = false
|
||||
window.toastr['success'](this.$t('settings.customization.items.item_unit_added'))
|
||||
this.closePaymentModeModal()
|
||||
return true
|
||||
} window.toastr['error'](response.data.error)
|
||||
} catch (err) {
|
||||
if (err.response.data.errors.name) {
|
||||
this.isLoading = true
|
||||
window.toastr['error'](this.$t('validation.item_unit_already_taken'))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async setData () {
|
||||
async setData() {
|
||||
this.formData = {
|
||||
id: this.modalData.id,
|
||||
name: this.modalData.name
|
||||
name: this.modalData.name,
|
||||
}
|
||||
},
|
||||
closePaymentModeModal () {
|
||||
closeItemUnitModal() {
|
||||
this.resetModalData()
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,75 +1,66 @@
|
||||
<template>
|
||||
<div class="mail-test-modal">
|
||||
<div class="mail-config-modal">
|
||||
<form action="" @submit.prevent="onTestMailSend">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('general.to') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="to"
|
||||
:invalid="$v.formData.to.$error"
|
||||
v-model="formData.to"
|
||||
type="text"
|
||||
@input="$v.formData.to.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.to.$error">
|
||||
<span v-if="!$v.formData.to.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.to.email" class="form-group__message text-danger"> {{ $t('validation.email_incorrect') }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('general.subject') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<div class="base-input">
|
||||
<base-input
|
||||
:invalid="$v.formData.subject.$error"
|
||||
v-model="formData.subject"
|
||||
type="text"
|
||||
@input="$v.formData.subject.$touch()"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="$v.formData.subject.$error">
|
||||
<span v-if="!$v.formData.subject.required" class="text-danger">{{ $t('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.subject.maxLength" class="text-danger">{{ $t('validation.subject_maxlength') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('general.message') }}<span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-text-area
|
||||
v-model="formData.message"
|
||||
:invalid="$v.formData.message.$error"
|
||||
rows="4"
|
||||
cols="50"
|
||||
@input="$v.formData.message.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.message.$error">
|
||||
<span v-if="!$v.formData.message.required" class="text-danger">{{ $t('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.message.maxLength" class="text-danger">{{ $t('validation.message_maxlength') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 md:p-8">
|
||||
<sw-input-group
|
||||
:label="$t('general.to')"
|
||||
class="mt-3"
|
||||
:error="emailError"
|
||||
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')"
|
||||
class="mt-3"
|
||||
:error="subjectError"
|
||||
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')"
|
||||
class="mt-3"
|
||||
:error="messageError"
|
||||
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="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
<div
|
||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
||||
>
|
||||
<sw-button
|
||||
variant="primary-outline"
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
type="button"
|
||||
@click="closeTaxModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
icon="save"
|
||||
type="submit"
|
||||
>
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</base-button>
|
||||
</sw-button>
|
||||
<sw-button variant="primary" type="submit" :loading="isLoading">
|
||||
<paper-airplane-icon v-if="!isLoading" class="mr-2" />
|
||||
{{ !isEdit ? $t('general.send') : $t('general.update') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -77,61 +68,96 @@
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength, email, maxLength } = require('vuelidate/lib/validators')
|
||||
import { PaperAirplaneIcon } from '@vue-hero-icons/outline'
|
||||
const {
|
||||
required,
|
||||
minLength,
|
||||
email,
|
||||
maxLength,
|
||||
} = require('vuelidate/lib/validators')
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
components: {
|
||||
PaperAirplaneIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
formData: {
|
||||
to: null,
|
||||
subject: null,
|
||||
message: null
|
||||
}
|
||||
message: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
...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
|
||||
email,
|
||||
},
|
||||
subject: {
|
||||
required,
|
||||
maxLength: maxLength(100)
|
||||
maxLength: maxLength(100),
|
||||
},
|
||||
message: {
|
||||
required,
|
||||
maxLength: maxLength(255)
|
||||
}
|
||||
}
|
||||
maxLength: maxLength(255),
|
||||
},
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
async mounted() {
|
||||
this.$refs.to.focus = true
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
resetFormData () {
|
||||
...mapActions('modal', ['closeModal', 'resetModalData']),
|
||||
...mapActions('company', ['sendTestMail']),
|
||||
resetFormData() {
|
||||
this.formData = {
|
||||
to: null,
|
||||
subject: null,
|
||||
message: null
|
||||
message: null,
|
||||
}
|
||||
this.$v.formData.$reset()
|
||||
},
|
||||
async onTestMailSend () {
|
||||
async onTestMailSend() {
|
||||
this.$v.formData.$touch()
|
||||
|
||||
if (this.$v.$invalid) {
|
||||
@@ -139,9 +165,9 @@ export default {
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
let response = await axios.post('/api/settings/test/mail', this.formData)
|
||||
if (response.data) {
|
||||
let response = await this.sendTestMail(this.formData)
|
||||
|
||||
if (response.data) {
|
||||
if (response.data.success) {
|
||||
window.toastr['success'](this.$tc('general.send_mail_successfully'))
|
||||
this.closeTaxModal()
|
||||
@@ -156,11 +182,11 @@ export default {
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
},
|
||||
closeTaxModal () {
|
||||
closeTaxModal() {
|
||||
this.resetModalData()
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
299
resources/assets/js/components/base/modal/NoteModal.vue
Normal file
299
resources/assets/js/components/base/modal/NoteModal.vue
Normal file
@@ -0,0 +1,299 @@
|
||||
<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')
|
||||
}
|
||||
},
|
||||
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,
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
this.setFields()
|
||||
if (this.modalDataID) {
|
||||
this.isEdit = true
|
||||
this.setData()
|
||||
} else {
|
||||
this.modalData
|
||||
? (this.noteType = this.modalData)
|
||||
: (this.noteType = 'Invoice')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
noteType() {
|
||||
this.setFields()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', ['closeModal', 'resetModalData']),
|
||||
...mapActions('notes', ['addNote', 'updateNote']),
|
||||
...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) {
|
||||
window.toastr['success'](
|
||||
this.$t('settings.customization.notes.note_updated')
|
||||
)
|
||||
|
||||
this.refreshData ? this.refreshData() : ''
|
||||
this.closeNoteModal()
|
||||
return true
|
||||
}
|
||||
window.toastr['error'](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
|
||||
window.toastr['success'](
|
||||
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
|
||||
}
|
||||
window.toastr['error'](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,79 +1,78 @@
|
||||
<template>
|
||||
<div class="payment-modes-modal">
|
||||
<form action="" @submit.prevent="submitPaymentMode">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('settings.customization.payments.mode_name') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="name"
|
||||
:invalid="$v.formData.name.$error"
|
||||
v-model="formData.name"
|
||||
type="text"
|
||||
@input="$v.formData.name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.name.$error">
|
||||
<span v-if="!$v.formData.name.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
type="button"
|
||||
@click="closePaymentModeModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
icon="save"
|
||||
type="submit"
|
||||
>
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<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 class="mr-2" v-if="!isLoading" />
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
formData: {
|
||||
id: null,
|
||||
name: null
|
||||
}
|
||||
name: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
'modalActive',
|
||||
'refreshData',
|
||||
]),
|
||||
nameError() {
|
||||
if (!this.$v.formData.name.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.formData.name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
},
|
||||
validations: {
|
||||
formData: {
|
||||
name: {
|
||||
required,
|
||||
minLength: minLength(2)
|
||||
}
|
||||
}
|
||||
minLength: minLength(2),
|
||||
},
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
async mounted() {
|
||||
this.$refs.name.focus = true
|
||||
if (this.modalDataID) {
|
||||
this.isEdit = true
|
||||
@@ -81,63 +80,68 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
...mapActions('payment', [
|
||||
'addPaymentMode',
|
||||
'updatePaymentMode'
|
||||
]),
|
||||
resetFormData () {
|
||||
...mapActions('modal', ['closeModal', 'resetModalData']),
|
||||
...mapActions('payment', ['addPaymentMode', 'updatePaymentMode']),
|
||||
resetFormData() {
|
||||
this.formData = {
|
||||
id: null,
|
||||
name: null
|
||||
name: null,
|
||||
}
|
||||
this.$v.formData.$reset()
|
||||
},
|
||||
async submitPaymentMode () {
|
||||
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) {
|
||||
window.toastr['success'](this.$t('settings.customization.payments.payment_mode_updated'))
|
||||
window.toastr['success'](
|
||||
this.$t('settings.customization.payments.payment_mode_updated')
|
||||
)
|
||||
this.refreshData ? this.refreshData() : ''
|
||||
this.closePaymentModeModal()
|
||||
return true
|
||||
} window.toastr['error'](response.data.error)
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
} else {
|
||||
try {
|
||||
response = await this.addPaymentMode(this.formData)
|
||||
if (response.data) {
|
||||
this.isLoading = false
|
||||
window.toastr['success'](this.$t('settings.customization.payments.payment_mode_added'))
|
||||
window.toastr['success'](
|
||||
this.$t('settings.customization.payments.payment_mode_added')
|
||||
)
|
||||
this.refreshData ? this.refreshData() : ''
|
||||
this.closePaymentModeModal()
|
||||
return true
|
||||
} window.toastr['error'](response.data.error)
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
} catch (err) {
|
||||
if (err.response.data.errors.name) {
|
||||
this.isLoading = true
|
||||
window.toastr['error'](this.$t('validation.payment_mode_already_taken'))
|
||||
this.isLoading = false
|
||||
window.toastr['error'](
|
||||
this.$t('validation.payment_mode_already_taken')
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async setData () {
|
||||
async setData() {
|
||||
this.formData = {
|
||||
id: this.modalData.id,
|
||||
name: this.modalData.name
|
||||
name: this.modalData.name,
|
||||
}
|
||||
},
|
||||
closePaymentModeModal () {
|
||||
closePaymentModeModal() {
|
||||
this.resetModalData()
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
271
resources/assets/js/components/base/modal/SendEstimateModal.vue
Normal file
271
resources/assets/js/components/base/modal/SendEstimateModal.vue
Normal file
@@ -0,0 +1,271 @@
|
||||
<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"
|
||||
@input="$v.formData.body.$touch()"
|
||||
class="mt-2"
|
||||
/>
|
||||
</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']),
|
||||
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
|
||||
}
|
||||
swal({
|
||||
title: this.$t('general.are_you_sure'),
|
||||
text: this.$t('estimates.confirm_send_estimate'),
|
||||
icon: '/assets/icon/check-circle-solid.svg',
|
||||
buttons: true,
|
||||
dangerMode: true,
|
||||
}).then(async (value) => {
|
||||
try {
|
||||
if (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
|
||||
window.toastr['success'](
|
||||
this.$tc('estimates.send_estimate_successfully')
|
||||
)
|
||||
return true
|
||||
}
|
||||
if (res.data.error === 'estimates.user_email_does_not_exist') {
|
||||
window.toastr['error'](
|
||||
this.$tc('estimates.user_email_does_not_exist')
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.isLoading = false
|
||||
window.toastr['error'](this.$tc('estimates.something_went_wrong'))
|
||||
}
|
||||
})
|
||||
},
|
||||
closeSendEstimateModal() {
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
266
resources/assets/js/components/base/modal/SendInvoiceModal.vue
Normal file
266
resources/assets/js/components/base/modal/SendInvoiceModal.vue
Normal file
@@ -0,0 +1,266 @@
|
||||
<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"
|
||||
@input="$v.formData.body.$touch()"
|
||||
class="mt-2"
|
||||
/>
|
||||
</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']),
|
||||
|
||||
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
|
||||
}
|
||||
swal({
|
||||
title: this.$t('general.are_you_sure'),
|
||||
text: this.$t('invoices.confirm_send_invoice'),
|
||||
icon: '/assets/icon/check-circle-solid.svg',
|
||||
buttons: true,
|
||||
dangerMode: true,
|
||||
}).then(async (value) => {
|
||||
try {
|
||||
if (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
|
||||
window.toastr['success'](
|
||||
this.$tc('invoices.send_invoice_successfully')
|
||||
)
|
||||
return true
|
||||
}
|
||||
if (res.data.error === 'invoices.user_email_does_not_exist') {
|
||||
window.toastr['error'](
|
||||
this.$tc('invoices.user_email_does_not_exist')
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.isLoading = false
|
||||
window.toastr['error'](this.$tc('invoices.something_went_wrong'))
|
||||
}
|
||||
})
|
||||
},
|
||||
closeSendInvoiceModal() {
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
263
resources/assets/js/components/base/modal/SendPaymentModal.vue
Normal file
263
resources/assets/js/components/base/modal/SendPaymentModal.vue
Normal file
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<div>
|
||||
<form action="" @submit.prevent="sendPaymentData">
|
||||
<div class="px-8 py-8 sm:p-6">
|
||||
<sw-input-group
|
||||
:label="$t('general.from')"
|
||||
class="mb-4"
|
||||
variant="vertical"
|
||||
:error="fromError"
|
||||
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"
|
||||
type="text"
|
||||
:invalid="$v.formData.to.$error"
|
||||
@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']),
|
||||
|
||||
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
|
||||
}
|
||||
swal({
|
||||
title: this.$t('general.are_you_sure'),
|
||||
text: this.$t('payments.confirm_send_payment'),
|
||||
icon: '/assets/icon/check-circle-solid.svg',
|
||||
buttons: true,
|
||||
dangerMode: true,
|
||||
}).then(async (value) => {
|
||||
try {
|
||||
if (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
|
||||
window.toastr['success'](
|
||||
this.$tc('payments.send_payment_successfully')
|
||||
)
|
||||
return true
|
||||
}
|
||||
if (res.data.error === 'payments.user_email_does_not_exist') {
|
||||
window.toastr['error'](
|
||||
this.$tc('payments.user_email_does_not_exist')
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.isLoading = false
|
||||
window.toastr['error'](this.$tc('payments.something_went_wrong'))
|
||||
}
|
||||
})
|
||||
},
|
||||
closeSendPaymentModal() {
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,124 @@
|
||||
<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"
|
||||
class="mt-2"
|
||||
track-by="id"
|
||||
:custom-label="getCustomLabel"
|
||||
/>
|
||||
</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']),
|
||||
|
||||
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()
|
||||
window.toastr['success'](this.$t('settings.disk.success'))
|
||||
}
|
||||
this.isLoading = true
|
||||
},
|
||||
|
||||
closeDisk() {
|
||||
this.closeModal()
|
||||
},
|
||||
|
||||
getCustomLabel({ driver, name }) {
|
||||
return `${name} — [${driver}]`
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,186 +1,194 @@
|
||||
<template>
|
||||
<div class="tax-type-modal">
|
||||
<form action="" @submit.prevent="submitTaxTypeData">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('tax_types.name') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="name"
|
||||
:invalid="$v.formData.name.$error"
|
||||
v-model="formData.name"
|
||||
type="text"
|
||||
@input="$v.formData.name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.name.$error">
|
||||
<span v-if="!$v.formData.name.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.name.minLength" class="form-group__message text-danger"> {{ $tc('validation.name_min_length', $v.formData.name.$params.minLength.min, { count: $v.formData.name.$params.minLength.min }) }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('tax_types.percent') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<div class="base-input">
|
||||
<money
|
||||
:class="{'invalid' : $v.formData.percent.$error}"
|
||||
v-model="formData.percent"
|
||||
v-bind="defaultInput"
|
||||
class="input-field"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="$v.formData.percent.$error">
|
||||
<span v-if="!$v.formData.percent.required" class="text-danger">{{ $t('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.percent.between" class="form-group__message text-danger">{{ $t('validation.enter_valid_tax_rate') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('tax_types.description') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-text-area
|
||||
v-model="formData.description"
|
||||
rows="4"
|
||||
cols="50"
|
||||
@input="$v.formData.description.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.description.$error">
|
||||
<span v-if="!$v.formData.description.maxLength" class="text-danger">{{ $t('validation.description_maxlength') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('tax_types.compound_tax') }}</label>
|
||||
<div class="col-sm-7 mr-4">
|
||||
<base-switch
|
||||
v-model="formData.compound_tax"
|
||||
class="btn-switch compound-tax-toggle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<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="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
<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') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
icon="save"
|
||||
type="submit"
|
||||
>
|
||||
</sw-button>
|
||||
<sw-button :loading="isLoading" variant="primary" type="submit">
|
||||
<save-icon class="mr-2" v-if="!isLoading" />
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</base-button>
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength, between, maxLength } = require('vuelidate/lib/validators')
|
||||
const {
|
||||
required,
|
||||
minLength,
|
||||
between,
|
||||
maxLength,
|
||||
} = require('vuelidate/lib/validators')
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
formData: {
|
||||
id: null,
|
||||
name: null,
|
||||
percent: '',
|
||||
percent: 0,
|
||||
description: null,
|
||||
compound_tax: false,
|
||||
collective_tax: 0
|
||||
collective_tax: 0,
|
||||
},
|
||||
defaultInput: {
|
||||
decimal: '.',
|
||||
thousands: ',',
|
||||
prefix: '% ',
|
||||
precision: 2,
|
||||
masked: false
|
||||
}
|
||||
masked: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
'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)
|
||||
minLength: minLength(3),
|
||||
},
|
||||
percent: {
|
||||
required,
|
||||
between: between(0, 100)
|
||||
between: between(0, 100),
|
||||
},
|
||||
description: {
|
||||
maxLength: maxLength(255)
|
||||
}
|
||||
}
|
||||
maxLength: maxLength(255),
|
||||
},
|
||||
},
|
||||
},
|
||||
// watch: {
|
||||
// 'modalDataID' (val) {
|
||||
// if (val) {
|
||||
// this.isEdit = true
|
||||
// this.setData()
|
||||
// } else {
|
||||
// this.isEdit = false
|
||||
// }
|
||||
// },
|
||||
// 'modalActive' (val) {
|
||||
// if (!this.modalActive) {
|
||||
// this.resetFormData()
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
async mounted () {
|
||||
async mounted() {
|
||||
this.$refs.name.focus = true
|
||||
if (this.modalDataID) {
|
||||
this.isEdit = true
|
||||
this.setData()
|
||||
// this.resetFormData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
...mapActions('taxType', [
|
||||
'addTaxType',
|
||||
'updateTaxType',
|
||||
'fetchTaxType'
|
||||
]),
|
||||
resetFormData () {
|
||||
...mapActions('modal', ['closeModal', 'resetModalData']),
|
||||
...mapActions('taxType', ['addTaxType', 'updateTaxType', 'fetchTaxType']),
|
||||
resetFormData() {
|
||||
this.formData = {
|
||||
id: null,
|
||||
name: null,
|
||||
percent: null,
|
||||
percent: 0,
|
||||
description: null,
|
||||
collective_tax: 0
|
||||
collective_tax: 0,
|
||||
}
|
||||
this.$v.formData.$reset()
|
||||
},
|
||||
async submitTaxTypeData () {
|
||||
async submitTaxTypeData() {
|
||||
this.$v.formData.$touch()
|
||||
|
||||
if (this.$v.$invalid) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
let response
|
||||
if (!this.isEdit) {
|
||||
@@ -190,31 +198,36 @@ export default {
|
||||
}
|
||||
if (response.data) {
|
||||
if (!this.isEdit) {
|
||||
window.toastr['success'](this.$t('settings.tax_types.created_message'))
|
||||
window.toastr['success'](
|
||||
this.$t('settings.tax_types.created_message')
|
||||
)
|
||||
} else {
|
||||
window.toastr['success'](this.$t('settings.tax_types.updated_message'))
|
||||
window.toastr['success'](
|
||||
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
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
},
|
||||
async setData () {
|
||||
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
|
||||
compound_tax: this.modalData.compound_tax ? true : false,
|
||||
}
|
||||
},
|
||||
closeTaxModal () {
|
||||
closeTaxModal() {
|
||||
this.resetModalData()
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
345
resources/assets/js/components/base/modal/disks/DoSpacesDisk.vue
Normal file
345
resources/assets/js/components/base/modal/disks/DoSpacesDisk.vue
Normal file
@@ -0,0 +1,345 @@
|
||||
<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>
|
||||
311
resources/assets/js/components/base/modal/disks/DropboxDisk.vue
Normal file
311
resources/assets/js/components/base/modal/disks/DropboxDisk.vue
Normal file
@@ -0,0 +1,311 @@
|
||||
<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>
|
||||
177
resources/assets/js/components/base/modal/disks/LocalDisk.vue
Normal file
177
resources/assets/js/components/base/modal/disks/LocalDisk.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<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>
|
||||
313
resources/assets/js/components/base/modal/disks/S3Disk.vue
Normal file
313
resources/assets/js/components/base/modal/disks/S3Disk.vue
Normal file
@@ -0,0 +1,313 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user