feat: complete basic profile update logic

This commit is contained in:
Muhsin Keloth
2024-04-17 13:07:04 +05:30
parent c432c58d6a
commit 4de6de2e56
3 changed files with 235 additions and 70 deletions
@@ -7,13 +7,62 @@
<h2 class="text-2xl font-medium text-slate-900 dark:text-white">
Profile Settings
</h2>
<user-basic-profile username="John Doe" size="72px" />
<user-basic-profile
:src="avatarUrl"
:display-name="displayName"
size="72px"
@change="handleImageUpload"
@update="updateUser"
/>
<form @submit.prevent="updateUser('profile')">
<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>
</form>
<personal-wrapper
header="Personal message signature"
description="Create a unique message signature to appear at the end of every message you send from any inbox. You can also include an inline image, which is supported in live-chat, email, and API inboxes."
:show-action-button="true"
button-text="Save message signature"
:show-action-button="false"
>
<template #settingsItem>
<message-signature />
@@ -74,7 +123,7 @@
</div>
</div>
</template>
<script setup>
<script>
import UserBasicProfile from './UserBasicProfile.vue';
import MessageSignature from './MessageSignature.vue';
import PersonalWrapper from './PersonalWrapper.vue';
@@ -83,21 +132,148 @@ import ChangePassword from './ChangePassword.vue';
import NotificationPreferences from './NotificationPreferences.vue';
import AudioNotifications from './AudioNotifications.vue';
import AccessToken from './AccessToken.vue';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import uiSettingsMixin, {
isEditorHotKeyEnabled,
} from 'dashboard/mixins/uiSettings';
import alertMixin from 'shared/mixins/alertMixin';
import { required, minLength, email } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import { clearCookiesOnLogout } from '../../../../store/utils/api';
import { hasValidAvatarUrl } from 'dashboard/helper/URLHelper';
const keyOptions = [
{
key: 'enter',
src: '/assets/images/dashboard/profile/hot-key-enter.svg',
heading: 'Enter (↵)',
content:
'Send messages by pressing Enter key instead of clicking send button.',
export default {
components: {
UserBasicProfile,
MessageSignature,
PersonalWrapper,
HotKeyCard,
ChangePassword,
NotificationPreferences,
AudioNotifications,
AccessToken,
},
{
key: 'cmd_enter',
src: '/assets/images/dashboard/profile/hot-key-ctrl-enter.svg',
heading: 'CMD / Ctrl + Enter (⌘ + ↵)',
content:
'Send messages by pressing Enter key instead of clicking send button.',
mixins: [alertMixin, globalConfigMixin, uiSettingsMixin],
data() {
return {
avatarFile: '',
avatarUrl: '',
name: '',
displayName: '',
email: '',
isProfileUpdating: false,
errorMessage: '',
keyOptions: [
{
key: 'enter',
src: '/assets/images/dashboard/profile/hot-key-enter.svg',
heading: 'Enter (↵)',
content:
'Send messages by pressing Enter key instead of clicking send button.',
},
{
key: 'cmd_enter',
src: '/assets/images/dashboard/profile/hot-key-ctrl-enter.svg',
heading: 'CMD / Ctrl + Enter (⌘ + ↵)',
content:
'Send messages by pressing Enter key instead of clicking send button.',
},
],
};
},
];
validations: {
name: {
required,
minLength: minLength(1),
},
displayName: {},
email: {
required,
email,
},
},
computed: {
...mapGetters({
currentUser: 'getCurrentUser',
currentUserId: 'getCurrentUserID',
globalConfig: 'globalConfig/get',
}),
showDeleteButton() {
return hasValidAvatarUrl(this.avatarUrl);
},
},
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'));
}
},
toggleEditorMessageKey(key) {
this.updateUISettings({ editor_message_key: key });
this.showAlert(
this.$t('PROFILE_SETTINGS.FORM.SEND_MESSAGE.UPDATE_SUCCESS')
);
},
},
};
</script>
@@ -1,14 +1,24 @@
<template>
<woot-message-editor
id="message-signature-input"
v-model="messageSignature"
class="message-editor h-[10rem]"
:is-format-mode="true"
:placeholder="$t('PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE.PLACEHOLDER')"
:enabled-menu-options="customEditorMenuList"
:enable-suggestions="false"
:show-image-resize-toolbar="true"
/>
<div class="flex flex-col gap-6">
<woot-message-editor
id="message-signature-input"
v-model="messageSignature"
class="message-editor h-[10rem]"
:is-format-mode="true"
:placeholder="$t('PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE.PLACEHOLDER')"
:enabled-menu-options="customEditorMenuList"
:enable-suggestions="false"
:show-image-resize-toolbar="true"
/>
<woot-button
class="w-fit"
:is-loading="isUpdating"
type="button"
@click.prevent="updateSignature"
>
{{ $t('PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.BTN_TEXT') }}
</woot-button>
</div>
</template>
<script>
@@ -5,17 +5,25 @@
Profile picture
</span>
<div
class="relative rounded-xl h-[72px] w-[72px]"
class="relative rounded-xl h-[72px] w-[72px] cursor-pointer"
:title="title"
@mouse-over="showUpload"
@click="openFileInput"
>
<img
class="rounded-xl h-[72px] w-[72px]"
src="https://i.pravatar.cc/300"
:src="src"
draggable="false"
@load="onImgLoad"
@error="onImgError"
/>
<input
ref="file"
type="file"
accept="image/png, image/jpeg, image/jpg, image/gif, image/webp"
style="display: none"
@change="handleImageUpload"
/>
<div
class="absolute z-10 flex items-center justify-center w-6 h-6 p-1 border border-white rounded-full select-none -top-2 -right-2 dark:border-white bg-slate-200 dark:bg-slate-700"
>
@@ -36,50 +44,10 @@
</div>
</div>
</div>
<div class="pt-6">
<form-input
name="full_name"
class="flex-1"
:class="{ error: false }"
:label="$t('REGISTER.FULL_NAME.LABEL')"
placeholder="Enter your name"
:has-error="false"
:error-message="$t('REGISTER.FULL_NAME.ERROR')"
/>
<form-input
name="display_name"
class="flex-1"
:class="{ error: false }"
label="Display name"
placeholder="Enter your display name"
:has-error="false"
:error-message="$t('REGISTER.FULL_NAME.ERROR')"
/>
<form-input
name="email"
class="flex-1"
:class="{ error: false }"
label="Email"
placeholder="Enter your email"
:has-error="false"
:error-message="$t('REGISTER.FULL_NAME.ERROR')"
/>
<woot-button
color-scheme="primary"
class="rounded-xl w-fit"
@click="$emit('click')"
>
Update profile
</woot-button>
</div>
</div>
</template>
<script>
import FormInput from 'v3/components/Form/Input.vue';
export default {
components: {
FormInput,
},
props: {
src: {
type: String,
@@ -125,6 +93,17 @@ export default {
showUpload() {
this.showUploadIcon = true;
},
openFileInput() {
// Trigger click event on the hidden file input
this.$refs.file.click();
},
handleImageUpload(event) {
const [file] = event.target.files;
this.$emit('change', {
file,
url: file ? URL.createObjectURL(file) : null,
});
},
},
};
</script>