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.
@@ -0,0 +1,154 @@
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 { resetPasswordOtpModal, newPasswordModal } = 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 onConfirm() {
24
+ try {
25
+ isLoading.value = true
26
+
27
+ const response = await $fetch(`${authApiURL}/password/validate-otp`, {
28
+ method: 'POST',
29
+ credentials: 'include',
30
+ headers: {
31
+ lang: locale.value,
32
+ },
33
+ body: {
34
+ email: intermediateState.value.email,
35
+ otp: otpFormatted.value,
36
+ },
37
+ })
38
+
39
+ intermediateState.value.token = response.data
40
+ intermediateState.value.otp = otpFormatted.value
41
+
42
+ resetPasswordOtpModal.value = false
43
+ newPasswordModal.value = true
44
+ }
45
+ catch (error) {
46
+ showError.value = true
47
+ $toast.error(error.data.message)
48
+ }
49
+ finally {
50
+ isLoading.value = false
51
+ }
52
+ }
53
+
54
+ async function onResend() {
55
+ try {
56
+ await $fetch(`${authApiURL}/password/email-otp`, {
57
+ method: 'POST',
58
+ credentials: 'include',
59
+ headers: {
60
+ lang: locale.value,
61
+ },
62
+ body: {
63
+ email: intermediateState.value.email,
64
+ },
65
+ })
66
+ runTimer()
67
+ }
68
+ catch (error) {
69
+ $toast.error(error.data.message)
70
+ }
71
+ }
72
+
73
+ function onClose() {
74
+ otp.value = ['', '', '', '', '', '']
75
+ showError.value = false
76
+ resetPasswordOtpModal.value = false
77
+ }
78
+
79
+ function handleEnter(e: KeyboardEvent) {
80
+ if (e.key === 'Enter') {
81
+ onConfirm()
82
+ }
83
+ }
84
+
85
+ const timer = ref(60)
86
+
87
+ function runTimer() {
88
+ const intervalId = setInterval(() => {
89
+ if (!timer.value) clearInterval(intervalId)
90
+ return timer.value--
91
+ }, 1000)
92
+ }
93
+
94
+ onMounted(() => {
95
+ runTimer()
96
+ document.addEventListener('keyup', handleEnter)
97
+ })
98
+
99
+ onBeforeUnmount(() => {
100
+ document.removeEventListener('keyup', handleEnter)
101
+ })
102
+ </script>
103
+
104
+ <template>
105
+ <div class="flex flex-col items-center gap-4 text-center">
106
+ <h2 class="text-2xl font-bold">
107
+ {{ t('modals.id.resetPasswordOtp.title') }}
108
+ </h2>
109
+
110
+ <a-icon-hand-with-phone-light class="size-32 dark:hidden" />
111
+ <a-icon-hand-with-phone-dark class="hidden size-32 dark:block" />
112
+
113
+ <div class="text-sm">
114
+ <p class="mb-1">
115
+ {{ t('modals.id.resetPasswordOtp.content') }}
116
+ </p>
117
+
118
+ <div v-if="timer > 0" class="text-2xl font-bold">
119
+ {{ timer }} {{ t('register.modal.seconds') }}
120
+ </div>
121
+ <button
122
+ v-else
123
+ class="text-blue-700 dark:text-blue-500"
124
+ @click="onResend"
125
+ >
126
+ {{ t('actions.resend') }}
127
+ </button>
128
+ </div>
129
+
130
+ <otp-input v-model="otp" v-model:error="showError" />
131
+
132
+ <div class="flex w-full gap-2">
133
+ <a-button
134
+ block
135
+ view="outline"
136
+ @click="onClose"
137
+ >
138
+ {{ t('actions.close') }}
139
+ </a-button>
140
+ <a-button
141
+ block
142
+ :loading="isLoading"
143
+ :disabled="otpFormatted.length < 6"
144
+ @click="onConfirm"
145
+ >
146
+ {{ t('actions.confirm') }}
147
+ </a-button>
148
+ </div>
149
+ </div>
150
+ </template>
151
+
152
+ <style scoped>
153
+
154
+ </style>
@@ -131,7 +131,7 @@ function moveFocus(index: number, to: string) {
131
131
  size="sm"
132
132
  icon-type="triangle"
133
133
  >
134
- {{ t('twoFactor.error') }}
134
+ {{ t('error.otp') }}
135
135
  </a-alert>
136
136
  </div>
137
137
  </template>
@@ -212,8 +212,8 @@ const contactLinks = {
212
212
  />
213
213
  </div>
214
214
  </div>
215
-
216
- <div class="flex flex-col gap-2 items-start">
215
+ <!--noindex-->
216
+ <div class="flex flex-col gap-2 items-start" data-nosnippet>
217
217
  <nuxt-link
218
218
  class="text-sm font-semibold pb-3 pr-4 border-b-[0.5px] border-white cursor-pointer"
219
219
  :to="contactLinks.link?.replace(/\/$/, '')"
@@ -249,6 +249,7 @@ const contactLinks = {
249
249
  </div>
250
250
  </div>
251
251
  </div>
252
+ <!--/noindex-->
252
253
  </div>
253
254
 
254
255
  <div class="lg:hidden flex gap-8 flex-wrap">
@@ -1,5 +1,6 @@
1
1
  <template>
2
- <div class="h-[272px]">
2
+ <!--noindex-->
3
+ <div class="h-[272px]" data-nosnippet>
3
4
  <h2 class="heading-02 mb-4">
4
5
  {{ t('header.contacts.almaty.title') }}
5
6
  </h2>
@@ -89,6 +90,7 @@
89
90
  <!-- </div>-->
90
91
  </div>
91
92
  </div>
93
+ <!--/noindex-->
92
94
  </template>
93
95
 
94
96
  <script setup lang="ts">
@@ -1,5 +1,6 @@
1
1
  <template>
2
- <div class="h-[272px]">
2
+ <!--noindex-->
3
+ <div class="h-[272px]" data-nosnippet>
3
4
  <h2 class="heading-02 mb-4">
4
5
  {{ t('header.contacts.astana.title') }}
5
6
  </h2>
@@ -23,6 +24,7 @@
23
24
  </div>
24
25
  </div>
25
26
  </div>
27
+ <!--/noindex-->
26
28
  </template>
27
29
 
28
30
  <script setup lang="ts">
@@ -1,17 +1,25 @@
1
1
  export function useIdModals() {
2
2
  const loginModal = useState('login-modal', () => false)
3
+ const twoFactorModal = useState('two-factor-modal', () => false)
4
+
3
5
  const registrationModal = useState('registration-modal', () => false)
6
+ const confirmAccountOtpModal = useState('confirm-account-otp-modal', () => false)
7
+ const confirmSuccessfulModal = useState('confirm-successful-modal', () => false)
8
+
4
9
  const recoveryModal = useState('recovery-modal', () => false)
5
- const emailModal = useState('email-modal', () => false)
10
+ const resetPasswordOtpModal = useState('reset-password-otp-modal', () => false)
6
11
  const newPasswordModal = useState('new-password-modal', () => false)
7
12
  const passwordSuccessfulModal = useState('password-successful-modal', () => false)
8
13
 
9
14
  return {
10
15
  loginModal,
16
+ twoFactorModal,
11
17
  registrationModal,
18
+ confirmAccountOtpModal,
12
19
  recoveryModal,
13
- emailModal,
20
+ resetPasswordOtpModal,
14
21
  newPasswordModal,
15
22
  passwordSuccessfulModal,
23
+ confirmSuccessfulModal,
16
24
  }
17
25
  }
package/lang/ru.ts CHANGED
@@ -470,7 +470,9 @@ const RuLocale = {
470
470
  back: 'Назад',
471
471
  recover: 'Восстановить',
472
472
  cancel: 'Отменить',
473
- install: 'Установить',
473
+ set: 'Установить',
474
+ resend: 'Отправить еще раз',
475
+ confirm: 'Подтвердить',
474
476
  },
475
477
  modals: {
476
478
  id: {
@@ -479,9 +481,9 @@ const RuLocale = {
479
481
  content: 'Укажите Вашу электронную почту / номер телефона',
480
482
  placeholder: 'Введите email или номер телефона',
481
483
  },
482
- email: {
483
- title: 'Внимание',
484
- content: 'На вашу почту мы вышлем инструкции по сбросу пароля',
484
+ resetPasswordOtp: {
485
+ title: 'Подтвердите действие',
486
+ content: 'Введите 6-значный код подтверждения отправленный на ваш адрес электронной почты',
485
487
  },
486
488
  newPassword: {
487
489
  title: 'Создание нового пароля',
@@ -499,6 +501,14 @@ const RuLocale = {
499
501
  confirm: 'Подтвердить',
500
502
  error: 'Вы ввели неверный код',
501
503
  },
504
+ passwordSuccessful: {
505
+ title: 'Отлично',
506
+ content: 'Вы успешно сменили пароль от учетной записи',
507
+ },
508
+ confirmSuccessful: {
509
+ title: 'Успешно!',
510
+ content: 'Электронная почта подтверждена. Спасибо!',
511
+ },
502
512
  },
503
513
  auth: {
504
514
  title: 'Нет доступа',
@@ -678,7 +688,7 @@ const RuLocale = {
678
688
  },
679
689
  },
680
690
  modal: {
681
- title: 'Подтверждение',
691
+ title: 'Подтверждение аккаунта',
682
692
  subtitle1: 'На вашу почту отправлено письмо с ссылкой на подтверждение аккаунта',
683
693
  subtitle2: 'Ожидание подтверждения, повторно отправить письмо можно через',
684
694
  confirmationEmail: 'Если Вы не получили письмо с подтверждением',
@@ -694,6 +704,7 @@ const RuLocale = {
694
704
  user_canceled_auth: 'Вы отменили авторизацию',
695
705
  email_not_verified: 'Почта не подтверждена',
696
706
  email: 'Неправильный email',
707
+ otp: 'Вы ввели неверный код',
697
708
  authorization_error_with_yandex:
698
709
  'Не удалось авторизоваться через Яндекс',
699
710
  authorization_error_with_google:
package/nuxt.config.ts CHANGED
@@ -14,6 +14,7 @@ export default defineNuxtConfig({
14
14
  '@nuxtjs/i18n',
15
15
  '@nuxtjs/google-fonts',
16
16
  '@nuxt/eslint',
17
+ '@pinia/nuxt',
17
18
  ],
18
19
 
19
20
  eslint: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "adata-ui",
3
3
  "type": "module",
4
- "version": "2.0.23",
4
+ "version": "2.0.25",
5
5
  "main": "./nuxt.config.ts",
6
6
  "scripts": {
7
7
  "dev": "nuxi dev .playground",
@@ -34,6 +34,7 @@
34
34
  "vue-tsc": "^2.2.12"
35
35
  },
36
36
  "dependencies": {
37
+ "@floating-ui/vue": "^1.1.9",
37
38
  "@headlessui/tailwindcss": "^0.2.2",
38
39
  "@headlessui/vue": "^1.7.23",
39
40
  "@nuxt/image": "1.8.1",
@@ -42,6 +43,7 @@
42
43
  "@nuxtjs/google-fonts": "^3.2.0",
43
44
  "@nuxtjs/i18n": "9.3.3",
44
45
  "@nuxtjs/tailwindcss": "^6.14.0",
46
+ "@pinia/nuxt": "^0.11.2",
45
47
  "@popperjs/core": "^2.11.8",
46
48
  "@samk-dev/nuxt-vcalendar": "^1.0.4",
47
49
  "@tailwindcss/aspect-ratio": "^0.4.2",
@@ -56,6 +58,7 @@
56
58
  "lodash.isequal": "^4.5.0",
57
59
  "maska": "^2.1.11",
58
60
  "ofetch": "^1.4.1",
61
+ "pinia": "^3.0.3",
59
62
  "sass": "^1.90.0",
60
63
  "scss": "^0.2.4",
61
64
  "tailwind-merge": "^2.6.0",
@@ -0,0 +1,12 @@
1
+ import { defineStore } from 'pinia'
2
+
3
+ export const useAuthStore = defineStore('auth', () => {
4
+ const intermediateState = ref({
5
+ email: '',
6
+ password: '',
7
+ otp: '',
8
+ token: '',
9
+ })
10
+
11
+ return { intermediateState }
12
+ })
@@ -1,45 +0,0 @@
1
- <script setup lang="ts">
2
-
3
- defineEmits<{ (e: 'back'): void, (e: 'repeated'): void }>()
4
-
5
- const timer = ref(60)
6
-
7
- function runTimer() {
8
- const intervalId = setInterval(() => {
9
- if (!timer.value) clearInterval(intervalId)
10
- return timer.value--
11
- }, 1000)
12
- }
13
-
14
- onMounted(() => runTimer())
15
- </script>
16
-
17
- <template>
18
- <section class="flex flex-col items-stretch gap-4 py-4 py-8 text-center md:px-8">
19
- <h2 class="text-2xl font-bold">
20
- {{ $t('register.modal.title') }}
21
- </h2>
22
- <span class="mx-auto">
23
- <a-ill-mail/>
24
- </span>
25
- <p class="text-sm">
26
- {{ $t('register.modal.subtitle1') }}
27
- </p>
28
- <p class="text-sm">
29
- {{ $t('register.modal.subtitle2') }}
30
- </p>
31
- <div v-if="timer > 0" class="text-2xl font-bold">
32
- {{ timer }} {{ $t('register.modal.seconds') }}
33
- </div>
34
- <button
35
- v-else
36
- class="text-sm text-blue-500"
37
- @click="$emit('repeated')"
38
- >
39
- {{ $t('register.modal.resend') }}
40
- </button>
41
- <a-button @click="$emit('back')">
42
- {{ $t('actions.back') }}
43
- </a-button>
44
- </section>
45
- </template>
@@ -1,29 +0,0 @@
1
- <script setup lang="ts">
2
- const { emailModal } = useIdModals()
3
- const { t } = useI18n()
4
- </script>
5
-
6
- <template>
7
- <a-modal v-model="emailModal">
8
- <div class="flex flex-col items-stretch gap-5 rounded-lg text-center">
9
- <h2 class="text-center text-2xl font-bold">
10
- {{ t('modals.id.email.title') }}
11
- </h2>
12
- <div class="flex justify-center">
13
- <span class="flex size-[100px] items-center justify-center rounded-full bg-[#BDC7CE26]">
14
- <a-ill-info />
15
- </span>
16
- </div>
17
- <p class="text-center text-sm">
18
- {{ t('modals.id.email.content') }}
19
- </p>
20
- <a-button @click="emailModal = false">
21
- {{ t('actions.close') }}
22
- </a-button>
23
- </div>
24
- </a-modal>
25
- </template>
26
-
27
- <style scoped>
28
-
29
- </style>