adata-ui 2.1.0 → 2.1.2

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.
Files changed (307) hide show
  1. package/.editorconfig +12 -12
  2. package/.nuxtrc +1 -1
  3. package/.playground/app.config.ts +5 -5
  4. package/README.md +75 -75
  5. package/app.config.ts +4 -3
  6. package/app.vue +1 -0
  7. package/assets/styles/index.scss +104 -0
  8. package/assets/styles/modules/_base.scss +5 -0
  9. package/assets/styles/modules/_typography.scss +152 -0
  10. package/components/elements/README.md +1 -1
  11. package/components/elements/accordion/AAccordion.vue +13 -12
  12. package/components/elements/curve-block/ACurveBlock.vue +94 -19
  13. package/components/elements/feature-description/AFeatureDescription.vue +4 -4
  14. package/components/elements/illustrations/noAccess.vue +11 -2
  15. package/components/elements/photos-animation/APhotosAnimation.vue +3 -1
  16. package/components/elements/select/ASelect.vue +65 -9
  17. package/components/features/lang-switcher/lang-switcher.vue +8 -1
  18. package/components/features/payment/banner/BasicPlusLimitBanner.vue +104 -0
  19. package/components/features/payment/banner/PaymentBanner.vue +108 -0
  20. package/components/features/payment/process/PaymentKaspiQrSidePanel.vue +158 -0
  21. package/components/features/payment/process/PaymentKaspiRedirectSidePanel.vue +112 -0
  22. package/components/features/payment/process/PaymentMethodSidePanel.vue +121 -0
  23. package/components/features/payment/process/PaymentProcess.vue +138 -0
  24. package/components/features/payment/process/PaymentTopUpSidePanel.vue +130 -0
  25. package/components/features/pk-mobile-services/APkMobileServices.vue +21 -2
  26. package/components/forms/README.md +1 -1
  27. package/components/forms/checkbox/ACheckbox.vue +0 -2
  28. package/components/forms/radio-button/ARadioButton.vue +21 -13
  29. package/components/forms/request-demo/ARequestDemo.vue +21 -7
  30. package/components/modals/AConfirmationEmail.vue +40 -0
  31. package/components/modals/AnotherDeviceModal.vue +3 -2
  32. package/components/modals/ConnectingTariffModal.vue +0 -1
  33. package/components/modals/ContentNavigationModal.vue +148 -75
  34. package/components/modals/Insufficient-funds-modal.vue +5 -2
  35. package/components/modals/LimitReachedModal.vue +4 -3
  36. package/components/modals/ReportBugModal.vue +3 -3
  37. package/components/modals/Resend.vue +82 -0
  38. package/components/modals/SubmitApplicationModal.vue +4 -0
  39. package/components/modals/id/AuthModal.vue +78 -0
  40. package/components/modals/id/IdAutoLogoutModal.vue +45 -0
  41. package/components/modals/id/IdBanner.vue +58 -0
  42. package/components/modals/id/IdConfirmAccountOtpModal.vue +186 -0
  43. package/components/modals/id/IdConfirmSuccessfulModal.vue +41 -0
  44. package/components/modals/id/IdLoginModal.vue +316 -0
  45. package/components/modals/id/IdModals.vue +114 -0
  46. package/components/modals/id/IdNewPasswordModal.vue +129 -0
  47. package/components/modals/id/IdOtpInput.vue +155 -0
  48. package/components/modals/id/IdPasswordSuccessfulModal.vue +25 -0
  49. package/components/modals/id/IdRecoveryModal.vue +117 -0
  50. package/components/modals/id/IdRegistrationModal.vue +215 -0
  51. package/components/modals/id/IdResetPasswordOtpModal.vue +158 -0
  52. package/components/modals/id/IdTwoFactorModal.vue +130 -0
  53. package/components/navigation/README.md +1 -1
  54. package/components/navigation/bottom-navigation/ABottomNavigation.vue +34 -29
  55. package/components/navigation/footer/AFooter.vue +210 -57
  56. package/components/navigation/footer/ui/{new-footer-accordion.vue → a-footer-accordion.vue} +2 -4
  57. package/components/navigation/header/AHeader.vue +59 -51
  58. package/components/navigation/header/AlmatyContacts.vue +16 -14
  59. package/components/navigation/header/AstanaContacts.vue +13 -11
  60. package/components/navigation/header/CardGallery.vue +5 -4
  61. package/components/navigation/header/HeaderLink.vue +16 -8
  62. package/components/navigation/header/NavList.vue +21 -5
  63. package/components/navigation/header/ProductMenu.vue +8 -78
  64. package/components/navigation/header/ProfileMenu.vue +10 -5
  65. package/components/navigation/header/TopHeader.vue +2 -2
  66. package/components/navigation/mobile-navigation/AMobileNavigation.vue +3 -3
  67. package/components/navigation/pill-tabs/APillTabs.vue +18 -4
  68. package/components/navigation/pill-tabs/types.ts +1 -0
  69. package/components/navigation/side-navigation/ASideNavigation.vue +23 -21
  70. package/components/overlays/README.md +1 -1
  71. package/components/overlays/side-panel/ASidePanel.vue +439 -0
  72. package/components/overlays/tooltip/ATooltip.vue +149 -154
  73. package/components/utils/removeTrailingSlash.ts +7 -0
  74. package/composables/useBuyTariffs.ts +91 -0
  75. package/composables/useHeaderNavigationLinks.ts +174 -297
  76. package/composables/useIdModals.ts +36 -0
  77. package/composables/usePayment.ts +74 -0
  78. package/composables/useUrls.ts +21 -0
  79. package/eslint.config.mjs +45 -0
  80. package/icons/adata-logo.vue +1 -1
  81. package/icons/ai-assistant.vue +13 -0
  82. package/icons/akimat.vue +20 -0
  83. package/icons/arrow/arrow-bottom-left-on-square.vue +1 -1
  84. package/icons/arrow/arrow-circle-reset.vue +1 -1
  85. package/icons/arrow/arrow-corner.vue +1 -1
  86. package/icons/arrow/arrow-graph-down.vue +1 -1
  87. package/icons/arrow/arrow-graph-up.vue +1 -1
  88. package/icons/arrow/arrow-square-down.vue +1 -1
  89. package/icons/arrow/arrow-top-right-on-square.vue +1 -1
  90. package/icons/arrow-currency-gray.vue +1 -1
  91. package/icons/arrow-currency-green.vue +1 -1
  92. package/icons/arrow-currency-red.vue +1 -1
  93. package/icons/avatar.vue +1 -1
  94. package/icons/bank.vue +5 -0
  95. package/icons/block.vue +1 -1
  96. package/icons/bookmark/bookmark-filled.vue +1 -1
  97. package/icons/bookmark/bookmark.vue +1 -1
  98. package/icons/browsers/browser-duck.vue +1 -1
  99. package/icons/browsers/browser-google.vue +7 -1
  100. package/icons/browsers/browser-yandex.vue +1 -1
  101. package/icons/building-vector.vue +1 -1
  102. package/icons/calculator.vue +1 -1
  103. package/icons/calendar.vue +1 -1
  104. package/icons/car.vue +1 -1
  105. package/icons/chart-bar.vue +5 -0
  106. package/icons/chart-pie.vue +16 -0
  107. package/icons/check/check-circle.vue +1 -1
  108. package/icons/check/check.vue +1 -1
  109. package/icons/check/checkmark-circle.vue +1 -1
  110. package/icons/check-sb.vue +7 -0
  111. package/icons/checkbox/checkbox-active.vue +1 -1
  112. package/icons/checkbox/checkbox-empty.vue +1 -1
  113. package/icons/checkbox/checkbox-intermediate.vue +1 -1
  114. package/icons/chevron/chevron-down.vue +1 -1
  115. package/icons/chevron/chevron-left.vue +1 -1
  116. package/icons/chevron/chevron-right.vue +1 -1
  117. package/icons/chevron/chevron-up.vue +1 -1
  118. package/icons/chevron/double-chevron-right.vue +1 -1
  119. package/icons/clipboard-text.vue +1 -1
  120. package/icons/clock.vue +1 -1
  121. package/icons/company/company-bazis.vue +3 -3
  122. package/icons/company/company-bereke.vue +13 -13
  123. package/icons/company/company-bigroup.vue +5 -5
  124. package/icons/company/company-erg.vue +6 -6
  125. package/icons/company/company-forte.vue +11 -11
  126. package/icons/company/company-halyk.vue +4 -4
  127. package/icons/company/company-jusan.vue +20 -3
  128. package/icons/company/company-kaspi.vue +3 -3
  129. package/icons/company/company-mycar.vue +2 -2
  130. package/icons/company/company-samruk.vue +9 -9
  131. package/icons/company-egov-small.vue +1 -1
  132. package/icons/company.vue +1 -1
  133. package/icons/copy.vue +1 -1
  134. package/icons/currency/currency-dollar.vue +1 -1
  135. package/icons/currency/currency-down.vue +1 -1
  136. package/icons/currency/currency-eur.vue +1 -1
  137. package/icons/currency/currency-rub.vue +1 -1
  138. package/icons/currency/currency-tenge.vue +9 -0
  139. package/icons/currency/currency-usd.vue +1 -1
  140. package/icons/currency/currency-yuan.vue +1 -1
  141. package/icons/delete.vue +1 -1
  142. package/icons/document.vue +1 -1
  143. package/icons/download.vue +1 -1
  144. package/icons/edit.vue +1 -1
  145. package/icons/education.vue +1 -1
  146. package/icons/egov-small.vue +1 -1
  147. package/icons/excel-icon.vue +14 -0
  148. package/icons/expand-window.vue +1 -1
  149. package/icons/eye-closed.vue +1 -1
  150. package/icons/eye-open.vue +1 -1
  151. package/icons/eye-opened.vue +1 -1
  152. package/icons/file/file.vue +1 -1
  153. package/icons/filter.vue +1 -1
  154. package/icons/flag.vue +1 -1
  155. package/icons/gift.vue +1 -1
  156. package/icons/globe.vue +1 -1
  157. package/icons/google.vue +41 -0
  158. package/icons/hand/hand-thumb-up-filled.vue +1 -1
  159. package/icons/hand/hand-thumb-up.vue +1 -1
  160. package/icons/hand-with-phone/hand-with-phone-dark.vue +1 -1
  161. package/icons/hand-with-phone/hand-with-phone-light.vue +1 -1
  162. package/icons/handshake.vue +1 -1
  163. package/icons/hcheck.vue +1 -1
  164. package/icons/hdocument.vue +1 -1
  165. package/icons/history.vue +1 -1
  166. package/icons/horizontal-more.vue +1 -1
  167. package/icons/hot-line.vue +6 -0
  168. package/icons/hummer.vue +1 -1
  169. package/icons/info/info-circle.vue +1 -1
  170. package/icons/invoice.vue +1 -1
  171. package/icons/kaspi-qr.vue +13 -0
  172. package/icons/link-chain.vue +1 -1
  173. package/icons/link.vue +1 -1
  174. package/icons/linkedin.vue +24 -24
  175. package/icons/loader-circle.vue +1 -1
  176. package/icons/location.vue +1 -1
  177. package/icons/lock.vue +1 -1
  178. package/icons/logo.vue +1 -1
  179. package/icons/logout.vue +1 -1
  180. package/icons/magnify/magnifying-glass-minus.vue +1 -1
  181. package/icons/magnify/magnifying-glass-plus.vue +1 -1
  182. package/icons/magnify/magnifying-glass.vue +1 -1
  183. package/icons/mail.vue +1 -1
  184. package/icons/mailru.vue +34 -0
  185. package/icons/main-filter.vue +1 -1
  186. package/icons/map/map-pin-filled.vue +1 -1
  187. package/icons/map/map-pin-rect.vue +1 -1
  188. package/icons/map/map-pin.vue +1 -1
  189. package/icons/map-marker-start.vue +1 -1
  190. package/icons/medal.vue +1 -1
  191. package/icons/menu-filled.vue +1 -1
  192. package/icons/menu.vue +1 -1
  193. package/icons/message/message.vue +1 -1
  194. package/icons/minus/minus-circle.vue +1 -1
  195. package/icons/money.vue +1 -1
  196. package/icons/monitoring.vue +1 -1
  197. package/icons/moon.vue +1 -1
  198. package/icons/more.vue +1 -1
  199. package/icons/notification.vue +1 -1
  200. package/icons/paperclip.vue +1 -1
  201. package/icons/payment/payment-card.vue +1 -1
  202. package/icons/payment/payment-kaspi.vue +1 -1
  203. package/icons/person-vector.vue +1 -1
  204. package/icons/person-with-briefcase.vue +1 -1
  205. package/icons/phone-filled.vue +1 -1
  206. package/icons/phone.vue +1 -1
  207. package/icons/plus/plus-circle.vue +1 -1
  208. package/icons/plus/plus.vue +1 -1
  209. package/icons/profile.vue +1 -1
  210. package/icons/radio/radio-check.vue +1 -1
  211. package/icons/radio/radio-empty.vue +1 -1
  212. package/icons/receipt.vue +1 -1
  213. package/icons/sanctions.vue +8 -0
  214. package/icons/scales/scale.vue +1 -1
  215. package/icons/scales/scales.vue +1 -1
  216. package/icons/scales/standing-scales.vue +1 -1
  217. package/icons/search.vue +1 -1
  218. package/icons/share/share-alt.vue +1 -1
  219. package/icons/share/share.vue +1 -1
  220. package/icons/socials/face-book.vue +1 -1
  221. package/icons/socials/instagram.vue +1 -1
  222. package/icons/socials/telegram.vue +1 -1
  223. package/icons/socials/tik-tok.vue +1 -1
  224. package/icons/socials/youtube.vue +1 -1
  225. package/icons/sort/sort-asc.vue +1 -1
  226. package/icons/sort/sort-desc.vue +1 -1
  227. package/icons/splitting-arrows.vue +1 -1
  228. package/icons/star/star-filled.vue +1 -1
  229. package/icons/star/star-half-filled.vue +1 -1
  230. package/icons/star/star.vue +1 -1
  231. package/icons/sun.vue +14 -14
  232. package/icons/sviazi.vue +1 -1
  233. package/icons/tag.vue +1 -1
  234. package/icons/tasks.vue +10 -0
  235. package/icons/tender-search.vue +1 -1
  236. package/icons/toasts/check-circle-toast.vue +1 -1
  237. package/icons/toasts/warning-triangle-toast.vue +1 -1
  238. package/icons/trash.vue +1 -1
  239. package/icons/triangle.vue +1 -1
  240. package/icons/truck.vue +1 -1
  241. package/icons/user.vue +1 -1
  242. package/icons/users-focus.vue +1 -1
  243. package/icons/users.vue +1 -1
  244. package/icons/warning/warning-circle.vue +1 -1
  245. package/icons/warning/warning-triangle-filled.vue +1 -1
  246. package/icons/warning/warning-triangle.vue +1 -1
  247. package/icons/whatsapp.vue +1 -1
  248. package/icons/work-bag.vue +1 -1
  249. package/icons/work-case.vue +9 -0
  250. package/icons/work-search.vue +1 -1
  251. package/icons/work.vue +1 -1
  252. package/icons/x-mark.vue +1 -1
  253. package/icons/yandex.vue +28 -0
  254. package/illustrations/address-location.vue +1 -1
  255. package/illustrations/ball-with-chain.vue +1 -1
  256. package/illustrations/bill.vue +1 -1
  257. package/illustrations/buildings.vue +1 -1
  258. package/illustrations/calendar.vue +1 -1
  259. package/illustrations/chains.vue +1 -1
  260. package/illustrations/coin-percent.vue +1 -1
  261. package/illustrations/coins-stack.vue +1 -1
  262. package/illustrations/delete-dark.vue +1 -1
  263. package/illustrations/delete.vue +1 -1
  264. package/illustrations/doc-with-stamp.vue +1 -1
  265. package/illustrations/document.vue +1 -1
  266. package/illustrations/door.vue +1 -1
  267. package/illustrations/empty-box.vue +1 -1
  268. package/illustrations/empty-wallet.vue +1 -1
  269. package/illustrations/graph-in-coin.vue +1 -1
  270. package/illustrations/hammer.vue +1 -1
  271. package/illustrations/hand-cash.vue +1 -1
  272. package/illustrations/info.vue +1 -1
  273. package/illustrations/mail.vue +1 -1
  274. package/illustrations/ok.vue +1 -1
  275. package/illustrations/people-group.vue +1 -1
  276. package/illustrations/person-with-phone.vue +1 -1
  277. package/illustrations/person.vue +1 -1
  278. package/illustrations/phone-check.vue +1 -1
  279. package/illustrations/phone-payment-method.vue +1 -1
  280. package/illustrations/stop-hand.vue +1 -1
  281. package/illustrations/stop-sign.vue +1 -1
  282. package/illustrations/suit.vue +1 -1
  283. package/illustrations/suitcase.vue +1 -1
  284. package/illustrations/terminal-dark.vue +1 -1
  285. package/illustrations/terminal.vue +1 -1
  286. package/illustrations/trash-can.vue +1 -1
  287. package/illustrations/turn-on-tariff.vue +1 -1
  288. package/illustrations/two-persons.vue +1 -1
  289. package/lang/en.ts +475 -270
  290. package/lang/kk.ts +476 -271
  291. package/lang/ru.ts +315 -107
  292. package/layouts/default.vue +13 -13
  293. package/nuxt.config.ts +42 -14
  294. package/package.json +69 -53
  295. package/public/kaspi/logo.svg +4 -0
  296. package/shared/constans/pages.ts +17 -2
  297. package/tailwind.config.ts +163 -0
  298. package/vitest.config.ts +14 -0
  299. package/.eslintrc.cjs +0 -4
  300. package/.playground/app.vue +0 -9
  301. package/.playground/pages/index.vue +0 -13
  302. package/.prettierignore +0 -24
  303. package/.prettierrc +0 -10
  304. package/assets/styles/index.css +0 -226
  305. package/components/modals/AuthModal.vue +0 -50
  306. package/components/navigation/footer/NewFooter.vue +0 -276
  307. package/components/navigation/footer/ui/footer-acccordion.vue +0 -119
@@ -0,0 +1,25 @@
1
+ <script setup lang="ts">
2
+ const { passwordSuccessfulModal } = 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.passwordSuccessful.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.passwordSuccessful.content') }}
16
+ </p>
17
+ <a-button @click="passwordSuccessfulModal = false">
18
+ {{ t('actions.close') }}
19
+ </a-button>
20
+ </div>
21
+ </template>
22
+
23
+ <style scoped>
24
+
25
+ </style>
@@ -0,0 +1,117 @@
1
+ <script setup lang="ts">
2
+ import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
3
+ import * as z from 'zod'
4
+
5
+ const { $toast } = useNuxtApp()
6
+ const { commonAuth } = useAppConfig()
7
+ const { t, locale } = useI18n()
8
+
9
+ const { loginModal, recoveryModal, resetPasswordOtpModal, intermediateState } = useIdModals()
10
+ const authApiURL = commonAuth.authApiURL
11
+ const emailField = ref('')
12
+ const loading = ref(false)
13
+ const submitted = ref(false)
14
+
15
+ const emailSchema = z.object({
16
+ emailField: z.string().nonempty(t('error.required')).email(t('error.email')),
17
+ })
18
+
19
+ const validation = computed(() => {
20
+ if (!submitted.value) return null
21
+ const result = emailSchema.safeParse({ emailField: emailField.value })
22
+ return result.success ? null : result.error
23
+ })
24
+
25
+ function getError(path: string) {
26
+ return validation.value?.issues.find(issue => issue.path[0] === path)?.message
27
+ }
28
+
29
+ async function onSubmit() {
30
+ try {
31
+ submitted.value = true
32
+ if (validation.value) return
33
+ loading.value = true
34
+
35
+ await $fetch(`${removeTrailingSlash(authApiURL)}/password/email-otp`, {
36
+ method: 'POST',
37
+ credentials: 'include',
38
+ headers: {
39
+ lang: locale.value,
40
+ },
41
+ body: {
42
+ email: emailField.value,
43
+ },
44
+ })
45
+ intermediateState.value.email = emailField.value
46
+
47
+ recoveryModal.value = false
48
+ resetPasswordOtpModal.value = true
49
+ }
50
+ catch (error) {
51
+ $toast.error(error.data.message)
52
+ }
53
+ finally {
54
+ loading.value = false
55
+ }
56
+ }
57
+
58
+ function handleEnter(e: KeyboardEvent) {
59
+ if (e.key === 'Enter') {
60
+ onSubmit()
61
+ }
62
+ }
63
+
64
+ function onCancel() {
65
+ recoveryModal.value = false
66
+ loginModal.value = true
67
+ }
68
+
69
+ watch(recoveryModal, (value) => {
70
+ if (!value) {
71
+ emailField.value = ''
72
+ }
73
+ })
74
+
75
+ onMounted(() => {
76
+ document.addEventListener('keyup', handleEnter)
77
+ })
78
+
79
+ onBeforeUnmount(() => {
80
+ document.removeEventListener('keyup', handleEnter)
81
+ })
82
+ </script>
83
+
84
+ <template>
85
+ <form
86
+ class="flex flex-col items-stretch gap-5 rounded-lg text-center"
87
+ novalidate
88
+ @submit.prevent="onSubmit"
89
+ >
90
+ <h2 class="text-center text-2xl font-bold">
91
+ {{ t('modals.id.recovery.title') }}
92
+ </h2>
93
+ <p class="text-center text-sm">
94
+ {{ t('modals.id.recovery.content') }}
95
+ </p>
96
+ <a-input-standard
97
+ v-model="emailField"
98
+ :label="t('modals.id.recovery.placeholder')"
99
+ :error="getError('emailField')"
100
+ />
101
+ <a-button :loading="loading">
102
+ {{ t('actions.recover') }}
103
+ </a-button>
104
+ <p class="text-center text-sm">
105
+ {{ t('reuse.or') }}
106
+ </p>
107
+ <a-button
108
+ type="button"
109
+ view="outline"
110
+ @click="onCancel"
111
+ >
112
+ {{ t('actions.cancel') }}
113
+ </a-button>
114
+ </form>
115
+ </template>
116
+
117
+ <style scoped></style>
@@ -0,0 +1,215 @@
1
+ <script setup lang="ts">
2
+ import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
3
+ import { PAGES } from '#adata-ui/shared/constans/pages'
4
+ import * as z from 'zod'
5
+ import { useUrls } from '#adata-ui/composables/useUrls'
6
+
7
+ const { $toast } = useNuxtApp()
8
+ const route = useRoute()
9
+
10
+ const localePath = useLocalePath()
11
+ const { t, locale } = useI18n()
12
+ const { commonAuth }: any = useAppConfig()
13
+ const { landing } = useUrls()
14
+ const authApiURL = commonAuth.authApiURL
15
+ const redirectUrl = useCookie('redirect_url')
16
+ const { loginModal, registrationModal, confirmAccountOtpModal, intermediateState } = useIdModals()
17
+
18
+ export interface RegistrationForm {
19
+ email: string
20
+ password: string
21
+ password_confirmation: string
22
+ }
23
+
24
+ const form = reactive<RegistrationForm>({
25
+ email: '',
26
+ password: '',
27
+ password_confirmation: '',
28
+ })
29
+
30
+ const agreement = ref(false)
31
+ const loading = ref(false)
32
+
33
+ const registerSchema = z.object({
34
+ email: z.string().nonempty(t('error.required')).email(t('error.email')),
35
+ password: z
36
+ .string()
37
+ .nonempty(t('error.required'))
38
+ .min(8, t('modals.id.register.errors.low_security', { length: 8 }))
39
+ .regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('modals.id.register.errors.low_security')),
40
+ password_confirmation: z
41
+ .string()
42
+ .nonempty(t('error.required'))
43
+ .min(8, t('modals.id.register.errors.low_security', { length: 8 }))
44
+ .regex(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/, t('modals.id.register.errors.low_security')),
45
+ }).refine(
46
+ data => data.password === data.password_confirmation,
47
+ {
48
+ message: t('modals.id.register.errors.sameAs'),
49
+ path: ['password_confirmation'],
50
+ },
51
+ )
52
+
53
+ const submitted = ref(false)
54
+
55
+ const validation = computed(() => {
56
+ if (!submitted.value) return null
57
+ const result = registerSchema.safeParse(form)
58
+ return result.success ? null : result.error
59
+ })
60
+
61
+ function getError(path: string) {
62
+ return validation.value?.issues?.find(issue => issue.path[0] === path)?.message
63
+ }
64
+
65
+ async function onSubmit() {
66
+ if (!agreement.value) return
67
+
68
+ submitted.value = true
69
+
70
+ if (validation.value) return
71
+
72
+ try {
73
+ loading.value = true
74
+ const { success, message } = await $fetch(`${removeTrailingSlash(authApiURL)}/v2/register`, {
75
+ method: 'POST',
76
+ credentials: 'include',
77
+ headers: {
78
+ lang: locale.value,
79
+ },
80
+ body: form,
81
+ })
82
+ if (success) {
83
+ intermediateState.value.email = form.email
84
+ intermediateState.value.password = form.password
85
+
86
+ registrationModal.value = false
87
+ confirmAccountOtpModal.value = true
88
+ }
89
+ }
90
+ catch (error) {
91
+ $toast.error(error.data.message.email || error.data.message.password[0])
92
+ }
93
+ finally {
94
+ loading.value = false
95
+ }
96
+ }
97
+
98
+ if (route.query.url) {
99
+ redirectUrl.value = route.query.url as string
100
+ }
101
+
102
+ // onMounted(() => {
103
+ // v$.value.$touch();
104
+ // });
105
+
106
+ function getUrl() {
107
+ return navigateTo(locale.value !== 'ru'
108
+ ? landing + localePath('/') + PAGES.userAgreement
109
+ : landing + PAGES.userAgreement, {
110
+ external: true,
111
+ open: {
112
+ target: '_blank',
113
+ },
114
+ })
115
+ }
116
+
117
+ function handleEnter(event: KeyboardEvent) {
118
+ if (event.key === 'Enter') {
119
+ onSubmit()
120
+ }
121
+ }
122
+
123
+ function onLogin() {
124
+ registrationModal.value = false
125
+ loginModal.value = true
126
+ }
127
+
128
+ watch(registrationModal, (value) => {
129
+ if (!value) {
130
+ form.email = ''
131
+ form.password = ''
132
+ form.password_confirmation = ''
133
+ agreement.value = false
134
+ }
135
+ })
136
+
137
+ onMounted(() => {
138
+ document.addEventListener('keyup', handleEnter)
139
+ })
140
+
141
+ onBeforeUnmount(() => {
142
+ document.removeEventListener('keyup', handleEnter)
143
+ })
144
+ </script>
145
+
146
+ <template>
147
+ <form
148
+ class="flex flex-col items-stretch gap-5"
149
+ novalidate
150
+ @submit.prevent="onSubmit"
151
+ >
152
+ <h2 class="text-center text-2xl font-bold">
153
+ {{ t('modals.id.register.title') }}
154
+ </h2>
155
+ <p class="text-center text-sm">
156
+ {{ t('modals.id.register.subtitle') }}
157
+ </p>
158
+ <a-input-standard
159
+ v-model="form.email"
160
+ :label="t('modals.id.register.labels.email')"
161
+ :error="getError('email')"
162
+ type="email"
163
+ />
164
+
165
+ <a-input-password
166
+ v-model="form.password"
167
+ :label="t('modals.id.register.labels.password')"
168
+ :error="getError('password')"
169
+ />
170
+
171
+ <a-input-password
172
+ v-model="form.password_confirmation"
173
+ :label="t('modals.id.register.labels.password_confirmation')"
174
+ :error="getError('password_confirmation')"
175
+ />
176
+ <a-alert color="blue">
177
+ {{ t('modals.id.register.alert') }}
178
+ <template #icon>
179
+ <a-icon-info-circle />
180
+ </template>
181
+ </a-alert>
182
+ <a-checkbox
183
+ v-model="agreement"
184
+ side="right"
185
+ name="confirm-agreement"
186
+ >
187
+ <i18n-t keypath="modals.id.register.agreement.text">
188
+ <template #link>
189
+ <nuxt-link-locale
190
+ class="text-blue-700"
191
+ @click="getUrl"
192
+ >
193
+ {{ t('modals.id.register.agreement.link') }}
194
+ </nuxt-link-locale>
195
+ </template>
196
+ </i18n-t>
197
+ </a-checkbox>
198
+ <a-button
199
+ :disabled="!agreement"
200
+ :loading="loading"
201
+ >
202
+ {{ t('modals.id.register.continue') }}
203
+ </a-button>
204
+ <p class="text-center text-sm">
205
+ {{ t('modals.id.register.haveAcc') }}
206
+ </p>
207
+ <a-button
208
+ type="button"
209
+ view="outline"
210
+ @click="onLogin"
211
+ >
212
+ {{ t('modals.id.register.enter') }}
213
+ </a-button>
214
+ </form>
215
+ </template>
@@ -0,0 +1,158 @@
1
+ <script setup lang="ts">
2
+ import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
3
+ import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
4
+
5
+ const { $toast } = useNuxtApp()
6
+ const { t, locale } = useI18n()
7
+ const { commonAuth } = useAppConfig()
8
+
9
+ const { resetPasswordOtpModal, newPasswordModal, intermediateState } = useIdModals()
10
+
11
+ const authApiURL = commonAuth.authApiURL
12
+
13
+ const otp = ref(['', '', '', '', '', ''])
14
+ const otpFormatted = computed(() => {
15
+ return otp.value.join('')
16
+ })
17
+ const showError = ref(false)
18
+ const isLoading = ref(false)
19
+
20
+ async function onConfirm() {
21
+ try {
22
+ isLoading.value = true
23
+
24
+ const response = await $fetch(`${removeTrailingSlash(authApiURL)}/password/validate-otp`, {
25
+ method: 'POST',
26
+ credentials: 'include',
27
+ headers: {
28
+ lang: locale.value,
29
+ },
30
+ body: {
31
+ email: intermediateState.value.email,
32
+ otp: otpFormatted.value,
33
+ },
34
+ })
35
+
36
+ intermediateState.value.token = response.data
37
+ intermediateState.value.otp = otpFormatted.value
38
+
39
+ resetPasswordOtpModal.value = false
40
+ newPasswordModal.value = true
41
+ }
42
+ catch (error) {
43
+ showError.value = true
44
+ }
45
+ finally {
46
+ isLoading.value = false
47
+ }
48
+ }
49
+
50
+ function resetOtp() {
51
+ otp.value = ['', '', '', '', '', '']
52
+ showError.value = false
53
+ }
54
+
55
+ function onClose() {
56
+ resetOtp()
57
+ resetPasswordOtpModal.value = false
58
+ }
59
+
60
+ const isResendLoading = ref(false)
61
+ async function onResend() {
62
+ try {
63
+ isResendLoading.value = true
64
+ await $fetch(`${removeTrailingSlash(authApiURL)}/password/email-otp`, {
65
+ method: 'POST',
66
+ credentials: 'include',
67
+ headers: {
68
+ lang: locale.value,
69
+ },
70
+ body: {
71
+ email: intermediateState.value.email,
72
+ },
73
+ })
74
+ resetOtp()
75
+ runTimer()
76
+ isResendLoading.value = false
77
+ }
78
+ catch (error) {
79
+ $toast.error(error.data.message)
80
+ }
81
+ }
82
+
83
+ function handleEnter(e: KeyboardEvent) {
84
+ if (e.key === 'Enter') {
85
+ onConfirm()
86
+ }
87
+ }
88
+
89
+ const timer = ref(60)
90
+
91
+ function runTimer() {
92
+ timer.value = 60
93
+ const intervalId = setInterval(() => {
94
+ if (!timer.value) clearInterval(intervalId)
95
+ return timer.value--
96
+ }, 1000)
97
+ }
98
+
99
+ onMounted(() => {
100
+ runTimer()
101
+ document.addEventListener('keyup', handleEnter)
102
+ })
103
+
104
+ onBeforeUnmount(() => {
105
+ document.removeEventListener('keyup', handleEnter)
106
+ })
107
+ </script>
108
+
109
+ <template>
110
+ <div class="flex flex-col items-center gap-4 text-center">
111
+ <h2 class="text-2xl font-bold">
112
+ {{ t('modals.id.resetPasswordOtp.title') }}
113
+ </h2>
114
+
115
+ <a-icon-hand-with-phone-light class="size-32 dark:hidden" />
116
+ <a-icon-hand-with-phone-dark class="hidden size-32 dark:block" />
117
+
118
+ <div class="text-sm">
119
+ <p class="mb-1">
120
+ {{ t('modals.id.resetPasswordOtp.content') }}
121
+ </p>
122
+
123
+ <div v-if="timer > 0" class="text-2xl font-bold">
124
+ {{ timer }} {{ t('modals.id.resetPasswordOtp.seconds') }}
125
+ </div>
126
+ <button
127
+ v-else
128
+ class="text-blue-700 dark:text-blue-500 flex items-center gap-2 mx-auto"
129
+ @click="onResend"
130
+ :disabled="isResendLoading"
131
+ >
132
+ <a-icon-loader-circle
133
+ v-if="isResendLoading"
134
+ class="animate-spin"
135
+ ></a-icon-loader-circle>
136
+ <span>{{ t('actions.resend') }}</span>
137
+ </button>
138
+ </div>
139
+
140
+ <id-otp-input
141
+ v-model="otp"
142
+ v-model:error="showError"
143
+ @on-completed="onConfirm"
144
+ />
145
+
146
+ <a-button
147
+ block
148
+ view="outline"
149
+ @click="onClose"
150
+ >
151
+ {{ t('actions.close') }}
152
+ </a-button>
153
+ </div>
154
+ </template>
155
+
156
+ <style scoped>
157
+
158
+ </style>
@@ -0,0 +1,130 @@
1
+ <script setup lang="ts">
2
+ import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
3
+ import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
4
+ import { useUrls } from '#adata-ui/composables/useUrls'
5
+
6
+ const { $toast } = useNuxtApp()
7
+ const { t, locale } = useI18n()
8
+ const { commonAuth } = useAppConfig()
9
+ const { pk } = useUrls()
10
+
11
+ const { twoFactorModal, intermediateState } = useIdModals()
12
+
13
+ const authApiURL = commonAuth.authApiURL
14
+ const regex = /^\/counterparty\/main\/company\/\d+\/basic-info$/;
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
+ isLoading.value = true
25
+ const login = await fetch(`${removeTrailingSlash(authApiURL)}/login`, {
26
+ method: 'POST',
27
+ credentials: 'include',
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ 'lang': locale.value,
31
+ },
32
+ body: JSON.stringify({
33
+ 'username': intermediateState.value.email,
34
+ 'password': intermediateState.value.password,
35
+ '2fa_code': otpFormatted.value,
36
+ }),
37
+ })
38
+ const { data, message } = await login.json().catch(() => ({}))
39
+
40
+ if (login.status > 202) {
41
+ if (login.status === 403) {
42
+ showError.value = true
43
+ isLoading.value = false
44
+ }
45
+ }
46
+ else {
47
+ const response = await fetch(`${removeTrailingSlash(authApiURL)}/access/cookie`, {
48
+ method: 'GET',
49
+ credentials: 'include',
50
+ headers: {
51
+ lang: locale.value,
52
+ },
53
+ })
54
+ const { data: cookiesData } = await response.json()
55
+ if (cookiesData?.access_token) {
56
+ const { access_token, expire_in } = cookiesData
57
+ const hostname = location.hostname.split('.').reverse()
58
+ useCookie('autoLogout').value = true
59
+
60
+ useCookie('accessToken', {
61
+ maxAge: expire_in,
62
+ domain: `.${hostname[1]}.${hostname[0]}`,
63
+ path: '/',
64
+ secure: true,
65
+ }).value = access_token
66
+ }
67
+ $toast.success(t('login.successfully'))
68
+ twoFactorModal.value = false
69
+
70
+ const path = window.location.pathname;
71
+
72
+ if (regex.test(path)) {
73
+ navigateTo(`${pk}/company/${path.split("/")[4]}`, { external: true })
74
+ } else {
75
+ window.location.reload()
76
+ }
77
+ }
78
+ isLoading.value = false
79
+ }
80
+
81
+ function onClose() {
82
+ otp.value = ['', '', '', '', '', '']
83
+ showError.value = false
84
+ twoFactorModal.value = false
85
+ }
86
+
87
+ function handleEnter(e: KeyboardEvent) {
88
+ if (e.key === 'Enter') {
89
+ onConfirm()
90
+ }
91
+ }
92
+
93
+ onMounted(() => {
94
+ document.addEventListener('keyup', handleEnter)
95
+ })
96
+
97
+ onBeforeUnmount(() => {
98
+ document.removeEventListener('keyup', handleEnter)
99
+ })
100
+ </script>
101
+
102
+ <template>
103
+ <div class="flex flex-col items-center gap-4">
104
+ <p class="heading-02 text-center">
105
+ {{ t('modals.id.twoFactor.title') }}
106
+ </p>
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
+ <id-otp-input
110
+ v-model="otp"
111
+ v-model:error="showError"
112
+ @on-completed="onConfirm"
113
+ />
114
+ <p class="body-400 text-center">
115
+ {{ t('modals.id.twoFactor.code') }}
116
+ </p>
117
+
118
+ <a-button
119
+ class="w-full"
120
+ view="outline"
121
+ @click="onClose"
122
+ >
123
+ {{ t('actions.close') }}
124
+ </a-button>
125
+ </div>
126
+ </template>
127
+
128
+ <style scoped>
129
+
130
+ </style>
@@ -1 +1 @@
1
- # breadcrumb, tabs
1
+ # breadcrumb, tabs