1<template>
2 <SettingsLayoutBase
3 :title="__('Profile')"
4 :description="__('Manage your profile information.')"
5 >
6 <template #content>
7 <div class="flex items-center justify-between gap-2 pt-1.5 pb-8">
8 <AvatarRow
9 :image="user.doc?.user_image"
10 :name="user.doc?.full_name"
11 :subtitle="user.doc?.email"
12 :busy="user.save.loading"
13 @upload="updateImage"
14 @remove="updateImage()"
15 @rename="updateFullName"
16 >
17 <template #badge>
18 <div
19 v-if="agentStatusStore.myStatus"
20 class="absolute -bottom-0.5 end-0 rounded-full bg-surface-elevation-2 p-1"
21 >
22 <div
23 class="size-3.5 rounded-full"
24 :class="agentStatusStore.statusColor(agentStatusStore.myStatus)"
25 />
26 </div>
27 </template>
28 </AvatarRow>
29 </div>
30 <div>
31 <div class="flex items-center justify-between h-7">
32 <div class="flex gap-2 items-center">
33 <span class="text-base-semibold text-ink-gray-9">
34 {{ __("Account Info & Security") }}
35 </span>
36 </div>
37 </div>
38 </div>
39
40 <div v-if="hasAgentRecord" class="flex items-center justify-between mt-6">
41 <div class="flex flex-col gap-1">
42 <span class="text-base-medium text-ink-gray-8">
43 {{ __("Availability") }}
44 </span>
45 <span class="text-p-sm text-ink-gray-6">
46 {{
47 __(
48 "Set your availability so your team knows when you're reachable."
49 )
50 }}
51 </span>
52 </div>
53 <AvailabilityMenu />
54 </div>
55 <div class="flex items-center justify-between mt-6">
56 <div class="flex flex-col gap-1">
57 <span class="text-base-medium text-ink-gray-8">
58 {{ __("Emails & Signature") }}
59 </span>
60 <span class="text-p-sm text-ink-gray-6">
61 {{
62 __(
63 "Manage your account emails and email signature for communication."
64 )
65 }}
66 </span>
67 </div>
68 <Button
69 :label="__('Configure')"
70 @click="emit('updateStep', 'user-email-settings')"
71 />
72 </div>
73 <div class="flex items-center justify-between mt-6">
74 <div class="flex flex-col gap-1">
75 <span class="text-base-medium text-ink-gray-8">
76 {{ __("Password") }}
77 </span>
78 <span class="text-p-sm text-ink-gray-6">{{
79 __("Change your account password for security.")
80 }}</span>
81 </div>
82 <Button
83 icon-left="lucide-lock"
84 :label="__('Change Password')"
85 @click="showChangePasswordModal = true"
86 />
87 </div>
88 </template>
89 </SettingsLayoutBase>
90 <ChangePasswordModal
91 v-if="showChangePasswordModal"
92 v-model="showChangePasswordModal"
93 :user="userId"
94 />
95</template>
96
97<script setup lang="ts">
98import { Button, createDocumentResource, toast } from "frappe-ui";
99import { ref } from "vue";
100
101import { useAuthStore } from "@/stores/auth";
102import { __ } from "@/translation";
103const emit = defineEmits(["updateStep"]);
104
105import AvailabilityMenu from "@/components/AvailabilityMenu.vue";
106import SettingsLayoutBase from "@/components/layouts/SettingsLayoutBase.vue";
107import { useAgentStatusStore } from "@/stores/agentStatus";
108import AvatarRow from "@opendesk/shared/AvatarRow.vue";
109import ChangePasswordModal from "@opendesk/shared/ChangePasswordModal.vue";
110
111const agentStatusStore = useAgentStatusStore();
112const showChangePasswordModal = ref(false);
113
114const { userId, hasAgentRecord } = useAuthStore();
115const user = createDocumentResource({ doctype: "User", name: userId });
116
117function updateFullName(fullName: string) {
118 const [firstName, ...lastName] = fullName.split(" ");
119 user.doc.first_name = firstName;
120 user.doc.last_name = lastName.join(" ");
121 save();
122}
123
124function save() {
125 user.save.submit(null, {
126 onSuccess: () => {
127 toast.success(__("Profile updated successfully."));
128 },
129 onError: (err: { message: string; messages: string[] }) => {
130 toast.error(err.message + ": " + err.messages[0]);
131 },
132 });
133}
134
135function updateImage(fileUrl = "") {
136 user.doc.user_image = fileUrl;
137 save();
138}
139</script>
140