File: //home/arjun/projects/buyercall/buyercall/assets/vue/widgets/ProfileSettings/Personalnfo.vue
<template>
<div class="row justify-content-center">
<div class="col-xl-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">Personal Information</h4>
<p class="card-title-desc">
Update your personal information to ensure your account stays
current.
</p>
<b-form @submit.prevent="formSubmit">
<div class="row">
<div class="text-left profile-avatar-container">
<div class="mb-1 profile-avatar-block">
<div class="profile-avatar avatar-lg" v-if="!avatar">
{{ avatarName }}
</div>
<img
class="rounded-circle header-profile-user avatar-lg"
alt="200x200"
:src="renderImageUrl"
data-holder-rendered="true"
v-else
/>
</div>
<div class="profile-avatar-text-block">
<b-button variant="link" class="image-change-button pt-0"
><input
class="form-control"
type="file"
@change="onChangeAvatar"
/>
<i v-if="avatar"> <Icon icon="bxs:edit-alt"/></i>
<i v-else> <Icon icon="bx:upload"/></i>
<span>{{ !avatar ? 'Upload Avatar' : 'Change' }}</span>
</b-button>
<span v-if="avatar"> | </span>
<b-button
variant="link"
class="image-change-button pt-0"
v-if="avatar"
@click="removeAvatar"
>
<i class="text-danger" v-if="avatar"> <Icon icon="bxs:trash"/></i>
<span class="text-danger">Remove</span>
</b-button>
<p>
<em class="image-size-specify-tag"
>Optimal size: 96px X 96px</em
>
</p>
</div>
</div>
<div class="col-md-12">
<div class="row">
<div class="col-md-4">
<b-form-group
class="mb-3"
label="First name"
label-for="formrow-firstName-input"
>
<b-form-input
id="formrow-firstName-input"
type="text"
placeholder="First name"
v-model="form.firstName"
name="firstName"
:class="{
'is-invalid': submitted && $v.form.firstName.$error,
}"
></b-form-input>
<div
v-if="submitted && $v.form.firstName.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.firstName.required"
>This value is required.</span
>
</div>
</b-form-group>
</div>
<div class="col-md-4">
<b-form-group
class="mb-3"
label="Last name"
label-for="formrow-lastName-input"
>
<b-form-input
id="formrow-lastName-input"
type="text"
placeholder="Last name"
v-model="form.lastName"
name="lastName"
:class="{
'is-invalid': submitted && $v.form.lastName.$error,
}"
></b-form-input>
<div
v-if="submitted && $v.form.lastName.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.lastName.required"
>This value is required.</span
>
</div>
</b-form-group>
</div>
<div class="col-md-4 mb-3">
<label>Timezone</label>
<multiselect
v-model="form.timeZoneId"
:options="timeZones"
:class="{
'is-invalid': submitted && $v.form.timeZoneId.$error,
}"
placeholder="Select timezone"
label="label"
></multiselect>
<div
v-if="submitted && $v.form.timeZoneId.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.timeZoneId.required"
>This value is required.</span
>
</div>
</div>
<div class="col-md-4">
<b-form-group
class="mb-3"
label="Job Title"
label-for="formrow-jobTitle-input"
>
<b-form-input
id="formrow-jobTitle-input"
type="text"
placeholder="Job Title"
v-model="form.jobTitle"
name="jobTitle"
></b-form-input>
<!-- <div
v-if="submitted && $v.form.jobTitle.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.jobTitle.required"
>This value is required.</span
>
</div> -->
</b-form-group>
</div>
<div class="col-md-4">
<b-form-group
class="mb-3"
label="Department"
label-for="formrow-department-input"
>
<b-form-input
id="formrow-department-input"
type="text"
placeholder="Department"
v-model="form.department"
name="department"
></b-form-input>
<!-- <div
v-if="submitted && $v.form.department.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.department.required"
>This value is required.</span
>
</div> -->
</b-form-group>
</div>
<div class="col-md-4 mb-3">
<label>Language</label>
<multiselect
v-model="form.languageId"
:options="languages"
:class="{
'is-invalid': submitted && $v.form.languageId.$error,
}"
placeholder="Select language"
label="label"
></multiselect>
<div
v-if="submitted && $v.form.languageId.$error"
class="invalid-feedback"
>
<span v-if="!$v.form.languageId.required"
>This value is required.</span
>
</div>
</div>
</div>
</div>
</div>
<div>
<b-button variant="primary" type="submit">
<i
class="bx bx-loader bx-spin font-size-16 align-middle me-2"
v-if="updateProfileInfoLoading"
></i>
Save</b-button
>
<b-button variant="light" @click="resetForm">Cancel</b-button>
</div>
</b-form>
</div>
</div>
</div>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect';
import { required } from 'vuelidate/lib/validators';
import { isFileWithinLimit, toastConfig } from '../../utils/util';
import { BForm ,BButton,BFormGroup,BFormInput} from 'bootstrap-vue-next'
import { Icon } from '@iconify/vue';
import * as _ from 'lodash';
export default {
components: {
Multiselect,
BForm,
BButton,
BFormGroup,
BFormInput,
Icon
},
props: {
testImages: {
type: Object,
required: true,
},
updateProfileInfoLoading: {
type: Boolean,
required: true,
},
timeZones: {
type: Array,
required: true,
},
languages: {
type: Array,
required: true,
},
profileData: {
type: Object,
required: true,
},
},
data() {
return {
avatar: null,
form: {
firstName: this.profileData.firstName,
lastName: this.profileData.lastName,
jobTitle: this.profileData.jobTitle,
department: this.profileData.department,
timeZoneId: _.find(
this.timeZones,
({ value }) => value === this.profileData.timeZoneId,
),
languageId: _.find(
this.languages,
({ value }) => value === this.profileData.languageId,
),
},
submitted: false,
};
},
validations: {
form: {
firstName: { required },
lastName: { required },
// jobTitle: { required },
// department: { required },
timeZoneId: { required },
languageId: { required },
},
},
mounted() {
const { profileImage = null } = this.profileData;
if (profileImage) {
this.avatar = this.profileData.profileImage;
}
},
computed: {
avatarName() {
if (!this.form.firstName && !this.form.lastName) {
return '';
}
return `${
this.form.firstName ? this.form.firstName.charAt(0).toUpperCase() : ''
}${this.form.lastName ? this.form.lastName.charAt(0).toUpperCase() : ''}`;
},
renderImageUrl() {
if (this.avatar == null) {
return null;
}
const image =
typeof this.avatar === 'object'
? URL.createObjectURL(this.avatar)
: this.avatar;
return image;
},
},
methods: {
removeAvatar() {
this.avatar = null;
},
formSubmit() {
this.submitted = true;
// this.$v.$touch();
// if (this.$v.$invalid) {
// return;
// }
const formData = new FormData();
formData.append(
'data',
JSON.stringify({
...this.form,
isImageDeleted:
this.avatar === null && this.profileData.profileImage
? true
: false,
}),
);
if (this.avatar !== null && typeof this.avatar === 'object') {
formData.append('file', this.avatar);
}
this.$emit('formSubmit', formData);
},
onChangeAvatar(e) {
const { files } = e.target;
if (files && files[0]) {
const tempFiles = [...files];
if (
tempFiles[0].type.includes('image') &&
isFileWithinLimit(tempFiles[0].size / 1024 / 1024, 5)
) {
let reader = new FileReader();
reader.readAsDataURL(tempFiles[0]);
reader.onload = (evt) => {
let img = new Image();
img.onload = () => {
if (img.height < 96 || img.width < 96) {
this.$toast.open(
toastConfig.toastError(
'The image should have a minmum height and width of 96px.',
),
);
} else if (img.height !== img.width) {
this.$toast.open(
toastConfig.toastError(
'The height and width of image should be same.',
),
);
} else {
this.avatar = tempFiles[0];
}
};
img.src = evt.target.result;
};
} else {
this.$emit(
'toast',
toastConfig.toastError(
'The file should be an image and should be less than 5MB',
),
);
}
}
e.target.value = '';
},
resetForm() {
this.form = {
firstName: this.profileData.firstName,
lastName: this.profileData.lastName,
jobTitle: this.profileData.jobTitle,
department: this.profileData.department,
timeZoneId: _.find(
this.timeZones,
({ value }) => value === this.profileData.timeZoneId,
),
languageId: _.find(
this.languages,
({ value }) => value === this.profileData.languageId,
),
};
const { profileImage = null } = this.profileData;
if (profileImage) {
this.avatar = this.profileData.profileImage;
} else {
this.avatar = null;
}
},
},
};
</script>