adata-ui 2.0.22 → 2.0.23

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/.editorconfig CHANGED
@@ -1,12 +1,12 @@
1
- root = true
2
-
3
- [*]
4
- indent_size = 2
5
- indent_style = space
6
- end_of_line = lf
7
- charset = utf-8
8
- trim_trailing_whitespace = true
9
- insert_final_newline = true
10
-
11
- [*.md]
12
- trim_trailing_whitespace = false
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
package/app.config.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export default defineAppConfig({
2
2
  myLayer: {
3
- name: 'Adata UI v2'
4
- }
3
+ name: 'Adata UI v2',
4
+ },
5
5
  })
6
6
 
7
7
  declare module '@nuxt/schema' {
@@ -22,6 +22,7 @@ declare module '@nuxt/schema' {
22
22
  complianceUrl?: string
23
23
  counterParty?: string
24
24
  langIsOn?: boolean
25
+ authMode?: 'local' | 'separate'
25
26
  }
26
27
  }
27
28
  }
@@ -72,7 +72,7 @@ onUnmounted(() => clearTimer())
72
72
  />
73
73
  </div>
74
74
  <p
75
- class="font-semibold text-xl transition-colors duration-300 ease-in-out"
75
+ class="font-semibold text-base lg:text-xl transition-colors duration-300 ease-in-out"
76
76
  :class="selected === idx ? 'dark:text-[#E3E5E8]' : 'text-gray-600 dark:text-gray-200'"
77
77
  >
78
78
  {{ item.title }}
@@ -88,7 +88,7 @@ onUnmounted(() => clearTimer())
88
88
  <div
89
89
  v-if="selected === idx"
90
90
  >
91
- <p class="text-sm pt-3">
91
+ <p class="text-xs lg:text-sm pt-3">
92
92
  {{ item.description }}
93
93
  </p>
94
94
  </div>
@@ -64,11 +64,13 @@ defineExpose({
64
64
  v-model="form.name"
65
65
  :label="t('modals.submit_application_modal.labels.name')"
66
66
  :error="getError('name')"
67
+ required
67
68
  />
68
69
  <a-input-standard
69
70
  v-model="form.email"
70
71
  :label="t('modals.submit_application_modal.labels.email')"
71
72
  :error="getError('email')"
73
+ required
72
74
  />
73
75
  <a-input-standard
74
76
  v-model="form.phone"
@@ -83,6 +85,7 @@ defineExpose({
83
85
  v-model="form.comment"
84
86
  :label="t('modals.submit_application_modal.labels.comment')"
85
87
  :error="getError('comment')"
88
+ required
86
89
  />
87
90
  </div>
88
91
  </div>
@@ -0,0 +1,76 @@
1
+ <script setup lang="ts">
2
+ const emit = defineEmits<{
3
+ (e: 'close'): void
4
+ }>()
5
+ const { t } = useI18n()
6
+ const isOpen = useAuthModal()
7
+ const { myLayer } = useAppConfig()
8
+ const loginUrl = myLayer.loginUrl
9
+
10
+ const { loginModal, registrationModal } = useIdModals()
11
+
12
+ function goAuth() {
13
+ if (myLayer.authMode !== 'local') {
14
+ if (window) {
15
+ let fullPath = encodeURIComponent(window.location.toString())
16
+ if (fullPath.includes('basic-info')) {
17
+ fullPath = fullPath.replace('%2Fcounterparty%2Fmain', '').replace('%2Fbasic-info', '')
18
+ }
19
+ window.location.href = `${loginUrl}?url=${fullPath}`
20
+ }
21
+ }
22
+ else {
23
+ isOpen.value = false
24
+ loginModal.value = true
25
+ }
26
+ }
27
+
28
+ function goRegister() {
29
+ if (myLayer.authMode !== 'local') {
30
+ if (window) {
31
+ let fullPath = encodeURIComponent(window.location.toString())
32
+ if (fullPath.includes('basic-info')) {
33
+ fullPath = fullPath.replace('%2Fcounterparty%2Fmain', '').replace('%2Fbasic-info', '')
34
+ }
35
+ window.location.href = `${loginUrl}register?url=${fullPath}`
36
+ }
37
+ }
38
+ else {
39
+ isOpen.value = false
40
+ registrationModal.value = true
41
+ }
42
+ }
43
+ </script>
44
+
45
+ <template>
46
+ <a-modal v-model="isOpen" :title="t('modals.auth.title')">
47
+ <div class="flex flex-col items-center gap-5 text-center text-sm">
48
+ <a-ill-door />
49
+ <div>{{ t('modals.auth.content') }}</div>
50
+ <a-button
51
+ block
52
+ variant="success"
53
+ @click="goAuth"
54
+ >
55
+ {{ t('modals.buttons.logIn') }}
56
+ </a-button>
57
+ <div>{{ t('modals.auth.firstTime') }}</div>
58
+ </div>
59
+ <template #footer>
60
+ <div class="flex gap-2">
61
+ <a-button
62
+ view="outline"
63
+ block
64
+ @click="emit('close')"
65
+ >
66
+ {{ t('modals.buttons.close') }}
67
+ </a-button>
68
+ <a-button block @click="goRegister">
69
+ {{ t('modals.buttons.register') }}
70
+ </a-button>
71
+ </div>
72
+ </template>
73
+ </a-modal>
74
+ </template>
75
+
76
+ <style scoped></style>
@@ -0,0 +1,29 @@
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>
@@ -1,10 +1,10 @@
1
1
  <script setup lang="ts">
2
- import { useToggle } from '@vueuse/shared'
3
- import * as z from 'zod'
4
2
  import AConfirmationEmail from '#adata-ui/components/modals/AConfirmationEmail.vue'
5
3
  import Resend from '#adata-ui/components/modals/Resend.vue'
6
4
  import TwoFactor from '#adata-ui/components/modals/two-factor/two-factor.vue'
7
5
  import { navigateToLocalizedPage } from '#adata-ui/utils/localizedNavigation'
6
+ import { useToggle } from '@vueuse/shared'
7
+ import * as z from 'zod'
8
8
 
9
9
  const { myLayer, commonAuth } = useAppConfig()
10
10
  const authApiURL = commonAuth.authApiURL
@@ -19,8 +19,7 @@ const { t, locale } = useI18n()
19
19
  const route = useRoute()
20
20
  const submitted = ref(false)
21
21
  const accessToken = ref(null)
22
- const loginModal = useLoginModal()
23
- const registrationModal = useRegistrationModal()
22
+ const { loginModal, registrationModal, recoveryModal } = useIdModals()
24
23
 
25
24
  export interface ILoginForm {
26
25
  username: string
@@ -29,7 +28,7 @@ export interface ILoginForm {
29
28
 
30
29
  const loginSchema = z.object({
31
30
  username: z.string().nonempty(t('register.form.errors.required')).email(t('register.form.errors.email')),
32
- password: z.string().nonempty(t('register.form.errors.required'))
31
+ password: z.string().nonempty(t('register.form.errors.required')),
33
32
  })
34
33
 
35
34
  const validation = computed(() => {
@@ -39,13 +38,13 @@ const validation = computed(() => {
39
38
  })
40
39
 
41
40
  function getError(path: string) {
42
- return validation.value?.issues.find((issue) => issue.path[0] === path)?.message
41
+ return validation.value?.issues.find(issue => issue.path[0] === path)?.message
43
42
  }
44
43
 
45
- function savePassAndLogin(form: { username: string; password: string }) {
44
+ function savePassAndLogin(form: { username: string, password: string }) {
46
45
  const { username, password } = form
47
46
  const cookieOptions = {
48
- expires: rememberMe.value ? new Date(Date.now() + 14 * 24 * 60 * 60 * 1000) : undefined // Срок действия 14 дней
47
+ expires: rememberMe.value ? new Date(Date.now() + 14 * 24 * 60 * 60 * 1000) : undefined, // Срок действия 14 дней
49
48
  }
50
49
  useCookie('username', cookieOptions).value = username
51
50
  useCookie('password', cookieOptions).value = password
@@ -58,7 +57,7 @@ function clearAuthCookie() {
58
57
  const loading = ref(false)
59
58
  const form: ILoginForm = reactive({
60
59
  username: useCookie('username').value || '',
61
- password: useCookie('password').value || ''
60
+ password: useCookie('password').value || '',
62
61
  })
63
62
  const rememberMe = ref(false)
64
63
 
@@ -71,33 +70,36 @@ async function submit() {
71
70
  credentials: 'include',
72
71
  headers: {
73
72
  'Content-Type': 'application/json',
74
- lang: locale.value
73
+ 'lang': locale.value,
75
74
  },
76
75
  body: JSON.stringify({
77
76
  username: form.username.trim().toLowerCase(),
78
- password: form.password.toString()
79
- })
77
+ password: form.password.toString(),
78
+ }),
80
79
  })
81
80
  const { data, message } = await login.json().catch(() => ({}))
82
81
  if (data) accessToken.value = data?.access_token
83
82
  if (login.status > 202) {
84
83
  if (login.status === 422) {
85
84
  $toast.error(t('error.validation'))
86
- } else {
85
+ }
86
+ else {
87
87
  $toast.error(message)
88
88
  }
89
- } else {
89
+ }
90
+ else {
90
91
  rememberMe.value ? savePassAndLogin(form) : clearAuthCookie()
91
92
  if (data.is_2fa_enabled) {
92
93
  isTwoFactorOpen.value = true
93
- } else if (data.email_is_verified) {
94
+ }
95
+ else if (data.email_is_verified) {
94
96
  const response = await fetch(`${authApiURL}/access/cookie`, {
95
97
  method: 'GET',
96
98
  credentials: 'include',
97
99
  headers: {
98
100
  Authorization: `Bearer ${accessToken.value}`,
99
- lang: locale.value
100
- }
101
+ lang: locale.value,
102
+ },
101
103
  })
102
104
  const { data: cookiesData } = await response.json()
103
105
  if (cookiesData) {
@@ -108,7 +110,8 @@ async function submit() {
108
110
  $toast.success(t('login.successfully'))
109
111
  loginModal.value = false
110
112
  window.location.reload()
111
- } else {
113
+ }
114
+ else {
112
115
  isConfirmationEmailModal.value = true
113
116
  }
114
117
  }
@@ -140,7 +143,7 @@ function toTariffs() {
140
143
  locale,
141
144
  projectUrl: myLayer.landingUrl,
142
145
  path: '/tariffs',
143
- target: '_self'
146
+ target: '_self',
144
147
  })
145
148
  }
146
149
 
@@ -159,13 +162,13 @@ async function handleConfirmOtp(otpCode: string) {
159
162
  credentials: 'include',
160
163
  headers: {
161
164
  'Content-Type': 'application/json',
162
- lang: locale.value
165
+ 'lang': locale.value,
163
166
  },
164
167
  body: JSON.stringify({
165
- username: form.username.trim(),
166
- password: form.password.toString(),
167
- '2fa_code': otpCode
168
- })
168
+ 'username': form.username.trim(),
169
+ 'password': form.password.toString(),
170
+ '2fa_code': otpCode,
171
+ }),
169
172
  })
170
173
  const { data, message } = await login.json().catch(() => ({}))
171
174
 
@@ -174,14 +177,15 @@ async function handleConfirmOtp(otpCode: string) {
174
177
  showOtpError.value = true
175
178
  isLoadingOtp.value = false
176
179
  }
177
- } else {
180
+ }
181
+ else {
178
182
  const response = await fetch(`${authApiURL}/access/cookie`, {
179
183
  method: 'GET',
180
184
  credentials: 'include',
181
185
  headers: {
182
186
  Authorization: `Bearer ${accessToken.value}`,
183
- lang: locale.value
184
- }
187
+ lang: locale.value,
188
+ },
185
189
  })
186
190
  const { data: cookiesData } = await response.json()
187
191
  if (cookiesData?.access_token) {
@@ -199,22 +203,18 @@ async function handleConfirmOtp(otpCode: string) {
199
203
 
200
204
  function handleEnter(e: KeyboardEvent) {
201
205
  if (
202
- e.key === 'Enter' &&
203
- !isTwoFactorOpen.value &&
204
- !isConfirmationEmailModal.value &&
205
- !isResendModal.value
206
+ e.key === 'Enter'
207
+ && !isTwoFactorOpen.value
208
+ && !isConfirmationEmailModal.value
209
+ && !isResendModal.value
206
210
  ) {
207
211
  submit()
208
212
  }
209
213
  }
210
214
 
211
215
  function onForgotPassword() {
212
- return navigateToLocalizedPage({
213
- locale,
214
- projectUrl: myLayer.loginUrl.slice(0, -1),
215
- path: `/password-recovery`,
216
- target: '_self',
217
- })
216
+ loginModal.value = false
217
+ recoveryModal.value = true
218
218
  }
219
219
 
220
220
  watch(loginModal, (value) => {
@@ -236,7 +236,7 @@ onBeforeUnmount(() => {
236
236
 
237
237
  <template>
238
238
  <a-modal v-model="loginModal">
239
- <div class="flex flex-col gap-5 rounded-lg bg-white dark:bg-gray-900">
239
+ <div class="flex flex-col gap-5">
240
240
  <h1 class="heading-02 text-center">
241
241
  {{ $t('login.form.title') }}
242
242
  </h1>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import IdEmailModal from '#adata-ui/components/modals/id/IdEmailModal.vue'
3
+ import IdLoginModal from '#adata-ui/components/modals/id/IdLoginModal.vue'
4
+ import IdNewPasswordModal from '#adata-ui/components/modals/id/IdNewPasswordModal.vue'
5
+ import IdPasswordSuccessfulModal from '#adata-ui/components/modals/id/IdPasswordSuccessfulModal.vue'
6
+ import IdRecoveryModal from '#adata-ui/components/modals/id/IdRecoveryModal.vue'
7
+ import IdRegistrationModal from '#adata-ui/components/modals/id/IdRegistrationModal.vue'
8
+ </script>
9
+
10
+ <template>
11
+ <id-login-modal />
12
+ <id-registration-modal />
13
+ <id-recovery-modal />
14
+ <id-email-modal />
15
+ <id-new-password-modal />
16
+ <id-password-successful-modal />
17
+ </template>
18
+
19
+ <style scoped></style>
@@ -0,0 +1,137 @@
1
+ <script setup lang="ts">
2
+ import * as z from 'zod'
3
+
4
+ const { $toast } = useNuxtApp()
5
+ const { commonAuth } = useAppConfig()
6
+ const route = useRoute()
7
+ const { t, locale } = useI18n()
8
+
9
+ const { email, token } = route.query
10
+ const authApiURL = commonAuth.authApiURL
11
+ const { loginModal, newPasswordModal, passwordSuccessfulModal } = useIdModals()
12
+
13
+ const form = reactive({
14
+ password: '',
15
+ password_confirmation: '',
16
+ })
17
+ const loading = ref(false)
18
+
19
+ const resetSchema = z.object({
20
+ password: z
21
+ .string()
22
+ .min(8, t('register.form.errors.low_security', { length: 8 }))
23
+ .regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('register.form.errors.low_security')),
24
+ password_confirmation: z
25
+ .string()
26
+ .min(8, t('register.form.errors.low_security', { length: 8 }))
27
+ .regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('register.form.errors.low_security')),
28
+ }).refine(
29
+ data => data.password === data.password_confirmation,
30
+ {
31
+ message: t('register.form.errors.sameAs'),
32
+ path: ['password_confirmation'],
33
+ },
34
+ )
35
+
36
+ const submitted = ref(false)
37
+
38
+ const validation = computed(() => {
39
+ if (!submitted.value) return null
40
+ const result = resetSchema.safeParse(form)
41
+ return result.success ? null : result.error
42
+ })
43
+
44
+ function getError(path: string) {
45
+ return validation.value?.issues?.find(issue => issue.path[0] === path)?.message
46
+ }
47
+
48
+ async function onSubmit() {
49
+ try {
50
+ submitted.value = true
51
+ if (validation.value) return
52
+ loading.value = true
53
+
54
+ const { data } = await $fetch(`${authApiURL}/password/reset`, {
55
+ method: 'POST',
56
+ credentials: 'include',
57
+ headers: {
58
+ lang: locale.value,
59
+ },
60
+ body: {
61
+ token,
62
+ email,
63
+ ...form,
64
+ },
65
+ })
66
+ if (data?.success) {
67
+ newPasswordModal.value = false
68
+ passwordSuccessfulModal.value = true
69
+ $toast.success(data.message)
70
+ }
71
+ }
72
+ catch (error) {
73
+ $toast.error(error?.data.message.password as string)
74
+ }
75
+ finally {
76
+ loading.value = false
77
+ }
78
+ }
79
+
80
+ // onMounted(() => {
81
+ // if (!email || !token) {
82
+ // newPasswordModal.value = false
83
+ // loginModal.value = true
84
+ // }
85
+ // })
86
+ </script>
87
+
88
+ <template>
89
+ <a-modal v-model="newPasswordModal">
90
+ <form
91
+ class="flex flex-col items-stretch gap-5"
92
+ novalidate
93
+ @submit.prevent="onSubmit"
94
+ >
95
+ <h2 class="text-center text-2xl font-bold">
96
+ {{ t('resetPassword.title') }}
97
+ </h2>
98
+ <p class="text-center text-sm">
99
+ {{ t('resetPassword.subtitle') }}
100
+ </p>
101
+
102
+ <a-input-password
103
+ v-model="form.password"
104
+ :label="t('register.form.labels.password')"
105
+ :error="getError('password')"
106
+ />
107
+
108
+ <a-alert color="blue">
109
+ {{ t('register.form.alert') }}
110
+ </a-alert>
111
+
112
+ <a-input-password
113
+ v-model="form.password_confirmation"
114
+ :label="t('register.form.labels.password_confirmation')"
115
+ :error="getError('password_confirmation')"
116
+ />
117
+
118
+ <a-button
119
+ :loading="loading"
120
+ >
121
+ {{ t('passwordRecovery.form.recover') }}
122
+ </a-button>
123
+
124
+ <p class="text-center text-sm">
125
+ {{ t('passwordRecovery.form.or') }}
126
+ </p>
127
+
128
+ <a-button
129
+ type="button"
130
+ view="outline"
131
+ @click="newPasswordModal = false"
132
+ >
133
+ {{ t('actions.cancel') }}
134
+ </a-button>
135
+ </form>
136
+ </a-modal>
137
+ </template>
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ const { passwordSuccessfulModal } = useIdModals()
3
+ </script>
4
+
5
+ <template>
6
+ <a-modal v-model="passwordSuccessfulModal">
7
+ <section class="flex flex-col items-stretch gap-4 text-center">
8
+ <h2 class="text-2xl font-bold">
9
+ {{ $t('resetPassword.successModal.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('resetPassword.successModal.subtitle') }}
16
+ </p>
17
+ <a-button @click="passwordSuccessfulModal = false">
18
+ {{ $t('resetPassword.successModal.goToAuthorization') }}
19
+ </a-button>
20
+ </section>
21
+ </a-modal>
22
+ </template>
23
+
24
+ <style scoped>
25
+
26
+ </style>
@@ -0,0 +1,114 @@
1
+ <script setup lang="ts">
2
+ import * as z from 'zod'
3
+
4
+ const { $toast } = useNuxtApp()
5
+ const { commonAuth } = useAppConfig()
6
+ const { t, locale } = useI18n()
7
+
8
+ const { recoveryModal, emailModal } = useIdModals()
9
+ const authApiURL = commonAuth.authApiURL
10
+ const emailField = ref('')
11
+ const loading = ref(false)
12
+ const submitted = ref(false)
13
+
14
+ const emailSchema = z.object({
15
+ emailField: z.string().nonempty(t('error.required')).email(t('error.email')),
16
+ })
17
+
18
+ const validation = computed(() => {
19
+ if (!submitted.value) return null
20
+ const result = emailSchema.safeParse({ emailField: emailField.value })
21
+ return result.success ? null : result.error
22
+ })
23
+
24
+ function getError(path: string) {
25
+ return validation.value?.issues.find(issue => issue.path[0] === path)?.message
26
+ }
27
+
28
+ async function onSubmit() {
29
+ try {
30
+ submitted.value = true
31
+ if (validation.value) return
32
+ loading.value = true
33
+
34
+ await $fetch(`${authApiURL}/password/email`, {
35
+ method: 'POST',
36
+ credentials: 'include',
37
+ headers: {
38
+ lang: locale.value,
39
+ },
40
+ body: {
41
+ email: emailField.value,
42
+ },
43
+ })
44
+ recoveryModal.value = false
45
+ emailModal.value = true
46
+ }
47
+ catch (error) {
48
+ $toast.error(error.data.message)
49
+ }
50
+ finally {
51
+ loading.value = false
52
+ }
53
+ }
54
+ function handleEnter(e: KeyboardEvent) {
55
+ if (e.key === 'Enter') {
56
+ onSubmit()
57
+ }
58
+ }
59
+
60
+ function onCancel() {
61
+ recoveryModal.value = false
62
+ }
63
+
64
+ watch(recoveryModal, (value) => {
65
+ if (!value) {
66
+ emailField.value = ''
67
+ }
68
+ })
69
+
70
+ onMounted(() => {
71
+ document.addEventListener('keyup', handleEnter)
72
+ })
73
+
74
+ onBeforeUnmount(() => {
75
+ document.removeEventListener('keyup', handleEnter)
76
+ })
77
+ </script>
78
+
79
+ <template>
80
+ <a-modal v-model="recoveryModal">
81
+ <form
82
+ class="flex flex-col items-stretch gap-5 rounded-lg text-center"
83
+ novalidate
84
+ @submit.prevent="onSubmit"
85
+ >
86
+ <h2 class="text-center text-2xl font-bold">
87
+ {{ t('modals.id.recovery.title') }}
88
+ </h2>
89
+ <p class="text-center text-sm">
90
+ {{ t('modals.id.recovery.content') }}
91
+ </p>
92
+ <a-input-standard
93
+ v-model="emailField"
94
+ :label="t('modals.id.recovery.placeholder')"
95
+ :error="getError('emailField')"
96
+ />
97
+ <a-button :loading="loading">
98
+ {{ t('actions.recover') }}
99
+ </a-button>
100
+ <p class="text-center text-sm">
101
+ {{ t('reuse.or') }}
102
+ </p>
103
+ <a-button
104
+ type="button"
105
+ view="outline"
106
+ @click="onCancel"
107
+ >
108
+ {{ t('actions.cancel') }}
109
+ </a-button>
110
+ </form>
111
+ </a-modal>
112
+ </template>
113
+
114
+ <style scoped></style>