mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-30 21:21:09 -04:00 
			
		
		
		
	init crater
This commit is contained in:
		
							
								
								
									
										311
									
								
								resources/assets/js/views/wizard/CompanyInfo.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								resources/assets/js/views/wizard/CompanyInfo.vue
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										216
									
								
								resources/assets/js/views/wizard/Database.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								resources/assets/js/views/wizard/Database.vue
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										208
									
								
								resources/assets/js/views/wizard/EmailConfiguration.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								resources/assets/js/views/wizard/EmailConfiguration.vue
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										115
									
								
								resources/assets/js/views/wizard/Index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								resources/assets/js/views/wizard/Index.vue
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										69
									
								
								resources/assets/js/views/wizard/Permission.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								resources/assets/js/views/wizard/Permission.vue
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										209
									
								
								resources/assets/js/views/wizard/Settings.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								resources/assets/js/views/wizard/Settings.vue
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										99
									
								
								resources/assets/js/views/wizard/SystemRequirement.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								resources/assets/js/views/wizard/SystemRequirement.vue
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										141
									
								
								resources/assets/js/views/wizard/UserProfile.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								resources/assets/js/views/wizard/UserProfile.vue
									
									
									
									
									
										Normal 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> | ||||
		Reference in New Issue
	
	Block a user