mirror of
https://github.com/crater-invoice/crater.git
synced 2025-12-16 18:32:55 -05:00
build version 400
This commit is contained in:
@@ -1,266 +0,0 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<form action="" @submit.prevent="next()">
|
||||
<p class="form-title">{{ $t('wizard.company_info') }}</p>
|
||||
<p class="form-desc">{{ $t('wizard.company_info_desc') }}</p>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label class="input-label">{{ $tc('settings.company_info.company_logo') }}</label>
|
||||
<div id="pick-avatar" class="image-upload-box">
|
||||
<div class="overlay">
|
||||
<font-awesome-icon class="white-icon" icon="camera"/>
|
||||
</div>
|
||||
<img v-if="previewLogo" :src="previewLogo" class="preview-logo">
|
||||
<div v-else class="upload-content">
|
||||
<font-awesome-icon class="upload-icon" icon="cloud-upload-alt"/>
|
||||
<p class="upload-text"> {{ $t('general.choose_file') }} </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<avatar-cropper
|
||||
:labels="{ submit: 'Submit', cancel: 'Cancel'}"
|
||||
:cropper-options="cropperOptions"
|
||||
:output-options="cropperOutputOptions"
|
||||
:output-quality="0.8"
|
||||
:upload-handler="cropperHandler"
|
||||
trigger="#pick-avatar"
|
||||
@changed="setFileObject"
|
||||
@error="handleUploadError"
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.company_name') }}</label><span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.companyData.name.$error"
|
||||
v-model.trim="companyData.name"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.companyData.name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.companyData.name.$error">
|
||||
<span v-if="!$v.companyData.name.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.country') }}</label><span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="country"
|
||||
:class="{'error': $v.companyData.country_id.$error }"
|
||||
:options="countries"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('general.select_country')"
|
||||
track-by="id"
|
||||
label="name"
|
||||
/>
|
||||
<div v-if="$v.companyData.country_id.$error">
|
||||
<span v-if="!$v.companyData.country_id.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.state') }}</label>
|
||||
<base-input
|
||||
v-model="companyData.state"
|
||||
name="state"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.city') }}</label>
|
||||
<base-input
|
||||
v-model="companyData.city"
|
||||
name="city"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.address') }}</label>
|
||||
<base-text-area
|
||||
:invalid="$v.companyData.address_street_1.$error"
|
||||
v-model.trim="companyData.address_street_1"
|
||||
:placeholder="$t('general.street_1')"
|
||||
name="billing_street1"
|
||||
rows="2"
|
||||
@input="$v.companyData.address_street_1.$touch()"
|
||||
/>
|
||||
<div v-if="$v.companyData.address_street_1.$error">
|
||||
<span v-if="!$v.companyData.address_street_1.maxLength" class="text-danger">{{ $t('validation.description_maxlength') }}</span>
|
||||
</div>
|
||||
<base-text-area
|
||||
:invalid="$v.companyData.address_street_2.$error"
|
||||
v-model="companyData.address_street_2"
|
||||
:placeholder="$t('general.street_2')"
|
||||
name="billing_street2"
|
||||
rows="2"
|
||||
@input="$v.companyData.address_street_2.$touch()"
|
||||
/>
|
||||
<div v-if="$v.companyData.address_street_2.$error">
|
||||
<span v-if="!$v.companyData.address_street_2.maxLength" class="text-danger">{{ $t('validation.description_maxlength') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<label class="form-label">{{ $t('wizard.zip_code') }}</label>
|
||||
<base-input
|
||||
v-model.trim="companyData.zip"
|
||||
type="text"
|
||||
name="zip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<label class="form-label">{{ $t('wizard.phone') }}</label>
|
||||
<base-input
|
||||
v-model.trim="companyData.phone"
|
||||
type="text"
|
||||
name="phone"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</base-button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import AvatarCropper from 'vue-avatar-cropper'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, maxLength } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect,
|
||||
AvatarCropper
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
cropperOutputOptions: {
|
||||
width: 150,
|
||||
height: 150
|
||||
},
|
||||
cropperOptions: {
|
||||
autoCropArea: 1,
|
||||
viewMode: 0,
|
||||
movable: true,
|
||||
zoomable: true
|
||||
},
|
||||
companyData: {
|
||||
logo: '',
|
||||
name: null,
|
||||
address_street_1: '',
|
||||
address_street_2: '',
|
||||
city: '',
|
||||
state: '',
|
||||
country_id: '',
|
||||
zip: '',
|
||||
phone: ''
|
||||
},
|
||||
loading: false,
|
||||
step: 1,
|
||||
countries: [],
|
||||
country: null,
|
||||
previewLogo: null
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
companyData: {
|
||||
name: {
|
||||
required
|
||||
},
|
||||
country_id: {
|
||||
required
|
||||
},
|
||||
address_street_1: {
|
||||
maxLength: maxLength(255)
|
||||
},
|
||||
address_street_2: {
|
||||
maxLength: maxLength(255)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
country ({ id }) {
|
||||
this.companyData.country_id = id
|
||||
return true
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.fetchCountry()
|
||||
},
|
||||
methods: {
|
||||
cropperHandler (cropper) {
|
||||
this.previewLogo = cropper.getCroppedCanvas().toDataURL(this.cropperOutputMime)
|
||||
},
|
||||
setFileObject (file) {
|
||||
this.fileObject = file
|
||||
},
|
||||
handleUploadError (message, type, xhr) {
|
||||
window.toastr['error']('Oops! Something went wrong...')
|
||||
},
|
||||
async next () {
|
||||
this.$v.companyData.$touch()
|
||||
if (this.$v.companyData.$invalid) {
|
||||
return true
|
||||
}
|
||||
this.loading = true
|
||||
let response = await window.axios.post('/api/admin/onboarding/company', this.companyData)
|
||||
|
||||
if (response.data) {
|
||||
if (this.fileObject && this.previewLogo) {
|
||||
let logoData = new FormData()
|
||||
logoData.append('company_logo', JSON.stringify({
|
||||
name: this.fileObject.name,
|
||||
data: this.previewLogo
|
||||
}))
|
||||
|
||||
await axios.post('/api/admin/onboarding/company/upload-logo', logoData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
'company': response.data.user.company.id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.$emit('next')
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
onFileChange (e) {
|
||||
var input = event.target
|
||||
this.companyData.logo = input.files[0]
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
this.previewLogo = e.target.result
|
||||
}
|
||||
reader.readAsDataURL(input.files[0])
|
||||
}
|
||||
},
|
||||
async fetchCountry () {
|
||||
let res = await window.axios.get('/api/countries')
|
||||
if (res) {
|
||||
this.countries = res.data.countries
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,219 +0,0 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<form action="" @submit.prevent="next()">
|
||||
<p class="form-title">{{ $t('wizard.database.database') }}</p>
|
||||
<p class="form-desc">{{ $t('wizard.database.desc') }}</p>
|
||||
<div class="row mt-5">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.database.app_url') }}</label>
|
||||
<span class="text-danger"> * </span>
|
||||
<base-input
|
||||
:invalid="$v.databaseData.app_url.$error"
|
||||
v-model.trim="databaseData.app_url"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.databaseData.app_url.$touch()"
|
||||
/>
|
||||
<div v-if="$v.databaseData.app_url.$error">
|
||||
<span v-if="!$v.databaseData.app_url.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.databaseData.app_url.isUrl" class="text-danger">
|
||||
{{ $tc('validation.invalid_url') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.database.connection') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="databaseData.database_connection"
|
||||
:invalid="$v.databaseData.database_connection.$error"
|
||||
:options="connections"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
@change="$v.databaseData.database_connection.$touch()"
|
||||
/>
|
||||
<div v-if="$v.databaseData.database_connection.$error">
|
||||
<span v-if="!$v.databaseData.database_connection.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.database.port') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.databaseData.database_port.$error"
|
||||
v-model.trim="databaseData.database_port"
|
||||
type="text"
|
||||
name="database_port"
|
||||
@input="$v.databaseData.database_port.$touch()"
|
||||
/>
|
||||
<div v-if="$v.databaseData.database_port.$error">
|
||||
<span v-if="!$v.databaseData.database_port.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.databaseData.database_port.numeric" class="text-danger">
|
||||
{{ $tc('validation.numbers_only') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.database.db_name') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.databaseData.database_name.$error"
|
||||
v-model.trim="databaseData.database_name"
|
||||
type="text"
|
||||
name="database_name"
|
||||
@input="$v.databaseData.database_name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.databaseData.database_name.$error">
|
||||
<span v-if="!$v.databaseData.database_name.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.database.username') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.databaseData.database_username.$error"
|
||||
v-model.trim="databaseData.database_username"
|
||||
type="text"
|
||||
name="database_username"
|
||||
@input="$v.databaseData.database_username.$touch()"
|
||||
/>
|
||||
<div v-if="$v.databaseData.database_username.$error">
|
||||
<span v-if="!$v.databaseData.database_username.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.database.password') }}</label>
|
||||
<base-input
|
||||
v-model.trim="databaseData.database_password"
|
||||
type="password"
|
||||
name="name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.database.host') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.databaseData.database_hostname.$error"
|
||||
v-model.trim="databaseData.database_hostname"
|
||||
type="text"
|
||||
name="database_hostname"
|
||||
@input="$v.databaseData.database_hostname.$touch()"
|
||||
/>
|
||||
<div v-if="$v.databaseData.database_hostname.$error">
|
||||
<span v-if="!$v.databaseData.database_hostname.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-5"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</base-button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, numeric, url } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
databaseData: {
|
||||
database_connection: 'mysql',
|
||||
database_hostname: '127.0.0.1',
|
||||
database_port: '3306',
|
||||
database_name: null,
|
||||
database_username: null,
|
||||
database_password: null,
|
||||
app_url: window.location.origin
|
||||
},
|
||||
loading: false,
|
||||
connections: [
|
||||
'sqlite',
|
||||
'mysql',
|
||||
'pgsql',
|
||||
'sqlsrv'
|
||||
]
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
databaseData: {
|
||||
database_connection: {
|
||||
required
|
||||
},
|
||||
database_hostname: {
|
||||
required
|
||||
},
|
||||
database_port: {
|
||||
required,
|
||||
numeric
|
||||
},
|
||||
database_name: {
|
||||
required
|
||||
},
|
||||
database_username: {
|
||||
required
|
||||
},
|
||||
app_url: {
|
||||
required,
|
||||
isUrl (val) {
|
||||
return this.$utils.checkValidUrl(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async next () {
|
||||
this.$v.databaseData.$touch()
|
||||
if (this.$v.databaseData.$invalid) {
|
||||
return true
|
||||
}
|
||||
this.loading = true
|
||||
try {
|
||||
let response = await window.axios.post('/api/admin/onboarding/environment/database', this.databaseData)
|
||||
if (response.data.success) {
|
||||
this.$emit('next')
|
||||
window.toastr['success'](this.$t('wizard.success.' + response.data.success))
|
||||
return true
|
||||
} else if (response.data.error) {
|
||||
window.toastr['error'](this.$t('wizard.errors.' + response.data.error))
|
||||
} else if (response.data.error_message) {
|
||||
window.toastr['error'](response.data.error_message)
|
||||
}
|
||||
} catch (e) {
|
||||
window.toastr['error'](e.response.data.message)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,78 +0,0 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<form action="" @submit.prevent="next()">
|
||||
<p class="form-title">{{ $t('wizard.mail.mail_config') }}</p>
|
||||
<p class="form-desc">{{ $t('wizard.mail.mail_config_desc') }}</p>
|
||||
<component
|
||||
:is="mail_driver"
|
||||
:config-data="mailConfigData"
|
||||
:loading="loading"
|
||||
:mail-drivers="mail_drivers"
|
||||
@on-change-driver="(val) => mail_driver = mailConfigData.mail_driver = val"
|
||||
@submit-data="next"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
import Smtp from './mailDriver/Smtp'
|
||||
import Mailgun from './mailDriver/Mailgun'
|
||||
import Ses from './mailDriver/Ses'
|
||||
import Basic from './mailDriver/Basic'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect,
|
||||
Smtp,
|
||||
Mailgun,
|
||||
Ses,
|
||||
sendmail: Basic,
|
||||
mail: Basic
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
mailConfigData: {
|
||||
mail_driver: 'mail'
|
||||
},
|
||||
mail_driver: 'mail',
|
||||
loading: false,
|
||||
mail_drivers: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getMailDrivers()
|
||||
},
|
||||
methods: {
|
||||
async getMailDrivers () {
|
||||
this.loading = true
|
||||
|
||||
let response = await window.axios.get('/api/admin/onboarding/environment/mail')
|
||||
|
||||
if (response.data) {
|
||||
this.mail_drivers = response.data
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async next (mailConfigData) {
|
||||
this.loading = true
|
||||
try {
|
||||
let response = await window.axios.post('/api/admin/onboarding/environment/mail', mailConfigData)
|
||||
if (response.data.success) {
|
||||
this.$emit('next')
|
||||
window.toastr['success'](this.$t('wizard.success.' + response.data.success))
|
||||
} else {
|
||||
window.toastr['error'](this.$t('wizard.errors.' + response.data.error))
|
||||
}
|
||||
this.loading = false
|
||||
return true
|
||||
} catch (e) {
|
||||
window.toastr['error']('Something went wrong')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,113 +0,0 @@
|
||||
<template>
|
||||
<div class="wizard">
|
||||
<div class="step-indicator">
|
||||
<img
|
||||
id="logo-crater"
|
||||
src="/assets/img/crater-logo.png"
|
||||
alt="Crater Logo"
|
||||
class="logo-main"
|
||||
>
|
||||
<div class="indicator-line">
|
||||
<div class="center">
|
||||
<div class="steps" :class="{'active': step === 1, 'completed': step > 1}">
|
||||
<font-awesome-icon v-if="step > 1" icon="check" class="icon-check"/>
|
||||
</div>
|
||||
<div class="steps" :class="{'active': step === 2, 'completed': step > 2}">
|
||||
<font-awesome-icon v-if="step > 2" icon="check" class="icon-check"/>
|
||||
</div>
|
||||
<div class="steps" :class="{'active': step === 3, 'completed': step > 3}">
|
||||
<font-awesome-icon v-if="step > 3" icon="check" class="icon-check"/>
|
||||
</div>
|
||||
<div class="steps" :class="{'active': step === 4, 'completed': step > 4}">
|
||||
<font-awesome-icon v-if="step > 4" icon="check" class="icon-check"/>
|
||||
</div>
|
||||
<div class="steps" :class="{'active': step === 5, 'completed': step > 5}">
|
||||
<font-awesome-icon v-if="step > 5" icon="check" class="icon-check"/>
|
||||
</div>
|
||||
<div class="steps" :class="{'active': step === 6, 'completed': step > 6}">
|
||||
<font-awesome-icon v-if="step > 6" icon="check" class="icon-check"/>
|
||||
</div>
|
||||
<div class="steps" :class="{'active': step === 7, 'completed': step > 7}">
|
||||
<font-awesome-icon v-if="step > 7" icon="check" class="icon-check"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-content">
|
||||
<div class="card wizard-card">
|
||||
<component
|
||||
:is="tab"
|
||||
@next="setTab"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import SystemRequirement from './SystemRequirement'
|
||||
import Permission from './Permission'
|
||||
import Database from './Database'
|
||||
import EmailConfiguration from './EmailConfiguration'
|
||||
import UserProfile from './UserProfile'
|
||||
import CompanyInfo from './CompanyInfo'
|
||||
import Settings from './Settings'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
step_1: SystemRequirement,
|
||||
step_2: Permission,
|
||||
step_3: Database,
|
||||
step_4: EmailConfiguration,
|
||||
step_5: UserProfile,
|
||||
step_6: CompanyInfo,
|
||||
step_7: Settings
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
tab: 'step_1',
|
||||
step: 1
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getOnboardingData()
|
||||
},
|
||||
methods: {
|
||||
async getOnboardingData () {
|
||||
let response = await window.axios.get('/api/admin/onboarding')
|
||||
if (response.data) {
|
||||
if (response.data.profile_complete === 'COMPLETED') {
|
||||
this.$router.push('/admin/dashboard')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let dbStep = parseInt(response.data.profile_complete)
|
||||
|
||||
if (dbStep) {
|
||||
this.step = dbStep + 1
|
||||
this.tab = `step_${dbStep + 1}`
|
||||
}
|
||||
|
||||
this.languages = response.data.languages
|
||||
this.currencies = response.data.currencies
|
||||
this.dateFormats = response.data.date_formats
|
||||
this.timeZones = response.data.time_zones
|
||||
|
||||
// this.settingData.currency = this.currencies.find(currency => currency.id === 1)
|
||||
// this.settingData.language = this.languages.find(language => language.code === 'en')
|
||||
// this.settingData.dateFormat = this.dateFormats.find(dateFormat => dateFormat.value === 'd M Y')
|
||||
}
|
||||
},
|
||||
setTab (data) {
|
||||
this.step++
|
||||
|
||||
if (this.step <= 7) {
|
||||
this.tab = 'step_' + this.step
|
||||
} else {
|
||||
// window.location.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<div class="card-body permissions">
|
||||
<p class="form-title">{{ $t('wizard.permissions.permissions') }}</p>
|
||||
<p class="form-desc">{{ $t('wizard.permissions.permission_desc') }}</p>
|
||||
<div class="d-flex justify-content-start">
|
||||
<div class="lists col-md-6">
|
||||
<div
|
||||
v-for="(permission, index) in permissions"
|
||||
:key="index"
|
||||
class="row list-items"
|
||||
>
|
||||
|
||||
<div class="col-sm-9 left-item">
|
||||
{{ permission.folder }}
|
||||
</div>
|
||||
<div class="col-sm-3 right-item">
|
||||
<span v-if="permission.isSet" class="verified"/>
|
||||
<span v-else class="not-verified"/>
|
||||
<span>{{ permission.permission }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
v-if="isContinue"
|
||||
class="pull-right mt-5"
|
||||
icon="arrow-right"
|
||||
right-icon
|
||||
color="theme"
|
||||
@click="next"
|
||||
>
|
||||
{{ $t('wizard.continue') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
permissions: [],
|
||||
errors: false,
|
||||
isContinue: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getPermissions()
|
||||
},
|
||||
methods: {
|
||||
async getPermissions () {
|
||||
this.loading = true
|
||||
|
||||
let response = await window.axios.get('/api/admin/onboarding/permissions', this.profileData)
|
||||
|
||||
if (response.data) {
|
||||
this.permissions = response.data.permissions.permissions
|
||||
this.errors = response.data.permissions.errors
|
||||
let self = this
|
||||
|
||||
if (this.errors) {
|
||||
swal({
|
||||
title: this.$t('wizard.permissions.permission_confirm_title'),
|
||||
text: this.$t('wizard.permissions.permission_confirm_desc'),
|
||||
icon: 'warning',
|
||||
buttons: true,
|
||||
dangerMode: true
|
||||
}).then(async (willConfirm) => {
|
||||
if (willConfirm) {
|
||||
self.isContinue = true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isContinue = true
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async next () {
|
||||
this.loading = true
|
||||
await this.$emit('next')
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,219 +0,0 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<form action="" @submit.prevent="next()">
|
||||
<p class="form-title">{{ $t('wizard.preferences') }}</p>
|
||||
<p class="form-desc">{{ $t('wizard.preferences_desc') }}</p>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.currency') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="settingData.currency"
|
||||
:class="{'error': $v.settingData.currency.$error }"
|
||||
:options="currencies"
|
||||
:custom-label="currencyNameWithCode"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.currencies.select_currency')"
|
||||
track-by="id"
|
||||
label="name"
|
||||
@input="$v.settingData.currency.$touch()"
|
||||
/>
|
||||
<div v-if="$v.settingData.currency.$error">
|
||||
<span v-if="!$v.settingData.currency.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.language') }}</label><span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="settingData.language"
|
||||
:class="{'error': $v.settingData.language.$error }"
|
||||
:options="languages"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.preferences.select_language')"
|
||||
label="name"
|
||||
@input="$v.settingData.language.$touch()"
|
||||
/>
|
||||
<div v-if="$v.settingData.language.$error">
|
||||
<span v-if="!$v.settingData.language.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.date_format') }}</label><span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="settingData.dateFormat"
|
||||
:class="{'error': $v.settingData.dateFormat.$error }"
|
||||
:options="dateFormats"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.preferences.select_date_formate')"
|
||||
label="display_date"
|
||||
@input="$v.settingData.dateFormat.$touch()"
|
||||
/>
|
||||
<div v-if="$v.settingData.dateFormat.$error">
|
||||
<span v-if="!$v.settingData.dateFormat.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.time_zone') }}</label><span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="settingData.timeZone"
|
||||
:class="{'error': $v.settingData.timeZone.$error }"
|
||||
:options="timeZones"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.preferences.select_date_formate')"
|
||||
label="key"
|
||||
@input="$v.settingData.timeZone.$touch()"
|
||||
/>
|
||||
<div v-if="$v.settingData.timeZone.$error">
|
||||
<span v-if="!$v.settingData.timeZone.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.fiscal_year') }}</label><span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="settingData.fiscalYear"
|
||||
:class="{'error': $v.settingData.fiscalYear.$error }"
|
||||
:options="fiscalYears"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.preferences.select_financial_year')"
|
||||
label="key"
|
||||
@input="$v.settingData.fiscalYear.$touch()"
|
||||
/>
|
||||
<div v-if="$v.settingData.fiscalYear.$error">
|
||||
<span v-if="!$v.settingData.fiscalYear.required" class="text-danger">{{ $tc('customers.errors.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button :loading="loading" class="pull-right" icon="save" color="theme" type="submit">
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</base-button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
import Ls from '../../services/ls'
|
||||
import { mapActions } from 'vuex'
|
||||
const { required, minLength, email } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
settingData: {
|
||||
language: null,
|
||||
currency: null,
|
||||
timeZone: null,
|
||||
dateFormat: null,
|
||||
fiscalYear: null
|
||||
},
|
||||
loading: false,
|
||||
step: 1,
|
||||
languages: [],
|
||||
currencies: [],
|
||||
timeZones: [],
|
||||
dateFormats: [],
|
||||
fiscalYears: []
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
settingData: {
|
||||
currency: {
|
||||
required
|
||||
},
|
||||
language: {
|
||||
required
|
||||
},
|
||||
dateFormat: {
|
||||
required
|
||||
},
|
||||
timeZone: {
|
||||
required
|
||||
},
|
||||
fiscalYear: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.getOnboardingData()
|
||||
},
|
||||
methods: {
|
||||
currencyNameWithCode ({name, code}) {
|
||||
return `${code} - ${name}`
|
||||
},
|
||||
...mapActions('auth', [
|
||||
'loginOnBoardingUser'
|
||||
]),
|
||||
async getOnboardingData () {
|
||||
let response = await window.axios.get('/api/admin/onboarding')
|
||||
if (response.data) {
|
||||
if (response.data.profile_complete === 'COMPLETED') {
|
||||
this.$router.push('/admin/dashboard')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let dbStep = parseInt(response.data.profile_complete)
|
||||
|
||||
if (dbStep) {
|
||||
this.step = dbStep + 1
|
||||
}
|
||||
|
||||
this.languages = response.data.languages
|
||||
this.currencies = response.data.currencies
|
||||
this.dateFormats = response.data.date_formats
|
||||
this.timeZones = response.data.time_zones
|
||||
this.fiscalYears = response.data.fiscal_years
|
||||
|
||||
this.settingData.currency = this.currencies.find(currency => currency.id === 1)
|
||||
this.settingData.language = this.languages.find(language => language.code === 'en')
|
||||
this.settingData.dateFormat = response.data.date_formats.find(dateFormat => dateFormat.carbon_format_value == 'd M Y')
|
||||
this.settingData.timeZone = this.timeZones.find(timeZone => timeZone.value === 'UTC')
|
||||
this.settingData.fiscalYear = this.fiscalYears.find(fiscalYear => fiscalYear.value === '1-12')
|
||||
}
|
||||
},
|
||||
async next () {
|
||||
this.$v.settingData.$touch()
|
||||
|
||||
if (this.$v.settingData.$invalid) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
|
||||
let data = {
|
||||
currency: this.settingData.currency.id,
|
||||
time_zone: this.settingData.timeZone.value,
|
||||
language: this.settingData.language.code,
|
||||
fiscal_year: this.settingData.fiscalYear.value,
|
||||
carbon_date_format: this.settingData.dateFormat.carbon_format_value,
|
||||
moment_date_format: this.settingData.dateFormat.moment_format_value
|
||||
}
|
||||
|
||||
let response = await window.axios.post('/api/admin/onboarding/settings', data)
|
||||
|
||||
if (response.data) {
|
||||
// this.$emit('next')
|
||||
this.loading = false
|
||||
Ls.set('auth.token', response.data.token)
|
||||
this.loginOnBoardingUser(response.data.token)
|
||||
window.toastr['success']('Login Successful')
|
||||
this.$router.push('/admin/dashboard')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,112 +0,0 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<p class="form-title">{{ $t('wizard.req.system_req') }}</p>
|
||||
<p class="form-desc">{{ $t('wizard.req.system_req_desc') }}</p>
|
||||
<div v-if="phpSupportInfo" class="d-flex justify-content-start">
|
||||
<div class="col-md-6">
|
||||
<div class="row list-items">
|
||||
<div class="col-md-9 left-item">
|
||||
{{ $t('wizard.req.php_req_version', { version: phpSupportInfo.minimum }) }}
|
||||
</div>
|
||||
<div class="col-md-3 right-item justify-content-end">
|
||||
{{ phpSupportInfo.current }}
|
||||
<span v-if="phpSupportInfo.supported" class="verified"/>
|
||||
<span v-else class="not-verified"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="requirements" class="d-flex justify-content-start">
|
||||
<div class="col-md-6">
|
||||
<div
|
||||
v-for="(requirement, index) in requirements"
|
||||
:key="index"
|
||||
class="row list-items"
|
||||
>
|
||||
|
||||
<div class="col-md-9 left-item">
|
||||
{{ index }}
|
||||
</div>
|
||||
<div class="col-md-3 right-item justify-content-end">
|
||||
<span v-if="requirement" class="verified"/>
|
||||
<span v-else class="not-verified"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
v-if="hasNext"
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="arrow-right"
|
||||
color="theme"
|
||||
right-icon
|
||||
@click="next"
|
||||
>
|
||||
{{ $t('wizard.continue') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
v-if="!requirements"
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
color="theme"
|
||||
@click="getRequirements"
|
||||
>
|
||||
{{ $t('wizard.req.check_req') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
requirements: null,
|
||||
phpSupportInfo: null,
|
||||
loading: false,
|
||||
isShow: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasNext () {
|
||||
if (this.requirements) {
|
||||
let isRequired = true
|
||||
for (const key in this.requirements) {
|
||||
if (!this.requirements[key]) {
|
||||
isRequired = false
|
||||
}
|
||||
}
|
||||
return this.requirements && this.phpSupportInfo.supported && isRequired
|
||||
}
|
||||
return false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
listToggle () {
|
||||
this.isShow = !this.isShow
|
||||
},
|
||||
async getRequirements () {
|
||||
this.loading = true
|
||||
|
||||
let response = await window.axios.get('/api/admin/onboarding/requirements', this.profileData)
|
||||
|
||||
if (response.data) {
|
||||
this.requirements = response.data.requirements.requirements.php
|
||||
this.phpSupportInfo = response.data.phpSupportInfo
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async next () {
|
||||
this.loading = true
|
||||
await this.$emit('next')
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,204 +0,0 @@
|
||||
<template>
|
||||
<div class="card-body">
|
||||
<form action="" @submit.prevent="next()">
|
||||
<p class="form-title">{{ $t('wizard.account_info') }}</p>
|
||||
<p class="form-desc">{{ $t('wizard.account_info_desc') }}</p>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $tc('settings.account_settings.profile_picture') }}</label>
|
||||
<div id="pick-avatar" class="image-upload-box avatar-upload">
|
||||
<div class="overlay">
|
||||
<font-awesome-icon class="white-icon" icon="camera"/>
|
||||
</div>
|
||||
<img v-if="previewAvatar" :src="previewAvatar" class="preview-logo">
|
||||
<div v-else class="upload-content">
|
||||
<font-awesome-icon class="upload-icon" icon="cloud-upload-alt"/>
|
||||
<p class="upload-text"> {{ $tc('general.choose_file') }} </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<avatar-cropper
|
||||
:labels="{ submit: 'submit', cancel: 'Cancel'}"
|
||||
:cropper-options="cropperOptions"
|
||||
:output-options="cropperOutputOptions"
|
||||
:output-quality="0.8"
|
||||
:upload-handler="cropperHandler"
|
||||
trigger="#pick-avatar"
|
||||
@changed="setFileObject"
|
||||
@error="handleUploadError"
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.name') }}</label><span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.profileData.name.$error"
|
||||
v-model.trim="profileData.name"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.profileData.name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.profileData.name.$error">
|
||||
<span v-if="!$v.profileData.name.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.profileData.name.minLength" class="text-danger"> {{ $tc('validation.name_min_length', $v.profileData.name.$params.minLength.min, { count: $v.profileData.name.$params.minLength.min }) }} </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.email') }}</label><span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.profileData.email.$error"
|
||||
v-model.trim="profileData.email"
|
||||
type="text"
|
||||
name="email"
|
||||
@input="$v.profileData.email.$touch()"
|
||||
/>
|
||||
<div v-if="$v.profileData.email.$error">
|
||||
<span v-if="!$v.profileData.email.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.profileData.email.email" class="text-danger">{{ $tc('validation.email_incorrect') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.password') }}</label><span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.profileData.password.$error"
|
||||
v-model.trim="profileData.password"
|
||||
type="password"
|
||||
name="password"
|
||||
@input="$v.profileData.password.$touch()"
|
||||
/>
|
||||
<div v-if="$v.profileData.password.$error">
|
||||
<span v-if="!$v.profileData.password.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.profileData.password.minLength" class="text-danger"> {{ $tc('validation.password_min_length', $v.profileData.password.$params.minLength.min, {count: $v.profileData.password.$params.minLength.min}) }} </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">{{ $t('wizard.confirm_password') }}</label><span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.profileData.confirm_password.$error"
|
||||
v-model.trim="profileData.confirm_password"
|
||||
type="password"
|
||||
name="confirm_password"
|
||||
@input="$v.profileData.confirm_password.$touch()"
|
||||
/>
|
||||
<div v-if="$v.profileData.confirm_password.$error">
|
||||
<span v-if="!$v.profileData.confirm_password.sameAsPassword" class="text-danger">{{ $tc('validation.password_incorrect') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</base-button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import AvatarCropper from 'vue-avatar-cropper'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
import { mapActions } from 'vuex'
|
||||
const { required, requiredIf, sameAs, minLength, email } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AvatarCropper
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
cropperOutputOptions: {
|
||||
width: 150,
|
||||
height: 150
|
||||
},
|
||||
cropperOptions: {
|
||||
autoCropArea: 1,
|
||||
viewMode: 0,
|
||||
movable: true,
|
||||
zoomable: true
|
||||
},
|
||||
profileData: {
|
||||
name: null,
|
||||
email: null,
|
||||
password: null,
|
||||
confirm_password: null
|
||||
},
|
||||
loading: false,
|
||||
previewAvatar: '/images/default-avatar.jpg',
|
||||
fileObject: null
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
profileData: {
|
||||
name: {
|
||||
required,
|
||||
minLength: minLength(3)
|
||||
},
|
||||
email: {
|
||||
email,
|
||||
required
|
||||
},
|
||||
password: {
|
||||
required,
|
||||
minLength: minLength(8)
|
||||
},
|
||||
confirm_password: {
|
||||
required: requiredIf('isRequired'),
|
||||
sameAsPassword: sameAs('password')
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isRequired () {
|
||||
if (this.profileData.password === null || this.profileData.password === undefined || this.profileData.password === '') {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('userProfile', [
|
||||
'uploadOnboardAvatar'
|
||||
]),
|
||||
cropperHandler (cropper) {
|
||||
this.previewAvatar = cropper.getCroppedCanvas().toDataURL(this.cropperOutputMime)
|
||||
},
|
||||
setFileObject (file) {
|
||||
this.fileObject = file
|
||||
},
|
||||
handleUploadError (message, type, xhr) {
|
||||
window.toastr['error']('Oops! Something went wrong...')
|
||||
},
|
||||
async next () {
|
||||
this.$v.profileData.$touch()
|
||||
if (this.$v.profileData.$invalid) {
|
||||
return true
|
||||
}
|
||||
this.loading = true
|
||||
let response = await window.axios.post('/api/admin/onboarding/profile', this.profileData)
|
||||
console.log('user_id', response.data.user.id)
|
||||
|
||||
if (response.data) {
|
||||
if (this.fileObject && this.previewAvatar) {
|
||||
let avatarData = new FormData()
|
||||
avatarData.append('admin_avatar', JSON.stringify({
|
||||
name: this.fileObject.name,
|
||||
data: this.previewAvatar,
|
||||
id: response.data.user.id
|
||||
}))
|
||||
|
||||
this.uploadOnboardAvatar(avatarData)
|
||||
}
|
||||
this.$emit('next')
|
||||
this.loading = false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
89
resources/assets/js/views/wizard/Wizard.vue
Normal file
89
resources/assets/js/views/wizard/Wizard.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col items-center justify-between w-full h-32 pt-10 step-indicator"
|
||||
>
|
||||
<img
|
||||
id="logo-crater"
|
||||
src="/assets/img/crater-logo.png"
|
||||
alt="Crater Logo"
|
||||
class="h-12"
|
||||
/>
|
||||
<sw-wizard
|
||||
:steps="7"
|
||||
:currentStep.sync="step"
|
||||
:allow-navigation-redirect="false"
|
||||
>
|
||||
<component :is="tab" @next="setTab" />
|
||||
</sw-wizard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SystemRequirement from './WizardSystemRequirementStep'
|
||||
import Permission from './WizardPermissionStep'
|
||||
import Database from './WizardDatabaseStep'
|
||||
import EmailConfiguration from './WizardEmailConfigStep'
|
||||
import UserProfile from './WizardUserProfileStep'
|
||||
import CompanyInfo from './WizardCompanyInfoStep'
|
||||
import Settings from './WizardSettingsStep'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
step_1: SystemRequirement,
|
||||
step_2: Permission,
|
||||
step_3: Database,
|
||||
step_4: EmailConfiguration,
|
||||
step_5: UserProfile,
|
||||
step_6: CompanyInfo,
|
||||
step_7: Settings,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
profile_complete: null,
|
||||
loading: false,
|
||||
tab: 'step_1',
|
||||
step: 1,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getProfileComplete()
|
||||
},
|
||||
methods: {
|
||||
async getProfileComplete() {
|
||||
let response = await axios.get('/api/v1/onboarding/wizard-step')
|
||||
|
||||
if (response.data.profile_complete === 'COMPLETED') {
|
||||
this.$router.push('/admin/dashboard')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let dbStep = parseInt(response.data.profile_complete)
|
||||
|
||||
if (dbStep) {
|
||||
this.step = dbStep + 1
|
||||
this.tab = `step_${dbStep + 1}`
|
||||
}
|
||||
},
|
||||
async setProfileComplete(data) {
|
||||
let status = {
|
||||
profile_complete: data,
|
||||
}
|
||||
|
||||
let response = await axios.post('/api/v1/onboarding/wizard-step', status)
|
||||
},
|
||||
async setTab(data) {
|
||||
if (data) {
|
||||
this.setProfileComplete(data)
|
||||
}
|
||||
this.step++
|
||||
|
||||
if (this.step <= 7) {
|
||||
this.tab = 'step_' + this.step
|
||||
} else {
|
||||
// window.location.reload()
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
324
resources/assets/js/views/wizard/WizardCompanyInfoStep.vue
Normal file
324
resources/assets/js/views/wizard/WizardCompanyInfoStep.vue
Normal file
@@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<sw-wizard-step
|
||||
:title="$t('wizard.company_info')"
|
||||
:description="$t('wizard.company_info_desc')"
|
||||
>
|
||||
<base-loader v-if="isFetching" :show-bg-overlay="true" />
|
||||
<form action="" @submit.prevent="next()">
|
||||
<div>
|
||||
<div class="grid grid-cols-1 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group :label="$tc('settings.company_info.company_logo')">
|
||||
<div
|
||||
id="logo-box"
|
||||
class="relative flex items-center justify-center h-24 p-5 mt-2 bg-transparent border-2 border-gray-200 border-dashed rounded-md image-upload-box"
|
||||
>
|
||||
<img
|
||||
v-if="previewLogo"
|
||||
:src="previewLogo"
|
||||
class="absolute opacity-100 preview-logo"
|
||||
style="max-height: 80%; animation: fadeIn 2s ease"
|
||||
/>
|
||||
<div v-else class="flex flex-col items-center">
|
||||
<cloud-upload-icon
|
||||
class="h-5 mb-2 text-xl leading-6 text-gray-400"
|
||||
/>
|
||||
<p class="text-xs leading-4 text-center text-gray-400">
|
||||
Drag a file here or
|
||||
<span id="pick-avatar" class="cursor-pointer text-primary-500"
|
||||
>browse</span
|
||||
>
|
||||
to choose a file
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<sw-avatar
|
||||
trigger="#logo-box"
|
||||
:preview-avatar="previewLogo"
|
||||
@changed="onChange"
|
||||
@uploadHandler="onUploadHandler"
|
||||
@handleUploadError="onHandleUploadError"
|
||||
>
|
||||
<template v-slot:icon>
|
||||
<cloud-upload-icon
|
||||
class="h-5 mb-2 text-xl leading-6 text-gray-400"
|
||||
/>
|
||||
</template>
|
||||
</sw-avatar>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.company_name')"
|
||||
:error="companyNameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.companyData.name.$error"
|
||||
v-model.trim="companyData.name"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.companyData.name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
<sw-input-group
|
||||
:label="$t('wizard.country')"
|
||||
:error="countryError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="country"
|
||||
:class="{ error: $v.companyData.country_id.$error }"
|
||||
:options="countries"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('general.select_country')"
|
||||
track-by="id"
|
||||
label="name"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group :label="$t('wizard.state')">
|
||||
<sw-input v-model="companyData.state" name="state" type="text" />
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group :label="$t('wizard.city')">
|
||||
<sw-input v-model="companyData.city" name="city" type="text" />
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<div>
|
||||
<sw-input-group
|
||||
:label="$t('wizard.address')"
|
||||
:error="address1Error"
|
||||
>
|
||||
<sw-textarea
|
||||
:invalid="$v.companyData.address_street_1.$error"
|
||||
v-model.trim="companyData.address_street_1"
|
||||
:placeholder="$t('general.street_1')"
|
||||
name="billing_street1"
|
||||
rows="2"
|
||||
@input="$v.companyData.address_street_1.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group :error="address2Error" class="mt-1 lg:mt-2 md:mt-2">
|
||||
<sw-textarea
|
||||
:invalid="$v.companyData.address_street_2.$error"
|
||||
v-model="companyData.address_street_2"
|
||||
:placeholder="$t('general.street_2')"
|
||||
name="billing_street2"
|
||||
rows="2"
|
||||
@input="$v.companyData.address_street_2.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<sw-input-group :label="$t('wizard.zip_code')">
|
||||
<sw-input v-model.trim="companyData.zip" type="text" name="zip" />
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group :label="$t('wizard.phone')" class="mt-4">
|
||||
<sw-input
|
||||
v-model.trim="companyData.phone"
|
||||
type="text"
|
||||
name="phone"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<sw-button
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
class="mt-4"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
>
|
||||
<save-icon v-if="!isLoading" class="mr-2" />
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</sw-wizard-step>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CloudUploadIcon } from '@vue-hero-icons/solid'
|
||||
import { mapActions } from 'vuex'
|
||||
const { required, maxLength } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CloudUploadIcon
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
companyData: {
|
||||
logo: '',
|
||||
name: null,
|
||||
address_street_1: '',
|
||||
address_street_2: '',
|
||||
city: '',
|
||||
state: '',
|
||||
country_id: '',
|
||||
zip: '',
|
||||
phone: '',
|
||||
},
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
step: 1,
|
||||
countries: [],
|
||||
country: null,
|
||||
previewLogo: null,
|
||||
fileObject: null,
|
||||
cropperOutputMime: '',
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
companyData: {
|
||||
name: {
|
||||
required,
|
||||
},
|
||||
country_id: {
|
||||
required,
|
||||
},
|
||||
address_street_1: {
|
||||
maxLength: maxLength(255),
|
||||
},
|
||||
address_street_2: {
|
||||
maxLength: maxLength(255),
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
country({ id }) {
|
||||
this.companyData.country_id = id
|
||||
return true
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
companyNameError() {
|
||||
if (!this.$v.companyData.name.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.companyData.name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
countryError() {
|
||||
if (!this.$v.companyData.country_id.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.companyData.country_id.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
address1Error() {
|
||||
if (!this.$v.companyData.address_street_1.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.companyData.address_street_1.maxLength) {
|
||||
return this.$t('validation.description_maxlength')
|
||||
}
|
||||
},
|
||||
address2Error() {
|
||||
if (!this.$v.companyData.address_street_2.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.companyData.address_street_2.maxLength) {
|
||||
return this.$t('validation.description_maxlength')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchCountries()
|
||||
},
|
||||
methods: {
|
||||
...mapActions('company', ['setSelectedCompany']),
|
||||
|
||||
onUploadHandler(cropper) {
|
||||
this.previewLogo = cropper
|
||||
.getCroppedCanvas()
|
||||
.toDataURL(this.cropperOutputMime)
|
||||
},
|
||||
|
||||
onHandleUploadError() {
|
||||
window.toastr['error']('Oops! Something went wrong...')
|
||||
},
|
||||
|
||||
onChange(file) {
|
||||
this.cropperOutputMime = file.type
|
||||
this.fileObject = file
|
||||
},
|
||||
|
||||
async next() {
|
||||
this.$v.companyData.$touch()
|
||||
|
||||
if (this.$v.companyData.$invalid) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
let response = await window.axios.put('/api/v1/company', this.companyData)
|
||||
|
||||
if (response.data) {
|
||||
this.setSelectedCompany(response.data.company)
|
||||
|
||||
if (this.fileObject && this.previewLogo) {
|
||||
let logoData = new FormData()
|
||||
logoData.append(
|
||||
'company_logo',
|
||||
JSON.stringify({
|
||||
name: this.fileObject.name,
|
||||
data: this.previewLogo,
|
||||
})
|
||||
)
|
||||
|
||||
await axios.post('/api/v1/company/upload-logo', logoData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
company: response.data.company.id,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
this.$emit('next', 6)
|
||||
this.isLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
onFileChange(e) {
|
||||
var input = event.target
|
||||
this.companyData.logo = input.files[0]
|
||||
if (input.files && input.files[0]) {
|
||||
var reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
this.previewLogo = e.target.result
|
||||
}
|
||||
reader.readAsDataURL(input.files[0])
|
||||
}
|
||||
},
|
||||
|
||||
async fetchCountries() {
|
||||
this.isFetching = true
|
||||
let res = await window.axios.get('/api/v1/countries')
|
||||
if (res) {
|
||||
this.countries = res.data.countries
|
||||
}
|
||||
this.isFetching = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
103
resources/assets/js/views/wizard/WizardDatabaseStep.vue
Normal file
103
resources/assets/js/views/wizard/WizardDatabaseStep.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<sw-wizard-step
|
||||
:title="$t('wizard.database.database')"
|
||||
:description="$t('wizard.database.desc')"
|
||||
>
|
||||
<base-loader v-if="isFetching" :show-bg-overlay="true" />
|
||||
<component
|
||||
:is="database_connection"
|
||||
:config-data="databaseData"
|
||||
:is-loading="isLoading"
|
||||
:is-fetching="isFetching"
|
||||
@on-change-driver="getDatabaseConfig"
|
||||
@submit-data="next"
|
||||
/>
|
||||
</sw-wizard-step>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { validationMixin } from 'vuelidate'
|
||||
import Mysql from './database/MysqlDatabase'
|
||||
import Pgsql from './database/PgsqlDatabase'
|
||||
import Sqlite from './database/SqliteDatabase'
|
||||
import Sqlsrv from './database/SqlsrvDatabase'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Mysql,
|
||||
Pgsql,
|
||||
Sqlite,
|
||||
Sqlsrv,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
databaseData: {
|
||||
database_connection: 'mysql',
|
||||
},
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
database_connection: 'mysql',
|
||||
connections: ['sqlite', 'mysql', 'pgsql', 'sqlsrv'],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDatabaseConfig(this.database_connection)
|
||||
},
|
||||
methods: {
|
||||
async getDatabaseConfig(connection) {
|
||||
this.isLoading = this.isFetching = true
|
||||
|
||||
let params = {
|
||||
connection,
|
||||
}
|
||||
|
||||
let response = await window.axios.get(
|
||||
'/api/v1/onboarding/database/config',
|
||||
{ params }
|
||||
)
|
||||
|
||||
if (response.data.success) {
|
||||
this.databaseData = response.data.config
|
||||
this.database_connection = connection
|
||||
this.databaseData.database_connection = connection
|
||||
this.isLoading = this.isFetching = false
|
||||
}
|
||||
},
|
||||
async next(databaseData) {
|
||||
this.isLoading = this.isFetching = true
|
||||
try {
|
||||
await window.axios.get('/sanctum/csrf-cookie')
|
||||
|
||||
let response = await window.axios.post(
|
||||
'/api/v1/onboarding/database/config',
|
||||
databaseData
|
||||
)
|
||||
|
||||
await window.axios.get('/sanctum/csrf-cookie')
|
||||
|
||||
if (response.data.success) {
|
||||
await window.axios.post('/api/v1/onboarding/finish')
|
||||
|
||||
this.$emit('next', 3)
|
||||
|
||||
window.toastr['success'](
|
||||
this.$t('wizard.success.' + response.data.success)
|
||||
)
|
||||
|
||||
return true
|
||||
} else if (response.data.error) {
|
||||
window.toastr['error'](
|
||||
this.$t('wizard.errors.' + response.data.error)
|
||||
)
|
||||
} else if (response.data.error_message) {
|
||||
window.toastr['error'](response.data.error_message)
|
||||
}
|
||||
} catch (e) {
|
||||
window.toastr['error'](e.response.data.message)
|
||||
} finally {
|
||||
this.isLoading = this.isFetching = false
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
87
resources/assets/js/views/wizard/WizardEmailConfigStep.vue
Normal file
87
resources/assets/js/views/wizard/WizardEmailConfigStep.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<sw-wizard-step
|
||||
:title="$t('wizard.mail.mail_config')"
|
||||
:description="$t('wizard.mail.mail_config_desc')"
|
||||
>
|
||||
<base-loader v-if="isFetching" :show-bg-overlay="true" />
|
||||
<form action="" @submit.prevent="next()">
|
||||
<component
|
||||
:is="mail_driver"
|
||||
:config-data="mailConfigData"
|
||||
:loading="isLoading"
|
||||
:mail-drivers="mail_drivers"
|
||||
@on-change-driver="
|
||||
(val) => (mail_driver = mailConfigData.mail_driver = val)
|
||||
"
|
||||
@submit-data="next"
|
||||
/>
|
||||
</form>
|
||||
</sw-wizard-step>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Smtp from './mail-driver/SmtpMailDriver'
|
||||
import Mailgun from './mail-driver/MailgunMailDriver'
|
||||
import Ses from './mail-driver/SesMailDriver'
|
||||
import Basic from './mail-driver/BasicMailDriver'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Smtp,
|
||||
Mailgun,
|
||||
Ses,
|
||||
sendmail: Basic,
|
||||
mail: Basic,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mailConfigData: {
|
||||
mail_driver: 'mail',
|
||||
},
|
||||
mail_driver: 'mail',
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
mail_drivers: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getMailDrivers()
|
||||
},
|
||||
methods: {
|
||||
async getMailDrivers() {
|
||||
this.isLoading = this.isFetching = true
|
||||
|
||||
let response = await window.axios.get('/api/v1/mail/drivers')
|
||||
|
||||
if (response.data) {
|
||||
this.mail_drivers = response.data
|
||||
this.isLoading = this.isFetching = false
|
||||
}
|
||||
},
|
||||
async next(mailConfigData) {
|
||||
this.isLoading = this.isFetching = true
|
||||
try {
|
||||
let response = await window.axios.post(
|
||||
'/api/v1/mail/config',
|
||||
mailConfigData
|
||||
)
|
||||
if (response.data.success) {
|
||||
this.$emit('next', 4)
|
||||
window.toastr['success'](
|
||||
this.$t('wizard.success.' + response.data.success)
|
||||
)
|
||||
} else {
|
||||
window.toastr['error'](
|
||||
this.$t('wizard.errors.' + response.data.error)
|
||||
)
|
||||
}
|
||||
this.isLoading = this.isFetching = false
|
||||
return true
|
||||
} catch (e) {
|
||||
this.isLoading = this.isFetching = false
|
||||
window.toastr['error']('Something went wrong')
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
103
resources/assets/js/views/wizard/WizardPermissionStep.vue
Normal file
103
resources/assets/js/views/wizard/WizardPermissionStep.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<sw-wizard-step
|
||||
:title="$t('wizard.permissions.permissions')"
|
||||
:description="$t('wizard.permissions.permission_desc')"
|
||||
>
|
||||
<base-loader v-if="isFetching" :show-bg-overlay="true" />
|
||||
<div class="relative">
|
||||
<div
|
||||
v-for="(permission, index) in permissions"
|
||||
:key="index"
|
||||
class="border border-gray-200"
|
||||
>
|
||||
<div class="grid grid-flow-row grid-cols-3 lg:gap-24 sm:gap-4">
|
||||
<div class="col-span-2 p-3">
|
||||
{{ permission.folder }}
|
||||
</div>
|
||||
<div class="p-3 text-right">
|
||||
<span
|
||||
v-if="permission.isSet"
|
||||
class="inline-block w-4 h-4 ml-3 mr-2 rounded-full bg-success"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="inline-block w-4 h-4 ml-3 mr-2 rounded-full bg-danger"
|
||||
/>
|
||||
<span>{{ permission.permission }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<sw-button
|
||||
v-show="!isFetching"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
class="mt-10"
|
||||
variant="primary"
|
||||
@click="next"
|
||||
>
|
||||
{{ $t('wizard.continue') }}
|
||||
<arrow-right-icon class="h-5 ml-2 -mr-1" />
|
||||
</sw-button>
|
||||
</div>
|
||||
</sw-wizard-step>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ArrowRightIcon } from '@vue-hero-icons/solid'
|
||||
export default {
|
||||
components: {
|
||||
ArrowRightIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isFetching: false,
|
||||
isLoading: false,
|
||||
permissions: [],
|
||||
errors: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getPermissions()
|
||||
},
|
||||
methods: {
|
||||
async getPermissions() {
|
||||
this.isLoading = this.isFetching = true
|
||||
|
||||
let response = await window.axios.get(
|
||||
'/api/v1/onboarding/permissions',
|
||||
this.profileData
|
||||
)
|
||||
|
||||
if (response.data) {
|
||||
this.permissions = response.data.permissions.permissions
|
||||
this.errors = response.data.permissions.errors
|
||||
let self = this
|
||||
|
||||
if (this.errors) {
|
||||
swal({
|
||||
title: this.$t('wizard.permissions.permission_confirm_title'),
|
||||
text: this.$t('wizard.permissions.permission_confirm_desc'),
|
||||
icon: 'warning',
|
||||
buttons: true,
|
||||
dangerMode: true,
|
||||
}).then(async (willConfirm) => {
|
||||
if (willConfirm) {
|
||||
self.isLoading = this.isFetching = false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isLoading = this.isFetching = false
|
||||
}
|
||||
|
||||
this.isLoading = this.isFetching = false
|
||||
}
|
||||
},
|
||||
async next() {
|
||||
this.isLoading = true
|
||||
await this.$emit('next')
|
||||
this.isLoading = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
297
resources/assets/js/views/wizard/WizardSettingsStep.vue
Normal file
297
resources/assets/js/views/wizard/WizardSettingsStep.vue
Normal file
@@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<sw-wizard-step
|
||||
:title="$t('wizard.preferences')"
|
||||
:description="$t('wizard.preferences_desc')"
|
||||
>
|
||||
<base-loader v-if="isFetching" :show-bg-overlay="true" />
|
||||
<form action="" @submit.prevent="next">
|
||||
<div>
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.currency')"
|
||||
:error="currencyError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="settingData.currency"
|
||||
:class="{ error: $v.settingData.currency.$error }"
|
||||
:options="currencies"
|
||||
:custom-label="currencyNameWithCode"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.currencies.select_currency')"
|
||||
track-by="id"
|
||||
label="name"
|
||||
@input="$v.settingData.currency.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('settings.preferences.default_language')"
|
||||
:error="languageError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="settingData.language"
|
||||
:class="{ error: $v.settingData.language.$error }"
|
||||
:options="languages"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.preferences.select_language')"
|
||||
label="name"
|
||||
@input="$v.settingData.language.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.date_format')"
|
||||
:error="dateFormatError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="settingData.dateFormat"
|
||||
:class="{ error: $v.settingData.dateFormat.$error }"
|
||||
:options="dateFormats"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.preferences.select_date_format')"
|
||||
label="display_date"
|
||||
@input="$v.settingData.dateFormat.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.time_zone')"
|
||||
:error="timeZoneError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="settingData.timeZone"
|
||||
:class="{ error: $v.settingData.timeZone.$error }"
|
||||
:options="timeZones"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.preferences.select_time_zone')"
|
||||
label="key"
|
||||
@input="$v.settingData.timeZone.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.fiscal_year')"
|
||||
:error="fiscalYearError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="settingData.fiscalYear"
|
||||
:class="{ error: $v.settingData.fiscalYear.$error }"
|
||||
:options="fiscalYears"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('settings.preferences.select_financial_year')"
|
||||
label="key"
|
||||
@input="$v.settingData.fiscalYear.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<sw-button
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
>
|
||||
<save-icon v-if="!isLoading" class="mr-2" />
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</sw-wizard-step>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Ls from '../../services/ls'
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
|
||||
const { required, minLength, email } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
settingData: {
|
||||
language: null,
|
||||
currency: null,
|
||||
timeZone: null,
|
||||
dateFormat: null,
|
||||
fiscalYear: null,
|
||||
},
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
step: 1,
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
settingData: {
|
||||
currency: {
|
||||
required,
|
||||
},
|
||||
language: {
|
||||
required,
|
||||
},
|
||||
dateFormat: {
|
||||
required,
|
||||
},
|
||||
timeZone: {
|
||||
required,
|
||||
},
|
||||
fiscalYear: {
|
||||
required,
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'languages',
|
||||
'currencies',
|
||||
'timeZones',
|
||||
'dateFormats',
|
||||
'fiscalYears',
|
||||
]),
|
||||
|
||||
...mapGetters('company', ['defaultFiscalYear', 'defaultTimeZone']),
|
||||
currencyError() {
|
||||
if (!this.$v.settingData.currency.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.settingData.currency.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
languageError() {
|
||||
if (!this.$v.settingData.language.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.settingData.language.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
dateFormatError() {
|
||||
if (!this.$v.settingData.dateFormat.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.settingData.dateFormat.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
timeZoneError() {
|
||||
if (!this.$v.settingData.timeZone.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.settingData.timeZone.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
fiscalYearError() {
|
||||
if (!this.$v.settingData.fiscalYear.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.settingData.fiscalYear.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// this.getOnboardingData()
|
||||
this.setInitialData()
|
||||
},
|
||||
methods: {
|
||||
...mapActions('company', ['updateCompanySettings', 'setSelectedCompany']),
|
||||
...mapActions([
|
||||
'fetchLanguages',
|
||||
'fetchCurrencies',
|
||||
'fetchFiscalYears',
|
||||
'fetchDateFormats',
|
||||
'fetchTimeZones',
|
||||
]),
|
||||
async setInitialData() {
|
||||
this.isFetching = true
|
||||
await this.fetchCurrencies()
|
||||
await this.fetchDateFormats()
|
||||
await this.fetchLanguages()
|
||||
await this.fetchFiscalYears()
|
||||
await this.fetchTimeZones()
|
||||
await this.fetchLanguages()
|
||||
|
||||
this.settingData.currency = this.currencies.find(
|
||||
(currency) => currency.id === 1
|
||||
)
|
||||
this.settingData.language = this.languages.find(
|
||||
(language) => language.code === 'en'
|
||||
)
|
||||
this.settingData.dateFormat = this.dateFormats.find(
|
||||
(dateFormat) => dateFormat.carbon_format_value == 'd M Y'
|
||||
)
|
||||
|
||||
this.settingData.timeZone = this.timeZones.find(
|
||||
(timeZone) => timeZone.value === 'UTC'
|
||||
)
|
||||
|
||||
this.settingData.fiscalYear = this.fiscalYears.find(
|
||||
(fiscalYear) => fiscalYear.value === '1-12'
|
||||
)
|
||||
this.isFetching = false
|
||||
},
|
||||
currencyNameWithCode({ name, code }) {
|
||||
return `${code} - ${name}`
|
||||
},
|
||||
async next() {
|
||||
this.$v.settingData.$touch()
|
||||
|
||||
if (this.$v.settingData.$invalid) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
let data = {
|
||||
settings: {
|
||||
currency: this.settingData.currency.id,
|
||||
time_zone: this.settingData.timeZone.value,
|
||||
language: this.settingData.language.code,
|
||||
fiscal_year: this.settingData.fiscalYear.value,
|
||||
carbon_date_format: this.settingData.dateFormat.carbon_format_value,
|
||||
moment_date_format: this.settingData.dateFormat.moment_format_value,
|
||||
},
|
||||
}
|
||||
|
||||
let response = await this.updateCompanySettings(data)
|
||||
|
||||
if (response.data) {
|
||||
this.isLoading = false
|
||||
this.updateUserSettings()
|
||||
Ls.set('auth.token', response.data.token)
|
||||
}
|
||||
},
|
||||
async updateUserSettings() {
|
||||
let data = {
|
||||
settings: {
|
||||
language: this.settingData.language.code,
|
||||
},
|
||||
}
|
||||
|
||||
let response = await axios.put('/api/v1/me/settings', data)
|
||||
|
||||
if (response.data) {
|
||||
this.$emit('next', 'COMPLETED')
|
||||
window.toastr['success']('Login Successful')
|
||||
this.$router.push('/admin/dashboard')
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
129
resources/assets/js/views/wizard/WizardSystemRequirementStep.vue
Normal file
129
resources/assets/js/views/wizard/WizardSystemRequirementStep.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<sw-wizard-step
|
||||
:title="$t('wizard.req.system_req')"
|
||||
:description="$t('wizard.req.system_req_desc')"
|
||||
>
|
||||
<div class="w-full md:w-2/3">
|
||||
<div class="mb-6">
|
||||
<div
|
||||
v-if="phpSupportInfo"
|
||||
class="grid grid-flow-row grid-cols-3 p-3 border border-gray-200 lg:gap-24 sm:gap-4"
|
||||
>
|
||||
<div class="col-span-2 text-sm">
|
||||
{{
|
||||
$t('wizard.req.php_req_version', {
|
||||
version: phpSupportInfo.minimum,
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
<div class="text-right">
|
||||
{{ phpSupportInfo.current }}
|
||||
<span
|
||||
v-if="phpSupportInfo.supported"
|
||||
class="inline-block w-4 h-4 ml-3 mr-2 rounded-full bg-success"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="inline-block w-4 h-4 ml-3 mr-2 rounded-full bg-danger"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="requirements">
|
||||
<div
|
||||
v-for="(requirement, index) in requirements"
|
||||
:key="index"
|
||||
class="grid grid-flow-row grid-cols-3 p-3 border border-gray-200 lg:gap-24 sm:gap-4"
|
||||
>
|
||||
<div class="col-span-2 text-sm">
|
||||
{{ index }}
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span
|
||||
v-if="requirement"
|
||||
class="inline-block w-4 h-4 ml-3 mr-2 rounded-full bg-success"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="inline-block w-4 h-4 ml-3 mr-2 rounded-full bg-danger"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<sw-button
|
||||
v-if="hasNext"
|
||||
class="mt-4 pull-right"
|
||||
variant="primary"
|
||||
@click="next"
|
||||
>
|
||||
{{ $t('wizard.continue') }}
|
||||
<arrow-right-icon class="h-5 ml-2 -mr-1" />
|
||||
</sw-button>
|
||||
<sw-button
|
||||
v-if="!requirements"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
class="mt-4"
|
||||
variant="primary"
|
||||
@click="getRequirements"
|
||||
>
|
||||
{{ $t('wizard.req.check_req') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</sw-wizard-step>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ArrowRightIcon } from '@vue-hero-icons/solid'
|
||||
export default {
|
||||
components: {
|
||||
ArrowRightIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
requirements: null,
|
||||
phpSupportInfo: null,
|
||||
isLoading: false,
|
||||
isShow: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasNext() {
|
||||
if (this.requirements) {
|
||||
let isRequired = true
|
||||
for (const key in this.requirements) {
|
||||
if (!this.requirements[key]) {
|
||||
isRequired = false
|
||||
}
|
||||
}
|
||||
return this.requirements && this.phpSupportInfo.supported && isRequired
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
listToggle() {
|
||||
this.isShow = !this.isShow
|
||||
},
|
||||
async getRequirements() {
|
||||
this.isLoading = true
|
||||
|
||||
let response = await window.axios.get(
|
||||
'/api/v1/onboarding/requirements',
|
||||
this.profileData
|
||||
)
|
||||
|
||||
if (response.data) {
|
||||
this.requirements = response.data.requirements.requirements.php
|
||||
this.phpSupportInfo = response.data.phpSupportInfo
|
||||
this.isLoading = false
|
||||
}
|
||||
},
|
||||
async next() {
|
||||
this.isLoading = true
|
||||
await this.$emit('next')
|
||||
this.isLoading = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
265
resources/assets/js/views/wizard/WizardUserProfileStep.vue
Normal file
265
resources/assets/js/views/wizard/WizardUserProfileStep.vue
Normal file
@@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<sw-wizard-step
|
||||
:title="$t('wizard.account_info')"
|
||||
:description="$t('wizard.account_info_desc')"
|
||||
>
|
||||
<form action="" @submit.prevent="next()">
|
||||
<div class="grid grid-cols-1 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$tc('settings.account_settings.profile_picture')"
|
||||
>
|
||||
<sw-avatar
|
||||
:preview-avatar="previewAvatar"
|
||||
:label="$tc('general.choose_file')"
|
||||
@changed="onChange"
|
||||
@uploadHandler="onUploadHandler"
|
||||
@handleUploadError="onHandleUploadError"
|
||||
>
|
||||
<template v-slot:icon>
|
||||
<cloud-upload-icon
|
||||
class="h-5 mb-2 text-xl leading-6 text-gray-400"
|
||||
/>
|
||||
</template>
|
||||
</sw-avatar>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group :label="$t('wizard.name')" :error="nameError" required>
|
||||
<sw-input
|
||||
:invalid="$v.profileData.name.$error"
|
||||
v-model.trim="profileData.name"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.profileData.name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.email')"
|
||||
:error="emailError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.profileData.email.$error"
|
||||
v-model.trim="profileData.email"
|
||||
type="text"
|
||||
name="email"
|
||||
@input="$v.profileData.email.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.password')"
|
||||
:error="passwordError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.profileData.password.$error"
|
||||
v-model.trim="profileData.password"
|
||||
type="password"
|
||||
name="password"
|
||||
@input="$v.profileData.password.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.confirm_password')"
|
||||
:error="confirmPasswordError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.profileData.confirm_password.$error"
|
||||
v-model.trim="profileData.confirm_password"
|
||||
type="password"
|
||||
name="confirm_password"
|
||||
@input="$v.profileData.confirm_password.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<sw-button
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
>
|
||||
<save-icon v-if="!isLoading" class="mr-2" />
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</sw-button>
|
||||
</form>
|
||||
</sw-wizard-step>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CloudUploadIcon } from '@vue-hero-icons/solid'
|
||||
import { mapActions } from 'vuex'
|
||||
const {
|
||||
required,
|
||||
requiredIf,
|
||||
sameAs,
|
||||
minLength,
|
||||
email,
|
||||
} = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CloudUploadIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
profileData: {
|
||||
name: null,
|
||||
email: null,
|
||||
password: null,
|
||||
confirm_password: null,
|
||||
},
|
||||
isLoading: false,
|
||||
previewAvatar: '/images/default-avatar.jpg',
|
||||
fileObject: null,
|
||||
cropperOutputMime: '',
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
profileData: {
|
||||
name: {
|
||||
required,
|
||||
minLength: minLength(3),
|
||||
},
|
||||
email: {
|
||||
email,
|
||||
required,
|
||||
},
|
||||
password: {
|
||||
required,
|
||||
minLength: minLength(8),
|
||||
},
|
||||
confirm_password: {
|
||||
required: requiredIf('isRequired'),
|
||||
sameAsPassword: sameAs('password'),
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
emailError() {
|
||||
if (!this.$v.profileData.email.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.profileData.email.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.profileData.email.email) {
|
||||
return this.$tc('validation.email_incorrect')
|
||||
}
|
||||
},
|
||||
nameError() {
|
||||
if (!this.$v.profileData.name.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.profileData.name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.profileData.name.minLength) {
|
||||
return this.$tc(
|
||||
'validation.name_min_length',
|
||||
this.$v.profileData.name.$params.minLength.min,
|
||||
{ count: this.$v.profileData.name.$params.minLength.min }
|
||||
)
|
||||
}
|
||||
},
|
||||
passwordError() {
|
||||
if (!this.$v.profileData.password.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.profileData.password.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
if (!this.$v.profileData.password.minLength) {
|
||||
return this.$tc(
|
||||
'validation.password_min_length',
|
||||
this.$v.profileData.password.$params.minLength.min,
|
||||
{ count: this.$v.profileData.password.$params.minLength.min }
|
||||
)
|
||||
}
|
||||
},
|
||||
confirmPasswordError() {
|
||||
if (!this.$v.profileData.confirm_password.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.profileData.confirm_password.sameAsPassword) {
|
||||
return this.$tc('validation.password_incorrect')
|
||||
}
|
||||
},
|
||||
isRequired() {
|
||||
if (
|
||||
this.profileData.password === null ||
|
||||
this.profileData.password === undefined ||
|
||||
this.profileData.password === ''
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('user', ['uploadAvatar']),
|
||||
onUploadHandler(cropper) {
|
||||
this.previewAvatar = cropper
|
||||
.getCroppedCanvas()
|
||||
.toDataURL(this.cropperOutputMime)
|
||||
},
|
||||
onHandleUploadError() {
|
||||
window.toastr['error']('Oops! Something went wrong...')
|
||||
},
|
||||
onChange(file) {
|
||||
this.cropperOutputMime = file.type
|
||||
this.fileObject = file
|
||||
},
|
||||
async next() {
|
||||
this.$v.profileData.$touch()
|
||||
if (this.$v.profileData.$invalid) {
|
||||
return true
|
||||
}
|
||||
this.isLoading = true
|
||||
let response = await window.axios.put('/api/v1/me', this.profileData)
|
||||
|
||||
if (response.data) {
|
||||
if (this.fileObject && this.previewAvatar) {
|
||||
let avatarData = new FormData()
|
||||
avatarData.append(
|
||||
'admin_avatar',
|
||||
JSON.stringify({
|
||||
name: this.fileObject.name,
|
||||
data: this.previewAvatar,
|
||||
id: response.data.user.id,
|
||||
})
|
||||
)
|
||||
|
||||
this.uploadAvatar(avatarData)
|
||||
}
|
||||
this.$emit('next', 5)
|
||||
this.isLoading = false
|
||||
}
|
||||
return true
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.avatar-upload {
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
306
resources/assets/js/views/wizard/database/MysqlDatabase.vue
Normal file
306
resources/assets/js/views/wizard/database/MysqlDatabase.vue
Normal file
@@ -0,0 +1,306 @@
|
||||
<template>
|
||||
<form action="" @submit.prevent="next()">
|
||||
<div>
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.app_url')"
|
||||
:error="urlError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.app_url.$error"
|
||||
v-model.trim="databaseData.app_url"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.databaseData.app_url.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.app_domain')"
|
||||
:error="domainError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.app_domain.$error"
|
||||
v-model.trim="databaseData.app_domain"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="crater.com"
|
||||
@input="$v.databaseData.app_domain.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.connection')"
|
||||
:error="connectionError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="databaseData.database_connection"
|
||||
:invalid="$v.databaseData.database_connection.$error"
|
||||
:options="connections"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
@input="onChangeConnection"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.port')"
|
||||
:error="portError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_port.$error"
|
||||
v-model.trim="databaseData.database_port"
|
||||
type="text"
|
||||
name="database_port"
|
||||
@input="$v.databaseData.database_port.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.db_name')"
|
||||
:error="nameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_name.$error"
|
||||
v-model.trim="databaseData.database_name"
|
||||
type="text"
|
||||
name="database_name"
|
||||
@input="$v.databaseData.database_name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.username')"
|
||||
:error="usernameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_username.$error"
|
||||
v-model.trim="databaseData.database_username"
|
||||
type="text"
|
||||
name="database_username"
|
||||
@input="$v.databaseData.database_username.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group :label="$t('wizard.database.password')">
|
||||
<sw-input
|
||||
v-model.trim="databaseData.database_password"
|
||||
type="password"
|
||||
name="name"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.host')"
|
||||
:error="hostnameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_hostname.$error"
|
||||
v-model.trim="databaseData.database_hostname"
|
||||
type="text"
|
||||
name="database_hostname"
|
||||
@input="$v.databaseData.database_hostname.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<sw-button
|
||||
v-show="!isFetching"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
variant="primary"
|
||||
class="mt-4"
|
||||
type="submit"
|
||||
>
|
||||
<save-icon v-if="!isLoading" class="h-5 mr-2" />
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { SaveIcon } from '@vue-hero-icons/outline'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, numeric, url } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SaveIcon,
|
||||
},
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
isFetching: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
databaseData: {
|
||||
database_connection: 'mysql',
|
||||
database_hostname: '127.0.0.1',
|
||||
database_port: '3306',
|
||||
database_name: null,
|
||||
database_username: null,
|
||||
database_password: null,
|
||||
app_url: window.location.origin,
|
||||
app_domain: window.location.origin.replace(/(^\w+:|^)\/\//, ''),
|
||||
},
|
||||
connections: ['sqlite', 'mysql', 'pgsql', 'sqlsrv'],
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
databaseData: {
|
||||
database_connection: {
|
||||
required,
|
||||
},
|
||||
database_hostname: {
|
||||
required,
|
||||
},
|
||||
database_port: {
|
||||
required,
|
||||
numeric,
|
||||
},
|
||||
database_name: {
|
||||
required,
|
||||
},
|
||||
database_username: {
|
||||
required,
|
||||
},
|
||||
app_url: {
|
||||
required,
|
||||
isUrl(val) {
|
||||
return this.$utils.checkValidUrl(val)
|
||||
},
|
||||
},
|
||||
app_domain: {
|
||||
required,
|
||||
isUrl(val) {
|
||||
return this.$utils.checkValidDomainUrl(val)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
urlError() {
|
||||
if (!this.$v.databaseData.app_url.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_url.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_url.isUrl) {
|
||||
return this.$tc('validation.invalid_url')
|
||||
}
|
||||
},
|
||||
domainError() {
|
||||
if (!this.$v.databaseData.app_domain.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_domain.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_domain.isUrl) {
|
||||
return this.$tc('validation.invalid_domain_url')
|
||||
}
|
||||
},
|
||||
connectionError() {
|
||||
if (!this.$v.databaseData.database_connection.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_connection.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
portError() {
|
||||
if (!this.$v.databaseData.database_port.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_port.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_port.numeric) {
|
||||
return this.$tc('validation.numbers_only')
|
||||
}
|
||||
},
|
||||
nameError() {
|
||||
if (!this.$v.databaseData.database_name.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
usernameError() {
|
||||
if (!this.$v.databaseData.database_username.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_username.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
hostnameError() {
|
||||
if (!this.$v.databaseData.database_hostname.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_hostname.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const key in this.databaseData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.databaseData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async next() {
|
||||
this.$v.databaseData.$touch()
|
||||
if (!this.$v.databaseData.$invalid) {
|
||||
this.$emit('submit-data', this.databaseData)
|
||||
}
|
||||
return false
|
||||
},
|
||||
onChangeConnection() {
|
||||
this.$v.databaseData.database_connection.$touch()
|
||||
this.$emit('on-change-driver', this.databaseData.database_connection)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
306
resources/assets/js/views/wizard/database/PgsqlDatabase.vue
Normal file
306
resources/assets/js/views/wizard/database/PgsqlDatabase.vue
Normal file
@@ -0,0 +1,306 @@
|
||||
<template>
|
||||
<form action="" @submit.prevent="next()">
|
||||
<div>
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.app_url')"
|
||||
:error="urlError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.app_url.$error"
|
||||
v-model.trim="databaseData.app_url"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.databaseData.app_url.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.app_domain')"
|
||||
:error="domainError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.app_domain.$error"
|
||||
v-model.trim="databaseData.app_domain"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="crater.com"
|
||||
@input="$v.databaseData.app_domain.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.connection')"
|
||||
:error="connectionError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="databaseData.database_connection"
|
||||
:invalid="$v.databaseData.database_connection.$error"
|
||||
:options="connections"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
@input="onChangeConnection"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.port')"
|
||||
:error="portError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_port.$error"
|
||||
v-model.trim="databaseData.database_port"
|
||||
type="text"
|
||||
name="database_port"
|
||||
@input="$v.databaseData.database_port.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.db_name')"
|
||||
:error="nameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_name.$error"
|
||||
v-model.trim="databaseData.database_name"
|
||||
type="text"
|
||||
name="database_name"
|
||||
@input="$v.databaseData.database_name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.username')"
|
||||
:error="usernameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_username.$error"
|
||||
v-model.trim="databaseData.database_username"
|
||||
type="text"
|
||||
name="database_username"
|
||||
@input="$v.databaseData.database_username.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group :label="$t('wizard.database.password')">
|
||||
<sw-input
|
||||
v-model.trim="databaseData.database_password"
|
||||
type="password"
|
||||
name="name"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.host')"
|
||||
:error="hostnameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_hostname.$error"
|
||||
v-model.trim="databaseData.database_hostname"
|
||||
type="text"
|
||||
name="database_hostname"
|
||||
@input="$v.databaseData.database_hostname.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<sw-button
|
||||
v-show="!isFetching"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
variant="primary"
|
||||
class="mt-4"
|
||||
type="submit"
|
||||
>
|
||||
<save-icon v-if="!isLoading" class="h-5 mr-2" />
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { SaveIcon } from '@vue-hero-icons/outline'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, numeric, url } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SaveIcon,
|
||||
},
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
isFetching: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
databaseData: {
|
||||
database_connection: 'mysql',
|
||||
database_hostname: '127.0.0.1',
|
||||
database_port: '3306',
|
||||
database_name: null,
|
||||
database_username: null,
|
||||
database_password: null,
|
||||
app_url: window.location.origin,
|
||||
app_domain: window.location.origin.replace(/(^\w+:|^)\/\//, ''),
|
||||
},
|
||||
connections: ['sqlite', 'mysql', 'pgsql', 'sqlsrv'],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
urlError() {
|
||||
if (!this.$v.databaseData.app_url.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_url.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_url.isUrl) {
|
||||
return this.$tc('validation.invalid_url')
|
||||
}
|
||||
},
|
||||
domainError() {
|
||||
if (!this.$v.databaseData.app_domain.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_domain.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_domain.isUrl) {
|
||||
return this.$tc('validation.invalid_domain_url')
|
||||
}
|
||||
},
|
||||
connectionError() {
|
||||
if (!this.$v.databaseData.database_connection.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_connection.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
portError() {
|
||||
if (!this.$v.databaseData.database_port.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_port.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_port.numeric) {
|
||||
return this.$tc('validation.numbers_only')
|
||||
}
|
||||
},
|
||||
nameError() {
|
||||
if (!this.$v.databaseData.database_name.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
usernameError() {
|
||||
if (!this.$v.databaseData.database_username.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_username.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
hostnameError() {
|
||||
if (!this.$v.databaseData.database_hostname.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_hostname.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
},
|
||||
validations: {
|
||||
databaseData: {
|
||||
database_connection: {
|
||||
required,
|
||||
},
|
||||
database_hostname: {
|
||||
required,
|
||||
},
|
||||
database_port: {
|
||||
required,
|
||||
numeric,
|
||||
},
|
||||
database_name: {
|
||||
required,
|
||||
},
|
||||
database_username: {
|
||||
required,
|
||||
},
|
||||
app_url: {
|
||||
required,
|
||||
isUrl(val) {
|
||||
return this.$utils.checkValidUrl(val)
|
||||
},
|
||||
},
|
||||
app_domain: {
|
||||
required,
|
||||
isUrl(val) {
|
||||
return this.$utils.checkValidDomainUrl(val)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const key in this.databaseData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.databaseData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async next() {
|
||||
this.$v.databaseData.$touch()
|
||||
if (!this.$v.databaseData.$invalid) {
|
||||
this.$emit('submit-data', this.databaseData)
|
||||
}
|
||||
return false
|
||||
},
|
||||
onChangeConnection() {
|
||||
this.$v.databaseData.database_connection.$touch()
|
||||
this.$emit('on-change-driver', this.databaseData.database_connection)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
208
resources/assets/js/views/wizard/database/SqliteDatabase.vue
Normal file
208
resources/assets/js/views/wizard/database/SqliteDatabase.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<form action="" @submit.prevent="next()">
|
||||
<div>
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.app_url')"
|
||||
:error="urlError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.app_url.$error"
|
||||
v-model.trim="databaseData.app_url"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.databaseData.app_url.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.app_domain')"
|
||||
:error="domainError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.app_domain.$error"
|
||||
v-model.trim="databaseData.app_domain"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="crater.com"
|
||||
@input="$v.databaseData.app_domain.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.connection')"
|
||||
:error="connectionError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="databaseData.database_connection"
|
||||
:invalid="$v.databaseData.database_connection.$error"
|
||||
:options="connections"
|
||||
:allow-empty="false"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
@input="onChangeConnection"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.db_path')"
|
||||
:error="nameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_name.$error"
|
||||
v-model.trim="databaseData.database_name"
|
||||
type="text"
|
||||
name="database_name"
|
||||
@input="$v.databaseData.database_name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<sw-button
|
||||
v-show="!isFetching"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
variant="primary"
|
||||
class="mt-4"
|
||||
type="submit"
|
||||
>
|
||||
<save-icon v-if="!isLoading" class="h-5 mr-2" />
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { SaveIcon } from '@vue-hero-icons/outline'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, numeric, url } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SaveIcon,
|
||||
},
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
isFetching: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
databaseData: {
|
||||
database_connection: 'mysql',
|
||||
database_name: null,
|
||||
app_url: window.location.origin,
|
||||
app_domain: window.location.origin.replace(/(^\w+:|^)\/\//, ''),
|
||||
},
|
||||
connections: ['sqlite', 'mysql', 'pgsql', 'sqlsrv'],
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
databaseData: {
|
||||
database_connection: {
|
||||
required,
|
||||
},
|
||||
database_name: {
|
||||
required,
|
||||
},
|
||||
app_url: {
|
||||
required,
|
||||
isUrl(val) {
|
||||
return this.$utils.checkValidUrl(val)
|
||||
},
|
||||
},
|
||||
app_domain: {
|
||||
required,
|
||||
isUrl(val) {
|
||||
return this.$utils.checkValidDomainUrl(val)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
urlError() {
|
||||
if (!this.$v.databaseData.app_url.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_url.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_url.isUrl) {
|
||||
return this.$tc('validation.invalid_url')
|
||||
}
|
||||
},
|
||||
domainError() {
|
||||
if (!this.$v.databaseData.app_domain.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_domain.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_domain.isUrl) {
|
||||
return this.$tc('validation.invalid_domain_url')
|
||||
}
|
||||
},
|
||||
connectionError() {
|
||||
if (!this.$v.databaseData.database_connection.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_connection.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
nameError() {
|
||||
if (!this.$v.databaseData.database_name.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const key in this.databaseData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.databaseData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async next() {
|
||||
this.$v.databaseData.$touch()
|
||||
if (!this.$v.databaseData.$invalid) {
|
||||
this.$emit('submit-data', this.databaseData)
|
||||
}
|
||||
return false
|
||||
},
|
||||
onChangeConnection() {
|
||||
this.$v.databaseData.database_connection.$touch()
|
||||
this.$emit('on-change-driver', this.databaseData.database_connection)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
306
resources/assets/js/views/wizard/database/SqlsrvDatabase.vue
Normal file
306
resources/assets/js/views/wizard/database/SqlsrvDatabase.vue
Normal file
@@ -0,0 +1,306 @@
|
||||
<template>
|
||||
<form action="" @submit.prevent="next()">
|
||||
<div>
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.app_url')"
|
||||
:error="urlError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.app_url.$error"
|
||||
v-model.trim="databaseData.app_url"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.databaseData.app_url.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.app_domain')"
|
||||
:error="domainError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.app_domain.$error"
|
||||
v-model.trim="databaseData.app_domain"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="crater.com"
|
||||
@input="$v.databaseData.app_domain.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.connection')"
|
||||
:error="connectionError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="databaseData.database_connection"
|
||||
:invalid="$v.databaseData.database_connection.$error"
|
||||
:options="connections"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="false"
|
||||
@input="onChangeConnection"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.port')"
|
||||
:error="portError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_port.$error"
|
||||
v-model.trim="databaseData.database_port"
|
||||
type="text"
|
||||
name="database_port"
|
||||
@input="$v.databaseData.database_port.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.db_name')"
|
||||
:error="nameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_name.$error"
|
||||
v-model.trim="databaseData.database_name"
|
||||
type="text"
|
||||
name="database_name"
|
||||
@input="$v.databaseData.database_name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.username')"
|
||||
:error="usernameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_username.$error"
|
||||
v-model.trim="databaseData.database_username"
|
||||
type="text"
|
||||
name="database_username"
|
||||
@input="$v.databaseData.database_username.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group :label="$t('wizard.database.password')">
|
||||
<sw-input
|
||||
v-model.trim="databaseData.database_password"
|
||||
type="password"
|
||||
name="name"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.database.host')"
|
||||
:error="hostnameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.databaseData.database_hostname.$error"
|
||||
v-model.trim="databaseData.database_hostname"
|
||||
type="text"
|
||||
name="database_hostname"
|
||||
@input="$v.databaseData.database_hostname.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<sw-button
|
||||
v-show="!isFetching"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
variant="primary"
|
||||
class="mt-4"
|
||||
type="submit"
|
||||
>
|
||||
<save-icon v-if="!isLoading" class="h-5 mr-2" />
|
||||
{{ $t('wizard.save_cont') }}
|
||||
</sw-button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { SaveIcon } from '@vue-hero-icons/outline'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, numeric, url } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SaveIcon,
|
||||
},
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
isFetching: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
databaseData: {
|
||||
database_connection: 'mysql',
|
||||
database_hostname: '127.0.0.1',
|
||||
database_port: '3306',
|
||||
database_name: null,
|
||||
database_username: null,
|
||||
database_password: null,
|
||||
app_url: window.location.origin,
|
||||
app_domain: window.location.origin.replace(/(^\w+:|^)\/\//, ''),
|
||||
},
|
||||
connections: ['sqlite', 'mysql', 'pgsql', 'sqlsrv'],
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
databaseData: {
|
||||
database_connection: {
|
||||
required,
|
||||
},
|
||||
database_hostname: {
|
||||
required,
|
||||
},
|
||||
database_port: {
|
||||
required,
|
||||
numeric,
|
||||
},
|
||||
database_name: {
|
||||
required,
|
||||
},
|
||||
database_username: {
|
||||
required,
|
||||
},
|
||||
app_url: {
|
||||
required,
|
||||
isUrl(val) {
|
||||
return this.$utils.checkValidUrl(val)
|
||||
},
|
||||
},
|
||||
app_domain: {
|
||||
required,
|
||||
isUrl(val) {
|
||||
return this.$utils.checkValidDomainUrl(val)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
urlError() {
|
||||
if (!this.$v.databaseData.app_url.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_url.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_url.isUrl) {
|
||||
return this.$tc('validation.invalid_url')
|
||||
}
|
||||
},
|
||||
domainError() {
|
||||
if (!this.$v.databaseData.app_domain.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_domain.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.app_domain.isUrl) {
|
||||
return this.$tc('validation.invalid_domain_url')
|
||||
}
|
||||
},
|
||||
connectionError() {
|
||||
if (!this.$v.databaseData.database_connection.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_connection.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
portError() {
|
||||
if (!this.$v.databaseData.database_port.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_port.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_port.numeric) {
|
||||
return this.$tc('validation.numbers_only')
|
||||
}
|
||||
},
|
||||
nameError() {
|
||||
if (!this.$v.databaseData.database_name.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
usernameError() {
|
||||
if (!this.$v.databaseData.database_username.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_username.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
hostnameError() {
|
||||
if (!this.$v.databaseData.database_hostname.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.databaseData.database_hostname.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const key in this.databaseData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.databaseData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async next() {
|
||||
this.$v.databaseData.$touch()
|
||||
if (!this.$v.databaseData.$invalid) {
|
||||
this.$emit('submit-data', this.databaseData)
|
||||
}
|
||||
return false
|
||||
},
|
||||
onChangeConnection() {
|
||||
this.$v.databaseData.database_connection.$touch()
|
||||
this.$emit('on-change-driver', this.databaseData.database_connection)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
160
resources/assets/js/views/wizard/mail-driver/BasicMailDriver.vue
Normal file
160
resources/assets/js/views/wizard/mail-driver/BasicMailDriver.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveEmailConfig">
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.driver')"
|
||||
:error="driverError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="mailConfigData.mail_driver"
|
||||
:invalid="$v.mailConfigData.mail_driver.$error"
|
||||
:options="mailDrivers"
|
||||
:allow-empty="false"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
@input="onChangeDriver"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.from_name')"
|
||||
:error="fromNameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.from_name.$error"
|
||||
v-model.trim="mailConfigData.from_name"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.mailConfigData.from_name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.from_mail')"
|
||||
:error="fromMailError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.from_mail.$error"
|
||||
v-model.trim="mailConfigData.from_mail"
|
||||
type="text"
|
||||
name="from_mail"
|
||||
@input="$v.mailConfigData.from_mail.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<sw-button
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
>
|
||||
<save-icon v-if="!loading" class="mr-2" />
|
||||
{{ $t('general.save') }}
|
||||
</sw-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const { required, email } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
mailDrivers: {
|
||||
type: Array,
|
||||
require: true,
|
||||
default: Array,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mailConfigData: {
|
||||
mail_driver: '',
|
||||
mail_host: '',
|
||||
from_mail: '',
|
||||
from_name: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
mailConfigData: {
|
||||
mail_driver: {
|
||||
required,
|
||||
},
|
||||
from_mail: {
|
||||
required,
|
||||
email,
|
||||
},
|
||||
from_name: {
|
||||
required,
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
driverError() {
|
||||
if (!this.$v.mailConfigData.mail_driver.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_driver.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
fromMailError() {
|
||||
if (!this.$v.mailConfigData.from_mail.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.from_mail.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.from_mail.email) {
|
||||
return this.$tc('validation.email_incorrect')
|
||||
}
|
||||
},
|
||||
fromNameError() {
|
||||
if (!this.$v.mailConfigData.from_name.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.from_name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const key in this.mailConfigData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.mailConfigData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveEmailConfig() {
|
||||
this.$v.mailConfigData.$touch()
|
||||
if (!this.$v.mailConfigData.$invalid) {
|
||||
this.$emit('submit-data', this.mailConfigData)
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onChangeDriver() {
|
||||
this.$v.mailConfigData.mail_driver.$touch()
|
||||
this.$emit('on-change-driver', this.mailConfigData.mail_driver)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveEmailConfig">
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.driver')"
|
||||
:error="driverError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="mailConfigData.mail_driver"
|
||||
:invalid="$v.mailConfigData.mail_driver.$error"
|
||||
:options="mailDrivers"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
@input="onChangeDriver"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.mailgun_domain')"
|
||||
:error="domainError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_mailgun_domain.$error"
|
||||
v-model.trim="mailConfigData.mail_mailgun_domain"
|
||||
type="text"
|
||||
name="mailgun_domain"
|
||||
@input="$v.mailConfigData.mail_mailgun_domain.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.mailgun_secret')"
|
||||
:error="secretError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_mailgun_secret.$error"
|
||||
v-model.trim="mailConfigData.mail_mailgun_secret"
|
||||
:type="getInputType"
|
||||
name="mailgun_secret"
|
||||
@input="$v.mailConfigData.mail_mailgun_secret.$touch()"
|
||||
>
|
||||
<template v-slot:rightIcon>
|
||||
<eye-off-icon
|
||||
v-if="isShowPassword"
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
<eye-icon
|
||||
v-else
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
</template>
|
||||
</sw-input>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.mailgun_endpoint')"
|
||||
:error="endpointError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_mailgun_endpoint.$error"
|
||||
v-model.trim="mailConfigData.mail_mailgun_endpoint"
|
||||
type="text"
|
||||
name="mailgun_endpoint"
|
||||
@input="$v.mailConfigData.mail_mailgun_endpoint.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.from_mail')"
|
||||
:error="fromMailError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.from_mail.$error"
|
||||
v-model.trim="mailConfigData.from_mail"
|
||||
type="text"
|
||||
name="from_mail"
|
||||
@input="$v.mailConfigData.from_mail.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.from_name')"
|
||||
:error="fromNameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.from_name.$error"
|
||||
v-model.trim="mailConfigData.from_name"
|
||||
type="text"
|
||||
name="from_name"
|
||||
@input="$v.mailConfigData.from_name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<sw-button
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
>
|
||||
<save-icon v-if="!loading" class="mr-2" />
|
||||
{{ $t('general.save') }}
|
||||
</sw-button>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
const { required, email } = require('vuelidate/lib/validators')
|
||||
import { EyeIcon, EyeOffIcon } from '@vue-hero-icons/outline'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
mailDrivers: {
|
||||
type: Array,
|
||||
require: true,
|
||||
default: Array,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
EyeIcon,
|
||||
EyeOffIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShowPassword: false,
|
||||
mailConfigData: {
|
||||
mail_driver: '',
|
||||
mail_mailgun_domain: '',
|
||||
mail_mailgun_secret: '',
|
||||
mail_mailgun_endpoint: '',
|
||||
from_mail: '',
|
||||
from_name: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
mailConfigData: {
|
||||
mail_driver: {
|
||||
required,
|
||||
},
|
||||
mail_mailgun_domain: {
|
||||
required,
|
||||
},
|
||||
mail_mailgun_endpoint: {
|
||||
required,
|
||||
},
|
||||
mail_mailgun_secret: {
|
||||
required,
|
||||
},
|
||||
from_mail: {
|
||||
required,
|
||||
email,
|
||||
},
|
||||
from_name: {
|
||||
required,
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
driverError() {
|
||||
if (!this.$v.mailConfigData.mail_driver.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_driver.required) {
|
||||
return tthis.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
domainError() {
|
||||
if (!this.$v.mailConfigData.mail_mailgun_domain.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_mailgun_domain.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
secretError() {
|
||||
if (!this.$v.mailConfigData.mail_mailgun_secret.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_mailgun_secret.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
endpointError() {
|
||||
if (!this.$v.mailConfigData.mail_mailgun_endpoint.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_mailgun_endpoint.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
fromMailError() {
|
||||
if (!this.$v.mailConfigData.from_mail.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.from_mail.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
if (!this.$v.mailConfigData.from_mail.email) {
|
||||
return this.$tc('validation.email_incorrect')
|
||||
}
|
||||
},
|
||||
fromNameError() {
|
||||
if (!this.$v.mailConfigData.from_name.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.from_name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
getInputType() {
|
||||
if (this.isShowPassword) {
|
||||
return 'text'
|
||||
}
|
||||
return 'password'
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const key in this.mailConfigData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.mailConfigData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveEmailConfig() {
|
||||
this.$v.mailConfigData.$touch()
|
||||
if (!this.$v.mailConfigData.$invalid) {
|
||||
this.$emit('submit-data', this.mailConfigData)
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onChangeDriver() {
|
||||
this.$v.mailConfigData.mail_driver.$touch()
|
||||
this.$emit('on-change-driver', this.mailConfigData.mail_driver)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
323
resources/assets/js/views/wizard/mail-driver/SesMailDriver.vue
Normal file
323
resources/assets/js/views/wizard/mail-driver/SesMailDriver.vue
Normal file
@@ -0,0 +1,323 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveEmailConfig">
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.driver')"
|
||||
:error="driverError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="mailConfigData.mail_driver"
|
||||
:invalid="$v.mailConfigData.mail_driver.$error"
|
||||
:options="mailDrivers"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
@input="onChangeDriver"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.host')"
|
||||
:error="hostError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_host.$error"
|
||||
v-model.trim="mailConfigData.mail_host"
|
||||
type="text"
|
||||
name="mail_host"
|
||||
@input="$v.mailConfigData.mail_host.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.port')"
|
||||
:error="portError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_port.$error"
|
||||
v-model.trim="mailConfigData.mail_port"
|
||||
type="text"
|
||||
name="mail_port"
|
||||
@input="$v.mailConfigData.mail_port.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.encryption')"
|
||||
:error="encryptionError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model.trim="mailConfigData.mail_encryption"
|
||||
:invalid="$v.mailConfigData.mail_encryption.$error"
|
||||
:options="encryptions"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
@input="$v.mailConfigData.mail_encryption.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.from_mail')"
|
||||
:error="fromEmailError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.from_mail.$error"
|
||||
v-model.trim="mailConfigData.from_mail"
|
||||
type="text"
|
||||
name="from_mail"
|
||||
@input="$v.mailConfigData.from_mail.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.from_name')"
|
||||
:error="fromNameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.from_name.$error"
|
||||
v-model.trim="mailConfigData.from_name"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.mailConfigData.from_name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.ses_key')"
|
||||
:error="keyError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_ses_key.$error"
|
||||
v-model.trim="mailConfigData.mail_ses_key"
|
||||
type="text"
|
||||
name="mail_ses_key"
|
||||
@input="$v.mailConfigData.mail_ses_key.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.ses_secret')"
|
||||
:error="secretError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_ses_secret.$error"
|
||||
v-model.trim="mailConfigData.mail_ses_secret"
|
||||
:type="getInputType"
|
||||
name="mail_ses_secret"
|
||||
@input="$v.mailConfigData.mail_ses_secret.$touch()"
|
||||
>
|
||||
<template v-slot:rightIcon>
|
||||
<eye-off-icon
|
||||
v-if="isShowPassword"
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
<eye-icon
|
||||
v-else
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
</template>
|
||||
</sw-input>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
<sw-button
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
>
|
||||
<save-icon v-if="!loading" class="mr-2" />
|
||||
{{ $t('general.save') }}
|
||||
</sw-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const { required, email, numeric } = require('vuelidate/lib/validators')
|
||||
import { EyeIcon, EyeOffIcon } from '@vue-hero-icons/outline'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
mailDrivers: {
|
||||
type: Array,
|
||||
require: true,
|
||||
default: Array,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
EyeIcon,
|
||||
EyeOffIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShowPassword: false,
|
||||
mailConfigData: {
|
||||
mail_driver: '',
|
||||
mail_host: '',
|
||||
mail_port: null,
|
||||
mail_ses_key: '',
|
||||
mail_ses_secret: '',
|
||||
mail_encryption: 'tls',
|
||||
from_mail: '',
|
||||
from_name: '',
|
||||
},
|
||||
encryptions: ['tls', 'ssl', 'starttls'],
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
mailConfigData: {
|
||||
mail_driver: {
|
||||
required,
|
||||
},
|
||||
mail_host: {
|
||||
required,
|
||||
},
|
||||
mail_port: {
|
||||
required,
|
||||
numeric,
|
||||
},
|
||||
mail_ses_key: {
|
||||
required,
|
||||
},
|
||||
mail_ses_secret: {
|
||||
required,
|
||||
},
|
||||
mail_encryption: {
|
||||
required,
|
||||
},
|
||||
from_mail: {
|
||||
required,
|
||||
email,
|
||||
},
|
||||
from_name: {
|
||||
required,
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
driverError() {
|
||||
if (!this.$v.mailConfigData.mail_driver.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_driver.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
hostError() {
|
||||
if (!this.$v.mailConfigData.mail_host.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_host.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
portError() {
|
||||
if (!this.$v.mailConfigData.mail_port.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_port.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_port.numeric) {
|
||||
return this.$tc('validation.numbers_only')
|
||||
}
|
||||
},
|
||||
encryptionError() {
|
||||
if (!this.$v.mailConfigData.mail_encryption.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_encryption.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
fromEmailError() {
|
||||
if (!this.$v.mailConfigData.from_mail.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.from_mail.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.from_mail.email) {
|
||||
return this.$tc('validation.email_incorrect')
|
||||
}
|
||||
},
|
||||
fromNameError() {
|
||||
if (!this.$v.mailConfigData.from_name.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.from_name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
keyError() {
|
||||
if (!this.$v.mailConfigData.mail_ses_key.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_ses_key.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
secretError() {
|
||||
if (!this.$v.mailConfigData.mail_ses_secret.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_ses_secret.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
getInputType() {
|
||||
if (this.isShowPassword) {
|
||||
return 'text'
|
||||
}
|
||||
return 'password'
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const key in this.mailConfigData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.mailConfigData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveEmailConfig() {
|
||||
this.$v.mailConfigData.$touch()
|
||||
if (!this.$v.mailConfigData.$invalid) {
|
||||
this.$emit('submit-data', this.mailConfigData)
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onChangeDriver() {
|
||||
this.$v.mailConfigData.mail_driver.$touch()
|
||||
this.$emit('on-change-driver', this.mailConfigData.mail_driver)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
333
resources/assets/js/views/wizard/mail-driver/SmtpMailDriver.vue
Normal file
333
resources/assets/js/views/wizard/mail-driver/SmtpMailDriver.vue
Normal file
@@ -0,0 +1,333 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveEmailConfig()">
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.driver')"
|
||||
:error="driverError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model="mailConfigData.mail_driver"
|
||||
:invalid="$v.mailConfigData.mail_driver.$error"
|
||||
:options="mailDrivers"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
@input="onChangeDriver"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.host')"
|
||||
:error="hostError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_host.$error"
|
||||
v-model.trim="mailConfigData.mail_host"
|
||||
type="text"
|
||||
name="mail_host"
|
||||
@input="$v.mailConfigData.mail_host.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.username')"
|
||||
:error="usernameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_username.$error"
|
||||
v-model.trim="mailConfigData.mail_username"
|
||||
type="text"
|
||||
name="db_name"
|
||||
@input="$v.mailConfigData.mail_username.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.password')"
|
||||
:error="passwordError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_password.$error"
|
||||
v-model.trim="mailConfigData.mail_password"
|
||||
:type="getInputType"
|
||||
name="password"
|
||||
@input="$v.mailConfigData.mail_password.$touch()"
|
||||
>
|
||||
<template v-slot:rightIcon>
|
||||
<eye-off-icon
|
||||
v-if="isShowPassword"
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
<eye-icon
|
||||
v-else
|
||||
class="w-5 h-5 mr-1 text-gray-500 cursor-pointer"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
</template>
|
||||
</sw-input>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 md:mb-6">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.port')"
|
||||
:error="portError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.mail_port.$error"
|
||||
v-model.trim="mailConfigData.mail_port"
|
||||
type="text"
|
||||
name="mail_port"
|
||||
@input="$v.mailConfigData.mail_port.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.encryption')"
|
||||
:error="encryptionError"
|
||||
required
|
||||
>
|
||||
<sw-select
|
||||
v-model.trim="mailConfigData.mail_encryption"
|
||||
:invalid="$v.mailConfigData.mail_encryption.$error"
|
||||
:options="encryptions"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
@input="$v.mailConfigData.mail_encryption.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 mb-6 md:grid-cols-2">
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.from_mail')"
|
||||
:error="fromEmailError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.from_mail.$error"
|
||||
v-model.trim="mailConfigData.from_mail"
|
||||
type="text"
|
||||
name="from_mail"
|
||||
@input="$v.mailConfigData.from_mail.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
|
||||
<sw-input-group
|
||||
:label="$t('wizard.mail.from_name')"
|
||||
:error="fromNameError"
|
||||
required
|
||||
>
|
||||
<sw-input
|
||||
:invalid="$v.mailConfigData.from_name.$error"
|
||||
v-model.trim="mailConfigData.from_name"
|
||||
type="text"
|
||||
name="from_name"
|
||||
@input="$v.mailConfigData.from_name.$touch()"
|
||||
/>
|
||||
</sw-input-group>
|
||||
</div>
|
||||
|
||||
<sw-button
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
>
|
||||
<save-icon v-if="!loading" class="mr-2" />
|
||||
{{ $t('general.save') }}
|
||||
</sw-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const { required, email, numeric } = require('vuelidate/lib/validators')
|
||||
import { EyeIcon, EyeOffIcon } from '@vue-hero-icons/outline'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false,
|
||||
},
|
||||
mailDrivers: {
|
||||
type: Array,
|
||||
require: true,
|
||||
default: Array,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
EyeIcon,
|
||||
EyeOffIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShowPassword: false,
|
||||
mailConfigData: {
|
||||
mail_driver: '',
|
||||
mail_host: '',
|
||||
mail_port: null,
|
||||
mail_username: '',
|
||||
mail_password: '',
|
||||
mail_encryption: 'tls',
|
||||
from_mail: '',
|
||||
from_name: '',
|
||||
},
|
||||
encryptions: ['tls', 'ssl', 'starttls'],
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
mailConfigData: {
|
||||
mail_driver: {
|
||||
required,
|
||||
},
|
||||
mail_host: {
|
||||
required,
|
||||
},
|
||||
mail_port: {
|
||||
required,
|
||||
numeric,
|
||||
},
|
||||
mail_username: {
|
||||
required,
|
||||
},
|
||||
mail_password: {
|
||||
required,
|
||||
},
|
||||
mail_encryption: {
|
||||
required,
|
||||
},
|
||||
from_mail: {
|
||||
required,
|
||||
email,
|
||||
},
|
||||
from_name: {
|
||||
required,
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
driverError() {
|
||||
if (!this.$v.mailConfigData.mail_driver.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.mail_driver.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
hostError() {
|
||||
if (!this.$v.mailConfigData.mail_host.$error) {
|
||||
return ''
|
||||
}
|
||||
if (!this.$v.mailConfigData.mail_host.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
usernameError() {
|
||||
if (!this.$v.mailConfigData.mail_username.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.mail_username.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
passwordError() {
|
||||
if (!this.$v.mailConfigData.mail_password.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.mail_password.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
portError() {
|
||||
if (!this.$v.mailConfigData.mail_port.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.mail_port.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.mail_port.numeric) {
|
||||
return this.$tc('validation.numbers_only')
|
||||
}
|
||||
},
|
||||
encryptionError() {
|
||||
if (!this.$v.mailConfigData.mail_encryption.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.mail_encryption.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
fromEmailError() {
|
||||
if (!this.$v.mailConfigData.from_mail.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.from_mail.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.from_mail.email) {
|
||||
return this.$tc('validation.email_incorrect')
|
||||
}
|
||||
},
|
||||
fromNameError() {
|
||||
if (!this.$v.mailConfigData.from_name.$error) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!this.$v.mailConfigData.from_name.required) {
|
||||
return this.$tc('validation.required')
|
||||
}
|
||||
},
|
||||
getInputType() {
|
||||
if (this.isShowPassword) {
|
||||
return 'text'
|
||||
}
|
||||
return 'password'
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
for (const key in this.mailConfigData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.mailConfigData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveEmailConfig() {
|
||||
this.$v.mailConfigData.$touch()
|
||||
if (!this.$v.mailConfigData.$invalid) {
|
||||
this.$emit('submit-data', this.mailConfigData)
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onChangeDriver() {
|
||||
this.$v.mailConfigData.mail_driver.$touch()
|
||||
this.$emit('on-change-driver', this.mailConfigData.mail_driver)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,160 +0,0 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveEmailConfig()">
|
||||
<div class="row">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.driver') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="mailConfigData.mail_driver"
|
||||
:invalid="$v.mailConfigData.mail_driver.$error"
|
||||
:options="mailDrivers"
|
||||
:allow-empty="false"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
@input="onChangeDriver"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_driver.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_driver.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.host') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_host.$error"
|
||||
v-model.trim="mailConfigData.mail_host"
|
||||
type="text"
|
||||
name="mail_host"
|
||||
@input="$v.mailConfigData.mail_host.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_host.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_host.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.from_mail') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.from_mail.$error"
|
||||
v-model.trim="mailConfigData.from_mail"
|
||||
type="text"
|
||||
name="from_mail"
|
||||
@input="$v.mailConfigData.from_mail.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.from_mail.$error">
|
||||
<span v-if="!$v.mailConfigData.from_mail.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.mailConfigData.from_mail.email" class="text-danger">
|
||||
{{ $tc('validation.email_incorrect') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.from_name') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.from_name.$error"
|
||||
v-model.trim="mailConfigData.from_name"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.mailConfigData.from_name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.from_name.$error">
|
||||
<span v-if="!$v.mailConfigData.from_name.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, email } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false
|
||||
},
|
||||
mailDrivers: {
|
||||
type: Array,
|
||||
require: true,
|
||||
default: Array
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
mailConfigData: {
|
||||
mail_driver: '',
|
||||
mail_host: '',
|
||||
from_mail: '',
|
||||
from_name: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
mailConfigData: {
|
||||
mail_driver: {
|
||||
required
|
||||
},
|
||||
from_mail: {
|
||||
required,
|
||||
email
|
||||
},
|
||||
from_name: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
for (const key in this.mailConfigData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.mailConfigData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveEmailConfig () {
|
||||
this.$v.mailConfigData.$touch()
|
||||
if (!this.$v.mailConfigData.$invalid) {
|
||||
this.$emit('submit-data', this.mailConfigData)
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onChangeDriver () {
|
||||
this.$v.mailConfigData.mail_driver.$touch()
|
||||
this.$emit('on-change-driver', this.mailConfigData.mail_driver)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,209 +0,0 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveEmailConfig()">
|
||||
<div class="row">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.driver') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="mailConfigData.mail_driver"
|
||||
:invalid="$v.mailConfigData.mail_driver.$error"
|
||||
:options="mailDrivers"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
@input="onChangeDriver"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_driver.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_driver.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.mailgun_domain') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_mailgun_domain.$error"
|
||||
v-model.trim="mailConfigData.mail_mailgun_domain"
|
||||
type="text"
|
||||
name="mailgun_domain"
|
||||
@input="$v.mailConfigData.mail_mailgun_domain.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_mailgun_domain.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_mailgun_domain.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.mailgun_secret') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_mailgun_secret.$error"
|
||||
v-model.trim="mailConfigData.mail_mailgun_secret"
|
||||
type="password"
|
||||
name="mailgun_secret"
|
||||
show-password
|
||||
@input="$v.mailConfigData.mail_mailgun_secret.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_mailgun_secret.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_mailgun_secret.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.mailgun_endpoint') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_mailgun_endpoint.$error"
|
||||
v-model.trim="mailConfigData.mail_mailgun_endpoint"
|
||||
type="text"
|
||||
name="mailgun_endpoint"
|
||||
@input="$v.mailConfigData.mail_mailgun_endpoint.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_mailgun_endpoint.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_mailgun_endpoint.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.mailConfigData.mail_mailgun_endpoint.numeric" class="text-danger">
|
||||
{{ $tc('validation.numbers_only') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.from_mail') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.from_mail.$error"
|
||||
v-model.trim="mailConfigData.from_mail"
|
||||
type="text"
|
||||
name="from_mail"
|
||||
@input="$v.mailConfigData.from_mail.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.from_mail.$error">
|
||||
<span v-if="!$v.mailConfigData.from_mail.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.mailConfigData.from_mail.email" class="text-danger">
|
||||
{{ $tc('validation.email_incorrect') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.from_name') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.from_name.$error"
|
||||
v-model.trim="mailConfigData.from_name"
|
||||
type="text"
|
||||
name="from_name"
|
||||
@input="$v.mailConfigData.from_name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.from_name.$error">
|
||||
<span v-if="!$v.mailConfigData.from_name.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, email } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false
|
||||
},
|
||||
mailDrivers: {
|
||||
type: Array,
|
||||
require: true,
|
||||
default: Array
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
mailConfigData: {
|
||||
mail_driver: '',
|
||||
mail_mailgun_domain: '',
|
||||
mail_mailgun_secret: '',
|
||||
mail_mailgun_endpoint: '',
|
||||
from_mail: '',
|
||||
from_name: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
mailConfigData: {
|
||||
mail_driver: {
|
||||
required
|
||||
},
|
||||
mail_mailgun_domain: {
|
||||
required
|
||||
},
|
||||
mail_mailgun_endpoint: {
|
||||
required
|
||||
},
|
||||
mail_mailgun_secret: {
|
||||
required
|
||||
},
|
||||
from_mail: {
|
||||
required,
|
||||
email
|
||||
},
|
||||
from_name: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
for (const key in this.mailConfigData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.mailConfigData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveEmailConfig () {
|
||||
this.$v.mailConfigData.$touch()
|
||||
if (!this.$v.mailConfigData.$invalid) {
|
||||
this.$emit('submit-data', this.mailConfigData)
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onChangeDriver () {
|
||||
this.$v.mailConfigData.mail_driver.$touch()
|
||||
this.$emit('on-change-driver', this.mailConfigData.mail_driver)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,254 +0,0 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveEmailConfig()">
|
||||
<div class="row">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.driver') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="mailConfigData.mail_driver"
|
||||
:invalid="$v.mailConfigData.mail_driver.$error"
|
||||
:options="mailDrivers"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
@input="onChangeDriver"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_driver.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_driver.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.host') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_host.$error"
|
||||
v-model.trim="mailConfigData.mail_host"
|
||||
type="text"
|
||||
name="mail_host"
|
||||
@input="$v.mailConfigData.mail_host.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_host.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_host.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.port') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_port.$error"
|
||||
v-model.trim="mailConfigData.mail_port"
|
||||
type="text"
|
||||
name="mail_port"
|
||||
@input="$v.mailConfigData.mail_port.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_port.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_port.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.mailConfigData.mail_port.numeric" class="text-danger">
|
||||
{{ $tc('validation.numbers_only') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.encryption') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model.trim="mailConfigData.mail_encryption"
|
||||
:invalid="$v.mailConfigData.mail_encryption.$error"
|
||||
:options="encryptions"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
@input="$v.mailConfigData.mail_encryption.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_encryption.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_encryption.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.from_mail') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.from_mail.$error"
|
||||
v-model.trim="mailConfigData.from_mail"
|
||||
type="text"
|
||||
name="from_mail"
|
||||
@input="$v.mailConfigData.from_mail.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.from_mail.$error">
|
||||
<span v-if="!$v.mailConfigData.from_mail.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.mailConfigData.from_mail.email" class="text-danger">
|
||||
{{ $tc('validation.email_incorrect') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.from_name') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.from_name.$error"
|
||||
v-model.trim="mailConfigData.from_name"
|
||||
type="text"
|
||||
name="name"
|
||||
@input="$v.mailConfigData.from_name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.from_name.$error">
|
||||
<span v-if="!$v.mailConfigData.from_name.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.ses_key') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_ses_key.$error"
|
||||
v-model.trim="mailConfigData.mail_ses_key"
|
||||
type="text"
|
||||
name="mail_ses_key"
|
||||
@input="$v.mailConfigData.mail_ses_key.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_ses_key.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_ses_key.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.ses_secret') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_ses_secret.$error"
|
||||
v-model.trim="mailConfigData.mail_ses_secret"
|
||||
type="password"
|
||||
name="mail_ses_secret"
|
||||
show-password
|
||||
@input="$v.mailConfigData.mail_ses_secret.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_ses_secret.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_ses_secret.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, email, numeric } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false
|
||||
},
|
||||
mailDrivers: {
|
||||
type: Array,
|
||||
require: true,
|
||||
default: Array
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
mailConfigData: {
|
||||
mail_driver: '',
|
||||
mail_host: '',
|
||||
mail_port: null,
|
||||
mail_ses_key: '',
|
||||
mail_ses_secret: '',
|
||||
mail_encryption: 'tls',
|
||||
from_mail: '',
|
||||
from_name: ''
|
||||
},
|
||||
encryptions: ['tls', 'ssl', 'starttls']
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
mailConfigData: {
|
||||
mail_driver: {
|
||||
required
|
||||
},
|
||||
mail_host: {
|
||||
required
|
||||
},
|
||||
mail_port: {
|
||||
required,
|
||||
numeric
|
||||
},
|
||||
mail_ses_key: {
|
||||
required
|
||||
},
|
||||
mail_ses_secret: {
|
||||
required
|
||||
},
|
||||
mail_encryption: {
|
||||
required
|
||||
},
|
||||
from_mail: {
|
||||
required,
|
||||
email
|
||||
},
|
||||
from_name: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
for (const key in this.mailConfigData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.mailConfigData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveEmailConfig () {
|
||||
this.$v.mailConfigData.$touch()
|
||||
if (!this.$v.mailConfigData.$invalid) {
|
||||
this.$emit('submit-data', this.mailConfigData)
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onChangeDriver () {
|
||||
this.$v.mailConfigData.mail_driver.$touch()
|
||||
this.$emit('on-change-driver', this.mailConfigData.mail_driver)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,254 +0,0 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveEmailConfig()">
|
||||
<div class="row">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.driver') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model="mailConfigData.mail_driver"
|
||||
:invalid="$v.mailConfigData.mail_driver.$error"
|
||||
:options="mailDrivers"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
@input="onChangeDriver"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_driver.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_driver.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.host') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_host.$error"
|
||||
v-model.trim="mailConfigData.mail_host"
|
||||
type="text"
|
||||
name="mail_host"
|
||||
@input="$v.mailConfigData.mail_host.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_host.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_host.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.username') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_username.$error"
|
||||
v-model.trim="mailConfigData.mail_username"
|
||||
type="text"
|
||||
name="db_name"
|
||||
@input="$v.mailConfigData.mail_username.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_username.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_username.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.password') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_password.$error"
|
||||
v-model.trim="mailConfigData.mail_password"
|
||||
type="password"
|
||||
name="name"
|
||||
show-password
|
||||
@input="$v.mailConfigData.mail_password.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_password.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_password.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.port') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.mail_port.$error"
|
||||
v-model.trim="mailConfigData.mail_port"
|
||||
type="text"
|
||||
name="mail_port"
|
||||
@input="$v.mailConfigData.mail_port.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_port.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_port.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.mailConfigData.mail_port.numeric" class="text-danger">
|
||||
{{ $tc('validation.numbers_only') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.encryption') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-select
|
||||
v-model.trim="mailConfigData.mail_encryption"
|
||||
:invalid="$v.mailConfigData.mail_encryption.$error"
|
||||
:options="encryptions"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
@input="$v.mailConfigData.mail_encryption.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.mail_encryption.$error">
|
||||
<span v-if="!$v.mailConfigData.mail_encryption.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-2">
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.from_mail') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.from_mail.$error"
|
||||
v-model.trim="mailConfigData.from_mail"
|
||||
type="text"
|
||||
name="from_mail"
|
||||
@input="$v.mailConfigData.from_mail.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.from_mail.$error">
|
||||
<span v-if="!$v.mailConfigData.from_mail.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
<span v-if="!$v.mailConfigData.from_mail.email" class="text-danger">
|
||||
{{ $tc('validation.email_incorrect') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 my-2">
|
||||
<label class="form-label">{{ $t('wizard.mail.from_name') }}</label>
|
||||
<span class="text-danger"> *</span>
|
||||
<base-input
|
||||
:invalid="$v.mailConfigData.from_name.$error"
|
||||
v-model.trim="mailConfigData.from_name"
|
||||
type="text"
|
||||
name="from_name"
|
||||
@input="$v.mailConfigData.from_name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.mailConfigData.from_name.$error">
|
||||
<span v-if="!$v.mailConfigData.from_name.required" class="text-danger">
|
||||
{{ $tc('validation.required') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
import MultiSelect from 'vue-multiselect'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, email, numeric } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MultiSelect
|
||||
},
|
||||
mixins: [validationMixin],
|
||||
props: {
|
||||
configData: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
require: true,
|
||||
default: false
|
||||
},
|
||||
mailDrivers: {
|
||||
type: Array,
|
||||
require: true,
|
||||
default: Array
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
mailConfigData: {
|
||||
mail_driver: '',
|
||||
mail_host: '',
|
||||
mail_port: null,
|
||||
mail_username: '',
|
||||
mail_password: '',
|
||||
mail_encryption: 'tls',
|
||||
from_mail: '',
|
||||
from_name: ''
|
||||
},
|
||||
encryptions: ['tls', 'ssl', 'starttls']
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
mailConfigData: {
|
||||
mail_driver: {
|
||||
required
|
||||
},
|
||||
mail_host: {
|
||||
required
|
||||
},
|
||||
mail_port: {
|
||||
required,
|
||||
numeric
|
||||
},
|
||||
mail_username: {
|
||||
required
|
||||
},
|
||||
mail_password: {
|
||||
required
|
||||
},
|
||||
mail_encryption: {
|
||||
required
|
||||
},
|
||||
from_mail: {
|
||||
required,
|
||||
email
|
||||
},
|
||||
from_name: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
for (const key in this.mailConfigData) {
|
||||
if (this.configData.hasOwnProperty(key)) {
|
||||
this.mailConfigData[key] = this.configData[key]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveEmailConfig () {
|
||||
this.$v.mailConfigData.$touch()
|
||||
if (!this.$v.mailConfigData.$invalid) {
|
||||
this.$emit('submit-data', this.mailConfigData)
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onChangeDriver () {
|
||||
this.$v.mailConfigData.mail_driver.$touch()
|
||||
this.$emit('on-change-driver', this.mailConfigData.mail_driver)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user