feat: edit profile on drawer

This commit is contained in:
puriphatt 2024-06-27 08:32:31 +00:00
parent 23725ad730
commit b24f785311
3 changed files with 156 additions and 188 deletions

View file

@ -21,9 +21,11 @@ defineProps<{
noDetail?: boolean;
noBg?: boolean;
detailColumnCount?: number;
canEditProfile?: boolean;
}>();
defineEmits<{
(e: 'editProfile'): void;
(e: 'deleteCard', id: string): void;
(
e: 'updateCard',
@ -160,6 +162,12 @@ defineEmits<{
bordered
class="avatar"
style="border: 2px solid var(--border-color)"
:class="{ 'edit-profile': canEditProfile }"
@click="
() => {
if (canEditProfile) $emit('editProfile');
}
"
>
<q-img
:src="v.img"
@ -360,4 +368,13 @@ defineEmits<{
background-color: var(--surface-2);
text-wrap: nowrap;
}
.edit-profile {
cursor: pointer;
transition: opacity 0.2s ease;
&:hover {
opacity: 80%;
}
}
</style>

View file

@ -1,9 +1,11 @@
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import { ref, onMounted, watch, computed } from 'vue';
import { storeToRefs } from 'pinia';
import { dialog } from 'src/stores/utils';
import { useI18n } from 'vue-i18n';
import useFlowStore from 'src/stores/flow';
import useUserStore from 'stores/user';
import useBranchStore from 'src/stores/branch';
import { dialog } from 'src/stores/utils';
import {
User,
@ -26,9 +28,7 @@ import FormPerson from 'src/components/02_personnel-management/FormPerson.vue';
import FormByType from 'src/components/02_personnel-management/FormByType.vue';
import DrawerInfo from 'src/components/DrawerInfo.vue';
import InfoForm from 'src/components/02_personnel-management/InfoForm.vue';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import useFlowStore from 'src/stores/flow';
import ProfileUpload from 'src/components/ProfileUpload.vue';
const { locale } = useI18n();
@ -144,6 +144,8 @@ reader.addEventListener('load', () => {
if (typeof reader.result === 'string') {
urlProfile.value = reader.result;
}
if (infoDrawerEdit.value) infoPersonCard.value[0].img = urlProfile.value;
});
watch(profileFile, () => {
@ -229,7 +231,8 @@ function onClose() {
brId.value = '';
userId.value = '';
userCode.value = '';
urlProfile.value = '';
urlProfile.value = undefined;
profileFile.value = undefined;
agencyFile.value = [];
modal.value = false;
isEdit.value = false;
@ -249,121 +252,101 @@ async function onSubmit() {
}
if (isEdit.value && userId.value) {
dialog({
color: 'primary',
icon: 'mdi-pencil-outline',
title: 'ยืนยันการแก้ไขข้อมูล',
actionText: 'ตกลง',
persistent: true,
message: 'คุณต้องการแก้ไขข้อมูล ใช่หรือไม่',
action: async () => {
if (!userId.value) return;
if (!userId.value) return;
const formDataEdit = {
...formData.value,
status: !statusToggle.value ? 'INACTIVE' : 'ACTIVE',
} as const;
await userStore.editById(userId.value, formDataEdit);
const formDataEdit = {
...formData.value,
status: !statusToggle.value ? 'INACTIVE' : 'ACTIVE',
} as const;
await userStore.editById(userId.value, formDataEdit);
if (
hqId.value &&
currentUser.value?.branch[0] &&
hqId.value !== currentUser.value.branch[0].id &&
brId.value !== currentUser.value.branch[0].id
) {
await branchStore.removeUser(
currentUser.value.branch[0].id,
userId.value,
);
if (
hqId.value &&
currentUser.value?.branch[0] &&
hqId.value !== currentUser.value.branch[0].id &&
brId.value !== currentUser.value.branch[0].id
) {
await branchStore.removeUser(
currentUser.value.branch[0].id,
userId.value,
);
await branchStore.addUser(
!!brId.value ? brId.value : hqId.value,
userId.value,
);
}
await branchStore.addUser(
!!brId.value ? brId.value : hqId.value,
userId.value,
);
}
if (!currentUser.value?.branch[0]) {
if (brId.value || hqId.value) {
await branchStore.addUser(
(!!brId.value ? brId.value : hqId.value)!,
userId.value,
);
}
}
if (!currentUser.value?.branch[0]) {
if (brId.value || hqId.value) {
await branchStore.addUser(
(!!brId.value ? brId.value : hqId.value)!,
userId.value,
);
}
}
if (userId.value && formDataEdit.userType === 'AGENCY') {
if (!agencyFile.value) return;
const payload: UserAttachmentCreate = {
file: agencyFile.value,
};
if (userId.value && formDataEdit.userType === 'AGENCY') {
if (!agencyFile.value) return;
const payload: UserAttachmentCreate = {
file: agencyFile.value,
};
if (payload?.file) {
await userStore.addAttachment(userId.value, payload);
}
}
if (payload?.file) {
await userStore.addAttachment(userId.value, payload);
}
}
userStore.fetchList({
includeBranch: true,
query: !!inputSearch.value ? inputSearch.value : undefined,
userType: selectorLabel.value ?? undefined,
});
typeStats.value = await userStore.typeStats();
const res = await branchStore.userStats(formData.value.userType);
if (res) {
userStats.value = res;
}
onClose();
},
userStore.fetchList({
includeBranch: true,
query: !!inputSearch.value ? inputSearch.value : undefined,
userType: selectorLabel.value ?? undefined,
});
typeStats.value = await userStore.typeStats();
const res = await branchStore.userStats(formData.value.userType);
if (res) {
userStats.value = res;
}
onClose();
} else {
dialog({
color: 'primary',
icon: 'mdi-account',
title: 'ยืนยันการเพิ่มบุคลากร',
actionText: 'ตกลง',
persistent: true,
message: 'คุณต้องการเพิ่มบุคลากร ใช่หรือไม่',
action: async () => {
if (!hqId.value) return;
if (!hqId.value) return;
statusToggle.value
? (formData.value.status = 'CREATED')
: (formData.value.status = 'INACTIVE');
statusToggle.value
? (formData.value.status = 'CREATED')
: (formData.value.status = 'INACTIVE');
const result = await userStore.create(formData.value);
if (result) {
await branchStore.addUser(
!!brId.value ? brId.value : hqId.value,
result.id,
);
}
const result = await userStore.create(formData.value);
if (result) {
await branchStore.addUser(
!!brId.value ? brId.value : hqId.value,
result.id,
);
}
if (result && formData.value.userType === 'AGENCY') {
if (!agencyFile.value) return;
if (result && formData.value.userType === 'AGENCY') {
if (!agencyFile.value) return;
const payload: UserAttachmentCreate = {
file: agencyFile.value,
};
const payload: UserAttachmentCreate = {
file: agencyFile.value,
};
if (payload?.file) {
await userStore.addAttachment(result.id, payload);
}
}
if (payload?.file) {
await userStore.addAttachment(result.id, payload);
}
}
selectorLabel.value = formData.value.userType;
userStore.fetchList({
includeBranch: true,
query: !!inputSearch.value ? inputSearch.value : undefined,
userType: selectorLabel.value ?? undefined,
});
typeStats.value = await userStore.typeStats();
const res = await branchStore.userStats(formData.value.userType);
if (res) {
userStats.value = res;
}
onClose();
},
selectorLabel.value = formData.value.userType;
userStore.fetchList({
includeBranch: true,
query: !!inputSearch.value ? inputSearch.value : undefined,
userType: selectorLabel.value ?? undefined,
});
typeStats.value = await userStore.typeStats();
const res = await branchStore.userStats(formData.value.userType);
if (res) {
userStats.value = res;
}
onClose();
}
flowStore.rotate();
}
@ -474,9 +457,13 @@ async function assignFormData(idEdit: string) {
userCode.value = foundUser.code;
urlProfile.value = foundUser.profileImageUrl;
isEdit.value = true;
profileSubmit.value = true;
hqId.value && (await userStore.fetchBrOption(hqId.value));
if (infoPersonCard.value) {
infoPersonCard.value[0].img = foundUser.profileImageUrl;
}
if (formData.value.districtId) {
await adrressStore.fetchSubDistrictByProvinceId(
formData.value.districtId,
@ -728,7 +715,11 @@ watch(
v-if="currentUser"
:category="$t('personnelTitle')"
bg-on
:badgeClass="formData.gender === 'male' ? 'app-bg-male' : 'app-bg-female'"
:badgeClass="
formData.gender === 'male'
? 'app-bg-male text-white'
: 'app-bg-female text-white'
"
:badgeLabel="userCode"
:isEdit="infoDrawerEdit"
:title="
@ -757,12 +748,18 @@ watch(
<div class="q-ma-md">
<AppBox class="surface-1" style="padding: 0">
<PersonCard
:can-edit-profile="infoDrawerEdit"
no-hover
no-action
no-detail
no-bg
:list="infoPersonCard"
:gridColumns="1"
@edit-profile="
() => {
inputFile.click();
}
"
/>
</AppBox>
</div>
@ -843,86 +840,12 @@ watch(
:close="() => onClose()"
>
<template #prepend>
<div class="text-center">
<div class="upload-img-preview">
<q-img
v-if="urlProfile"
:src="urlProfile"
style="object-fit: cover; width: 100%; height: 100%"
/>
<q-icon
v-else
name="mdi-account full-height"
size="3vw"
style="color: var(--border-color)"
/>
</div>
<div
v-if="urlProfile && !profileSubmit"
class="col-12 row q-mt-md q-col-gutter-x-md"
>
<div class="col-6">
<q-btn
id="btn-profile-cancel"
dense
unelevated
outlined
padding="8px"
class="cancel-img-btn full-width"
:label="$t('cancel')"
@click="urlProfile = ''"
/>
</div>
<div class="col-6">
<q-btn
id="btn-profile-save"
dense
unelevated
outlined
padding="8px"
class="submit-img-btn full-width"
:label="$t('save')"
@click="profileSubmit = true"
/>
</div>
</div>
<q-btn
id="btn-profile-edit"
v-else-if="urlProfile && profileSubmit"
dense
unelevated
outlined
padding="8px"
icon="mdi-pencil-outline"
class="edit-img-btn q-mt-md full-width"
:label="$t('formDialogBtnEditProfile')"
@click.prevent="inputFile.click(), (profileSubmit = false)"
/>
<q-btn
id="btn-profile-upload"
v-else
dense
unelevated
outlined
padding="8px"
class="upload-img-btn q-mt-md full-width"
:label="$t('formDialogBtnUploadProfile')"
:class="{ dark: $q.dark.isActive }"
@click="inputFile.click()"
/>
<q-separator class="col-12 q-my-md" />
<div class="text-left q-pt-md">
<q-toggle
dense
size="md"
v-model="statusToggle"
padding="none"
class="q-pr-md"
/>
<span>{{ $t('formDialogTitleUserStatus') }}</span>
</div>
</div>
<ProfileUpload
v-model:url-profile="urlProfile"
v-model:status-toggle="statusToggle"
v-model:profile-submit="profileSubmit"
@input-file="inputFile.click()"
/>
</template>
<template #information>

View file

@ -269,6 +269,12 @@ const inputFile = (() => {
const reader = new FileReader();
reader.addEventListener('load', () => {
if (typeof reader.result === 'string') profileUrl.value = reader.result;
if (infoDrawerEdit.value && currentCustomer.value)
currentCustomer.value.imageUrl = profileUrl.value as string;
if (infoDrawerEmployeeEdit.value)
infoEmployeePersonCard.value[0].img = profileUrl.value;
});
element.addEventListener('change', () => {
@ -977,6 +983,7 @@ async function assignFormDataEmployee(id: string) {
currentEmployeeCode.value = foundEmployee.code;
currentEmployee.value = foundEmployee;
profileUrl.value = foundEmployee.profileImageUrl;
foundEmployee.profileImageUrl
@ -1041,6 +1048,10 @@ async function assignFormDataEmployee(id: string) {
} else {
formDataEmployeeSameAddr.value = false;
}
if (infoEmployeePersonCard.value) {
infoEmployeePersonCard.value[0].img = foundEmployee.profileImageUrl;
}
}
flowStore.rotate();
}
@ -2302,6 +2313,9 @@ watch(selectorLabel, async () => {
"
v-model:drawer-open="infoDrawer"
:badgeLabel="currentCustomer?.code"
:badgeClass="
currentCustomer?.customerType === 'CORP' ? 'app-bg-corp' : 'app-bg-pers'
"
:undo="() => undo()"
:isEdit="infoDrawerEdit"
:close="() => onClose()"
@ -2317,8 +2331,9 @@ watch(selectorLabel, async () => {
<InfoForm>
<template #person-card>
<div class="q-ma-md">
<AppBox class="surface-1" style="padding: 0">
<AppBox class="surface-1 bordered-b" style="padding: 0">
<UsersDetailCardComponent
:can-edit-profile="infoDrawerEdit"
:hideButton="true"
v-if="!!currentCustomer"
no-bg
@ -2339,6 +2354,11 @@ watch(selectorLabel, async () => {
status: currentCustomer.status,
code: 'HQ006',
}"
@edit-profile="
() => {
inputFile.click();
}
"
/>
</AppBox>
</div>
@ -2497,7 +2517,9 @@ watch(selectorLabel, async () => {
:title="$t('formTitleBranch', { msg: currentBranch.name })"
v-model:drawer-open="infoDrawerBranch"
:badgeLabel="currentBranch.code"
badgeClass="app-bg-pers"
:badgeClass="
currentCustomer?.customerType === 'CORP' ? 'app-bg-corp' : 'app-bg-pers'
"
:undo="
() => {
cloneData();
@ -2752,12 +2774,18 @@ watch(selectorLabel, async () => {
<div class="q-ma-md">
<AppBox class="surface-1" style="padding: 0">
<PersonCard
:can-edit-profile="infoDrawerEmployeeEdit"
no-hover
no-action
no-detail
no-bg
:list="infoEmployeePersonCard"
:gridColumns="1"
@edit-profile="
() => {
inputFile.click();
}
"
/>
</AppBox>
</div>