pukaad-ui-lib 1.240.0 → 1.242.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/input/input-password.vue +8 -5
- package/dist/runtime/components/modal/modal-email-OTP.d.vue.ts +12 -2
- package/dist/runtime/components/modal/modal-email-OTP.vue +23 -18
- package/dist/runtime/components/modal/modal-email-OTP.vue.d.ts +12 -2
- package/dist/runtime/components/modal/modal-forgot-password.d.vue.ts +13 -0
- package/dist/runtime/components/modal/modal-forgot-password.vue +146 -0
- package/dist/runtime/components/modal/modal-forgot-password.vue.d.ts +13 -0
- package/dist/runtime/components/modal/modal-password-new.d.vue.ts +4 -2
- package/dist/runtime/components/modal/modal-password-new.vue +40 -14
- package/dist/runtime/components/modal/modal-password-new.vue.d.ts +4 -2
- package/dist/runtime/components/modal/modal-user-account-search.d.vue.ts +13 -3
- package/dist/runtime/components/modal/modal-user-account-search.vue +130 -18
- package/dist/runtime/components/modal/modal-user-account-search.vue.d.ts +13 -3
- package/package.json +1 -1
- package/dist/runtime/components/modal/modal-user-account-list.d.vue.ts +0 -18
- package/dist/runtime/components/modal/modal-user-account-list.vue +0 -51
- package/dist/runtime/components/modal/modal-user-account-list.vue.d.ts +0 -18
- /package/dist/runtime/assets/svg/socials/{WhatsApp.svg → Whatsapp.svg} +0 -0
package/dist/module.json
CHANGED
|
@@ -15,13 +15,15 @@
|
|
|
15
15
|
{{ props.label }}
|
|
16
16
|
<span v-if="props.required" class="text-destructive">*</span>
|
|
17
17
|
</div>
|
|
18
|
-
<
|
|
18
|
+
<Button
|
|
19
19
|
v-if="!props.disabledForgotPassword"
|
|
20
|
-
|
|
20
|
+
variant="text"
|
|
21
|
+
color="primary"
|
|
22
|
+
class="font-body-medium"
|
|
21
23
|
@click="handleForgotPassword"
|
|
22
24
|
>
|
|
23
25
|
ลืมรหัสผ่าน
|
|
24
|
-
</
|
|
26
|
+
</Button>
|
|
25
27
|
</ShadFormLabel>
|
|
26
28
|
</template>
|
|
27
29
|
</InputTextField>
|
|
@@ -46,6 +48,7 @@
|
|
|
46
48
|
|
|
47
49
|
<script setup>
|
|
48
50
|
import { ref, computed } from "vue";
|
|
51
|
+
import Button from "../button.vue";
|
|
49
52
|
const props = defineProps({
|
|
50
53
|
new: { type: Boolean, required: false, default: false },
|
|
51
54
|
disabledForgotPassword: { type: Boolean, required: false, default: false },
|
|
@@ -124,8 +127,8 @@ const defaultRules = (v) => {
|
|
|
124
127
|
if (isNotNoSpace) return "\u0E2B\u0E49\u0E32\u0E21\u0E40\u0E27\u0E49\u0E19\u0E27\u0E23\u0E23\u0E04";
|
|
125
128
|
return true;
|
|
126
129
|
};
|
|
127
|
-
const handleForgotPassword = () => {
|
|
128
|
-
|
|
130
|
+
const handleForgotPassword = (e) => {
|
|
131
|
+
emits("forgotPassword", e);
|
|
129
132
|
};
|
|
130
133
|
const inputTextFieldRef = ref();
|
|
131
134
|
const setErrors = (errMsg) => {
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
export interface ModalEmailOTPProps {
|
|
2
2
|
email?: string;
|
|
3
3
|
confirmedText?: string;
|
|
4
|
+
/** Custom API path for requesting OTP. Defaults to /me/email-otp-request */
|
|
5
|
+
requestPath?: string;
|
|
6
|
+
/** Custom request body. When provided, used instead of { email }. */
|
|
7
|
+
requestBody?: Record<string, any>;
|
|
8
|
+
/** Custom API path for verifying OTP. Defaults to /me/email-otp-verify */
|
|
9
|
+
verifyPath?: string;
|
|
10
|
+
/** Extra body fields merged with { code } when verifying. Defaults to { email }. */
|
|
11
|
+
verifyBody?: Record<string, any>;
|
|
12
|
+
/** If provided, sets the initial countdown and skips auto-request on open. */
|
|
13
|
+
initialExpiredTime?: string;
|
|
4
14
|
}
|
|
5
15
|
type __VLS_Props = ModalEmailOTPProps;
|
|
6
16
|
type __VLS_ModelProps = {
|
|
@@ -10,10 +20,10 @@ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
|
10
20
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
21
|
"update:modelValue": (value: boolean) => any;
|
|
12
22
|
} & {
|
|
13
|
-
complete: () => any;
|
|
23
|
+
complete: (data?: any) => any;
|
|
14
24
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
15
25
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
16
|
-
onComplete?: (() => any) | undefined;
|
|
26
|
+
onComplete?: ((data?: any) => any) | undefined;
|
|
17
27
|
}>, {
|
|
18
28
|
confirmedText: string;
|
|
19
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -44,7 +44,12 @@ const { CountdownTime } = useCountDown();
|
|
|
44
44
|
const emits = defineEmits(["complete"]);
|
|
45
45
|
const props = defineProps({
|
|
46
46
|
email: { type: String, required: false },
|
|
47
|
-
confirmedText: { type: String, required: false, default: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19" }
|
|
47
|
+
confirmedText: { type: String, required: false, default: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19" },
|
|
48
|
+
requestPath: { type: String, required: false },
|
|
49
|
+
requestBody: { type: Object, required: false },
|
|
50
|
+
verifyPath: { type: String, required: false },
|
|
51
|
+
verifyBody: { type: Object, required: false },
|
|
52
|
+
initialExpiredTime: { type: String, required: false }
|
|
48
53
|
});
|
|
49
54
|
const isOpen = defineModel({ type: Boolean, ...{
|
|
50
55
|
default: false
|
|
@@ -64,16 +69,15 @@ const maskedEmail = computed(() => {
|
|
|
64
69
|
});
|
|
65
70
|
const onVerifyOTP = async () => {
|
|
66
71
|
try {
|
|
67
|
-
|
|
72
|
+
const path = props.verifyPath ?? "/me/email-otp-verify";
|
|
73
|
+
const body = props.verifyBody ? { ...props.verifyBody, code: valueOTP.value } : { code: valueOTP.value, email: props.email };
|
|
74
|
+
const response = await api(path, {
|
|
68
75
|
method: "POST",
|
|
69
|
-
body
|
|
70
|
-
code: valueOTP.value,
|
|
71
|
-
email: props.email
|
|
72
|
-
}
|
|
76
|
+
body
|
|
73
77
|
});
|
|
74
78
|
valueOTP.value = "";
|
|
75
79
|
isOpen.value = false;
|
|
76
|
-
emits("complete");
|
|
80
|
+
emits("complete", response?.data);
|
|
77
81
|
} catch (e) {
|
|
78
82
|
$toast.error("OTP \u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07");
|
|
79
83
|
}
|
|
@@ -81,16 +85,13 @@ const onVerifyOTP = async () => {
|
|
|
81
85
|
const handleSendEmail = async () => {
|
|
82
86
|
try {
|
|
83
87
|
isLoading.value = true;
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
);
|
|
88
|
+
const path = props.requestPath ?? "/me/email-otp-request";
|
|
89
|
+
const body = props.requestBody ?? { email: props.email };
|
|
90
|
+
if (!props.requestBody && !props.email) throw new Error("\u0E01\u0E23\u0E38\u0E13\u0E32\u0E23\u0E30\u0E1A\u0E38 email");
|
|
91
|
+
const response = await api(path, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
body
|
|
94
|
+
});
|
|
94
95
|
timeExp.value = response.data.expired_time;
|
|
95
96
|
} catch (err) {
|
|
96
97
|
$toast.error("\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14 \u0E1A\u0E32\u0E07\u0E2D\u0E22\u0E48\u0E32\u0E07 !");
|
|
@@ -101,7 +102,11 @@ const handleSendEmail = async () => {
|
|
|
101
102
|
watch(isOpen, (v) => {
|
|
102
103
|
if (v) {
|
|
103
104
|
valueOTP.value = "";
|
|
104
|
-
|
|
105
|
+
if (props.initialExpiredTime) {
|
|
106
|
+
timeExp.value = props.initialExpiredTime;
|
|
107
|
+
} else {
|
|
108
|
+
handleSendEmail();
|
|
109
|
+
}
|
|
105
110
|
} else {
|
|
106
111
|
timeExp.value = "";
|
|
107
112
|
}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
export interface ModalEmailOTPProps {
|
|
2
2
|
email?: string;
|
|
3
3
|
confirmedText?: string;
|
|
4
|
+
/** Custom API path for requesting OTP. Defaults to /me/email-otp-request */
|
|
5
|
+
requestPath?: string;
|
|
6
|
+
/** Custom request body. When provided, used instead of { email }. */
|
|
7
|
+
requestBody?: Record<string, any>;
|
|
8
|
+
/** Custom API path for verifying OTP. Defaults to /me/email-otp-verify */
|
|
9
|
+
verifyPath?: string;
|
|
10
|
+
/** Extra body fields merged with { code } when verifying. Defaults to { email }. */
|
|
11
|
+
verifyBody?: Record<string, any>;
|
|
12
|
+
/** If provided, sets the initial countdown and skips auto-request on open. */
|
|
13
|
+
initialExpiredTime?: string;
|
|
4
14
|
}
|
|
5
15
|
type __VLS_Props = ModalEmailOTPProps;
|
|
6
16
|
type __VLS_ModelProps = {
|
|
@@ -10,10 +20,10 @@ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
|
10
20
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
21
|
"update:modelValue": (value: boolean) => any;
|
|
12
22
|
} & {
|
|
13
|
-
complete: () => any;
|
|
23
|
+
complete: (data?: any) => any;
|
|
14
24
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
15
25
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
16
|
-
onComplete?: (() => any) | undefined;
|
|
26
|
+
onComplete?: ((data?: any) => any) | undefined;
|
|
17
27
|
}>, {
|
|
18
28
|
confirmedText: string;
|
|
19
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue?: boolean;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: boolean) => any;
|
|
6
|
+
} & {
|
|
7
|
+
complete: () => any;
|
|
8
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
9
|
+
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
10
|
+
onComplete?: (() => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
v-for="modal in modals"
|
|
4
|
+
:key="modal.key"
|
|
5
|
+
:is="modal.component"
|
|
6
|
+
v-bind="modalProps[modal.key]"
|
|
7
|
+
v-model="modalStates[modal.key]"
|
|
8
|
+
@complete="(data) => handleComplete(modal.key, data)"
|
|
9
|
+
@close="isOpen = false"
|
|
10
|
+
/>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup>
|
|
14
|
+
import { reactive, ref, computed, watch } from "vue";
|
|
15
|
+
import { useNuxtApp } from "nuxt/app";
|
|
16
|
+
import { useApi } from "../../composables/useApi";
|
|
17
|
+
import ModalUserAccountSearch from "@/runtime/components/modal/modal-user-account-search.vue";
|
|
18
|
+
import ModalPhoneOTP from "@/runtime/components/modal/modal-phone-OTP.vue";
|
|
19
|
+
import ModalEmailOTP from "@/runtime/components/modal/modal-email-OTP.vue";
|
|
20
|
+
import ModalPasswordNew from "@/runtime/components/modal/modal-password-new.vue";
|
|
21
|
+
const { $toast } = useNuxtApp();
|
|
22
|
+
const api = useApi();
|
|
23
|
+
const emit = defineEmits(["complete"]);
|
|
24
|
+
const isOpen = defineModel({ type: Boolean, ...{ default: false } });
|
|
25
|
+
const phone = ref("");
|
|
26
|
+
const maskedPhone = ref("");
|
|
27
|
+
const maskedEmail = ref(null);
|
|
28
|
+
const method = ref("sms");
|
|
29
|
+
const expiredTime = ref("");
|
|
30
|
+
const resetToken = ref("");
|
|
31
|
+
const isLoading = ref(false);
|
|
32
|
+
const modals = [
|
|
33
|
+
{ key: "accountSearch", component: ModalUserAccountSearch },
|
|
34
|
+
{ key: "phoneOTP", component: ModalPhoneOTP },
|
|
35
|
+
{ key: "emailOTP", component: ModalEmailOTP },
|
|
36
|
+
{ key: "passwordNew", component: ModalPasswordNew }
|
|
37
|
+
];
|
|
38
|
+
const modalStates = reactive(
|
|
39
|
+
Object.fromEntries(modals.map((m) => [m.key, false]))
|
|
40
|
+
);
|
|
41
|
+
const modalProps = computed(() => ({
|
|
42
|
+
accountSearch: {
|
|
43
|
+
confirmedText: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19"
|
|
44
|
+
},
|
|
45
|
+
phoneOTP: {
|
|
46
|
+
phone: phone.value,
|
|
47
|
+
phoneLabel: maskedPhone.value,
|
|
48
|
+
confirmedText: "\u0E16\u0E31\u0E14\u0E44\u0E1B"
|
|
49
|
+
},
|
|
50
|
+
emailOTP: {
|
|
51
|
+
email: maskedEmail.value ?? "",
|
|
52
|
+
requestPath: "/auth/forgot-password/send-otp",
|
|
53
|
+
requestBody: { phone: phone.value, method: "email" },
|
|
54
|
+
verifyPath: "/auth/forgot-password/verify-otp",
|
|
55
|
+
verifyBody: { phone: phone.value },
|
|
56
|
+
initialExpiredTime: expiredTime.value,
|
|
57
|
+
confirmedText: "\u0E16\u0E31\u0E14\u0E44\u0E1B"
|
|
58
|
+
},
|
|
59
|
+
passwordNew: {
|
|
60
|
+
resetToken: resetToken.value,
|
|
61
|
+
disabledForceLogout: false,
|
|
62
|
+
title: "\u0E15\u0E31\u0E49\u0E07\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E48\u0E32\u0E19\u0E43\u0E2B\u0E21\u0E48",
|
|
63
|
+
confirmText: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19"
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
const handleComplete = async (key, data) => {
|
|
67
|
+
if (key === "accountSearch") {
|
|
68
|
+
const result = data;
|
|
69
|
+
phone.value = result.phone;
|
|
70
|
+
method.value = result.method;
|
|
71
|
+
maskedPhone.value = result.maskedPhone;
|
|
72
|
+
maskedEmail.value = result.maskedEmail;
|
|
73
|
+
await callSendOTP();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (key === "phoneOTP") {
|
|
77
|
+
await callVerifyOTP(data);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (key === "emailOTP") {
|
|
81
|
+
const token = data?.reset_token;
|
|
82
|
+
if (!token) {
|
|
83
|
+
$toast?.error?.("\u0E44\u0E21\u0E48\u0E1E\u0E1A reset token");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
resetToken.value = token;
|
|
87
|
+
modalStates.passwordNew = true;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (key === "passwordNew") {
|
|
91
|
+
isOpen.value = false;
|
|
92
|
+
$toast?.success?.("\u0E23\u0E35\u0E40\u0E0B\u0E47\u0E15\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E48\u0E32\u0E19\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08 !");
|
|
93
|
+
emit("complete");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const callSendOTP = async () => {
|
|
98
|
+
isLoading.value = true;
|
|
99
|
+
try {
|
|
100
|
+
const res = await api("/auth/forgot-password/send-otp", {
|
|
101
|
+
method: "POST",
|
|
102
|
+
body: { phone: phone.value, method: method.value }
|
|
103
|
+
});
|
|
104
|
+
expiredTime.value = res.data.expired_time;
|
|
105
|
+
if (method.value === "sms") {
|
|
106
|
+
modalStates.phoneOTP = true;
|
|
107
|
+
} else {
|
|
108
|
+
modalStates.emailOTP = true;
|
|
109
|
+
}
|
|
110
|
+
} catch (e) {
|
|
111
|
+
const msg = e?.data?.message?.description || e?.data?.message || "\u0E40\u0E01\u0E34\u0E14\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E43\u0E19\u0E01\u0E32\u0E23\u0E2A\u0E48\u0E07 OTP";
|
|
112
|
+
$toast?.error?.(msg);
|
|
113
|
+
} finally {
|
|
114
|
+
isLoading.value = false;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const callVerifyOTP = async (code) => {
|
|
118
|
+
isLoading.value = true;
|
|
119
|
+
try {
|
|
120
|
+
const res = await api("/auth/forgot-password/verify-otp", {
|
|
121
|
+
method: "POST",
|
|
122
|
+
body: { phone: phone.value, code }
|
|
123
|
+
});
|
|
124
|
+
resetToken.value = res.data.reset_token;
|
|
125
|
+
modalStates.passwordNew = true;
|
|
126
|
+
} catch (e) {
|
|
127
|
+
const msg = e?.data?.message?.description || e?.data?.message || "OTP \u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07\u0E2B\u0E23\u0E37\u0E2D\u0E2B\u0E21\u0E14\u0E2D\u0E32\u0E22\u0E38";
|
|
128
|
+
$toast?.error?.(msg);
|
|
129
|
+
} finally {
|
|
130
|
+
isLoading.value = false;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
watch(isOpen, (v) => {
|
|
134
|
+
if (v) {
|
|
135
|
+
phone.value = "";
|
|
136
|
+
maskedPhone.value = "";
|
|
137
|
+
maskedEmail.value = null;
|
|
138
|
+
method.value = "sms";
|
|
139
|
+
expiredTime.value = "";
|
|
140
|
+
resetToken.value = "";
|
|
141
|
+
modalStates.accountSearch = true;
|
|
142
|
+
} else {
|
|
143
|
+
modals.forEach((m) => modalStates[m.key] = false);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
</script>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue?: boolean;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: boolean) => any;
|
|
6
|
+
} & {
|
|
7
|
+
complete: () => any;
|
|
8
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
9
|
+
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
10
|
+
onComplete?: (() => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
@@ -2,6 +2,8 @@ interface Props {
|
|
|
2
2
|
title?: string;
|
|
3
3
|
confirmText?: string;
|
|
4
4
|
loginToken?: string;
|
|
5
|
+
/** When provided, uses forgot-password reset endpoint instead of password/create */
|
|
6
|
+
resetToken?: string;
|
|
5
7
|
disabledForceLogout?: boolean;
|
|
6
8
|
}
|
|
7
9
|
type __VLS_Props = Props;
|
|
@@ -14,13 +16,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
14
16
|
"update:modelValue": (value: boolean) => any;
|
|
15
17
|
complete: (data: {
|
|
16
18
|
secId: string;
|
|
17
|
-
}) => any;
|
|
19
|
+
} | null) => any;
|
|
18
20
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
19
21
|
onClose?: (() => any) | undefined;
|
|
20
22
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
21
23
|
onComplete?: ((data: {
|
|
22
24
|
secId: string;
|
|
23
|
-
}) => any) | undefined;
|
|
25
|
+
} | null) => any) | undefined;
|
|
24
26
|
}>, {
|
|
25
27
|
title: string;
|
|
26
28
|
confirmText: string;
|
|
@@ -5,21 +5,23 @@
|
|
|
5
5
|
v-model="isOpen"
|
|
6
6
|
@close="emit('close')"
|
|
7
7
|
@submit="handleSubmit"
|
|
8
|
+
width="425px"
|
|
8
9
|
>
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
10
|
+
<div class="flex flex-col gap-2">
|
|
11
|
+
<InputPassword
|
|
12
|
+
disabled-forgot-password
|
|
13
|
+
new
|
|
14
|
+
required
|
|
15
|
+
label="รหัสผ่าน"
|
|
16
|
+
placeholder="กรอกรหัสผ่าน"
|
|
17
|
+
v-model="password"
|
|
18
|
+
/>
|
|
19
|
+
<InputCheckbox
|
|
20
|
+
v-if="!props.disabledForceLogout"
|
|
21
|
+
label="ออกจากระบบ Pukaad ในอุปกรณ์อื่นๆทั้งหมด"
|
|
22
|
+
v-model="logoutAll"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
23
25
|
<template #footer="{ meta }">
|
|
24
26
|
<Button
|
|
25
27
|
type="submit"
|
|
@@ -36,15 +38,18 @@
|
|
|
36
38
|
<script setup>
|
|
37
39
|
import { ref, computed, watch } from "vue";
|
|
38
40
|
import { useNuxtApp, useRuntimeConfig } from "nuxt/app";
|
|
41
|
+
import { useApi } from "../../composables/useApi";
|
|
39
42
|
const props = defineProps({
|
|
40
43
|
title: { type: String, required: false, default: "\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E48\u0E32\u0E19\u0E43\u0E2B\u0E21\u0E48" },
|
|
41
44
|
confirmText: { type: String, required: false, default: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19" },
|
|
42
45
|
loginToken: { type: String, required: false },
|
|
46
|
+
resetToken: { type: String, required: false },
|
|
43
47
|
disabledForceLogout: { type: Boolean, required: false, default: false }
|
|
44
48
|
});
|
|
45
49
|
const emit = defineEmits(["complete", "close"]);
|
|
46
50
|
const { $toast } = useNuxtApp();
|
|
47
51
|
const config = useRuntimeConfig();
|
|
52
|
+
const api = useApi();
|
|
48
53
|
const isOpen = defineModel({ type: Boolean, ...{ default: false } });
|
|
49
54
|
const loading = ref(false);
|
|
50
55
|
const password = ref("");
|
|
@@ -59,6 +64,27 @@ watch(isOpen, (open) => {
|
|
|
59
64
|
}
|
|
60
65
|
});
|
|
61
66
|
const handleSubmit = async () => {
|
|
67
|
+
if (props.resetToken) {
|
|
68
|
+
loading.value = true;
|
|
69
|
+
try {
|
|
70
|
+
await api("/auth/forgot-password/reset-password", {
|
|
71
|
+
method: "POST",
|
|
72
|
+
body: {
|
|
73
|
+
reset_token: props.resetToken,
|
|
74
|
+
new_password: password.value,
|
|
75
|
+
logout_all: logoutAll.value
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
emit("complete", null);
|
|
79
|
+
isOpen.value = false;
|
|
80
|
+
} catch (e) {
|
|
81
|
+
const msg = e?.data?.message?.description || e?.data?.message || "\u0E40\u0E01\u0E34\u0E14\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E43\u0E19\u0E01\u0E32\u0E23\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D";
|
|
82
|
+
$toast?.error?.(msg);
|
|
83
|
+
} finally {
|
|
84
|
+
loading.value = false;
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
62
88
|
if (!props.loginToken) {
|
|
63
89
|
$toast?.error?.("\u0E44\u0E21\u0E48\u0E1E\u0E1A login token");
|
|
64
90
|
return;
|
|
@@ -2,6 +2,8 @@ interface Props {
|
|
|
2
2
|
title?: string;
|
|
3
3
|
confirmText?: string;
|
|
4
4
|
loginToken?: string;
|
|
5
|
+
/** When provided, uses forgot-password reset endpoint instead of password/create */
|
|
6
|
+
resetToken?: string;
|
|
5
7
|
disabledForceLogout?: boolean;
|
|
6
8
|
}
|
|
7
9
|
type __VLS_Props = Props;
|
|
@@ -14,13 +16,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
14
16
|
"update:modelValue": (value: boolean) => any;
|
|
15
17
|
complete: (data: {
|
|
16
18
|
secId: string;
|
|
17
|
-
}) => any;
|
|
19
|
+
} | null) => any;
|
|
18
20
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
19
21
|
onClose?: (() => any) | undefined;
|
|
20
22
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
21
23
|
onComplete?: ((data: {
|
|
22
24
|
secId: string;
|
|
23
|
-
}) => any) | undefined;
|
|
25
|
+
} | null) => any) | undefined;
|
|
24
26
|
}>, {
|
|
25
27
|
title: string;
|
|
26
28
|
confirmText: string;
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export interface ModalUserAccountSearchResult {
|
|
2
|
+
phone: string;
|
|
3
|
+
method: "sms" | "email";
|
|
4
|
+
maskedPhone: string;
|
|
5
|
+
maskedEmail: string | null;
|
|
6
|
+
hasEmail: boolean;
|
|
7
|
+
}
|
|
1
8
|
type __VLS_Props = {
|
|
2
9
|
confirmedText?: string;
|
|
3
10
|
};
|
|
@@ -6,11 +13,14 @@ type __VLS_ModelProps = {
|
|
|
6
13
|
};
|
|
7
14
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
8
15
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
-
|
|
10
|
-
|
|
16
|
+
"update:modelValue": (value: boolean) => any;
|
|
17
|
+
} & {
|
|
18
|
+
close: () => any;
|
|
19
|
+
complete: (data: ModalUserAccountSearchResult) => any;
|
|
11
20
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
21
|
+
onClose?: (() => any) | undefined;
|
|
12
22
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
13
|
-
onComplete?: ((
|
|
23
|
+
onComplete?: ((data: ModalUserAccountSearchResult) => any) | undefined;
|
|
14
24
|
}>, {
|
|
15
25
|
confirmedText: string;
|
|
16
26
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,44 +1,156 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Modal
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<Modal
|
|
3
|
+
:title="step === 'search' ? '\u0E04\u0E49\u0E19\u0E2B\u0E32\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13' : '\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E27\u0E34\u0E18\u0E35\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A'"
|
|
4
|
+
v-model="modelValue"
|
|
5
|
+
width="425px"
|
|
6
|
+
:loading="isLoading"
|
|
7
|
+
>
|
|
8
|
+
<!-- Step 1: phone + recaptcha -->
|
|
9
|
+
<div v-if="step === 'search'" class="flex flex-col gap-[24px]">
|
|
10
|
+
<p class="font-body-large">
|
|
5
11
|
ป้อนเบอร์โทรศัพท์ที่เชื่อมโยงกับบัญชีของคุณ เพื่อเปลี่ยนรหัสผ่าน
|
|
6
|
-
</
|
|
12
|
+
</p>
|
|
7
13
|
<InputPhone
|
|
8
14
|
label="เบอร์โทรศัพท์"
|
|
9
15
|
placeholder="กรอกเบอร์โทรศัพท์"
|
|
10
16
|
v-model="phone"
|
|
11
|
-
full-width
|
|
12
17
|
/>
|
|
13
18
|
<InputRecaptcha ref="recaptchaRef" name="recaptcha" v-model="recaptcha" />
|
|
14
19
|
</div>
|
|
20
|
+
|
|
21
|
+
<!-- Step 2: select OTP method -->
|
|
22
|
+
<div v-else-if="step === 'list'" class="flex flex-col">
|
|
23
|
+
<template v-for="(item, index) in accountItems" :key="index">
|
|
24
|
+
<div class="py-[12px] px-[16px]">
|
|
25
|
+
<InputRadio
|
|
26
|
+
:item="item.value"
|
|
27
|
+
label-position="left"
|
|
28
|
+
v-model="selectedMethod"
|
|
29
|
+
>
|
|
30
|
+
<template v-slot:[`label-${item.value}-text`]>
|
|
31
|
+
<div
|
|
32
|
+
class="flex flex-col w-full text-gray font-body-medium-prominent"
|
|
33
|
+
>
|
|
34
|
+
<div v-if="item.type === 'email'">ส่งรหัสไปทางอีเมล</div>
|
|
35
|
+
<div v-else-if="item.type === 'phone'">ส่งรหัสไปทาง SMS</div>
|
|
36
|
+
<div>{{ item.label }}</div>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
</InputRadio>
|
|
40
|
+
</div>
|
|
41
|
+
<Divider v-if="index !== accountItems.length - 1" />
|
|
42
|
+
</template>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<!-- Footer slot (must be direct child of Modal) -->
|
|
15
46
|
<template #footer>
|
|
16
47
|
<Button
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
48
|
+
v-if="step === 'search'"
|
|
49
|
+
class="w-full"
|
|
50
|
+
color="primary"
|
|
51
|
+
:disabled="!phone || !recaptcha || isLoading"
|
|
52
|
+
@click="onSearchNext"
|
|
21
53
|
>
|
|
22
|
-
|
|
54
|
+
ถัดไป
|
|
23
55
|
</Button>
|
|
56
|
+
<div v-else-if="step === 'list'" class="flex flex-col gap-[8px] w-full">
|
|
57
|
+
<Button
|
|
58
|
+
class="w-full"
|
|
59
|
+
color="primary"
|
|
60
|
+
:disabled="!selectedMethod"
|
|
61
|
+
@click="onListConfirm"
|
|
62
|
+
>
|
|
63
|
+
{{ props.confirmedText }}
|
|
64
|
+
</Button>
|
|
65
|
+
<Button variant="text" color="primary" class="w-full" @click="goBack"
|
|
66
|
+
>ไม่ใช่คุณใช่ไหม?</Button
|
|
67
|
+
>
|
|
68
|
+
</div>
|
|
24
69
|
</template>
|
|
25
70
|
</Modal>
|
|
26
71
|
</template>
|
|
27
72
|
|
|
28
73
|
<script setup>
|
|
29
|
-
import { ref } from "vue";
|
|
30
|
-
|
|
74
|
+
import { ref, computed, watch } from "vue";
|
|
75
|
+
import { useNuxtApp } from "nuxt/app";
|
|
76
|
+
import { useApi } from "../../composables/useApi";
|
|
77
|
+
import Button from "../button.vue";
|
|
78
|
+
const { $toast } = useNuxtApp();
|
|
79
|
+
const api = useApi();
|
|
80
|
+
const emit = defineEmits(["complete", "close"]);
|
|
31
81
|
const props = defineProps({
|
|
32
82
|
confirmedText: { type: String, required: false, default: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19" }
|
|
33
83
|
});
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
} });
|
|
84
|
+
const modelValue = defineModel({ type: Boolean, ...{ default: false } });
|
|
85
|
+
const step = ref("search");
|
|
86
|
+
const isLoading = ref(false);
|
|
38
87
|
const phone = ref("");
|
|
39
88
|
const recaptcha = ref("");
|
|
40
|
-
const
|
|
41
|
-
|
|
89
|
+
const recaptchaRef = ref(null);
|
|
90
|
+
const maskedPhone = ref("");
|
|
91
|
+
const maskedEmail = ref(null);
|
|
92
|
+
const hasEmail = ref(false);
|
|
93
|
+
const selectedMethod = ref(null);
|
|
94
|
+
const accountItems = computed(() => {
|
|
95
|
+
const items = [
|
|
96
|
+
{ type: "phone", value: "sms", label: maskedPhone.value }
|
|
97
|
+
];
|
|
98
|
+
if (hasEmail.value && maskedEmail.value) {
|
|
99
|
+
items.push({ type: "email", value: "email", label: maskedEmail.value });
|
|
100
|
+
}
|
|
101
|
+
return items;
|
|
102
|
+
});
|
|
103
|
+
const onSearchNext = async () => {
|
|
104
|
+
isLoading.value = true;
|
|
105
|
+
try {
|
|
106
|
+
const res = await api("/auth/forgot-password/find-account", {
|
|
107
|
+
method: "POST",
|
|
108
|
+
body: { phone: phone.value, token: recaptcha.value }
|
|
109
|
+
});
|
|
110
|
+
maskedPhone.value = res.data.masked_phone;
|
|
111
|
+
maskedEmail.value = res.data.masked_email;
|
|
112
|
+
hasEmail.value = res.data.has_email;
|
|
113
|
+
selectedMethod.value = null;
|
|
114
|
+
step.value = "list";
|
|
115
|
+
} catch (e) {
|
|
116
|
+
const msg = e?.data?.message?.description || e?.data?.message || "\u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E17\u0E35\u0E48\u0E43\u0E0A\u0E49\u0E40\u0E1A\u0E2D\u0E23\u0E4C\u0E42\u0E17\u0E23\u0E19\u0E35\u0E49";
|
|
117
|
+
$toast?.error?.(msg);
|
|
118
|
+
} finally {
|
|
119
|
+
isLoading.value = false;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const onListConfirm = () => {
|
|
123
|
+
if (!selectedMethod.value) return;
|
|
124
|
+
emitComplete();
|
|
125
|
+
};
|
|
126
|
+
const emitComplete = () => {
|
|
127
|
+
emit("complete", {
|
|
128
|
+
phone: phone.value,
|
|
129
|
+
method: selectedMethod.value ?? "sms",
|
|
130
|
+
maskedPhone: maskedPhone.value,
|
|
131
|
+
maskedEmail: maskedEmail.value,
|
|
132
|
+
hasEmail: hasEmail.value
|
|
133
|
+
});
|
|
42
134
|
modelValue.value = false;
|
|
43
135
|
};
|
|
136
|
+
const goBack = () => {
|
|
137
|
+
step.value = "search";
|
|
138
|
+
phone.value = "";
|
|
139
|
+
recaptcha.value = "";
|
|
140
|
+
selectedMethod.value = null;
|
|
141
|
+
maskedPhone.value = "";
|
|
142
|
+
maskedEmail.value = null;
|
|
143
|
+
hasEmail.value = false;
|
|
144
|
+
};
|
|
145
|
+
watch(modelValue, (v) => {
|
|
146
|
+
if (!v) {
|
|
147
|
+
step.value = "search";
|
|
148
|
+
phone.value = "";
|
|
149
|
+
recaptcha.value = "";
|
|
150
|
+
selectedMethod.value = null;
|
|
151
|
+
maskedPhone.value = "";
|
|
152
|
+
maskedEmail.value = null;
|
|
153
|
+
hasEmail.value = false;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
44
156
|
</script>
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export interface ModalUserAccountSearchResult {
|
|
2
|
+
phone: string;
|
|
3
|
+
method: "sms" | "email";
|
|
4
|
+
maskedPhone: string;
|
|
5
|
+
maskedEmail: string | null;
|
|
6
|
+
hasEmail: boolean;
|
|
7
|
+
}
|
|
1
8
|
type __VLS_Props = {
|
|
2
9
|
confirmedText?: string;
|
|
3
10
|
};
|
|
@@ -6,11 +13,14 @@ type __VLS_ModelProps = {
|
|
|
6
13
|
};
|
|
7
14
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
8
15
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
-
|
|
10
|
-
|
|
16
|
+
"update:modelValue": (value: boolean) => any;
|
|
17
|
+
} & {
|
|
18
|
+
close: () => any;
|
|
19
|
+
complete: (data: ModalUserAccountSearchResult) => any;
|
|
11
20
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
21
|
+
onClose?: (() => any) | undefined;
|
|
12
22
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
13
|
-
onComplete?: ((
|
|
23
|
+
onComplete?: ((data: ModalUserAccountSearchResult) => any) | undefined;
|
|
14
24
|
}>, {
|
|
15
25
|
confirmedText: string;
|
|
16
26
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ModalUserAccountListProps, ModalUserAccountListItem } from "@/types/components/modal/modal-user-account-list";
|
|
2
|
-
type __VLS_Props = ModalUserAccountListProps;
|
|
3
|
-
type __VLS_ModelProps = {
|
|
4
|
-
modelValue?: boolean;
|
|
5
|
-
};
|
|
6
|
-
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
7
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
-
"update:modelValue": (value: boolean) => any;
|
|
9
|
-
} & {
|
|
10
|
-
complete: (value: ModalUserAccountListItem | null) => any;
|
|
11
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
12
|
-
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
13
|
-
onComplete?: ((value: ModalUserAccountListItem | null) => any) | undefined;
|
|
14
|
-
}>, {
|
|
15
|
-
items: ModalUserAccountListItem[];
|
|
16
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
|
-
declare const _default: typeof __VLS_export;
|
|
18
|
-
export default _default;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<Modal title="เลือกวิธีตรวจสอบ" v-model="modelValue">
|
|
3
|
-
<template v-for="(item, index) in props.items" :key="index">
|
|
4
|
-
<div class="py-[12px] px-[16px]">
|
|
5
|
-
<InputRadio :item="item.value" label-position="left" v-model="selected">
|
|
6
|
-
<template v-slot:[`label-${item.value}-text`]>
|
|
7
|
-
<div
|
|
8
|
-
class="flex flex-col w-full text-gray font-body-medium-prominent"
|
|
9
|
-
>
|
|
10
|
-
<div v-if="item.type === 'email'">ส่งรหัสไปทางอีเมล</div>
|
|
11
|
-
<div v-else-if="item.type === 'phone'">ส่งรหัสไปทาง SMS</div>
|
|
12
|
-
<div>{{ item.label }}</div>
|
|
13
|
-
</div>
|
|
14
|
-
</template>
|
|
15
|
-
</InputRadio>
|
|
16
|
-
</div>
|
|
17
|
-
<Divider v-if="index !== props.items.length - 1" />
|
|
18
|
-
</template>
|
|
19
|
-
|
|
20
|
-
<template #footer>
|
|
21
|
-
<Button
|
|
22
|
-
color="primary"
|
|
23
|
-
full-width
|
|
24
|
-
@click="onConfirm"
|
|
25
|
-
:disabled="!selected"
|
|
26
|
-
>
|
|
27
|
-
ยืนยัน
|
|
28
|
-
</Button>
|
|
29
|
-
</template>
|
|
30
|
-
</Modal>
|
|
31
|
-
</template>
|
|
32
|
-
|
|
33
|
-
<script setup>
|
|
34
|
-
import { ref } from "vue";
|
|
35
|
-
const emit = defineEmits(["complete"]);
|
|
36
|
-
const props = defineProps({
|
|
37
|
-
items: { type: Array, required: false, default: () => [] }
|
|
38
|
-
});
|
|
39
|
-
const selected = ref(null);
|
|
40
|
-
const modelValue = defineModel({ type: Boolean, ...{
|
|
41
|
-
default: false
|
|
42
|
-
} });
|
|
43
|
-
const onConfirm = () => {
|
|
44
|
-
const selectedItem = props.items.find(
|
|
45
|
-
(item) => item.value === selected.value
|
|
46
|
-
);
|
|
47
|
-
emit("complete", selectedItem ?? null);
|
|
48
|
-
modelValue.value = false;
|
|
49
|
-
selected.value = null;
|
|
50
|
-
};
|
|
51
|
-
</script>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ModalUserAccountListProps, ModalUserAccountListItem } from "@/types/components/modal/modal-user-account-list";
|
|
2
|
-
type __VLS_Props = ModalUserAccountListProps;
|
|
3
|
-
type __VLS_ModelProps = {
|
|
4
|
-
modelValue?: boolean;
|
|
5
|
-
};
|
|
6
|
-
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
7
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
-
"update:modelValue": (value: boolean) => any;
|
|
9
|
-
} & {
|
|
10
|
-
complete: (value: ModalUserAccountListItem | null) => any;
|
|
11
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
12
|
-
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
13
|
-
onComplete?: ((value: ModalUserAccountListItem | null) => any) | undefined;
|
|
14
|
-
}>, {
|
|
15
|
-
items: ModalUserAccountListItem[];
|
|
16
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
|
-
declare const _default: typeof __VLS_export;
|
|
18
|
-
export default _default;
|
|
File without changes
|