WIP my account page
This commit is contained in:
@@ -9,7 +9,9 @@
|
|||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
"Clear": "Clear",
|
"Clear": "Clear",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Confirm": "Confirm"
|
"Confirm": "Confirm",
|
||||||
|
"Edit": "Edit",
|
||||||
|
"Reset": "Reset"
|
||||||
},
|
},
|
||||||
"Map":{
|
"Map":{
|
||||||
"FileName": "File Name",
|
"FileName": "File Name",
|
||||||
|
|||||||
@@ -30,8 +30,7 @@
|
|||||||
{{ i18next.t("AcctMgmt.AccountNotUnique") }}
|
{{ i18next.t("AcctMgmt.AccountNotUnique") }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-row w-full flex py-2 h-[40px] mb-4 items-center
|
<div class="input-row w-full flex py-2 h-[40px] mb-4 items-center
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="general my-account flex justify-center w-full h-full p-8">
|
<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-[536px]">
|
||||||
<h1 id="general_acct_info_user_name" class="text-[32px] leading-[64px] font-medium mb-2">
|
<h1 id="general_acct_info_user_name" class="text-[32px] leading-[64px] font-medium mb-2">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
@@ -15,20 +15,115 @@
|
|||||||
</span> times.
|
</span> times.
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
<main class="flex flex-col pt-6 px-6 w-[536px]">
|
||||||
|
<h1 class="text-[20px] font-medium mb-4">
|
||||||
|
{{ i18next.t("AcctMgmt.UserInfo") }}
|
||||||
|
</h1>
|
||||||
|
<div class="row w-full flex py-2 h-[40px] mb-4 items-center">
|
||||||
|
<div class="field-label text-sm flex items-center font-medium mr-4">
|
||||||
|
<span class="align-right-span flex w-[80px]">
|
||||||
|
{{ i18next.t("AcctMgmt.Account") }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="account flex flex-col">
|
||||||
|
<span class="flex text-[#0F172A] text-[14px]">{{ 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">
|
||||||
|
<span class="error-msg-text flex text-[#FF3366] h-[24px]">
|
||||||
|
{{ i18next.t("AcctMgmt.AccountNotUnique") }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row w-full flex py-2 h-[40px] mb-4 items-center">
|
||||||
|
<div class="field-label text-sm flex items-center font-medium mr-4">
|
||||||
|
<span class="align-right-span flex w-[80px]">
|
||||||
|
{{ i18next.t("AcctMgmt.FullName") }}
|
||||||
|
</span>
|
||||||
|
</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"
|
||||||
|
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
|
||||||
|
">
|
||||||
|
{{ i18next.t("Global.Save") }}
|
||||||
|
</button>
|
||||||
|
<button v-else class="flex save-btn rounded-full text-[#666666] h-[40px] w-[80px] items-center
|
||||||
|
bg-[#FFFFFF] justify-center cursor-pointer ml-20 border border-[#666666]"
|
||||||
|
@click="onEditNameClick"
|
||||||
|
>
|
||||||
|
{{ i18next.t("Global.Edit") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="row w-full flex py-2 mb-4">
|
||||||
|
<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 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'"
|
||||||
|
v-model="inputPwd"
|
||||||
|
autocomplete="off" :class="{'color-[#FF3366]': !isPwdLengthValid,
|
||||||
|
'color-[#64748B]': isPwdLengthValid,}"/>
|
||||||
|
<img id='eye_button' v-if="isPwdEyeOn" src='@/assets/icon-eye-open.svg' class="absolute right-[8px] cursor-pointer"
|
||||||
|
@mousedown="togglePwdEyeBtn(true)" @mouseup="togglePwdEyeBtn(false)" alt=""/>
|
||||||
|
<img v-else src='@/assets/icon-eye-hide.svg' class="absolute right-[8px] cursor-pointer"
|
||||||
|
@mousedown="togglePwdEyeBtn(true)" @mouseup="togglePwdEyeBtn(false)" alt="eye"/>
|
||||||
|
</div>
|
||||||
|
<div class="error-msg-section flex justify-start mt-4">
|
||||||
|
<img v-show="!isPwdLengthValid" src="@/assets/icon-alert.svg" alt="!" class="exclamation-img flex mr-2">
|
||||||
|
<span class="error-msg-text flex text-[#FF3366] h-[24px]">
|
||||||
|
{{ isPwdLengthValid ? "" : i18next.t("AcctMgmt.PwdLengthNotEnough") }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button-column flex flex-col">
|
||||||
|
<button v-if='isPwdEditable' class="flex save-btn rounded-full text-[#FFFFFF] h-[40px] w-[80px] items-center
|
||||||
|
bg-[#0099FF] justify-center cursor-pointer ml-20"
|
||||||
|
@click="onSavePwdClick">
|
||||||
|
{{ i18next.t("Global.Save") }}
|
||||||
|
</button>
|
||||||
|
<button v-else class="flex reset-btn rounded-full text-[#666666] h-[40px] w-[80px] items-center
|
||||||
|
bg-[#FFFFFF] justify-center cursor-pointer ml-20 border border-[#666666]"
|
||||||
|
@click="onResetPwdClick"
|
||||||
|
>
|
||||||
|
{{ i18next.t("Global.Reset") }}
|
||||||
|
</button>
|
||||||
|
<div class="flex dummy-cell h-[40px]"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMounted, onBeforeMount, computed, ref } from 'vue';
|
import { onMounted, computed, ref, onBeforeMount, } from 'vue';
|
||||||
import i18next from '@/i18n/i18n.js';
|
import i18next from '@/i18n/i18n.js';
|
||||||
|
import LoginStore from '@/stores/login';
|
||||||
import useAcctMgmtStore from '@/stores/acctMgmt.ts';
|
import useAcctMgmtStore from '@/stores/acctMgmt.ts';
|
||||||
import ModalHeader from './ModalHeader.vue';
|
|
||||||
import Badge from '../../components/Badge.vue';
|
import Badge from '../../components/Badge.vue';
|
||||||
import LoadingStore from '@/stores/loading.js';
|
import LoadingStore from '@/stores/loading.js';
|
||||||
|
import { PWD_VALID_LENGTH } from '@/constants/constants.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const loadingStore = LoadingStore();
|
const loadingStore = LoadingStore();
|
||||||
|
const loginStore = LoginStore();
|
||||||
const acctMgmtStore = useAcctMgmtStore();
|
const acctMgmtStore = useAcctMgmtStore();
|
||||||
const visitTime = ref(0);
|
const visitTime = ref(0);
|
||||||
const currentViewingUser = computed(() => acctMgmtStore.currentViewingUser);
|
const currentViewingUser = computed(() => acctMgmtStore.currentViewingUser);
|
||||||
@@ -39,6 +134,42 @@ export default {
|
|||||||
is_active,
|
is_active,
|
||||||
} = currentViewingUser.value;
|
} = currentViewingUser.value;
|
||||||
|
|
||||||
|
const inputName = ref(name);
|
||||||
|
const inputPwd = ref('');
|
||||||
|
const isNameEditable = ref(false);
|
||||||
|
const isPwdEditable = ref(false);
|
||||||
|
const isPwdEyeOn = ref(false);
|
||||||
|
const isPwdLengthValid = ref(true);
|
||||||
|
|
||||||
|
const onEditNameClick = () => {
|
||||||
|
isNameEditable.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onResetPwdClick = () => {
|
||||||
|
isPwdEditable.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSavePwdClick = () => {
|
||||||
|
validatePwdLength();
|
||||||
|
if (isPwdLengthValid.value) {
|
||||||
|
isPwdEditable.value = false;
|
||||||
|
inputPwd.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const togglePwdEyeBtn = (toBeOpen) => {
|
||||||
|
isPwdEyeOn.value = toBeOpen;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validatePwdLength = () => {
|
||||||
|
isPwdLengthValid.value = inputPwd.value.length >= PWD_VALID_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(async() => {
|
||||||
|
// 在此設定 current viewing user 的來源是登入者的身分
|
||||||
|
await acctMgmtStore.getUserDetail(loginStore.userData.username);
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadingStore.setIsLoading(false);
|
loadingStore.setIsLoading(false);
|
||||||
});
|
});
|
||||||
@@ -50,6 +181,16 @@ export default {
|
|||||||
is_admin,
|
is_admin,
|
||||||
is_active,
|
is_active,
|
||||||
visitTime,
|
visitTime,
|
||||||
|
inputName,
|
||||||
|
inputPwd,
|
||||||
|
isNameEditable,
|
||||||
|
isPwdEditable,
|
||||||
|
isPwdEyeOn,
|
||||||
|
isPwdLengthValid,
|
||||||
|
onEditNameClick,
|
||||||
|
onResetPwdClick,
|
||||||
|
onSavePwdClick,
|
||||||
|
togglePwdEyeBtn,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|||||||
Reference in New Issue
Block a user