iachat/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue
Sivin Varghese beedfc47bf
feat: Allow users to select Cmd+Enter as a hotkey (#4401)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-10-03 15:27:34 -07:00

307 lines
8.9 KiB
Vue

<template>
<div class="columns profile--settings">
<form @submit.prevent="updateUser('profile')">
<div class="small-12 row profile--settings--row">
<div class="columns small-3">
<h4 class="block-title">
{{ $t('PROFILE_SETTINGS.FORM.PROFILE_SECTION.TITLE') }}
</h4>
<p>{{ $t('PROFILE_SETTINGS.FORM.PROFILE_SECTION.NOTE') }}</p>
</div>
<div class="columns small-9 medium-5">
<woot-avatar-uploader
:label="$t('PROFILE_SETTINGS.FORM.PROFILE_IMAGE.LABEL')"
:src="avatarUrl"
@change="handleImageUpload"
/>
<div v-if="showDeleteButton" class="avatar-delete-btn">
<woot-button
type="button"
color-scheme="alert"
variant="hollow"
size="small"
@click="deleteAvatar"
>
{{ $t('PROFILE_SETTINGS.DELETE_AVATAR') }}
</woot-button>
</div>
<label :class="{ error: $v.name.$error }">
{{ $t('PROFILE_SETTINGS.FORM.NAME.LABEL') }}
<input
v-model="name"
type="text"
:placeholder="$t('PROFILE_SETTINGS.FORM.NAME.PLACEHOLDER')"
@input="$v.name.$touch"
/>
<span v-if="$v.name.$error" class="message">
{{ $t('PROFILE_SETTINGS.FORM.NAME.ERROR') }}
</span>
</label>
<label :class="{ error: $v.displayName.$error }">
{{ $t('PROFILE_SETTINGS.FORM.DISPLAY_NAME.LABEL') }}
<input
v-model="displayName"
type="text"
:placeholder="
$t('PROFILE_SETTINGS.FORM.DISPLAY_NAME.PLACEHOLDER')
"
@input="$v.displayName.$touch"
/>
</label>
<label
v-if="!globalConfig.disableUserProfileUpdate"
:class="{ error: $v.email.$error }"
>
{{ $t('PROFILE_SETTINGS.FORM.EMAIL.LABEL') }}
<input
v-model.trim="email"
type="email"
:placeholder="$t('PROFILE_SETTINGS.FORM.EMAIL.PLACEHOLDER')"
@input="$v.email.$touch"
/>
<span v-if="$v.email.$error" class="message">
{{ $t('PROFILE_SETTINGS.FORM.EMAIL.ERROR') }}
</span>
</label>
<woot-button type="submit" :is-loading="isProfileUpdating">
{{ $t('PROFILE_SETTINGS.BTN_TEXT') }}
</woot-button>
</div>
</div>
</form>
<message-signature />
<div class="profile--settings--row row">
<div class="columns small-3">
<h4 class="block-title">
{{ $t('PROFILE_SETTINGS.FORM.SEND_MESSAGE.TITLE') }}
</h4>
<p>
{{ $t('PROFILE_SETTINGS.FORM.SEND_MESSAGE.NOTE') }}
</p>
</div>
<div class="columns small-9 medium-5 card-preview">
<button
v-for="keyOption in keyOptions"
:key="keyOption.key"
class="preview-button"
@click="toggleEditorMessageKey(keyOption.key)"
>
<preview-card
:heading="keyOption.heading"
:content="keyOption.content"
:src="keyOption.src"
:active="isEditorHotKeyEnabled(uiSettings, keyOption.key)"
/>
</button>
</div>
</div>
<change-password v-if="!globalConfig.disableUserProfileUpdate" />
<notification-settings />
<div class="profile--settings--row row">
<div class="columns small-3">
<h4 class="block-title">
{{ $t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.TITLE') }}
</h4>
<p>
{{
useInstallationName(
$t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.NOTE'),
globalConfig.installationName
)
}}
</p>
</div>
<div class="columns small-9 medium-5">
<woot-code :script="currentUser.access_token" />
</div>
</div>
</div>
</template>
<script>
import { required, minLength, email } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import { clearCookiesOnLogout } from '../../../../store/utils/api';
import NotificationSettings from './NotificationSettings';
import alertMixin from 'shared/mixins/alertMixin';
import ChangePassword from './ChangePassword';
import MessageSignature from './MessageSignature';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import uiSettingsMixin, {
isEditorHotKeyEnabled,
} from 'dashboard/mixins/uiSettings';
import PreviewCard from 'dashboard/components/ui/PreviewCard.vue';
export default {
components: {
NotificationSettings,
ChangePassword,
MessageSignature,
PreviewCard,
},
mixins: [alertMixin, globalConfigMixin, uiSettingsMixin],
data() {
return {
avatarFile: '',
avatarUrl: '',
name: '',
displayName: '',
email: '',
isProfileUpdating: false,
errorMessage: '',
keyOptions: [
{
key: 'enter',
src: '/assets/images/dashboard/editor/enter-editor.png',
heading: this.$t(
'PROFILE_SETTINGS.FORM.SEND_MESSAGE.CARD.ENTER_KEY.HEADING'
),
content: this.$t(
'PROFILE_SETTINGS.FORM.SEND_MESSAGE.CARD.ENTER_KEY.CONTENT'
),
},
{
key: 'cmd_enter',
src: '/assets/images/dashboard/editor/cmd-editor.png',
heading: this.$t(
'PROFILE_SETTINGS.FORM.SEND_MESSAGE.CARD.CMD_ENTER_KEY.HEADING'
),
content: this.$t(
'PROFILE_SETTINGS.FORM.SEND_MESSAGE.CARD.CMD_ENTER_KEY.CONTENT'
),
},
],
};
},
validations: {
name: {
required,
minLength: minLength(1),
},
displayName: {},
email: {
required,
email,
},
},
computed: {
...mapGetters({
currentUser: 'getCurrentUser',
currentUserId: 'getCurrentUserID',
globalConfig: 'globalConfig/get',
}),
},
watch: {
currentUserId(newCurrentUserId, prevCurrentUserId) {
if (prevCurrentUserId !== newCurrentUserId) {
this.initializeUser();
}
},
},
mounted() {
if (this.currentUserId) {
this.initializeUser();
}
},
methods: {
initializeUser() {
this.name = this.currentUser.name;
this.email = this.currentUser.email;
this.avatarUrl = this.currentUser.avatar_url;
this.displayName = this.currentUser.display_name;
},
isEditorHotKeyEnabled,
async updateUser() {
this.$v.$touch();
if (this.$v.$invalid) {
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.ERROR'));
return;
}
this.isProfileUpdating = true;
const hasEmailChanged = this.currentUser.email !== this.email;
try {
await this.$store.dispatch('updateProfile', {
name: this.name,
email: this.email,
avatar: this.avatarFile,
displayName: this.displayName,
});
this.isProfileUpdating = false;
if (hasEmailChanged) {
clearCookiesOnLogout();
this.errorMessage = this.$t('PROFILE_SETTINGS.AFTER_EMAIL_CHANGED');
}
this.errorMessage = this.$t('PROFILE_SETTINGS.UPDATE_SUCCESS');
} catch (error) {
this.errorMessage = this.$t('RESET_PASSWORD.API.ERROR_MESSAGE');
if (error?.response?.data?.error) {
this.errorMessage = error.response.data.error;
}
} finally {
this.isProfileUpdating = false;
this.showAlert(this.errorMessage);
}
},
handleImageUpload({ file, url }) {
this.avatarFile = file;
this.avatarUrl = url;
},
async deleteAvatar() {
try {
await this.$store.dispatch('deleteAvatar');
this.avatarUrl = '';
this.avatarFile = '';
this.showAlert(this.$t('PROFILE_SETTINGS.AVATAR_DELETE_SUCCESS'));
} catch (error) {
this.showAlert(this.$t('PROFILE_SETTINGS.AVATAR_DELETE_FAILED'));
}
},
showDeleteButton() {
return this.avatarUrl && !this.avatarUrl.includes('www.gravatar.com');
},
toggleEditorMessageKey(key) {
this.updateUISettings({ editor_message_key: key });
this.showAlert(
this.$t('PROFILE_SETTINGS.FORM.SEND_MESSAGE.UPDATE_SUCCESS')
);
},
},
};
</script>
<style lang="scss">
@import '~dashboard/assets/scss/variables.scss';
@import '~dashboard/assets/scss/mixins.scss';
.profile--settings {
overflow: auto;
padding: 24px;
}
.profile--settings--row {
@include border-normal-bottom;
align-items: center;
display: flex;
padding: $space-normal;
.small-3 {
padding: $space-normal $space-medium $space-normal 0;
}
.small-9 {
padding: $space-normal;
}
.card-preview {
display: flex;
flex-direction: row;
.preview-button {
cursor: pointer;
margin-right: var(--space-normal);
}
}
}
</style>