adata-ui 2.0.29 → 2.0.31
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/components/elements/feature-description/AFeatureDescription.vue +2 -2
- package/components/modals/id/IdConfirmAccountOtpModal.vue +70 -46
- package/components/modals/id/IdConfirmSuccessfulModal.vue +7 -2
- package/components/modals/id/IdLoginModal.vue +1 -1
- package/components/modals/id/IdModals.vue +1 -1
- package/components/modals/id/{otp-input.vue → IdOtpInput.vue} +15 -8
- package/components/modals/id/IdRegistrationModal.vue +4 -3
- package/components/modals/id/IdResetPasswordOtpModal.vue +21 -35
- package/components/modals/id/IdTwoFactorModal.vue +14 -19
- package/lang/en.ts +1 -1
- package/lang/kk.ts +1 -1
- package/lang/ru.ts +1 -1
- package/package.json +1 -1
|
@@ -68,12 +68,12 @@ onUnmounted(() => clearTimer())
|
|
|
68
68
|
<component
|
|
69
69
|
:is="item.icon"
|
|
70
70
|
class="shrink-0 size-6 transition-colors duration-300 ease-in-out"
|
|
71
|
-
:class="selected === idx ? 'text-white dark:text-gray-900' : 'text-gray-600 dark:text-
|
|
71
|
+
:class="selected === idx ? 'text-white dark:text-gray-900' : 'text-gray-600 dark:text-[#9DA3AC]'"
|
|
72
72
|
/>
|
|
73
73
|
</div>
|
|
74
74
|
<p
|
|
75
75
|
class="font-semibold text-base lg:text-xl transition-colors duration-300 ease-in-out"
|
|
76
|
-
:class="selected === idx ? 'dark:text-[#E3E5E8]' : 'text-gray-600 dark:text-
|
|
76
|
+
:class="selected === idx ? 'dark:text-[#E3E5E8]' : 'text-gray-600 dark:text-[#9DA3AC]'"
|
|
77
77
|
>
|
|
78
78
|
{{ item.title }}
|
|
79
79
|
</p>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
|
|
3
3
|
import { useAuthStore } from '#adata-ui/stores/auth.store'
|
|
4
4
|
|
|
5
5
|
const { $toast } = useNuxtApp()
|
|
@@ -17,26 +17,42 @@ const otp = ref(['', '', '', '', '', ''])
|
|
|
17
17
|
const otpFormatted = computed(() => {
|
|
18
18
|
return otp.value.join('')
|
|
19
19
|
})
|
|
20
|
-
const attempts = ref(5)
|
|
21
20
|
const showError = ref(false)
|
|
22
21
|
const isLoading = ref(false)
|
|
23
22
|
|
|
24
|
-
async function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
23
|
+
async function loginUser() {
|
|
24
|
+
const login = await fetch(`${authApiURL}/login`, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
credentials: 'include',
|
|
27
|
+
headers: {
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
'lang': locale.value,
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify({
|
|
32
|
+
username: intermediateState.value.email,
|
|
33
|
+
password: intermediateState.value.password,
|
|
34
|
+
}),
|
|
35
|
+
})
|
|
36
|
+
await login.json().catch(() => ({}))
|
|
37
|
+
|
|
38
|
+
const response = await fetch(`${authApiURL}/access/cookie`, {
|
|
39
|
+
method: 'GET',
|
|
40
|
+
credentials: 'include',
|
|
41
|
+
headers: {
|
|
42
|
+
lang: locale.value,
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
const { data: cookiesData } = await response.json()
|
|
46
|
+
if (cookiesData) {
|
|
47
|
+
const { access_token, expire_in } = cookiesData
|
|
48
|
+
const hostname = location.hostname.split('.').reverse()
|
|
49
|
+
|
|
50
|
+
useCookie('accessToken', {
|
|
51
|
+
maxAge: expire_in,
|
|
52
|
+
domain: `.${hostname[1]}.${hostname[0]}`,
|
|
53
|
+
path: '/',
|
|
54
|
+
secure: true,
|
|
55
|
+
}).value = access_token
|
|
40
56
|
}
|
|
41
57
|
}
|
|
42
58
|
|
|
@@ -56,31 +72,49 @@ async function onConfirm() {
|
|
|
56
72
|
},
|
|
57
73
|
})
|
|
58
74
|
|
|
75
|
+
await loginUser()
|
|
76
|
+
|
|
59
77
|
confirmAccountOtpModal.value = false
|
|
60
78
|
confirmSuccessfulModal.value = true
|
|
61
79
|
}
|
|
62
80
|
catch (error) {
|
|
63
|
-
if (error.data?.retry_after) {
|
|
64
|
-
attempts.value = 0
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
attempts.value--
|
|
68
|
-
}
|
|
69
81
|
showError.value = true
|
|
70
|
-
$toast.error(error.data.message)
|
|
71
82
|
}
|
|
72
83
|
finally {
|
|
73
84
|
isLoading.value = false
|
|
74
85
|
}
|
|
75
86
|
}
|
|
76
87
|
|
|
77
|
-
function
|
|
88
|
+
function resetOtp() {
|
|
78
89
|
otp.value = ['', '', '', '', '', '']
|
|
79
90
|
showError.value = false
|
|
80
|
-
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function onClose() {
|
|
94
|
+
resetOtp()
|
|
81
95
|
confirmAccountOtpModal.value = false
|
|
82
96
|
}
|
|
83
97
|
|
|
98
|
+
async function onResend() {
|
|
99
|
+
try {
|
|
100
|
+
await $fetch(`${authApiURL}/email/resend-otp`, {
|
|
101
|
+
method: 'GET',
|
|
102
|
+
credentials: 'include',
|
|
103
|
+
headers: {
|
|
104
|
+
lang: locale.value,
|
|
105
|
+
},
|
|
106
|
+
params: {
|
|
107
|
+
email: intermediateState.value.email,
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
resetOtp()
|
|
111
|
+
runTimer()
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
$toast.error(error.data)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
84
118
|
const timer = ref(60)
|
|
85
119
|
|
|
86
120
|
function runTimer() {
|
|
@@ -133,28 +167,18 @@ onBeforeUnmount(() => {
|
|
|
133
167
|
</button>
|
|
134
168
|
</div>
|
|
135
169
|
|
|
136
|
-
<otp-input
|
|
170
|
+
<id-otp-input
|
|
137
171
|
v-model="otp"
|
|
138
172
|
v-model:error="showError"
|
|
139
|
-
|
|
173
|
+
@on-completed="onConfirm"
|
|
140
174
|
/>
|
|
141
175
|
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
</a-button>
|
|
150
|
-
<a-button
|
|
151
|
-
block
|
|
152
|
-
:loading="isLoading"
|
|
153
|
-
:disabled="otpFormatted.length < 6 || attempts === 0"
|
|
154
|
-
@click="onConfirm"
|
|
155
|
-
>
|
|
156
|
-
{{ t('actions.confirm') }}
|
|
157
|
-
</a-button>
|
|
158
|
-
</div>
|
|
176
|
+
<a-button
|
|
177
|
+
block
|
|
178
|
+
view="outline"
|
|
179
|
+
@click="onClose"
|
|
180
|
+
>
|
|
181
|
+
{{ t('actions.close') }}
|
|
182
|
+
</a-button>
|
|
159
183
|
</div>
|
|
160
184
|
</template>
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
const { confirmSuccessfulModal } = useIdModals()
|
|
3
2
|
const { t } = useI18n()
|
|
3
|
+
const { confirmSuccessfulModal } = useIdModals()
|
|
4
|
+
|
|
5
|
+
function onClose() {
|
|
6
|
+
confirmSuccessfulModal.value = false
|
|
7
|
+
window.location.reload()
|
|
8
|
+
}
|
|
4
9
|
</script>
|
|
5
10
|
|
|
6
11
|
<template>
|
|
@@ -14,7 +19,7 @@ const { t } = useI18n()
|
|
|
14
19
|
<p class="text-sm">
|
|
15
20
|
{{ t('modals.id.confirmSuccessful.content') }}
|
|
16
21
|
</p>
|
|
17
|
-
<a-button view="outline" @click="
|
|
22
|
+
<a-button view="outline" @click="onClose">
|
|
18
23
|
{{ t('actions.close') }}
|
|
19
24
|
</a-button>
|
|
20
25
|
</div>
|
|
@@ -36,7 +36,7 @@ const {
|
|
|
36
36
|
<a-modal v-model="confirmAccountOtpModal" prevent-close>
|
|
37
37
|
<id-confirm-account-otp-modal v-if="confirmAccountOtpModal" />
|
|
38
38
|
</a-modal>
|
|
39
|
-
<a-modal v-model="confirmSuccessfulModal">
|
|
39
|
+
<a-modal v-model="confirmSuccessfulModal" prevent-close>
|
|
40
40
|
<id-confirm-successful-modal v-if="confirmSuccessfulModal" />
|
|
41
41
|
</a-modal>
|
|
42
42
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const emit = defineEmits<{
|
|
3
|
+
(e: 'onCompleted', value: string): void
|
|
4
4
|
}>()
|
|
5
5
|
|
|
6
6
|
const length = 6 // Длина OTP
|
|
@@ -9,6 +9,12 @@ const otp = defineModel()
|
|
|
9
9
|
const otpRefs = ref([])
|
|
10
10
|
const { t } = useI18n()
|
|
11
11
|
|
|
12
|
+
function checkCompletion() {
|
|
13
|
+
if (otp.value.every(val => val !== '')) {
|
|
14
|
+
emit('onCompleted', otp.value.join(''))
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
function onInput(event, index) {
|
|
13
19
|
const value = event.target.value
|
|
14
20
|
showError.value = false
|
|
@@ -20,6 +26,7 @@ function onInput(event, index) {
|
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
otp.value[index] = value
|
|
29
|
+
checkCompletion()
|
|
23
30
|
|
|
24
31
|
// Перемещаем фокус на следующий элемент, если введен символ
|
|
25
32
|
if (value && index < length - 1) {
|
|
@@ -63,6 +70,7 @@ function onPaste(event) {
|
|
|
63
70
|
otp.value[index] = char
|
|
64
71
|
}
|
|
65
72
|
})
|
|
73
|
+
checkCompletion()
|
|
66
74
|
|
|
67
75
|
// Ставим фокус на следующий незаполненный элемент
|
|
68
76
|
const firstEmptyIndex = otp.value.findIndex(val => val === '')
|
|
@@ -117,8 +125,11 @@ function moveFocus(index: number, to: string) {
|
|
|
117
125
|
v-model="otp[index]"
|
|
118
126
|
type="text"
|
|
119
127
|
maxlength="1"
|
|
120
|
-
class="bg-deepblue-900/5
|
|
121
|
-
:class="{
|
|
128
|
+
class="size-10 rounded bg-deepblue-900/5 text-center text-lg caret-transparent focus:outline-none dark:bg-[#E3E5E80D]"
|
|
129
|
+
:class="{
|
|
130
|
+
'border border-[#E74135] bg-[#E741351A] dark:border-[#F47E75] dark:bg-[#F47E751A]': showError,
|
|
131
|
+
'focus:border focus:border-blue-700 dark:focus:border-blue-500': !showError,
|
|
132
|
+
}"
|
|
122
133
|
@input="onInput($event, index)"
|
|
123
134
|
@keydown.backspace="onBackspace(index, $event)"
|
|
124
135
|
@keydown.enter.prevent
|
|
@@ -137,10 +148,6 @@ function moveFocus(index: number, to: string) {
|
|
|
137
148
|
>
|
|
138
149
|
{{ t('error.otp') }}
|
|
139
150
|
</a-alert>
|
|
140
|
-
|
|
141
|
-
<p v-show="showError" class="mt-1 text-xs text-red-500 dark:text-red-400">
|
|
142
|
-
{{ t('modals.id.resetPasswordOtp.attempts', { n: attempts }) }}
|
|
143
|
-
</p>
|
|
144
151
|
</div>
|
|
145
152
|
</template>
|
|
146
153
|
|
|
@@ -74,7 +74,7 @@ async function onSubmit() {
|
|
|
74
74
|
|
|
75
75
|
try {
|
|
76
76
|
loading.value = true
|
|
77
|
-
const { success, message } = await $fetch(`${authApiURL}/register`, {
|
|
77
|
+
const { success, message } = await $fetch(`${authApiURL}/v2/register`, {
|
|
78
78
|
method: 'POST',
|
|
79
79
|
credentials: 'include',
|
|
80
80
|
headers: {
|
|
@@ -84,9 +84,10 @@ async function onSubmit() {
|
|
|
84
84
|
})
|
|
85
85
|
if (success) {
|
|
86
86
|
intermediateState.value.email = form.email
|
|
87
|
+
intermediateState.value.password = form.password
|
|
88
|
+
|
|
87
89
|
registrationModal.value = false
|
|
88
90
|
confirmAccountOtpModal.value = true
|
|
89
|
-
$toast.success(message)
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
catch (error) {
|
|
@@ -117,7 +118,7 @@ function getUrl() {
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
function handleEnter(event: KeyboardEvent) {
|
|
120
|
-
if (event.key === 'Enter'
|
|
121
|
+
if (event.key === 'Enter') {
|
|
121
122
|
onSubmit()
|
|
122
123
|
}
|
|
123
124
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
|
|
3
3
|
import { useAuthStore } from '#adata-ui/stores/auth.store'
|
|
4
4
|
|
|
5
5
|
const { $toast } = useNuxtApp()
|
|
@@ -17,7 +17,6 @@ const otp = ref(['', '', '', '', '', ''])
|
|
|
17
17
|
const otpFormatted = computed(() => {
|
|
18
18
|
return otp.value.join('')
|
|
19
19
|
})
|
|
20
|
-
const attempts = ref(5)
|
|
21
20
|
const showError = ref(false)
|
|
22
21
|
const isLoading = ref(false)
|
|
23
22
|
|
|
@@ -44,20 +43,23 @@ async function onConfirm() {
|
|
|
44
43
|
newPasswordModal.value = true
|
|
45
44
|
}
|
|
46
45
|
catch (error) {
|
|
47
|
-
if (error.data?.retry_after) {
|
|
48
|
-
attempts.value = 0
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
attempts.value--
|
|
52
|
-
}
|
|
53
46
|
showError.value = true
|
|
54
|
-
$toast.error(error.data.message)
|
|
55
47
|
}
|
|
56
48
|
finally {
|
|
57
49
|
isLoading.value = false
|
|
58
50
|
}
|
|
59
51
|
}
|
|
60
52
|
|
|
53
|
+
function resetOtp() {
|
|
54
|
+
otp.value = ['', '', '', '', '', '']
|
|
55
|
+
showError.value = false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function onClose() {
|
|
59
|
+
resetOtp()
|
|
60
|
+
resetPasswordOtpModal.value = false
|
|
61
|
+
}
|
|
62
|
+
|
|
61
63
|
async function onResend() {
|
|
62
64
|
try {
|
|
63
65
|
await $fetch(`${authApiURL}/password/email-otp`, {
|
|
@@ -70,6 +72,7 @@ async function onResend() {
|
|
|
70
72
|
email: intermediateState.value.email,
|
|
71
73
|
},
|
|
72
74
|
})
|
|
75
|
+
resetOtp()
|
|
73
76
|
runTimer()
|
|
74
77
|
}
|
|
75
78
|
catch (error) {
|
|
@@ -77,13 +80,6 @@ async function onResend() {
|
|
|
77
80
|
}
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
function onClose() {
|
|
81
|
-
otp.value = ['', '', '', '', '', '']
|
|
82
|
-
attempts.value = 5
|
|
83
|
-
showError.value = false
|
|
84
|
-
resetPasswordOtpModal.value = false
|
|
85
|
-
}
|
|
86
|
-
|
|
87
83
|
function handleEnter(e: KeyboardEvent) {
|
|
88
84
|
if (e.key === 'Enter') {
|
|
89
85
|
onConfirm()
|
|
@@ -136,29 +132,19 @@ onBeforeUnmount(() => {
|
|
|
136
132
|
</button>
|
|
137
133
|
</div>
|
|
138
134
|
|
|
139
|
-
<otp-input
|
|
135
|
+
<id-otp-input
|
|
140
136
|
v-model="otp"
|
|
141
137
|
v-model:error="showError"
|
|
142
|
-
|
|
138
|
+
@on-completed="onConfirm"
|
|
143
139
|
/>
|
|
144
140
|
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
</a-button>
|
|
153
|
-
<a-button
|
|
154
|
-
block
|
|
155
|
-
:loading="isLoading"
|
|
156
|
-
:disabled="otpFormatted.length < 6 || attempts === 0"
|
|
157
|
-
@click="onConfirm"
|
|
158
|
-
>
|
|
159
|
-
{{ t('actions.confirm') }}
|
|
160
|
-
</a-button>
|
|
161
|
-
</div>
|
|
141
|
+
<a-button
|
|
142
|
+
block
|
|
143
|
+
view="outline"
|
|
144
|
+
@click="onClose"
|
|
145
|
+
>
|
|
146
|
+
{{ t('actions.close') }}
|
|
147
|
+
</a-button>
|
|
162
148
|
</div>
|
|
163
149
|
</template>
|
|
164
150
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
|
|
3
3
|
import { useAuthStore } from '#adata-ui/stores/auth.store'
|
|
4
4
|
|
|
5
5
|
const { $toast } = useNuxtApp()
|
|
@@ -98,27 +98,22 @@ onBeforeUnmount(() => {
|
|
|
98
98
|
</p>
|
|
99
99
|
<a-icon-hand-with-phone-light class="size-32 dark:hidden" />
|
|
100
100
|
<a-icon-hand-with-phone-dark class="hidden size-32 dark:block" />
|
|
101
|
-
<otp-input
|
|
101
|
+
<id-otp-input
|
|
102
|
+
v-model="otp"
|
|
103
|
+
v-model:error="showError"
|
|
104
|
+
@on-completed="onConfirm"
|
|
105
|
+
/>
|
|
102
106
|
<p class="body-400 text-center">
|
|
103
107
|
{{ t('modals.id.twoFactor.code') }}
|
|
104
108
|
</p>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<a-button
|
|
114
|
-
:loading="isLoading"
|
|
115
|
-
:disabled="otpFormatted.length < 6"
|
|
116
|
-
class="w-full"
|
|
117
|
-
@click="onConfirm"
|
|
118
|
-
>
|
|
119
|
-
{{ t('actions.confirm') }}
|
|
120
|
-
</a-button>
|
|
121
|
-
</div>
|
|
109
|
+
|
|
110
|
+
<a-button
|
|
111
|
+
class="w-full"
|
|
112
|
+
view="outline"
|
|
113
|
+
@click="onClose"
|
|
114
|
+
>
|
|
115
|
+
{{ t('actions.close') }}
|
|
116
|
+
</a-button>
|
|
122
117
|
</div>
|
|
123
118
|
</template>
|
|
124
119
|
|
package/lang/en.ts
CHANGED
|
@@ -520,7 +520,7 @@ const EnLocale: RuLocale = {
|
|
|
520
520
|
resetPasswordOtp: {
|
|
521
521
|
title: 'Confirm action',
|
|
522
522
|
content: 'Enter the 6-digit confirmation code sent to your email address',
|
|
523
|
-
seconds: '
|
|
523
|
+
seconds: 'seconds',
|
|
524
524
|
attempts: 'Remaining attempts: {n}',
|
|
525
525
|
},
|
|
526
526
|
newPassword: {
|
package/lang/kk.ts
CHANGED
|
@@ -521,7 +521,7 @@ const KkLocale: RuLocale = {
|
|
|
521
521
|
resetPasswordOtp: {
|
|
522
522
|
title: 'Әрекетті растау',
|
|
523
523
|
content: 'Электрондық поштаға жіберілген 6 таңбалы кодты енгізіңіз',
|
|
524
|
-
seconds: '
|
|
524
|
+
seconds: 'секунд',
|
|
525
525
|
attempts: 'Қалған әрекет саны: {n}',
|
|
526
526
|
},
|
|
527
527
|
newPassword: {
|
package/lang/ru.ts
CHANGED
|
@@ -522,7 +522,7 @@ const RuLocale = {
|
|
|
522
522
|
resetPasswordOtp: {
|
|
523
523
|
title: 'Подтвердите действие',
|
|
524
524
|
content: 'Введите 6-значный код подтверждения отправленный на ваш адрес электронной почты',
|
|
525
|
-
seconds: '
|
|
525
|
+
seconds: 'секунд',
|
|
526
526
|
attempts: 'Повторных попыток осталось: {n}',
|
|
527
527
|
},
|
|
528
528
|
newPassword: {
|