adata-ui 2.0.23 → 2.0.25
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/curve-block/ACurveBlock.vue +3 -6
- package/components/elements/select/ASelect.vue +50 -5
- package/components/modals/id/IdConfirmAccountOtpModal.vue +147 -0
- package/components/modals/id/IdConfirmSuccessfulModal.vue +25 -0
- package/components/modals/id/IdLoginModal.vue +150 -131
- package/components/modals/id/IdModals.vue +41 -7
- package/components/modals/id/IdNewPasswordModal.vue +55 -62
- package/components/modals/id/IdPasswordSuccessfulModal.vue +15 -16
- package/components/modals/id/IdRecoveryModal.vue +39 -34
- package/components/modals/id/IdRegistrationModal.vue +75 -103
- package/components/modals/id/IdResetPasswordOtpModal.vue +154 -0
- package/components/modals/two-factor/otp-input.vue +1 -1
- package/components/navigation/footer/NewFooter.vue +3 -2
- package/components/navigation/header/AlmatyContacts.vue +3 -1
- package/components/navigation/header/AstanaContacts.vue +3 -1
- package/composables/useIdModals.ts +10 -2
- package/lang/ru.ts +16 -5
- package/nuxt.config.ts +1 -0
- package/package.json +4 -1
- package/stores/auth.store.ts +12 -0
- package/components/modals/Accept.vue +0 -45
- package/components/modals/id/IdEmailModal.vue +0 -29
|
@@ -13,12 +13,11 @@ const props = defineProps<{
|
|
|
13
13
|
<component
|
|
14
14
|
:is="to ? NuxtLinkLocale : 'button'"
|
|
15
15
|
:to="to"
|
|
16
|
-
class="curve-block relative w-
|
|
16
|
+
class="curve-block relative w-full cursor-pointer"
|
|
17
17
|
active-class="active-item"
|
|
18
18
|
>
|
|
19
19
|
<svg
|
|
20
|
-
|
|
21
|
-
height="182"
|
|
20
|
+
class="w-full"
|
|
22
21
|
viewBox="-1 -1 308 184"
|
|
23
22
|
xmlns="http://www.w3.org/2000/svg"
|
|
24
23
|
>
|
|
@@ -79,9 +78,7 @@ const props = defineProps<{
|
|
|
79
78
|
</div>
|
|
80
79
|
|
|
81
80
|
<svg
|
|
82
|
-
class="absolute bottom-0 right-0"
|
|
83
|
-
width="48"
|
|
84
|
-
height="48"
|
|
81
|
+
class="absolute bottom-0 right-0 size-12 2xl:size-14"
|
|
85
82
|
viewBox="0 0 48 48"
|
|
86
83
|
xmlns="http://www.w3.org/2000/svg"
|
|
87
84
|
>
|
|
@@ -6,6 +6,8 @@ import { onClickOutside, useToggle } from '@vueuse/core'
|
|
|
6
6
|
import { isEqual } from 'lodash-es'
|
|
7
7
|
import type { Ref } from 'vue'
|
|
8
8
|
|
|
9
|
+
import { useFloating, offset, flip, shift, size as floatingSize, autoUpdate } from '@floating-ui/vue'
|
|
10
|
+
|
|
9
11
|
type Props = {
|
|
10
12
|
label: string
|
|
11
13
|
required?: boolean
|
|
@@ -61,6 +63,32 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
61
63
|
|
|
62
64
|
const emits = defineEmits<Emits>()
|
|
63
65
|
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
const reference = ref<HTMLElement | null>(null)
|
|
69
|
+
const floating = ref<HTMLElement | null>(null)
|
|
70
|
+
const { x, y, strategy, update } = useFloating(reference, floating, {
|
|
71
|
+
placement: 'bottom-start',
|
|
72
|
+
strategy: 'absolute',
|
|
73
|
+
middleware: [
|
|
74
|
+
offset(6),
|
|
75
|
+
flip({ fallbackPlacements: ['top-start'] }),
|
|
76
|
+
shift({ padding: 8 }),
|
|
77
|
+
floatingSize({
|
|
78
|
+
apply({ availableHeight, elements, rects }) {
|
|
79
|
+
const el = elements.floating as HTMLElement
|
|
80
|
+
el.style.width = `${rects.reference.width}px`
|
|
81
|
+
el.style.maxHeight = `${Math.max(140, Math.min(availableHeight, 320))}px`
|
|
82
|
+
el.style.overflowY = 'auto'
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
],
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
let cleanup: (() => void) | null = null
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
64
92
|
const modelValue = defineModel<T | T[] | null | any>({ required: true })
|
|
65
93
|
const search = defineModel<T | null | any>('search')
|
|
66
94
|
const isOpen = defineModel<T | null | any>('open', {
|
|
@@ -235,10 +263,21 @@ onUpdated(() => (countedVisibleItems.value = countOfVisibleItems.value))
|
|
|
235
263
|
defineExpose({
|
|
236
264
|
onClear
|
|
237
265
|
})
|
|
266
|
+
watch(() => isOpen.value, (open) => {
|
|
267
|
+
if (open && reference.value && floating.value) {
|
|
268
|
+
cleanup = autoUpdate(reference.value, floating.value, update)
|
|
269
|
+
} else {
|
|
270
|
+
cleanup?.()
|
|
271
|
+
cleanup = null
|
|
272
|
+
}
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
onUnmounted(() => cleanup?.())
|
|
238
276
|
</script>
|
|
239
277
|
<template>
|
|
240
278
|
<div ref="wrapper" class="relative w-full rounded-md text-sm">
|
|
241
279
|
<button
|
|
280
|
+
ref="reference"
|
|
242
281
|
:class="[
|
|
243
282
|
clearable ? 'pr-16' : 'pr-9',
|
|
244
283
|
{
|
|
@@ -262,7 +301,7 @@ defineExpose({
|
|
|
262
301
|
</span>
|
|
263
302
|
<component :is="startIcon" v-if="startIcon" />
|
|
264
303
|
|
|
265
|
-
<span :class="{ 'py-1': size === 'md' }" class="w-full text-start">
|
|
304
|
+
<span :class="{ 'py-1': size === 'md' }" class=" w-full text-start">
|
|
266
305
|
<span v-if="valueToShow">
|
|
267
306
|
<span v-if="!multiple" class="line-clamp-1 text-deepblue-900 dark:text-gray-200">
|
|
268
307
|
<slot name="single-selected" :value="valueToShow">{{ valueToShow[keyToShow] }}</slot>
|
|
@@ -310,10 +349,16 @@ defineExpose({
|
|
|
310
349
|
</span>
|
|
311
350
|
</button>
|
|
312
351
|
<transition>
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
352
|
+
<div
|
|
353
|
+
v-if="isOpen"
|
|
354
|
+
ref="floating"
|
|
355
|
+
class="z-[10000] rounded-md bg-white shadow-[0_1px_8px_0_rgba(139,146,156,0.3)] dark:bg-gray-900"
|
|
356
|
+
:style="{
|
|
357
|
+
position: strategy,
|
|
358
|
+
left: x != null ? `${x}px` : '',
|
|
359
|
+
top: y != null ? `${y}px` : '',
|
|
360
|
+
}"
|
|
361
|
+
>
|
|
317
362
|
<slot :options="options" name="options">
|
|
318
363
|
<ul class="select m-2 max-h-[250px] overflow-y-auto overflow-x-hidden">
|
|
319
364
|
<li v-if="searchFromOut" class="p-1">
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import OtpInput from '#adata-ui/components/modals/two-factor/otp-input.vue'
|
|
3
|
+
import { useAuthStore } from '#adata-ui/stores/auth.store'
|
|
4
|
+
|
|
5
|
+
const { $toast } = useNuxtApp()
|
|
6
|
+
const { t, locale } = useI18n()
|
|
7
|
+
const { commonAuth } = useAppConfig()
|
|
8
|
+
|
|
9
|
+
const authStore = useAuthStore()
|
|
10
|
+
const { intermediateState } = storeToRefs(authStore)
|
|
11
|
+
|
|
12
|
+
const { confirmAccountOtpModal, confirmSuccessfulModal } = useIdModals()
|
|
13
|
+
|
|
14
|
+
const authApiURL = commonAuth.authApiURL
|
|
15
|
+
|
|
16
|
+
const otp = ref(['', '', '', '', '', ''])
|
|
17
|
+
const otpFormatted = computed(() => {
|
|
18
|
+
return otp.value.join('')
|
|
19
|
+
})
|
|
20
|
+
const showError = ref(false)
|
|
21
|
+
const isLoading = ref(false)
|
|
22
|
+
|
|
23
|
+
async function onResend() {
|
|
24
|
+
try {
|
|
25
|
+
await $fetch(`${authApiURL}/email/resend-otp`, {
|
|
26
|
+
method: 'GET',
|
|
27
|
+
credentials: 'include',
|
|
28
|
+
headers: {
|
|
29
|
+
lang: locale.value,
|
|
30
|
+
},
|
|
31
|
+
body: {
|
|
32
|
+
email: intermediateState.value.email,
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
runTimer()
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
$toast.error(error.data)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function onConfirm() {
|
|
43
|
+
try {
|
|
44
|
+
isLoading.value = true
|
|
45
|
+
|
|
46
|
+
await $fetch(`${authApiURL}/email/verify-otp`, {
|
|
47
|
+
method: 'GET',
|
|
48
|
+
credentials: 'include',
|
|
49
|
+
headers: {
|
|
50
|
+
lang: locale.value,
|
|
51
|
+
},
|
|
52
|
+
params: {
|
|
53
|
+
email: intermediateState.value.email,
|
|
54
|
+
otp_code: otpFormatted.value,
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
confirmAccountOtpModal.value = false
|
|
59
|
+
confirmSuccessfulModal.value = true
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
showError.value = true
|
|
63
|
+
$toast.error(error.data.message)
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
isLoading.value = false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function onClose() {
|
|
71
|
+
otp.value = ['', '', '', '', '', '']
|
|
72
|
+
showError.value = false
|
|
73
|
+
confirmAccountOtpModal.value = false
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const timer = ref(60)
|
|
77
|
+
|
|
78
|
+
function runTimer() {
|
|
79
|
+
const intervalId = setInterval(() => {
|
|
80
|
+
if (!timer.value) clearInterval(intervalId)
|
|
81
|
+
return timer.value--
|
|
82
|
+
}, 1000)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function handleEnter(e: KeyboardEvent) {
|
|
86
|
+
if (e.key === 'Enter') {
|
|
87
|
+
onConfirm()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
onMounted(() => {
|
|
92
|
+
runTimer()
|
|
93
|
+
document.addEventListener('keyup', handleEnter)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
onBeforeUnmount(() => {
|
|
97
|
+
document.removeEventListener('keyup', handleEnter)
|
|
98
|
+
})
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<template>
|
|
102
|
+
<div class="flex flex-col items-center gap-4 text-center">
|
|
103
|
+
<h2 class="text-2xl font-bold">
|
|
104
|
+
{{ t('register.modal.title') }}
|
|
105
|
+
</h2>
|
|
106
|
+
|
|
107
|
+
<a-icon-hand-with-phone-light class="size-32 dark:hidden" />
|
|
108
|
+
<a-icon-hand-with-phone-dark class="hidden size-32 dark:block" />
|
|
109
|
+
|
|
110
|
+
<div class="text-sm">
|
|
111
|
+
<p class="mb-1">
|
|
112
|
+
{{ t('modals.id.resetPasswordOtp.content') }}
|
|
113
|
+
</p>
|
|
114
|
+
|
|
115
|
+
<div v-if="timer > 0" class="text-2xl font-bold">
|
|
116
|
+
{{ timer }} {{ t('register.modal.seconds') }}
|
|
117
|
+
</div>
|
|
118
|
+
<button
|
|
119
|
+
v-else
|
|
120
|
+
class="text-blue-700 dark:text-blue-500"
|
|
121
|
+
@click="onResend"
|
|
122
|
+
>
|
|
123
|
+
{{ t('actions.resend') }}
|
|
124
|
+
</button>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<otp-input v-model="otp" v-model:error="showError" />
|
|
128
|
+
|
|
129
|
+
<div class="flex w-full gap-2">
|
|
130
|
+
<a-button
|
|
131
|
+
block
|
|
132
|
+
view="outline"
|
|
133
|
+
@click="onClose"
|
|
134
|
+
>
|
|
135
|
+
{{ t('actions.close') }}
|
|
136
|
+
</a-button>
|
|
137
|
+
<a-button
|
|
138
|
+
block
|
|
139
|
+
:loading="isLoading"
|
|
140
|
+
:disabled="otpFormatted.length < 6"
|
|
141
|
+
@click="onConfirm"
|
|
142
|
+
>
|
|
143
|
+
{{ t('actions.confirm') }}
|
|
144
|
+
</a-button>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</template>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const { confirmSuccessfulModal } = useIdModals()
|
|
3
|
+
const { t } = useI18n()
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<div class="flex flex-col gap-4 text-center">
|
|
8
|
+
<h2 class="text-2xl font-bold">
|
|
9
|
+
{{ t('modals.id.confirmSuccessful.title') }}
|
|
10
|
+
</h2>
|
|
11
|
+
<span class="mx-auto size-[100px] rounded-full bg-[#BDC7CE26]">
|
|
12
|
+
<a-ill-ok />
|
|
13
|
+
</span>
|
|
14
|
+
<p class="text-sm">
|
|
15
|
+
{{ t('modals.id.confirmSuccessful.content') }}
|
|
16
|
+
</p>
|
|
17
|
+
<a-button view="outline" @click="confirmSuccessfulModal = false">
|
|
18
|
+
{{ t('actions.close') }}
|
|
19
|
+
</a-button>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<style scoped>
|
|
24
|
+
|
|
25
|
+
</style>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import AConfirmationEmail from '#adata-ui/components/modals/AConfirmationEmail.vue'
|
|
3
|
-
import Resend from '#adata-ui/components/modals/Resend.vue'
|
|
4
2
|
import TwoFactor from '#adata-ui/components/modals/two-factor/two-factor.vue'
|
|
3
|
+
import { useAuthStore } from '#adata-ui/stores/auth.store'
|
|
5
4
|
import { navigateToLocalizedPage } from '#adata-ui/utils/localizedNavigation'
|
|
6
5
|
import { useToggle } from '@vueuse/shared'
|
|
7
6
|
import * as z from 'zod'
|
|
@@ -13,13 +12,14 @@ const isConfirmationEmailModal = ref(false)
|
|
|
13
12
|
const isTwoFactorOpen = ref(false)
|
|
14
13
|
const isLoadingOtp = ref(false)
|
|
15
14
|
const { $api, $toast } = useNuxtApp()
|
|
16
|
-
const localePath = useLocalePath()
|
|
17
15
|
const showOtpError = ref(false)
|
|
18
16
|
const { t, locale } = useI18n()
|
|
19
|
-
const route = useRoute()
|
|
20
17
|
const submitted = ref(false)
|
|
21
18
|
const accessToken = ref(null)
|
|
22
|
-
const { loginModal, registrationModal, recoveryModal } = useIdModals()
|
|
19
|
+
const { loginModal, registrationModal, recoveryModal, confirmAccountOtpModal } = useIdModals()
|
|
20
|
+
|
|
21
|
+
const authStore = useAuthStore()
|
|
22
|
+
const { intermediateState } = storeToRefs(authStore)
|
|
23
23
|
|
|
24
24
|
export interface ILoginForm {
|
|
25
25
|
username: string
|
|
@@ -84,7 +84,22 @@ async function submit() {
|
|
|
84
84
|
$toast.error(t('error.validation'))
|
|
85
85
|
}
|
|
86
86
|
else {
|
|
87
|
-
|
|
87
|
+
intermediateState.value.email = form.username
|
|
88
|
+
intermediateState.value.password = form.password
|
|
89
|
+
|
|
90
|
+
await fetch(`${authApiURL}/email/resend-otp`, {
|
|
91
|
+
method: 'GET',
|
|
92
|
+
credentials: 'include',
|
|
93
|
+
headers: {
|
|
94
|
+
'Content-Type': 'application/json',
|
|
95
|
+
'lang': locale.value,
|
|
96
|
+
},
|
|
97
|
+
body: JSON.stringify({
|
|
98
|
+
email: intermediateState.value.email,
|
|
99
|
+
}),
|
|
100
|
+
}).catch(() => {})
|
|
101
|
+
|
|
102
|
+
confirmAccountOtpModal.value = true
|
|
88
103
|
}
|
|
89
104
|
}
|
|
90
105
|
else {
|
|
@@ -112,7 +127,20 @@ async function submit() {
|
|
|
112
127
|
window.location.reload()
|
|
113
128
|
}
|
|
114
129
|
else {
|
|
115
|
-
|
|
130
|
+
intermediateState.value.email = form.username
|
|
131
|
+
intermediateState.value.password = form.password
|
|
132
|
+
confirmAccountOtpModal.value = true
|
|
133
|
+
|
|
134
|
+
$fetch(`${authApiURL}/email/resend-otp`, {
|
|
135
|
+
method: 'GET',
|
|
136
|
+
credentials: 'include',
|
|
137
|
+
headers: {
|
|
138
|
+
lang: locale.value,
|
|
139
|
+
},
|
|
140
|
+
body: {
|
|
141
|
+
email: intermediateState.value.email,
|
|
142
|
+
},
|
|
143
|
+
}).catch(() => {})
|
|
116
144
|
}
|
|
117
145
|
}
|
|
118
146
|
loading.value = false
|
|
@@ -165,8 +193,8 @@ async function handleConfirmOtp(otpCode: string) {
|
|
|
165
193
|
'lang': locale.value,
|
|
166
194
|
},
|
|
167
195
|
body: JSON.stringify({
|
|
168
|
-
'username':
|
|
169
|
-
'password':
|
|
196
|
+
'username': intermediateState.value.email.trim(),
|
|
197
|
+
'password': intermediateState.value.password.toString(),
|
|
170
198
|
'2fa_code': otpCode,
|
|
171
199
|
}),
|
|
172
200
|
})
|
|
@@ -195,6 +223,7 @@ async function handleConfirmOtp(otpCode: string) {
|
|
|
195
223
|
}
|
|
196
224
|
$toast.success(t('login.successfully'))
|
|
197
225
|
loginModal.value = false
|
|
226
|
+
window.location.reload()
|
|
198
227
|
|
|
199
228
|
isTwoFactorOpen.value = false
|
|
200
229
|
}
|
|
@@ -217,14 +246,6 @@ function onForgotPassword() {
|
|
|
217
246
|
recoveryModal.value = true
|
|
218
247
|
}
|
|
219
248
|
|
|
220
|
-
watch(loginModal, (value) => {
|
|
221
|
-
if (!value) {
|
|
222
|
-
form.username = ''
|
|
223
|
-
form.password = ''
|
|
224
|
-
rememberMe.value = false
|
|
225
|
-
}
|
|
226
|
-
})
|
|
227
|
-
|
|
228
249
|
onMounted(() => {
|
|
229
250
|
document.addEventListener('keyup', handleEnter)
|
|
230
251
|
})
|
|
@@ -235,124 +256,122 @@ onBeforeUnmount(() => {
|
|
|
235
256
|
</script>
|
|
236
257
|
|
|
237
258
|
<template>
|
|
238
|
-
<
|
|
239
|
-
<
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
<
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
<div class="flex
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
for="remember_me"
|
|
266
|
-
class="cursor-pointer"
|
|
267
|
-
>{{
|
|
268
|
-
$t('login.form.remember_me')
|
|
269
|
-
}}</label>
|
|
270
|
-
</div>
|
|
271
|
-
<button
|
|
272
|
-
class="link-s-400"
|
|
273
|
-
@click="onForgotPassword"
|
|
274
|
-
>
|
|
275
|
-
{{ $t('login.form.forget_password') }}
|
|
276
|
-
</button>
|
|
277
|
-
</div>
|
|
278
|
-
</div>
|
|
279
|
-
<div class="flex items-center gap-4">
|
|
280
|
-
<div class="h-px w-full bg-deepblue-500/30" />
|
|
281
|
-
<div class="flex shrink-0 gap-4">
|
|
282
|
-
<span
|
|
283
|
-
class="cursor-pointer"
|
|
284
|
-
@click="authWithSocial('google')"
|
|
285
|
-
>
|
|
286
|
-
<a-icon-google />
|
|
287
|
-
</span>
|
|
288
|
-
<span
|
|
289
|
-
class="cursor-pointer"
|
|
290
|
-
@click="authWithSocial('yandex')"
|
|
291
|
-
>
|
|
292
|
-
<a-icon-yandex />
|
|
293
|
-
</span>
|
|
294
|
-
<span
|
|
259
|
+
<div class="flex flex-col gap-5">
|
|
260
|
+
<h1 class="heading-02 text-center">
|
|
261
|
+
{{ $t('login.form.title') }}
|
|
262
|
+
</h1>
|
|
263
|
+
<p class="body-400 text-center">
|
|
264
|
+
{{ $t('login.form.subtitle') }}
|
|
265
|
+
</p>
|
|
266
|
+
<div class="flex flex-col gap-4">
|
|
267
|
+
<a-input-standard
|
|
268
|
+
v-model="form.username"
|
|
269
|
+
type="email"
|
|
270
|
+
:label="$t('login.form.labels.email')"
|
|
271
|
+
:error="getError('username')"
|
|
272
|
+
/>
|
|
273
|
+
<a-input-password
|
|
274
|
+
v-model="form.password"
|
|
275
|
+
:label="$t('login.form.labels.password')"
|
|
276
|
+
:error="getError('password')"
|
|
277
|
+
/>
|
|
278
|
+
<div class="flex items-center justify-between">
|
|
279
|
+
<div class="body-400 flex gap-2">
|
|
280
|
+
<a-checkbox
|
|
281
|
+
v-model="rememberMe"
|
|
282
|
+
name="remember_me"
|
|
283
|
+
/>
|
|
284
|
+
<label
|
|
285
|
+
for="remember_me"
|
|
295
286
|
class="cursor-pointer"
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
</span>
|
|
287
|
+
>{{
|
|
288
|
+
$t('login.form.remember_me')
|
|
289
|
+
}}</label>
|
|
300
290
|
</div>
|
|
301
|
-
<
|
|
291
|
+
<button
|
|
292
|
+
class="link-s-400"
|
|
293
|
+
@click="onForgotPassword"
|
|
294
|
+
>
|
|
295
|
+
{{ $t('login.form.forget_password') }}
|
|
296
|
+
</button>
|
|
302
297
|
</div>
|
|
303
|
-
<a-button
|
|
304
|
-
:loading="loading"
|
|
305
|
-
type="submit"
|
|
306
|
-
@click="submit"
|
|
307
|
-
>
|
|
308
|
-
{{ $t('actions.login') }}
|
|
309
|
-
</a-button>
|
|
310
|
-
<p class="body-400 text-center">
|
|
311
|
-
{{ $t('login.form.first_time') }}
|
|
312
|
-
</p>
|
|
313
|
-
|
|
314
|
-
<a-button
|
|
315
|
-
type="button"
|
|
316
|
-
view="outline"
|
|
317
|
-
class="w-full"
|
|
318
|
-
@click="onRegister"
|
|
319
|
-
>
|
|
320
|
-
{{ $t('actions.register') }}
|
|
321
|
-
</a-button>
|
|
322
|
-
|
|
323
|
-
<a-button
|
|
324
|
-
type="button"
|
|
325
|
-
view="transparent"
|
|
326
|
-
class="w-full"
|
|
327
|
-
@click="toTariffs"
|
|
328
|
-
>
|
|
329
|
-
{{ $t('actions.toTariffs') }}
|
|
330
|
-
</a-button>
|
|
331
|
-
|
|
332
|
-
<a-alert
|
|
333
|
-
class="max-w-screen-sm !text-[10px]"
|
|
334
|
-
size="xs"
|
|
335
|
-
>
|
|
336
|
-
{{ $t('info.userAgreement') }}
|
|
337
|
-
</a-alert>
|
|
338
298
|
</div>
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
299
|
+
<div class="flex items-center gap-4">
|
|
300
|
+
<div class="h-px w-full bg-deepblue-500/30" />
|
|
301
|
+
<div class="flex shrink-0 gap-4">
|
|
302
|
+
<span
|
|
303
|
+
class="cursor-pointer"
|
|
304
|
+
@click="authWithSocial('google')"
|
|
305
|
+
>
|
|
306
|
+
<a-icon-google />
|
|
307
|
+
</span>
|
|
308
|
+
<span
|
|
309
|
+
class="cursor-pointer"
|
|
310
|
+
@click="authWithSocial('yandex')"
|
|
311
|
+
>
|
|
312
|
+
<a-icon-yandex />
|
|
313
|
+
</span>
|
|
314
|
+
<span
|
|
315
|
+
class="cursor-pointer"
|
|
316
|
+
@click="authWithSocial('mailru')"
|
|
317
|
+
>
|
|
318
|
+
<a-icon-mailru />
|
|
319
|
+
</span>
|
|
320
|
+
</div>
|
|
321
|
+
<div class="h-px w-full bg-deepblue-500/30" />
|
|
322
|
+
</div>
|
|
323
|
+
<a-button
|
|
324
|
+
:loading="loading"
|
|
325
|
+
type="submit"
|
|
326
|
+
@click="submit"
|
|
327
|
+
>
|
|
328
|
+
{{ $t('actions.login') }}
|
|
329
|
+
</a-button>
|
|
330
|
+
<p class="body-400 text-center">
|
|
331
|
+
{{ $t('login.form.first_time') }}
|
|
332
|
+
</p>
|
|
333
|
+
|
|
334
|
+
<a-button
|
|
335
|
+
type="button"
|
|
336
|
+
view="outline"
|
|
337
|
+
class="w-full"
|
|
338
|
+
@click="onRegister"
|
|
339
|
+
>
|
|
340
|
+
{{ $t('actions.register') }}
|
|
341
|
+
</a-button>
|
|
342
|
+
|
|
343
|
+
<a-button
|
|
344
|
+
type="button"
|
|
345
|
+
view="transparent"
|
|
346
|
+
class="w-full"
|
|
347
|
+
@click="toTariffs"
|
|
348
|
+
>
|
|
349
|
+
{{ $t('actions.toTariffs') }}
|
|
350
|
+
</a-button>
|
|
351
|
+
|
|
352
|
+
<a-alert
|
|
353
|
+
class="max-w-screen-sm !text-[10px]"
|
|
354
|
+
size="xs"
|
|
355
|
+
>
|
|
356
|
+
{{ $t('info.userAgreement') }}
|
|
357
|
+
</a-alert>
|
|
358
|
+
</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> -->
|
|
356
375
|
|
|
357
376
|
<two-factor
|
|
358
377
|
v-model="isTwoFactorOpen"
|