iachat/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue
Sojan Jose 873cfa08d8
feat: Ability to reset api_access_token (#11565)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
2025-05-29 14:42:13 +05:30

300 lines
9.5 KiB
Vue

<script>
import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { useUISettings } from 'dashboard/composables/useUISettings';
import { useFontSize } from 'dashboard/composables/useFontSize';
import { clearCookiesOnLogout } from 'dashboard/store/utils/api.js';
import { copyTextToClipboard } from 'shared/helpers/clipboard';
import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import UserProfilePicture from './UserProfilePicture.vue';
import UserBasicDetails from './UserBasicDetails.vue';
import MessageSignature from './MessageSignature.vue';
import FontSize from './FontSize.vue';
import HotKeyCard from './HotKeyCard.vue';
import ChangePassword from './ChangePassword.vue';
import NotificationPreferences from './NotificationPreferences.vue';
import AudioNotifications from './AudioNotifications.vue';
import FormSection from 'dashboard/components/FormSection.vue';
import AccessToken from './AccessToken.vue';
import Policy from 'dashboard/components/policy.vue';
import {
ROLES,
CONVERSATION_PERMISSIONS,
} from 'dashboard/constants/permissions.js';
export default {
components: {
MessageSignature,
FormSection,
FontSize,
UserProfilePicture,
Policy,
UserBasicDetails,
HotKeyCard,
ChangePassword,
NotificationPreferences,
AudioNotifications,
AccessToken,
},
mixins: [globalConfigMixin],
setup() {
const { isEditorHotKeyEnabled, updateUISettings } = useUISettings();
const { currentFontSize, updateFontSize } = useFontSize();
return {
currentFontSize,
updateFontSize,
isEditorHotKeyEnabled,
updateUISettings,
};
},
data() {
return {
avatarFile: '',
avatarUrl: '',
name: '',
displayName: '',
email: '',
messageSignature: '',
hotKeys: [
{
key: 'enter',
title: this.$t(
'PROFILE_SETTINGS.FORM.SEND_MESSAGE.CARD.ENTER_KEY.HEADING'
),
description: this.$t(
'PROFILE_SETTINGS.FORM.SEND_MESSAGE.CARD.ENTER_KEY.CONTENT'
),
lightImage: '/assets/images/dashboard/profile/hot-key-enter.svg',
darkImage: '/assets/images/dashboard/profile/hot-key-enter-dark.svg',
},
{
key: 'cmd_enter',
title: this.$t(
'PROFILE_SETTINGS.FORM.SEND_MESSAGE.CARD.CMD_ENTER_KEY.HEADING'
),
description: this.$t(
'PROFILE_SETTINGS.FORM.SEND_MESSAGE.CARD.CMD_ENTER_KEY.CONTENT'
),
lightImage: '/assets/images/dashboard/profile/hot-key-ctrl-enter.svg',
darkImage:
'/assets/images/dashboard/profile/hot-key-ctrl-enter-dark.svg',
},
],
notificationPermissions: [...ROLES, ...CONVERSATION_PERMISSIONS],
audioNotificationPermissions: [...ROLES, ...CONVERSATION_PERMISSIONS],
};
},
computed: {
...mapGetters({
currentUser: 'getCurrentUser',
currentUserId: 'getCurrentUserID',
globalConfig: 'globalConfig/get',
}),
},
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;
this.messageSignature = this.currentUser.message_signature;
},
async dispatchUpdate(payload, successMessage, errorMessage) {
let alertMessage = '';
try {
await this.$store.dispatch('updateProfile', payload);
alertMessage = successMessage;
return true; // return the value so that the status can be known
} catch (error) {
alertMessage = parseAPIErrorResponse(error) || errorMessage;
return false; // return the value so that the status can be known
} finally {
useAlert(alertMessage);
}
},
async updateProfile(userAttributes) {
const { name, email, displayName } = userAttributes;
const hasEmailChanged = this.currentUser.email !== email;
this.name = name || this.name;
this.email = email || this.email;
this.displayName = displayName || this.displayName;
const updatePayload = {
name: this.name,
email: this.email,
displayName: this.displayName,
avatar: this.avatarFile,
};
const success = await this.dispatchUpdate(
updatePayload,
hasEmailChanged
? this.$t('PROFILE_SETTINGS.AFTER_EMAIL_CHANGED')
: this.$t('PROFILE_SETTINGS.UPDATE_SUCCESS'),
this.$t('RESET_PASSWORD.API.ERROR_MESSAGE')
);
if (hasEmailChanged && success) clearCookiesOnLogout();
},
async updateSignature(signature) {
const payload = { message_signature: signature };
let successMessage = this.$t(
'PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.API_SUCCESS'
);
let errorMessage = this.$t(
'PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.API_ERROR'
);
await this.dispatchUpdate(payload, successMessage, errorMessage);
},
updateProfilePicture({ file, url }) {
this.avatarFile = file;
this.avatarUrl = url;
},
async deleteProfilePicture() {
try {
await this.$store.dispatch('deleteAvatar');
this.avatarUrl = '';
this.avatarFile = '';
useAlert(this.$t('PROFILE_SETTINGS.AVATAR_DELETE_SUCCESS'));
} catch (error) {
useAlert(this.$t('PROFILE_SETTINGS.AVATAR_DELETE_FAILED'));
}
},
toggleHotKey(key) {
this.hotKeys = this.hotKeys.map(hotKey =>
hotKey.key === key ? { ...hotKey, active: !hotKey.active } : hotKey
);
this.updateUISettings({ editor_message_key: key });
useAlert(this.$t('PROFILE_SETTINGS.FORM.SEND_MESSAGE.UPDATE_SUCCESS'));
},
async onCopyToken(value) {
await copyTextToClipboard(value);
useAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
},
async resetAccessToken() {
const success = await this.$store.dispatch('resetAccessToken');
if (success) {
useAlert(this.$t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.RESET_SUCCESS'));
} else {
useAlert(this.$t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.RESET_ERROR'));
}
},
},
};
</script>
<template>
<div class="grid py-16 px-5 font-inter mx-auto gap-16 sm:max-w-screen-md">
<div class="flex flex-col gap-6">
<h2 class="text-2xl font-medium text-ash-900">
{{ $t('PROFILE_SETTINGS.TITLE') }}
</h2>
<UserProfilePicture
:src="avatarUrl"
:name="name"
@change="updateProfilePicture"
@delete="deleteProfilePicture"
/>
<UserBasicDetails
:name="name"
:display-name="displayName"
:email="email"
:email-enabled="!globalConfig.disableUserProfileUpdate"
@update-user="updateProfile"
/>
</div>
<FormSection
:title="$t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.TITLE')"
:description="$t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.NOTE')"
>
<FontSize
:value="currentFontSize"
:label="$t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.TITLE')"
:description="
$t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.NOTE')
"
@change="updateFontSize"
/>
</FormSection>
<FormSection
:title="$t('PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.TITLE')"
:description="$t('PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.NOTE')"
>
<MessageSignature
:message-signature="messageSignature"
@update-signature="updateSignature"
/>
</FormSection>
<FormSection
:title="$t('PROFILE_SETTINGS.FORM.SEND_MESSAGE.TITLE')"
:description="$t('PROFILE_SETTINGS.FORM.SEND_MESSAGE.NOTE')"
>
<div
class="flex flex-col justify-between w-full gap-5 sm:gap-4 sm:flex-row"
>
<button
v-for="hotKey in hotKeys"
:key="hotKey.key"
class="px-0 reset-base w-full sm:flex-1"
>
<HotKeyCard
:key="hotKey.title"
:title="hotKey.title"
:description="hotKey.description"
:light-image="hotKey.lightImage"
:dark-image="hotKey.darkImage"
:active="isEditorHotKeyEnabled(hotKey.key)"
@click="toggleHotKey(hotKey.key)"
/>
</button>
</div>
</FormSection>
<FormSection
v-if="!globalConfig.disableUserProfileUpdate"
:title="$t('PROFILE_SETTINGS.FORM.PASSWORD_SECTION.TITLE')"
>
<ChangePassword />
</FormSection>
<Policy :permissions="audioNotificationPermissions">
<FormSection
:title="$t('PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.TITLE')"
:description="
$t('PROFILE_SETTINGS.FORM.AUDIO_NOTIFICATIONS_SECTION.NOTE')
"
>
<AudioNotifications />
</FormSection>
</Policy>
<Policy :permissions="notificationPermissions">
<FormSection :title="$t('PROFILE_SETTINGS.FORM.NOTIFICATIONS.TITLE')">
<NotificationPreferences />
</FormSection>
</Policy>
<FormSection
:title="$t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.TITLE')"
:description="
useInstallationName(
$t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.NOTE'),
globalConfig.installationName
)
"
>
<AccessToken
:value="currentUser.access_token"
@on-copy="onCopyToken"
@on-reset="resetAccessToken"
/>
</FormSection>
</div>
</template>