init crater

This commit is contained in:
Mohit Panjwani
2019-11-11 12:16:00 +05:30
commit bdf2ba51d6
668 changed files with 158503 additions and 0 deletions

View File

@ -0,0 +1,311 @@
<template>
<div class="card-body">
<form action="" @submit.prevent="next()">
<!-- <div v-if="previewLogo" class="upload-logo">
<label class="form-label">{{ $t('wizard.logo_preview') }}</label><br>
<img v-if="previewLogo" :src="previewLogo" class="preview-logo">
</div> -->
<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">
<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: 'Cancle'}"
:cropper-options="cropperOptions"
:output-options="cropperOutputOptions"
:output-quality="0.8"
:upload-handler="cropperHandler"
trigger="#pick-avatar"
@changed="setFileObject"
/>
</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"
@input="fetchState()"
/>
<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-select
v-model="state"
:options="states"
:searchable="true"
:show-labels="false"
:disabled="isDisabledState"
:placeholder="$t('general.select_state')"
track-by="id"
label="name"
@input="fetchCities"
/>
</div>
<div class="col-md-6">
<label class="form-label">{{ $t('wizard.city') }}</label>
<base-select
v-model="city"
:options="cities"
:searchable="true"
:show-labels="false"
:disabled="isDisabledCity"
:placeholder="$t('general.select_city')"
track-by="id"
label="name"
/>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label class="form-label">{{ $t('wizard.address') }}</label>
<base-text-area
v-model.trim="companyData.address_street_1"
:placeholder="$t('general.street_1')"
name="billing_street1"
rows="2"
/>
<base-text-area
v-model="companyData.address_street_2"
:placeholder="$t('general.street_2')"
name="billing_street2"
rows="2"
/>
</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'
import Ls from '../../services/ls'
const { required, minLength, email } = 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_id: '',
state_id: '',
country_id: '',
zip: '',
phone: ''
},
loading: false,
step: 1,
countries: [],
country: null,
states: [],
state: null,
cities: [],
city: null,
previewLogo: null,
isDisabledCity: true,
isDisabledState: true
}
},
validations: {
companyData: {
name: {
required
},
country_id: {
required
}
}
},
watch: {
country ({ id }) {
this.companyData.country_id = id
this.state = null
this.city = null
if (id !== null && id !== undefined) {
this.isDisabledState = false
return true
}
this.isDisabledState = true
return true
},
state (newState) {
if (newState !== null && newState !== undefined) {
this.city = null
this.companyData.state_id = newState.id
this.isDisabledCity = false
return true
}
this.companyData.state_id = null
this.isDisabledCity = true
this.cities = []
this.city = null
this.companyData.city_id = null
return true
},
city (newCity) {
if (newCity !== null && newCity !== undefined) {
this.companyData.city_id = newCity.id
return true
}
this.companyData.city_id = null
return true
}
},
mounted () {
this.fetchCountry()
},
methods: {
cropperHandler (cropper) {
this.previewLogo = cropper.getCroppedCanvas().toDataURL(this.cropperOutputMime)
},
setFileObject (file) {
this.fileObject = file
},
async next () {
this.$v.companyData.$touch()
if (this.$v.companyData.$invalid) {
return true
}
this.loading = true
let data = new FormData()
data.append('logo', this.fileObject)
data.append('name', this.companyData.name)
data.append('address_street_1', this.companyData.address_street_1)
data.append('address_street_2', this.companyData.address_street_2)
data.append('city_id', this.companyData.city_id)
data.append('state_id', this.companyData.state_id)
data.append('country_id', this.companyData.country_id)
data.append('zip', this.companyData.zip)
data.append('phone', this.companyData.phone)
let response = await window.axios.post('/api/admin/onboarding/company', data, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
if (response.data) {
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
}
},
async fetchState () {
this.$v.companyData.country_id.$touch()
let res = await window.axios.get(`/api/states/${this.country.id}`)
if (res) {
this.states = res.data.states
}
},
async fetchCities () {
if (this.state === null || this.state === undefined) {
return false
}
let res = await window.axios.get(`/api/cities/${this.state.id}`)
if (res) {
this.cities = res.data.cities
}
}
}
}
</script>

View File

@ -0,0 +1,216 @@
<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.url" 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>
<span class="text-danger"> *</span>
<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: null
},
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,
url
}
}
},
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 {
window.toastr['error'](this.$t('wizard.errors.' + response.data.error))
}
this.loading = false
} catch (e) {
console.log(e)
window.toastr['error']('Somethig went wrong')
}
}
}
}
</script>

View File

@ -0,0 +1,208 @@
<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>
<div class="row my-2 mt-5">
<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="mail_drivers"
:searchable="true"
:show-labels="false"
@change="$v.mailConfigData.mail_driver.$touch()"
/>
<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="mail_password"
name="name"
@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-input
:invalid="$v.mailConfigData.mail_encryption.$error"
v-model.trim="mailConfigData.mail_encryption"
type="text"
name="name"
@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>
<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'
import Ls from '../../services/ls'
const { required, email, numeric } = require('vuelidate/lib/validators')
export default {
components: {
MultiSelect
},
mixins: [validationMixin],
data () {
return {
mailConfigData: {
mail_driver: 'smtp',
mail_host: 'mailtrap.io',
mail_port: 2525,
mail_username: 'cc3c64516febd4',
mail_password: 'e6a0176301f587',
mail_encryption: 'tls'
},
loading: false,
mail_drivers: []
}
},
validations: {
mailConfigData: {
mail_driver: {
required
},
mail_host: {
required
},
mail_port: {
required,
numeric
},
mail_username: {
required
},
mail_password: {
required
},
mail_encryption: {
required
}
}
},
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 () {
this.$v.mailConfigData.$touch()
if (this.$v.mailConfigData.$invalid) {
return true
}
this.loading = true
try {
let response = await window.axios.post('/api/admin/onboarding/environment/mail', this.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']('Somethig went wrong')
}
}
}
}
</script>

View File

@ -0,0 +1,115 @@
<template>
<div class="wizard">
<div class="step-indicator">
<img
id="logo-crater"
src="/assets/img/crater-logo.png"
alt="Crater Logo"
width="225"
height="50"
class="logo"
>
<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>

View File

@ -0,0 +1,69 @@
<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="!errors"
class="pull-right mt-5"
icon="arrow-right"
right-icon
color="theme"
@click="next"
>
{{ $t('wizard.continue') }}
</base-button>
</div>
</template>
<script>
import Ls from '../../services/ls'
export default {
data () {
return {
loading: false,
permissions: [],
errors: 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
this.loading = false
}
},
async next () {
this.loading = true
await this.$emit('next')
this.loading = false
}
}
}
</script>

View File

@ -0,0 +1,209 @@
<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"
: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'
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: {
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.$router.push('/admin/dashboard')
}
}
}
}
</script>

View File

@ -0,0 +1,99 @@
<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="requirements"
:loading="loading"
class="pull-right mt-4"
icon="arrow-right"
color="theme"
right-icon
@click="next"
>
{{ $t('wizard.continue') }}
</base-button>
<base-button
v-else
: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'
import Ls from '../../services/ls'
export default {
components: {
MultiSelect
},
mixins: [validationMixin],
data () {
return {
requirements: null,
phpSupportInfo: null,
loading: false,
isShow: true
}
},
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>

View File

@ -0,0 +1,141 @@
<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">
<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.required') }}</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>
</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 MultiSelect from 'vue-multiselect'
import { validationMixin } from 'vuelidate'
import Ls from '../../services/ls'
const { required, requiredIf, sameAs, minLength, email } = require('vuelidate/lib/validators')
export default {
components: {
MultiSelect
},
mixins: [validationMixin],
data () {
return {
profileData: {
name: null,
email: null,
password: null,
confirm_password: null
},
loading: false
}
},
validations: {
profileData: {
name: {
required,
minLength: minLength(3)
},
email: {
email,
required
},
password: {
required
},
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: {
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)
if (response.data) {
this.$emit('next')
this.loading = false
}
return true
}
}
}
</script>