adata-ui 2.0.28 → 2.0.30
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/.nuxtrc +1 -1
- package/.playground/app.config.ts +5 -5
- package/README.md +75 -75
- package/components/elements/README.md +1 -1
- package/components/forms/README.md +1 -1
- package/components/modals/AConfirmationEmail.vue +40 -40
- package/components/modals/Resend.vue +81 -81
- package/components/modals/id/IdConfirmAccountOtpModal.vue +77 -40
- package/components/modals/id/IdConfirmSuccessfulModal.vue +7 -2
- package/components/modals/id/IdLoginModal.vue +45 -128
- package/components/modals/id/IdModals.vue +6 -2
- package/components/modals/id/IdNewPasswordModal.vue +7 -5
- package/components/modals/{two-factor/otp-input.vue → id/IdOtpInput.vue} +14 -2
- package/components/modals/id/IdRegistrationModal.vue +22 -21
- package/components/modals/id/IdResetPasswordOtpModal.vue +27 -28
- package/components/modals/id/IdTwoFactorModal.vue +122 -0
- package/components/navigation/README.md +1 -1
- package/components/overlays/README.md +1 -1
- package/icons/google.vue +41 -41
- package/icons/linkedin.vue +24 -24
- package/icons/mailru.vue +34 -34
- package/icons/sun.vue +14 -14
- package/icons/yandex.vue +28 -28
- package/lang/en.ts +351 -330
- package/lang/kk.ts +352 -331
- package/lang/ru.ts +42 -66
- package/layouts/default.vue +13 -13
- package/package.json +1 -1
- package/components/modals/two-factor/two-factor.vue +0 -79
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import TwoFactor from '#adata-ui/components/modals/two-factor/two-factor.vue'
|
|
3
2
|
import { useAuthStore } from '#adata-ui/stores/auth.store'
|
|
4
3
|
import { navigateToLocalizedPage } from '#adata-ui/utils/localizedNavigation'
|
|
5
|
-
import { useToggle } from '@vueuse/shared'
|
|
6
4
|
import * as z from 'zod'
|
|
7
5
|
|
|
6
|
+
const { $toast } = useNuxtApp()
|
|
8
7
|
const { myLayer, commonAuth } = useAppConfig()
|
|
9
|
-
const authApiURL = commonAuth.authApiURL
|
|
10
|
-
const [isResendModal, toggleResendModal] = useToggle()
|
|
11
|
-
const isConfirmationEmailModal = ref(false)
|
|
12
|
-
const isTwoFactorOpen = ref(false)
|
|
13
|
-
const isLoadingOtp = ref(false)
|
|
14
|
-
const { $api, $toast } = useNuxtApp()
|
|
15
|
-
const showOtpError = ref(false)
|
|
16
8
|
const { t, locale } = useI18n()
|
|
17
|
-
const submitted = ref(false)
|
|
18
|
-
const accessToken = ref(null)
|
|
19
|
-
const { loginModal, registrationModal, recoveryModal, confirmAccountOtpModal } = useIdModals()
|
|
20
9
|
|
|
21
10
|
const authStore = useAuthStore()
|
|
22
11
|
const { intermediateState } = storeToRefs(authStore)
|
|
23
12
|
|
|
13
|
+
const { loginModal, registrationModal, recoveryModal, confirmAccountOtpModal, twoFactorModal } = useIdModals()
|
|
14
|
+
|
|
15
|
+
const authApiURL = commonAuth.authApiURL
|
|
16
|
+
|
|
17
|
+
const submitted = ref(false)
|
|
18
|
+
const accessToken = ref(null)
|
|
19
|
+
|
|
24
20
|
export interface ILoginForm {
|
|
25
21
|
username: string
|
|
26
22
|
password: string
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
const loginSchema = z.object({
|
|
30
|
-
username: z.string().nonempty(t('
|
|
31
|
-
password: z.string().nonempty(t('
|
|
26
|
+
username: z.string().nonempty(t('error.required')).email(t('error.email')),
|
|
27
|
+
password: z.string().nonempty(t('error.required')),
|
|
32
28
|
})
|
|
33
29
|
|
|
34
30
|
const validation = computed(() => {
|
|
@@ -78,34 +74,38 @@ async function submit() {
|
|
|
78
74
|
}),
|
|
79
75
|
})
|
|
80
76
|
const { data, message } = await login.json().catch(() => ({}))
|
|
77
|
+
|
|
78
|
+
intermediateState.value.email = form.username
|
|
79
|
+
intermediateState.value.password = form.password
|
|
80
|
+
|
|
81
81
|
if (data) accessToken.value = data?.access_token
|
|
82
82
|
if (login.status > 202) {
|
|
83
83
|
if (login.status === 422) {
|
|
84
84
|
$toast.error(t('error.validation'))
|
|
85
85
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
intermediateState.value.password = form.password
|
|
86
|
+
if (login.status === 206) {
|
|
87
|
+
confirmAccountOtpModal.value = true
|
|
89
88
|
|
|
90
|
-
|
|
89
|
+
$fetch(`${authApiURL}/email/resend-otp`, {
|
|
91
90
|
method: 'GET',
|
|
92
91
|
credentials: 'include',
|
|
93
92
|
headers: {
|
|
94
|
-
|
|
95
|
-
'lang': locale.value,
|
|
93
|
+
lang: locale.value,
|
|
96
94
|
},
|
|
97
|
-
|
|
95
|
+
params: {
|
|
98
96
|
email: intermediateState.value.email,
|
|
99
|
-
}
|
|
97
|
+
},
|
|
100
98
|
}).catch(() => {})
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
$toast.error(message)
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
104
|
else {
|
|
106
105
|
rememberMe.value ? savePassAndLogin(form) : clearAuthCookie()
|
|
107
106
|
if (data.is_2fa_enabled) {
|
|
108
|
-
|
|
107
|
+
loginModal.value = false
|
|
108
|
+
twoFactorModal.value = true
|
|
109
109
|
}
|
|
110
110
|
else if (data.email_is_verified) {
|
|
111
111
|
const response = await fetch(`${authApiURL}/access/cookie`, {
|
|
@@ -120,15 +120,19 @@ async function submit() {
|
|
|
120
120
|
if (cookiesData) {
|
|
121
121
|
const { access_token, expire_in } = cookiesData
|
|
122
122
|
const hostname = location.hostname.split('.').reverse()
|
|
123
|
-
|
|
123
|
+
|
|
124
|
+
useCookie('accessToken', {
|
|
125
|
+
maxAge: expire_in,
|
|
126
|
+
domain: `.${hostname[1]}.${hostname[0]}`,
|
|
127
|
+
path: '/',
|
|
128
|
+
secure: true,
|
|
129
|
+
}).value = access_token
|
|
124
130
|
}
|
|
125
131
|
$toast.success(t('login.successfully'))
|
|
126
132
|
loginModal.value = false
|
|
127
133
|
window.location.reload()
|
|
128
134
|
}
|
|
129
135
|
else {
|
|
130
|
-
intermediateState.value.email = form.username
|
|
131
|
-
intermediateState.value.password = form.password
|
|
132
136
|
confirmAccountOtpModal.value = true
|
|
133
137
|
|
|
134
138
|
$fetch(`${authApiURL}/email/resend-otp`, {
|
|
@@ -137,7 +141,7 @@ async function submit() {
|
|
|
137
141
|
headers: {
|
|
138
142
|
lang: locale.value,
|
|
139
143
|
},
|
|
140
|
-
|
|
144
|
+
params: {
|
|
141
145
|
email: intermediateState.value.email,
|
|
142
146
|
},
|
|
143
147
|
}).catch(() => {})
|
|
@@ -154,13 +158,6 @@ function authWithSocial(social: string) {
|
|
|
154
158
|
document.location.replace(`https://auth.${mode}.kz/api/login/social?source=${social}`)
|
|
155
159
|
}
|
|
156
160
|
|
|
157
|
-
async function onResend() {
|
|
158
|
-
const { data, success, message } = await $api.auth.emailResend()
|
|
159
|
-
if (success) {
|
|
160
|
-
$toast.success(message)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
161
|
function onRegister() {
|
|
165
162
|
loginModal.value = false
|
|
166
163
|
registrationModal.value = true
|
|
@@ -179,64 +176,8 @@ onMounted(() => {
|
|
|
179
176
|
rememberMe.value = !!useCookie('username').value && !!useCookie('password').value
|
|
180
177
|
})
|
|
181
178
|
|
|
182
|
-
function confirmationEmailResend() {
|
|
183
|
-
isConfirmationEmailModal.value = false
|
|
184
|
-
toggleResendModal()
|
|
185
|
-
}
|
|
186
|
-
async function handleConfirmOtp(otpCode: string) {
|
|
187
|
-
isLoadingOtp.value = true
|
|
188
|
-
const login = await fetch(`${authApiURL}/login`, {
|
|
189
|
-
method: 'POST',
|
|
190
|
-
credentials: 'include',
|
|
191
|
-
headers: {
|
|
192
|
-
'Content-Type': 'application/json',
|
|
193
|
-
'lang': locale.value,
|
|
194
|
-
},
|
|
195
|
-
body: JSON.stringify({
|
|
196
|
-
'username': intermediateState.value.email.trim(),
|
|
197
|
-
'password': intermediateState.value.password.toString(),
|
|
198
|
-
'2fa_code': otpCode,
|
|
199
|
-
}),
|
|
200
|
-
})
|
|
201
|
-
const { data, message } = await login.json().catch(() => ({}))
|
|
202
|
-
|
|
203
|
-
if (login.status > 202) {
|
|
204
|
-
if (login.status === 403) {
|
|
205
|
-
showOtpError.value = true
|
|
206
|
-
isLoadingOtp.value = false
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
const response = await fetch(`${authApiURL}/access/cookie`, {
|
|
211
|
-
method: 'GET',
|
|
212
|
-
credentials: 'include',
|
|
213
|
-
headers: {
|
|
214
|
-
Authorization: `Bearer ${accessToken.value}`,
|
|
215
|
-
lang: locale.value,
|
|
216
|
-
},
|
|
217
|
-
})
|
|
218
|
-
const { data: cookiesData } = await response.json()
|
|
219
|
-
if (cookiesData?.access_token) {
|
|
220
|
-
const { access_token, expire_in } = cookiesData
|
|
221
|
-
const hostname = location.hostname.split('.').reverse()
|
|
222
|
-
document.cookie = `accessToken=${access_token}; max-age=${expire_in}; domain=.${hostname[1]}.${hostname[0]}; path=/`
|
|
223
|
-
}
|
|
224
|
-
$toast.success(t('login.successfully'))
|
|
225
|
-
loginModal.value = false
|
|
226
|
-
window.location.reload()
|
|
227
|
-
|
|
228
|
-
isTwoFactorOpen.value = false
|
|
229
|
-
}
|
|
230
|
-
isLoadingOtp.value = false
|
|
231
|
-
}
|
|
232
|
-
|
|
233
179
|
function handleEnter(e: KeyboardEvent) {
|
|
234
|
-
if (
|
|
235
|
-
e.key === 'Enter'
|
|
236
|
-
&& !isTwoFactorOpen.value
|
|
237
|
-
&& !isConfirmationEmailModal.value
|
|
238
|
-
&& !isResendModal.value
|
|
239
|
-
) {
|
|
180
|
+
if (e.key === 'Enter') {
|
|
240
181
|
submit()
|
|
241
182
|
}
|
|
242
183
|
}
|
|
@@ -258,21 +199,21 @@ onBeforeUnmount(() => {
|
|
|
258
199
|
<template>
|
|
259
200
|
<div class="flex flex-col gap-5">
|
|
260
201
|
<h1 class="heading-02 text-center">
|
|
261
|
-
{{
|
|
202
|
+
{{ t('modals.id.login.title') }}
|
|
262
203
|
</h1>
|
|
263
204
|
<p class="body-400 text-center">
|
|
264
|
-
{{
|
|
205
|
+
{{ t('modals.id.login.subtitle') }}
|
|
265
206
|
</p>
|
|
266
207
|
<div class="flex flex-col gap-4">
|
|
267
208
|
<a-input-standard
|
|
268
209
|
v-model="form.username"
|
|
269
210
|
type="email"
|
|
270
|
-
:label="
|
|
211
|
+
:label="t('modals.id.login.labels.email')"
|
|
271
212
|
:error="getError('username')"
|
|
272
213
|
/>
|
|
273
214
|
<a-input-password
|
|
274
215
|
v-model="form.password"
|
|
275
|
-
:label="
|
|
216
|
+
:label="t('modals.id.login.labels.password')"
|
|
276
217
|
:error="getError('password')"
|
|
277
218
|
/>
|
|
278
219
|
<div class="flex items-center justify-between">
|
|
@@ -285,14 +226,14 @@ onBeforeUnmount(() => {
|
|
|
285
226
|
for="remember_me"
|
|
286
227
|
class="cursor-pointer"
|
|
287
228
|
>{{
|
|
288
|
-
|
|
229
|
+
t('modals.id.login.remember_me')
|
|
289
230
|
}}</label>
|
|
290
231
|
</div>
|
|
291
232
|
<button
|
|
292
233
|
class="link-s-400"
|
|
293
234
|
@click="onForgotPassword"
|
|
294
235
|
>
|
|
295
|
-
{{
|
|
236
|
+
{{ t('modals.id.login.forget_password') }}
|
|
296
237
|
</button>
|
|
297
238
|
</div>
|
|
298
239
|
</div>
|
|
@@ -325,10 +266,10 @@ onBeforeUnmount(() => {
|
|
|
325
266
|
type="submit"
|
|
326
267
|
@click="submit"
|
|
327
268
|
>
|
|
328
|
-
{{
|
|
269
|
+
{{ t('actions.login') }}
|
|
329
270
|
</a-button>
|
|
330
271
|
<p class="body-400 text-center">
|
|
331
|
-
{{
|
|
272
|
+
{{ t('modals.id.login.first_time') }}
|
|
332
273
|
</p>
|
|
333
274
|
|
|
334
275
|
<a-button
|
|
@@ -337,7 +278,7 @@ onBeforeUnmount(() => {
|
|
|
337
278
|
class="w-full"
|
|
338
279
|
@click="onRegister"
|
|
339
280
|
>
|
|
340
|
-
{{
|
|
281
|
+
{{ t('actions.register') }}
|
|
341
282
|
</a-button>
|
|
342
283
|
|
|
343
284
|
<a-button
|
|
@@ -346,40 +287,16 @@ onBeforeUnmount(() => {
|
|
|
346
287
|
class="w-full"
|
|
347
288
|
@click="toTariffs"
|
|
348
289
|
>
|
|
349
|
-
{{
|
|
290
|
+
{{ t('actions.toTariffs') }}
|
|
350
291
|
</a-button>
|
|
351
292
|
|
|
352
293
|
<a-alert
|
|
353
294
|
class="max-w-screen-sm !text-[10px]"
|
|
354
295
|
size="xs"
|
|
355
296
|
>
|
|
356
|
-
{{
|
|
297
|
+
{{ t('info.userAgreement') }}
|
|
357
298
|
</a-alert>
|
|
358
299
|
</div>
|
|
359
|
-
|
|
360
|
-
<!-- <a-modal v-model="isResendModal"> -->
|
|
361
|
-
<!-- <resend -->
|
|
362
|
-
<!-- v-if="isResendModal" -->
|
|
363
|
-
<!-- @close="isResendModal = false" -->
|
|
364
|
-
<!-- @resend="onResend" -->
|
|
365
|
-
<!-- /> -->
|
|
366
|
-
<!-- </a-modal> -->
|
|
367
|
-
|
|
368
|
-
<!-- <a-modal v-model="isConfirmationEmailModal"> -->
|
|
369
|
-
<!-- <a-confirmation-email -->
|
|
370
|
-
<!-- v-if="isConfirmationEmailModal" -->
|
|
371
|
-
<!-- @close="isConfirmationEmailModal = false" -->
|
|
372
|
-
<!-- @resend="confirmationEmailResend" -->
|
|
373
|
-
<!-- /> -->
|
|
374
|
-
<!-- </a-modal> -->
|
|
375
|
-
|
|
376
|
-
<two-factor
|
|
377
|
-
v-model="isTwoFactorOpen"
|
|
378
|
-
v-model:error="showOtpError"
|
|
379
|
-
:loading="isLoadingOtp"
|
|
380
|
-
@confirm="handleConfirmOtp"
|
|
381
|
-
@close="isTwoFactorOpen = false"
|
|
382
|
-
/>
|
|
383
300
|
</template>
|
|
384
301
|
|
|
385
302
|
<style scoped></style>
|
|
@@ -7,6 +7,7 @@ import IdPasswordSuccessfulModal from '#adata-ui/components/modals/id/IdPassword
|
|
|
7
7
|
import IdRecoveryModal from '#adata-ui/components/modals/id/IdRecoveryModal.vue'
|
|
8
8
|
import IdRegistrationModal from '#adata-ui/components/modals/id/IdRegistrationModal.vue'
|
|
9
9
|
import IdResetPasswordOtpModal from '#adata-ui/components/modals/id/IdResetPasswordOtpModal.vue'
|
|
10
|
+
import IdTwoFactorModal from '#adata-ui/components/modals/id/IdTwoFactorModal.vue'
|
|
10
11
|
|
|
11
12
|
const {
|
|
12
13
|
loginModal,
|
|
@@ -25,14 +26,17 @@ const {
|
|
|
25
26
|
<a-modal v-model="loginModal">
|
|
26
27
|
<id-login-modal />
|
|
27
28
|
</a-modal>
|
|
29
|
+
<a-modal v-model="twoFactorModal">
|
|
30
|
+
<id-two-factor-modal />
|
|
31
|
+
</a-modal>
|
|
28
32
|
|
|
29
33
|
<a-modal v-model="registrationModal">
|
|
30
34
|
<id-registration-modal v-if="registrationModal" />
|
|
31
35
|
</a-modal>
|
|
32
|
-
<a-modal v-model="confirmAccountOtpModal">
|
|
36
|
+
<a-modal v-model="confirmAccountOtpModal" prevent-close>
|
|
33
37
|
<id-confirm-account-otp-modal v-if="confirmAccountOtpModal" />
|
|
34
38
|
</a-modal>
|
|
35
|
-
<a-modal v-model="confirmSuccessfulModal">
|
|
39
|
+
<a-modal v-model="confirmSuccessfulModal" prevent-close>
|
|
36
40
|
<id-confirm-successful-modal v-if="confirmSuccessfulModal" />
|
|
37
41
|
</a-modal>
|
|
38
42
|
|
|
@@ -21,16 +21,18 @@ const loading = ref(false)
|
|
|
21
21
|
const resetSchema = z.object({
|
|
22
22
|
password: z
|
|
23
23
|
.string()
|
|
24
|
-
.
|
|
25
|
-
.
|
|
24
|
+
.nonempty(t('error.required'))
|
|
25
|
+
.min(8, t('modals.id.register.errors.low_security', { length: 8 }))
|
|
26
|
+
.regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('modals.id.register.errors.low_security')),
|
|
26
27
|
password_confirmation: z
|
|
27
28
|
.string()
|
|
28
|
-
.
|
|
29
|
-
.
|
|
29
|
+
.nonempty(t('error.required'))
|
|
30
|
+
.min(8, t('modals.id.register.errors.low_security', { length: 8 }))
|
|
31
|
+
.regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('modals.id.register.errors.low_security')),
|
|
30
32
|
}).refine(
|
|
31
33
|
data => data.password === data.password_confirmation,
|
|
32
34
|
{
|
|
33
|
-
message: t('register.
|
|
35
|
+
message: t('modals.id.register.errors.sameAs'),
|
|
34
36
|
path: ['password_confirmation'],
|
|
35
37
|
},
|
|
36
38
|
)
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
+
const emit = defineEmits<{
|
|
3
|
+
(e: 'onCompleted', value: string): void
|
|
4
|
+
}>()
|
|
5
|
+
|
|
2
6
|
const length = 6 // Длина OTP
|
|
3
7
|
const showError = defineModel('error')
|
|
4
8
|
const otp = defineModel()
|
|
5
9
|
const otpRefs = ref([])
|
|
6
10
|
const { t } = useI18n()
|
|
7
11
|
|
|
12
|
+
function checkCompletion() {
|
|
13
|
+
if (otp.value.every(val => val !== '')) {
|
|
14
|
+
emit('onCompleted', otp.value.join(''))
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
function onInput(event, index) {
|
|
9
19
|
const value = event.target.value
|
|
10
20
|
showError.value = false
|
|
@@ -16,6 +26,7 @@ function onInput(event, index) {
|
|
|
16
26
|
}
|
|
17
27
|
|
|
18
28
|
otp.value[index] = value
|
|
29
|
+
checkCompletion()
|
|
19
30
|
|
|
20
31
|
// Перемещаем фокус на следующий элемент, если введен символ
|
|
21
32
|
if (value && index < length - 1) {
|
|
@@ -59,6 +70,7 @@ function onPaste(event) {
|
|
|
59
70
|
otp.value[index] = char
|
|
60
71
|
}
|
|
61
72
|
})
|
|
73
|
+
checkCompletion()
|
|
62
74
|
|
|
63
75
|
// Ставим фокус на следующий незаполненный элемент
|
|
64
76
|
const firstEmptyIndex = otp.value.findIndex(val => val === '')
|
|
@@ -113,8 +125,8 @@ function moveFocus(index: number, to: string) {
|
|
|
113
125
|
v-model="otp[index]"
|
|
114
126
|
type="text"
|
|
115
127
|
maxlength="1"
|
|
116
|
-
class="bg-deepblue-900/5
|
|
117
|
-
:class="{ 'border border-[#E74135] dark:border-[#F47E75] dark:bg-[#F47E751A]
|
|
128
|
+
class="size-10 rounded bg-deepblue-900/5 text-center text-lg caret-transparent focus:border focus:border-blue-500 focus:outline-none dark:bg-[#E3E5E80D]"
|
|
129
|
+
:class="{ 'border border-[#E74135] bg-[#E741351A] dark:border-[#F47E75] dark:bg-[#F47E751A]': showError }"
|
|
118
130
|
@input="onInput($event, index)"
|
|
119
131
|
@keydown.backspace="onBackspace(index, $event)"
|
|
120
132
|
@keydown.enter.prevent
|
|
@@ -34,21 +34,21 @@ const agreement = ref(false)
|
|
|
34
34
|
const loading = ref(false)
|
|
35
35
|
|
|
36
36
|
const registerSchema = z.object({
|
|
37
|
-
email: z.string().nonempty(t('
|
|
37
|
+
email: z.string().nonempty(t('error.required')).email(t('error.email')),
|
|
38
38
|
password: z
|
|
39
39
|
.string()
|
|
40
|
-
.nonempty(t('
|
|
41
|
-
.min(8, t('register.
|
|
42
|
-
.regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('register.
|
|
40
|
+
.nonempty(t('error.required'))
|
|
41
|
+
.min(8, t('modals.id.register.errors.low_security', { length: 8 }))
|
|
42
|
+
.regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('modals.id.register.errors.low_security')),
|
|
43
43
|
password_confirmation: z
|
|
44
44
|
.string()
|
|
45
|
-
.nonempty(t('
|
|
46
|
-
.min(8, t('register.
|
|
47
|
-
.regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('register.
|
|
45
|
+
.nonempty(t('error.required'))
|
|
46
|
+
.min(8, t('modals.id.register.errors.low_security', { length: 8 }))
|
|
47
|
+
.regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('modals.id.register.errors.low_security')),
|
|
48
48
|
}).refine(
|
|
49
49
|
data => data.password === data.password_confirmation,
|
|
50
50
|
{
|
|
51
|
-
message: t('register.
|
|
51
|
+
message: t('modals.id.register.errors.sameAs'),
|
|
52
52
|
path: ['password_confirmation'],
|
|
53
53
|
},
|
|
54
54
|
)
|
|
@@ -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
|
}
|
|
@@ -152,31 +153,31 @@ onBeforeUnmount(() => {
|
|
|
152
153
|
@submit.prevent="onSubmit"
|
|
153
154
|
>
|
|
154
155
|
<h2 class="text-center text-2xl font-bold">
|
|
155
|
-
{{ t('register.
|
|
156
|
+
{{ t('modals.id.register.title') }}
|
|
156
157
|
</h2>
|
|
157
158
|
<p class="text-center text-sm">
|
|
158
|
-
{{ t('register.
|
|
159
|
+
{{ t('modals.id.register.subtitle') }}
|
|
159
160
|
</p>
|
|
160
161
|
<a-input-standard
|
|
161
162
|
v-model="form.email"
|
|
162
|
-
:label="t('register.
|
|
163
|
+
:label="t('modals.id.register.labels.email')"
|
|
163
164
|
:error="getError('email')"
|
|
164
165
|
type="email"
|
|
165
166
|
/>
|
|
166
167
|
|
|
167
168
|
<a-input-password
|
|
168
169
|
v-model="form.password"
|
|
169
|
-
:label="t('register.
|
|
170
|
+
:label="t('modals.id.register.labels.password')"
|
|
170
171
|
:error="getError('password')"
|
|
171
172
|
/>
|
|
172
173
|
|
|
173
174
|
<a-input-password
|
|
174
175
|
v-model="form.password_confirmation"
|
|
175
|
-
:label="t('register.
|
|
176
|
+
:label="t('modals.id.register.labels.password_confirmation')"
|
|
176
177
|
:error="getError('password_confirmation')"
|
|
177
178
|
/>
|
|
178
179
|
<a-alert color="blue">
|
|
179
|
-
{{ t('register.
|
|
180
|
+
{{ t('modals.id.register.alert') }}
|
|
180
181
|
<template #icon>
|
|
181
182
|
<a-icon-info-circle />
|
|
182
183
|
</template>
|
|
@@ -185,13 +186,13 @@ onBeforeUnmount(() => {
|
|
|
185
186
|
v-model="agreement"
|
|
186
187
|
side="right"
|
|
187
188
|
>
|
|
188
|
-
<i18n-t keypath="register.
|
|
189
|
+
<i18n-t keypath="modals.id.register.agreement.text">
|
|
189
190
|
<template #link>
|
|
190
191
|
<nuxt-link-locale
|
|
191
192
|
class="text-blue-700"
|
|
192
193
|
@click="getUrl"
|
|
193
194
|
>
|
|
194
|
-
{{ t('register.
|
|
195
|
+
{{ t('modals.id.register.agreement.link') }}
|
|
195
196
|
</nuxt-link-locale>
|
|
196
197
|
</template>
|
|
197
198
|
</i18n-t>
|
|
@@ -200,17 +201,17 @@ onBeforeUnmount(() => {
|
|
|
200
201
|
:disabled="!agreement"
|
|
201
202
|
:loading="loading"
|
|
202
203
|
>
|
|
203
|
-
{{ t('register.
|
|
204
|
+
{{ t('modals.id.register.continue') }}
|
|
204
205
|
</a-button>
|
|
205
206
|
<p class="text-center text-sm">
|
|
206
|
-
{{ t('register.
|
|
207
|
+
{{ t('modals.id.register.haveAcc') }}
|
|
207
208
|
</p>
|
|
208
209
|
<a-button
|
|
209
210
|
type="button"
|
|
210
211
|
view="outline"
|
|
211
212
|
@click="onLogin"
|
|
212
213
|
>
|
|
213
|
-
{{ t('register.
|
|
214
|
+
{{ t('modals.id.register.enter') }}
|
|
214
215
|
</a-button>
|
|
215
216
|
</form>
|
|
216
217
|
</template>
|
|
@@ -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()
|
|
@@ -44,13 +44,22 @@ async function onConfirm() {
|
|
|
44
44
|
}
|
|
45
45
|
catch (error) {
|
|
46
46
|
showError.value = true
|
|
47
|
-
$toast.error(error.data.message)
|
|
48
47
|
}
|
|
49
48
|
finally {
|
|
50
49
|
isLoading.value = false
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
|
|
53
|
+
function resetOtp() {
|
|
54
|
+
otp.value = ['', '', '', '', '', '']
|
|
55
|
+
showError.value = false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function onClose() {
|
|
59
|
+
resetOtp()
|
|
60
|
+
resetPasswordOtpModal.value = false
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
async function onResend() {
|
|
55
64
|
try {
|
|
56
65
|
await $fetch(`${authApiURL}/password/email-otp`, {
|
|
@@ -63,6 +72,7 @@ async function onResend() {
|
|
|
63
72
|
email: intermediateState.value.email,
|
|
64
73
|
},
|
|
65
74
|
})
|
|
75
|
+
resetOtp()
|
|
66
76
|
runTimer()
|
|
67
77
|
}
|
|
68
78
|
catch (error) {
|
|
@@ -70,12 +80,6 @@ async function onResend() {
|
|
|
70
80
|
}
|
|
71
81
|
}
|
|
72
82
|
|
|
73
|
-
function onClose() {
|
|
74
|
-
otp.value = ['', '', '', '', '', '']
|
|
75
|
-
showError.value = false
|
|
76
|
-
resetPasswordOtpModal.value = false
|
|
77
|
-
}
|
|
78
|
-
|
|
79
83
|
function handleEnter(e: KeyboardEvent) {
|
|
80
84
|
if (e.key === 'Enter') {
|
|
81
85
|
onConfirm()
|
|
@@ -85,6 +89,7 @@ function handleEnter(e: KeyboardEvent) {
|
|
|
85
89
|
const timer = ref(60)
|
|
86
90
|
|
|
87
91
|
function runTimer() {
|
|
92
|
+
timer.value = 60
|
|
88
93
|
const intervalId = setInterval(() => {
|
|
89
94
|
if (!timer.value) clearInterval(intervalId)
|
|
90
95
|
return timer.value--
|
|
@@ -116,7 +121,7 @@ onBeforeUnmount(() => {
|
|
|
116
121
|
</p>
|
|
117
122
|
|
|
118
123
|
<div v-if="timer > 0" class="text-2xl font-bold">
|
|
119
|
-
{{ timer }} {{ t('
|
|
124
|
+
{{ timer }} {{ t('modals.id.resetPasswordOtp.seconds') }}
|
|
120
125
|
</div>
|
|
121
126
|
<button
|
|
122
127
|
v-else
|
|
@@ -127,25 +132,19 @@ onBeforeUnmount(() => {
|
|
|
127
132
|
</button>
|
|
128
133
|
</div>
|
|
129
134
|
|
|
130
|
-
<otp-input
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
:disabled="otpFormatted.length < 6"
|
|
144
|
-
@click="onConfirm"
|
|
145
|
-
>
|
|
146
|
-
{{ t('actions.confirm') }}
|
|
147
|
-
</a-button>
|
|
148
|
-
</div>
|
|
135
|
+
<id-otp-input
|
|
136
|
+
v-model="otp"
|
|
137
|
+
v-model:error="showError"
|
|
138
|
+
@on-completed="onConfirm"
|
|
139
|
+
/>
|
|
140
|
+
|
|
141
|
+
<a-button
|
|
142
|
+
block
|
|
143
|
+
view="outline"
|
|
144
|
+
@click="onClose"
|
|
145
|
+
>
|
|
146
|
+
{{ t('actions.close') }}
|
|
147
|
+
</a-button>
|
|
149
148
|
</div>
|
|
150
149
|
</template>
|
|
151
150
|
|