iachat/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactForm.vue
Shivam Mishra a88d155dd7
feat: update tool-chain to latest (#7975)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2023-09-27 14:02:34 +05:30

429 lines
12 KiB
Vue

<template>
<form
class="contact--form w-full pt-6 px-8 pb-8"
@submit.prevent="handleSubmit"
>
<div>
<div class="w-full">
<woot-avatar-uploader
:label="$t('CONTACT_FORM.FORM.AVATAR.LABEL')"
:src="avatarUrl"
:username-avatar="name"
:delete-avatar="!!avatarUrl"
class="settings-item"
@change="handleImageUpload"
@onAvatarDelete="handleAvatarDelete"
/>
</div>
</div>
<div>
<div class="w-full">
<label :class="{ error: $v.name.$error }">
{{ $t('CONTACT_FORM.FORM.NAME.LABEL') }}
<input
v-model.trim="name"
type="text"
:placeholder="$t('CONTACT_FORM.FORM.NAME.PLACEHOLDER')"
@input="$v.name.$touch"
/>
</label>
<label :class="{ error: $v.email.$error }">
{{ $t('CONTACT_FORM.FORM.EMAIL_ADDRESS.LABEL') }}
<input
v-model.trim="email"
type="text"
:placeholder="$t('CONTACT_FORM.FORM.EMAIL_ADDRESS.PLACEHOLDER')"
@input="$v.email.$touch"
/>
<span v-if="$v.email.$error" class="message">
{{ $t('CONTACT_FORM.FORM.EMAIL_ADDRESS.ERROR') }}
</span>
</label>
</div>
</div>
<div class="w-full">
<label :class="{ error: $v.description.$error }">
{{ $t('CONTACT_FORM.FORM.BIO.LABEL') }}
<textarea
v-model.trim="description"
type="text"
:placeholder="$t('CONTACT_FORM.FORM.BIO.PLACEHOLDER')"
@input="$v.description.$touch"
/>
</label>
</div>
<div>
<div class="w-full">
<label
:class="{
error: isPhoneNumberNotValid,
}"
>
{{ $t('CONTACT_FORM.FORM.PHONE_NUMBER.LABEL') }}
<woot-phone-input
v-model="phoneNumber"
:value="phoneNumber"
:error="isPhoneNumberNotValid"
:placeholder="$t('CONTACT_FORM.FORM.PHONE_NUMBER.PLACEHOLDER')"
@input="onPhoneNumberInputChange"
@blur="$v.phoneNumber.$touch"
@setCode="setPhoneCode"
/>
<span v-if="isPhoneNumberNotValid" class="message">
{{ phoneNumberError }}
</span>
</label>
<div
v-if="isPhoneNumberNotValid || !phoneNumber"
class="callout small warning text-sm dark:bg-yellow-200/20 dark:text-yellow-400"
>
{{ $t('CONTACT_FORM.FORM.PHONE_NUMBER.HELP') }}
</div>
</div>
</div>
<woot-input
v-model.trim="companyName"
class="w-full"
:label="$t('CONTACT_FORM.FORM.COMPANY_NAME.LABEL')"
:placeholder="$t('CONTACT_FORM.FORM.COMPANY_NAME.PLACEHOLDER')"
/>
<div>
<div class="w-full">
<label>
{{ $t('CONTACT_FORM.FORM.COUNTRY.LABEL') }}
</label>
<multiselect
v-model="country"
track-by="id"
label="name"
:placeholder="$t('CONTACT_FORM.FORM.COUNTRY.PLACEHOLDER')"
selected-label
:select-label="$t('CONTACT_FORM.FORM.COUNTRY.SELECT_PLACEHOLDER')"
:deselect-label="$t('CONTACT_FORM.FORM.COUNTRY.REMOVE')"
:custom-label="countryNameWithCode"
:max-height="160"
:options="countries"
:allow-empty="true"
:option-height="104"
/>
</div>
</div>
<woot-input
v-model="city"
class="w-full"
:label="$t('CONTACT_FORM.FORM.CITY.LABEL')"
:placeholder="$t('CONTACT_FORM.FORM.CITY.PLACEHOLDER')"
/>
<div class="w-full">
<label> Social Profiles </label>
<div
v-for="socialProfile in socialProfileKeys"
:key="socialProfile.key"
class="input-group"
>
<span class="input-group-label">{{ socialProfile.prefixURL }}</span>
<input
v-model="socialProfileUserNames[socialProfile.key]"
class="input-group-field"
type="text"
/>
</div>
</div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
<div class="w-full">
<woot-submit-button
:loading="inProgress"
:button-text="$t('CONTACT_FORM.FORM.SUBMIT')"
/>
<button class="button clear" @click.prevent="onCancel">
{{ $t('CONTACT_FORM.FORM.CANCEL') }}
</button>
</div>
</div>
</form>
</template>
<script>
import alertMixin from 'shared/mixins/alertMixin';
import {
DuplicateContactException,
ExceptionWithMessage,
} from 'shared/helpers/CustomErrors';
import { required, email } from 'vuelidate/lib/validators';
import countries from 'shared/constants/countries.js';
import { isPhoneNumberValid } from 'shared/helpers/Validators';
import parsePhoneNumber from 'libphonenumber-js';
export default {
mixins: [alertMixin],
props: {
contact: {
type: Object,
default: () => ({}),
},
inProgress: {
type: Boolean,
default: false,
},
onSubmit: {
type: Function,
default: () => {},
},
},
data() {
return {
countries: countries,
companyName: '',
description: '',
email: '',
name: '',
phoneNumber: '',
activeDialCode: '',
avatarFile: null,
avatarUrl: '',
country: {
id: '',
name: '',
},
city: '',
socialProfileUserNames: {
facebook: '',
twitter: '',
linkedin: '',
github: '',
},
socialProfileKeys: [
{ key: 'facebook', prefixURL: 'https://facebook.com/' },
{ key: 'twitter', prefixURL: 'https://twitter.com/' },
{ key: 'linkedin', prefixURL: 'https://linkedin.com/' },
{ key: 'github', prefixURL: 'https://github.com/' },
],
};
},
validations: {
name: {
required,
},
description: {},
email: {
email,
},
companyName: {},
phoneNumber: {},
bio: {},
},
computed: {
parsePhoneNumber() {
return parsePhoneNumber(this.phoneNumber);
},
isPhoneNumberNotValid() {
if (this.phoneNumber !== '') {
return (
!isPhoneNumberValid(this.phoneNumber, this.activeDialCode) ||
(this.phoneNumber !== '' ? this.activeDialCode === '' : false)
);
}
return false;
},
phoneNumberError() {
if (this.activeDialCode === '') {
return this.$t('CONTACT_FORM.FORM.PHONE_NUMBER.DIAL_CODE_ERROR');
}
if (!isPhoneNumberValid(this.phoneNumber, this.activeDialCode)) {
return this.$t('CONTACT_FORM.FORM.PHONE_NUMBER.ERROR');
}
return '';
},
setPhoneNumber() {
if (this.parsePhoneNumber && this.parsePhoneNumber.countryCallingCode) {
return this.phoneNumber;
}
if (this.phoneNumber === '' && this.activeDialCode !== '') {
return '';
}
return this.activeDialCode
? `${this.activeDialCode}${this.phoneNumber}`
: '';
},
},
watch: {
contact() {
this.setContactObject();
},
},
mounted() {
this.setContactObject();
this.setDialCode();
},
methods: {
onCancel() {
this.$emit('cancel');
},
onSuccess() {
this.$emit('success');
},
countryNameWithCode({ name, id }) {
if (!id) return name;
if (!name && !id) return '';
return `${name} (${id})`;
},
setDialCode() {
if (
this.phoneNumber !== '' &&
this.parsePhoneNumber &&
this.parsePhoneNumber.countryCallingCode
) {
const dialCode = this.parsePhoneNumber.countryCallingCode;
this.activeDialCode = `+${dialCode}`;
}
},
setContactObject() {
const {
email: emailAddress,
phone_number: phoneNumber,
name,
} = this.contact;
const additionalAttributes = this.contact.additional_attributes || {};
this.name = name || '';
this.email = emailAddress || '';
this.phoneNumber = phoneNumber || '';
this.companyName = additionalAttributes.company_name || '';
this.country = {
id: additionalAttributes.country_code || '',
name:
additionalAttributes.country ||
this.$t('CONTACT_FORM.FORM.COUNTRY.SELECT_COUNTRY'),
};
this.city = additionalAttributes.city || '';
this.description = additionalAttributes.description || '';
this.avatarUrl = this.contact.thumbnail || '';
const {
social_profiles: socialProfiles = {},
screen_name: twitterScreenName,
} = additionalAttributes;
this.socialProfileUserNames = {
twitter: socialProfiles.twitter || twitterScreenName || '',
facebook: socialProfiles.facebook || '',
linkedin: socialProfiles.linkedin || '',
github: socialProfiles.github || '',
instagram: socialProfiles.instagram || '',
};
},
getContactObject() {
if (this.country === null) {
this.country = {
id: '',
name: '',
};
}
const contactObject = {
id: this.contact.id,
name: this.name,
email: this.email,
phone_number: this.setPhoneNumber,
additional_attributes: {
...this.contact.additional_attributes,
description: this.description,
company_name: this.companyName,
country_code: this.country.id,
country:
this.country.name ===
this.$t('CONTACT_FORM.FORM.COUNTRY.SELECT_COUNTRY')
? ''
: this.country.name,
city: this.city,
social_profiles: this.socialProfileUserNames,
},
};
if (this.avatarFile) {
contactObject.avatar = this.avatarFile;
contactObject.isFormData = true;
}
return contactObject;
},
onPhoneNumberInputChange(value, code) {
this.activeDialCode = code;
},
setPhoneCode(code) {
if (this.phoneNumber !== '' && this.parsePhoneNumber) {
const dialCode = this.parsePhoneNumber.countryCallingCode;
if (dialCode === code) {
return;
}
this.activeDialCode = `+${dialCode}`;
const newPhoneNumber = this.phoneNumber.replace(
`+${dialCode}`,
`${code}`
);
this.phoneNumber = newPhoneNumber;
} else {
this.activeDialCode = code;
}
},
async handleSubmit() {
this.$v.$touch();
if (this.$v.$invalid || this.isPhoneNumberNotValid) {
return;
}
try {
await this.onSubmit(this.getContactObject());
this.onSuccess();
this.showAlert(this.$t('CONTACT_FORM.SUCCESS_MESSAGE'));
} catch (error) {
if (error instanceof DuplicateContactException) {
if (error.data.includes('email')) {
this.showAlert(
this.$t('CONTACT_FORM.FORM.EMAIL_ADDRESS.DUPLICATE')
);
} else if (error.data.includes('phone_number')) {
this.showAlert(this.$t('CONTACT_FORM.FORM.PHONE_NUMBER.DUPLICATE'));
}
} else if (error instanceof ExceptionWithMessage) {
this.showAlert(error.data);
} else {
this.showAlert(this.$t('CONTACT_FORM.ERROR_MESSAGE'));
}
}
},
handleImageUpload({ file, url }) {
this.avatarFile = file;
this.avatarUrl = url;
},
async handleAvatarDelete() {
try {
if (this.contact && this.contact.id) {
await this.$store.dispatch('contacts/deleteAvatar', this.contact.id);
this.showAlert(
this.$t('CONTACT_FORM.DELETE_AVATAR.API.SUCCESS_MESSAGE')
);
}
this.avatarFile = null;
this.avatarUrl = '';
this.activeDialCode = '';
} catch (error) {
this.showAlert(
error.message
? error.message
: this.$t('CONTACT_FORM.DELETE_AVATAR.API.ERROR_MESSAGE')
);
}
},
},
};
</script>
<style scoped lang="scss">
.input-group-label {
@apply text-sm bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-100 border-slate-200 dark:border-slate-600;
}
::v-deep {
.multiselect .multiselect__tags .multiselect__single {
@apply pl-0;
}
}
</style>