persist installed. MyAccount in progress

This commit is contained in:
Cindy Chang
2024-08-29 14:19:27 +08:00
parent 495fcf7b03
commit 1883818b8b
6 changed files with 184 additions and 20 deletions

View File

@@ -25,6 +25,7 @@ interface EditDetail {
}
export default defineStore('acctMgmtStore', {
persist: true,
state: () => ({
allUserAccoutList: [] as User[],
isAcctMenuOpen: false,
@@ -181,6 +182,37 @@ export default defineStore('acctMgmtStore', {
return false;
}
},
async editAccountName(userToEdit: string, newName: string): Promise<boolean> {
const apiEdit = `/api/users/${userToEdit}`;
try {
const response = await this.$axios.put(apiEdit, {
username: userToEdit,
name: newName,
is_active: this.currentViewingUser.is_active,
});
return response.status === 200;
} catch (error) {
apiError(error, 'Failed to edit name of account.');
return false;
}
},
async editAccountPwd(userToEdit: string, newPwd: string): Promise<boolean> {
const apiEdit = `/api/users/${userToEdit}`;
try {
const response = await this.$axios.put(apiEdit, {
username: userToEdit,
name: this.currentViewingUser.name,
password: newPwd,
is_active: this.currentViewingUser.is_active,
});
return response.status === 200;
} catch (error) {
apiError(error, 'Failed to edit password of account.');
return false;
}
},
/** Add a role to the user in database.
* @param {string} usernameToEdit
* @param {string} roleCode

View File

@@ -1,5 +1,7 @@
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
export default pinia;

View File

@@ -1,6 +1,6 @@
<template>
<div class="general my-account flex flex-col items-center w-full h-full p-8">
<main class="flex main-part flex-col px-6 mt-6 w-[536px]">
<main class="flex main-part flex-col px-6 mt-6 w-[600px]">
<h1 id="general_acct_info_user_name" class="text-[32px] leading-[64px] font-medium mb-2">
{{ name }}
</h1>
@@ -15,7 +15,7 @@
</span> times.
</div>
</main>
<main class="flex flex-col pt-6 px-6 w-[536px]">
<main class="flex flex-col pt-6 px-6 w-[600px]">
<h1 class="text-[20px] font-medium mb-4">
{{ i18next.t("AcctMgmt.UserInfo") }}
</h1>
@@ -26,7 +26,7 @@
</span>
</div>
<div class="account flex flex-col">
<span class="flex text-[#0F172A] text-[14px]">{{ username }}</span>
<span class="flex text-[#0F172A] text-[16px]">{{ username }}</span>
<div v-show="false" class="error-wrapper my-2">
<div class="error-msg-section flex justify-start">
<img src="@/assets/icon-alert.svg" alt="!" class="exclamation-img flex mr-2">
@@ -45,15 +45,15 @@
</div>
<input v-if='isNameEditable' id="input_name_field"
class="w-[280px] h-[40px] rounded p-1 border border-[1px] border-[#64748B] flex items-center outline-none"
v-model="inputName" :readonly="!isNameEditable"
v-model="inputName"
autocomplete="off"
/>
<span v-else class="not-editable displayable name w-[280px]">
{{ name }}
</span>
<button v-if='isNameEditable' class="flex save-btn rounded-full text-[#FFFFFF] h-[40px] w-[80px] items-center
bg-[#0099FF] justify-center cursor-pointer ml-20
">
bg-[#0099FF] justify-center cursor-pointer ml-20"
@click="onSaveNameClick">
{{ i18next.t("Global.Save") }}
</button>
<button v-else class="flex save-btn rounded-full text-[#666666] h-[40px] w-[80px] items-center
@@ -63,19 +63,18 @@
{{ i18next.t("Global.Edit") }}
</button>
</div>
<div class="row w-full flex py-2 mb-4">
<div class="row w-full flex py-2 mb-4 border-b border-b-[#CBD5E1] border-b-[1px]">
<div class="field-label flex flex-col text-sm font-medium mr-4">
<span class="flex h-[40px] w-[80px] items-center">
{{ i18next.t("AcctMgmt.Password") }}
</span>
<div class="flex dummy-cell"></div>
</div>
<div class="flex input-and-error-msg flex-col w-[242px]">
<!-- 280 扣掉 24 眼睛的寬度 256 還要扣掉留白的寬度 -->
<div class="flex input-and-error-msg flex-col w-[280px]">
<div v-if='isPwdEditable' class="input-and-eye flex items-center h-[40px] relative border-[1px] rounded"
:class="{'border-[#FF3366]': !isPwdLengthValid, 'border-[#64748B]': isPwdLengthValid,}"
>
<input class="outline-none p-1 w-[242px]" :type="isPwdEyeOn ? 'text' : 'password'"
<input class="outline-none p-1 w-[280px]" :type="isPwdEyeOn ? 'text' : 'password'"
v-model="inputPwd"
autocomplete="off" :class="{'color-[#FF3366]': !isPwdLengthValid,
'color-[#64748B]': isPwdLengthValid,}"/>
@@ -104,20 +103,20 @@
{{ i18next.t("Global.Reset") }}
</button>
<div class="flex dummy-cell h-[40px]"></div>
</div>
</div>
</div>
</main>
</div>
</template>
<script>
import { onMounted, computed, ref, onBeforeMount, } from 'vue';
import { onMounted, computed, ref, onBeforeMount, watch, } from 'vue';
import i18next from '@/i18n/i18n.js';
import LoginStore from '@/stores/login';
import useAcctMgmtStore from '@/stores/acctMgmt.ts';
import Badge from '../../components/Badge.vue';
import LoadingStore from '@/stores/loading.js';
import { useToast } from 'vue-toast-notification';
import { PWD_VALID_LENGTH } from '@/constants/constants.js';
export default {
@@ -125,16 +124,18 @@ export default {
const loadingStore = LoadingStore();
const loginStore = LoginStore();
const acctMgmtStore = useAcctMgmtStore();
const toast = useToast();
const visitTime = ref(0);
const currentViewingUser = computed(() => acctMgmtStore.currentViewingUser);
const name = computed(() => acctMgmtStore.currentViewingUser.name);
const {
username,
name,
is_admin,
is_active,
} = currentViewingUser.value;
const inputName = ref(name);
const inputName = ref(name.value); // remember to add .value postfix
const inputPwd = ref('');
const isNameEditable = ref(false);
const isPwdEditable = ref(false);
@@ -142,18 +143,32 @@ export default {
const isPwdLengthValid = ref(true);
const onEditNameClick = () => {
isNameEditable.value = true;
isNameEditable.value = true;
}
const onResetPwdClick = () => {
isPwdEditable.value = true;
}
const onSavePwdClick = () => {
const onSaveNameClick = async() => {
if(inputName.value.length > 0) {
await acctMgmtStore.editAccountName(username, inputName.value);
await toast.success(i18next.t("AcctMgmt.MsgAccountEdited"));
await acctMgmtStore.getUserDetail(username);
isNameEditable.value = false;
inputName.value = name.value; // updated value
}
};
const onSavePwdClick = async() => {
validatePwdLength();
if (isPwdLengthValid.value) {
isPwdEditable.value = false;
inputPwd.value = '';
isPwdEditable.value = false;
await acctMgmtStore.editAccountPwd(username, inputPwd.value);
await toast.success(i18next.t("AcctMgmt.MsgAccountEdited"));
inputPwd.value = '';
// remember to force update
await acctMgmtStore.getUserDetail(loginStore.userData.username);
}
}
@@ -165,6 +180,11 @@ export default {
isPwdLengthValid.value = inputPwd.value.length >= PWD_VALID_LENGTH;
}
watch(() => acctMgmtStore.currentViewingUser, (newVal, oldVal) => {
console.log('currentViewingUser updated:', newVal);
console.log('newVal.name', newVal.name);
});
onBeforeMount(async() => {
// 在此設定 current viewing user 的來源是登入者的身分
await acctMgmtStore.getUserDetail(loginStore.userData.username);
@@ -190,6 +210,7 @@ export default {
onEditNameClick,
onResetPwdClick,
onSavePwdClick,
onSaveNameClick,
togglePwdEyeBtn,
};
},