adata-ui 2.0.24 → 2.0.26
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/ContentNavigationModal.vue +38 -32
- package/components/modals/Resend.vue +81 -81
- 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/README.md +1 -1
- package/components/overlays/README.md +1 -1
- package/composables/useIdModals.ts +10 -2
- package/icons/chart-pie.vue +16 -0
- 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/work-case.vue +9 -0
- package/icons/yandex.vue +28 -28
- package/lang/ru.ts +16 -5
- package/layouts/default.vue +13 -13
- package/nuxt.config.ts +1 -0
- package/package.json +3 -1
- package/stores/auth.store.ts +12 -0
- package/components/modals/Accept.vue +0 -45
- package/components/modals/id/IdEmailModal.vue +0 -29
package/.nuxtrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
typescript.includeWorkspace = true
|
|
1
|
+
typescript.includeWorkspace = true
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export default defineAppConfig({
|
|
2
|
-
myLayer: {
|
|
3
|
-
name: 'My amazing Nuxt layer (overwritten)'
|
|
4
|
-
}
|
|
5
|
-
})
|
|
1
|
+
export default defineAppConfig({
|
|
2
|
+
myLayer: {
|
|
3
|
+
name: 'My amazing Nuxt layer (overwritten)'
|
|
4
|
+
}
|
|
5
|
+
})
|
package/README.md
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
# Adata UI with Nuxt 3 using Layers
|
|
2
|
-
|
|
3
|
-
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
|
4
|
-
|
|
5
|
-
## Setup
|
|
6
|
-
|
|
7
|
-
Make sure to install the dependencies:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# npm
|
|
11
|
-
npm install
|
|
12
|
-
|
|
13
|
-
# pnpm
|
|
14
|
-
pnpm install
|
|
15
|
-
|
|
16
|
-
# yarn
|
|
17
|
-
yarn install
|
|
18
|
-
|
|
19
|
-
# bun
|
|
20
|
-
bun install
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Development Server
|
|
24
|
-
|
|
25
|
-
Start the development server on `https://localhost:3000`:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
# npm
|
|
29
|
-
npm run dev
|
|
30
|
-
|
|
31
|
-
# pnpm
|
|
32
|
-
pnpm run dev
|
|
33
|
-
|
|
34
|
-
# yarn
|
|
35
|
-
yarn dev
|
|
36
|
-
|
|
37
|
-
# bun
|
|
38
|
-
bun run dev
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Production
|
|
42
|
-
|
|
43
|
-
Build the application for production:
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
# npm
|
|
47
|
-
npm run build
|
|
48
|
-
|
|
49
|
-
# pnpm
|
|
50
|
-
pnpm run build
|
|
51
|
-
|
|
52
|
-
# yarn
|
|
53
|
-
yarn build
|
|
54
|
-
|
|
55
|
-
# bun
|
|
56
|
-
bun run build
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Locally preview production build:
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
# npm
|
|
63
|
-
npm run preview
|
|
64
|
-
|
|
65
|
-
# pnpm
|
|
66
|
-
pnpm run preview
|
|
67
|
-
|
|
68
|
-
# yarn
|
|
69
|
-
yarn preview
|
|
70
|
-
|
|
71
|
-
# bun
|
|
72
|
-
bun run preview
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
|
1
|
+
# Adata UI with Nuxt 3 using Layers
|
|
2
|
+
|
|
3
|
+
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
Make sure to install the dependencies:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# npm
|
|
11
|
+
npm install
|
|
12
|
+
|
|
13
|
+
# pnpm
|
|
14
|
+
pnpm install
|
|
15
|
+
|
|
16
|
+
# yarn
|
|
17
|
+
yarn install
|
|
18
|
+
|
|
19
|
+
# bun
|
|
20
|
+
bun install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Development Server
|
|
24
|
+
|
|
25
|
+
Start the development server on `https://localhost:3000`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# npm
|
|
29
|
+
npm run dev
|
|
30
|
+
|
|
31
|
+
# pnpm
|
|
32
|
+
pnpm run dev
|
|
33
|
+
|
|
34
|
+
# yarn
|
|
35
|
+
yarn dev
|
|
36
|
+
|
|
37
|
+
# bun
|
|
38
|
+
bun run dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Production
|
|
42
|
+
|
|
43
|
+
Build the application for production:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# npm
|
|
47
|
+
npm run build
|
|
48
|
+
|
|
49
|
+
# pnpm
|
|
50
|
+
pnpm run build
|
|
51
|
+
|
|
52
|
+
# yarn
|
|
53
|
+
yarn build
|
|
54
|
+
|
|
55
|
+
# bun
|
|
56
|
+
bun run build
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Locally preview production build:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# npm
|
|
63
|
+
npm run preview
|
|
64
|
+
|
|
65
|
+
# pnpm
|
|
66
|
+
pnpm run preview
|
|
67
|
+
|
|
68
|
+
# yarn
|
|
69
|
+
yarn preview
|
|
70
|
+
|
|
71
|
+
# bun
|
|
72
|
+
bun run preview
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
# button, alerts, dropdown
|
|
1
|
+
# button, alerts, dropdown
|
|
@@ -1 +1 @@
|
|
|
1
|
-
# inputs
|
|
1
|
+
# inputs
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const emit = defineEmits<{
|
|
3
|
-
(e: 'resend'): void
|
|
4
|
-
(e: 'close'): void
|
|
5
|
-
}>()
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<template>
|
|
9
|
-
<div class="flex flex-col justify-center items-center gap-5">
|
|
10
|
-
<p class="heading-02">
|
|
11
|
-
{{ $t('login.modal.title') }}
|
|
12
|
-
</p>
|
|
13
|
-
<a-ill-mail />
|
|
14
|
-
<p class="body-400 text-center">
|
|
15
|
-
{{ $t('login.modal.subtitle1') }}
|
|
16
|
-
</p>
|
|
17
|
-
<p class="body-400 text-center">
|
|
18
|
-
{{ $t('login.modal.confirmationEmail') }}
|
|
19
|
-
</p>
|
|
20
|
-
<div class="flex flex-col gap-2 w-full">
|
|
21
|
-
<a-button
|
|
22
|
-
class="w-full"
|
|
23
|
-
view="outline"
|
|
24
|
-
@click="emit('close')"
|
|
25
|
-
>
|
|
26
|
-
{{ $t('login.modal.back') }}
|
|
27
|
-
</a-button>
|
|
28
|
-
<a-button
|
|
29
|
-
class="w-full"
|
|
30
|
-
@click="emit('resend')"
|
|
31
|
-
>
|
|
32
|
-
{{ $t('login.modal.resend') }}
|
|
33
|
-
</a-button>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
</template>
|
|
37
|
-
|
|
38
|
-
<style scoped>
|
|
39
|
-
|
|
40
|
-
</style>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const emit = defineEmits<{
|
|
3
|
+
(e: 'resend'): void
|
|
4
|
+
(e: 'close'): void
|
|
5
|
+
}>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<div class="flex flex-col justify-center items-center gap-5">
|
|
10
|
+
<p class="heading-02">
|
|
11
|
+
{{ $t('login.modal.title') }}
|
|
12
|
+
</p>
|
|
13
|
+
<a-ill-mail />
|
|
14
|
+
<p class="body-400 text-center">
|
|
15
|
+
{{ $t('login.modal.subtitle1') }}
|
|
16
|
+
</p>
|
|
17
|
+
<p class="body-400 text-center">
|
|
18
|
+
{{ $t('login.modal.confirmationEmail') }}
|
|
19
|
+
</p>
|
|
20
|
+
<div class="flex flex-col gap-2 w-full">
|
|
21
|
+
<a-button
|
|
22
|
+
class="w-full"
|
|
23
|
+
view="outline"
|
|
24
|
+
@click="emit('close')"
|
|
25
|
+
>
|
|
26
|
+
{{ $t('login.modal.back') }}
|
|
27
|
+
</a-button>
|
|
28
|
+
<a-button
|
|
29
|
+
class="w-full"
|
|
30
|
+
@click="emit('resend')"
|
|
31
|
+
>
|
|
32
|
+
{{ $t('login.modal.resend') }}
|
|
33
|
+
</a-button>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<style scoped>
|
|
39
|
+
|
|
40
|
+
</style>
|
|
@@ -26,6 +26,7 @@ import {useCurrentModule} from "#adata-ui/composables/projectState";
|
|
|
26
26
|
import IconCalc from '#adata-ui/icons/calculator.vue'
|
|
27
27
|
import { buildLocalizedUrl } from '#adata-ui/utils/localizedNavigation'
|
|
28
28
|
import { AIconFiles } from '#components'
|
|
29
|
+
import MapPinRect from '#adata-ui/icons/map/map-pin-rect.vue'
|
|
29
30
|
type Emits = {
|
|
30
31
|
(e: 'pushMain'): void
|
|
31
32
|
}
|
|
@@ -37,6 +38,10 @@ const emits = defineEmits<Emits>()
|
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
const tabOptions = [
|
|
41
|
+
{
|
|
42
|
+
name: 'header.products.edo.label',
|
|
43
|
+
key: 'edo',
|
|
44
|
+
},
|
|
40
45
|
{
|
|
41
46
|
name: 'header.products.counterparties.label',
|
|
42
47
|
key: 'pk',
|
|
@@ -49,14 +54,14 @@ const tabOptions = [
|
|
|
49
54
|
name: 'header.products.tenders.label',
|
|
50
55
|
key: 'tenders',
|
|
51
56
|
},
|
|
52
|
-
{
|
|
53
|
-
name: 'header.products.fines.label',
|
|
54
|
-
key: 'fines',
|
|
55
|
-
},
|
|
56
57
|
{
|
|
57
58
|
name: 'header.products.analytics.label',
|
|
58
59
|
key: 'analytics',
|
|
59
60
|
},
|
|
61
|
+
{
|
|
62
|
+
name: 'header.products.fines.label',
|
|
63
|
+
key: 'fines',
|
|
64
|
+
},
|
|
60
65
|
{
|
|
61
66
|
name: 'header.products.fea.label',
|
|
62
67
|
key: 'fea',
|
|
@@ -65,12 +70,15 @@ const tabOptions = [
|
|
|
65
70
|
name: 'header.products.compliance.label',
|
|
66
71
|
key: 'compliance',
|
|
67
72
|
},
|
|
68
|
-
{
|
|
69
|
-
name: 'header.products.edo.label',
|
|
70
|
-
key: 'edo',
|
|
71
|
-
}
|
|
72
73
|
]
|
|
73
74
|
const sideLinks = <any>{
|
|
75
|
+
edo: [
|
|
76
|
+
{
|
|
77
|
+
label: 'header.products.edo.label',
|
|
78
|
+
icon: AIconFiles,
|
|
79
|
+
link: 'https://edo.adata.kz' + PAGES.edo.l
|
|
80
|
+
}
|
|
81
|
+
],
|
|
74
82
|
pk: [
|
|
75
83
|
{
|
|
76
84
|
icon: IconSearch,
|
|
@@ -147,23 +155,6 @@ const sideLinks = <any>{
|
|
|
147
155
|
link: myLayer.tenderUrl + PAGES.tender.plans
|
|
148
156
|
}
|
|
149
157
|
],
|
|
150
|
-
fines: [
|
|
151
|
-
{
|
|
152
|
-
icon: IconCheckCircle,
|
|
153
|
-
label: 'header.products.fines.items.fines.title',
|
|
154
|
-
link: myLayer.avtoUrl + PAGES.fines.main
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
icon: IconCar,
|
|
158
|
-
label: 'header.products.fines.items.auto.title',
|
|
159
|
-
link: myLayer.avtoUrl + PAGES.fines.avto
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
icon: IconTruck,
|
|
163
|
-
label: 'header.products.fines.items.wholesaleAuto.title',
|
|
164
|
-
link: myLayer.avtoUrl + PAGES.fines.bulk
|
|
165
|
-
}
|
|
166
|
-
],
|
|
167
158
|
analytics: [
|
|
168
159
|
// {
|
|
169
160
|
// icon: IconSearch,
|
|
@@ -191,6 +182,23 @@ const sideLinks = <any>{
|
|
|
191
182
|
link: myLayer.analyticsNewUrl + PAGES.analytics.rating
|
|
192
183
|
}
|
|
193
184
|
],
|
|
185
|
+
fines: [
|
|
186
|
+
{
|
|
187
|
+
icon: IconCheckCircle,
|
|
188
|
+
label: 'header.products.fines.items.fines.title',
|
|
189
|
+
link: myLayer.avtoUrl + PAGES.fines.main
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
icon: IconCar,
|
|
193
|
+
label: 'header.products.fines.items.auto.title',
|
|
194
|
+
link: myLayer.avtoUrl + PAGES.fines.avto
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
icon: IconTruck,
|
|
198
|
+
label: 'header.products.fines.items.wholesaleAuto.title',
|
|
199
|
+
link: myLayer.avtoUrl + PAGES.fines.bulk
|
|
200
|
+
}
|
|
201
|
+
],
|
|
194
202
|
fea: [
|
|
195
203
|
{
|
|
196
204
|
label: 'header.products.fea.items.i.t',
|
|
@@ -216,6 +224,11 @@ const sideLinks = <any>{
|
|
|
216
224
|
label: 'header.products.fea.items.tr.t',
|
|
217
225
|
icon: IconGlobe,
|
|
218
226
|
link: `${myLayer.tnvedUrl}${PAGES.fea.tr}`
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
label: 'header.products.fea.items.importerMap.t',
|
|
230
|
+
icon: MapPinRect,
|
|
231
|
+
link: `${myLayer.tnvedUrl}${PAGES.fea.importerMap}`
|
|
219
232
|
}
|
|
220
233
|
],
|
|
221
234
|
compliance: [
|
|
@@ -225,13 +238,6 @@ const sideLinks = <any>{
|
|
|
225
238
|
link: myLayer.complianceUrl + PAGES.compliance.l
|
|
226
239
|
}
|
|
227
240
|
],
|
|
228
|
-
edo: [
|
|
229
|
-
{
|
|
230
|
-
label: 'header.products.edo.label',
|
|
231
|
-
icon: AIconFiles,
|
|
232
|
-
link: 'https://edo.adata.kz' + PAGES.edo.l
|
|
233
|
-
}
|
|
234
|
-
]
|
|
235
241
|
}
|
|
236
242
|
const currentLinks = ref(sideLinks[tab.value])
|
|
237
243
|
|
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
|
|
3
|
-
const emit = defineEmits<{
|
|
4
|
-
(e: 'resend'): void
|
|
5
|
-
(e: 'close'): void
|
|
6
|
-
}>()
|
|
7
|
-
|
|
8
|
-
const timer = ref(60)
|
|
9
|
-
const isResend = ref(false)
|
|
10
|
-
const route = useRoute()
|
|
11
|
-
const appConfig = useAppConfig()
|
|
12
|
-
const landingUrl = appConfig.myLayer.landingUrl
|
|
13
|
-
|
|
14
|
-
function runTimer() {
|
|
15
|
-
timer.value = 60
|
|
16
|
-
const intervalId = setInterval(() => {
|
|
17
|
-
if (timer.value <= 0) {
|
|
18
|
-
isResend.value = true
|
|
19
|
-
clearInterval(intervalId);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
timer.value--;
|
|
23
|
-
}, 1000);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
onMounted(() => resend())
|
|
27
|
-
|
|
28
|
-
const resend = () => {
|
|
29
|
-
isResend.value = false
|
|
30
|
-
runTimer()
|
|
31
|
-
emit('resend')
|
|
32
|
-
}
|
|
33
|
-
const goToMain = () => {
|
|
34
|
-
if (route.query.url) {
|
|
35
|
-
document.location.replace(route.query.url)
|
|
36
|
-
} else {
|
|
37
|
-
document.location.replace(landingUrl)
|
|
38
|
-
}
|
|
39
|
-
emit('close')
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
</script>
|
|
43
|
-
|
|
44
|
-
<template>
|
|
45
|
-
<div class="flex flex-col justify-center items-center gap-5">
|
|
46
|
-
<p class="heading-02">
|
|
47
|
-
{{ $t('login.modal.title') }}
|
|
48
|
-
</p>
|
|
49
|
-
<a-ill-mail />
|
|
50
|
-
<p class="body-400 text-center">
|
|
51
|
-
{{ $t('login.modal.subtitle1') }}
|
|
52
|
-
</p>
|
|
53
|
-
<p class="body-400 text-center">
|
|
54
|
-
{{ $t('login.modal.subtitle2') }}
|
|
55
|
-
</p>
|
|
56
|
-
<p
|
|
57
|
-
v-if="!isResend"
|
|
58
|
-
class="heading-02"
|
|
59
|
-
>
|
|
60
|
-
{{ timer }} {{ $t('login.modal.seconds') }}
|
|
61
|
-
</p>
|
|
62
|
-
<a-button
|
|
63
|
-
v-else
|
|
64
|
-
class="w-full"
|
|
65
|
-
view="outline"
|
|
66
|
-
@click="resend"
|
|
67
|
-
>
|
|
68
|
-
{{ $t('login.modal.resend') }}
|
|
69
|
-
</a-button>
|
|
70
|
-
<a-button
|
|
71
|
-
class="w-full"
|
|
72
|
-
@click="goToMain"
|
|
73
|
-
>
|
|
74
|
-
{{ $t('login.modal.back') }}
|
|
75
|
-
</a-button>
|
|
76
|
-
</div>
|
|
77
|
-
</template>
|
|
78
|
-
|
|
79
|
-
<style scoped>
|
|
80
|
-
|
|
81
|
-
</style>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
const emit = defineEmits<{
|
|
4
|
+
(e: 'resend'): void
|
|
5
|
+
(e: 'close'): void
|
|
6
|
+
}>()
|
|
7
|
+
|
|
8
|
+
const timer = ref(60)
|
|
9
|
+
const isResend = ref(false)
|
|
10
|
+
const route = useRoute()
|
|
11
|
+
const appConfig = useAppConfig()
|
|
12
|
+
const landingUrl = appConfig.myLayer.landingUrl
|
|
13
|
+
|
|
14
|
+
function runTimer() {
|
|
15
|
+
timer.value = 60
|
|
16
|
+
const intervalId = setInterval(() => {
|
|
17
|
+
if (timer.value <= 0) {
|
|
18
|
+
isResend.value = true
|
|
19
|
+
clearInterval(intervalId);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
timer.value--;
|
|
23
|
+
}, 1000);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
onMounted(() => resend())
|
|
27
|
+
|
|
28
|
+
const resend = () => {
|
|
29
|
+
isResend.value = false
|
|
30
|
+
runTimer()
|
|
31
|
+
emit('resend')
|
|
32
|
+
}
|
|
33
|
+
const goToMain = () => {
|
|
34
|
+
if (route.query.url) {
|
|
35
|
+
document.location.replace(route.query.url)
|
|
36
|
+
} else {
|
|
37
|
+
document.location.replace(landingUrl)
|
|
38
|
+
}
|
|
39
|
+
emit('close')
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<div class="flex flex-col justify-center items-center gap-5">
|
|
46
|
+
<p class="heading-02">
|
|
47
|
+
{{ $t('login.modal.title') }}
|
|
48
|
+
</p>
|
|
49
|
+
<a-ill-mail />
|
|
50
|
+
<p class="body-400 text-center">
|
|
51
|
+
{{ $t('login.modal.subtitle1') }}
|
|
52
|
+
</p>
|
|
53
|
+
<p class="body-400 text-center">
|
|
54
|
+
{{ $t('login.modal.subtitle2') }}
|
|
55
|
+
</p>
|
|
56
|
+
<p
|
|
57
|
+
v-if="!isResend"
|
|
58
|
+
class="heading-02"
|
|
59
|
+
>
|
|
60
|
+
{{ timer }} {{ $t('login.modal.seconds') }}
|
|
61
|
+
</p>
|
|
62
|
+
<a-button
|
|
63
|
+
v-else
|
|
64
|
+
class="w-full"
|
|
65
|
+
view="outline"
|
|
66
|
+
@click="resend"
|
|
67
|
+
>
|
|
68
|
+
{{ $t('login.modal.resend') }}
|
|
69
|
+
</a-button>
|
|
70
|
+
<a-button
|
|
71
|
+
class="w-full"
|
|
72
|
+
@click="goToMain"
|
|
73
|
+
>
|
|
74
|
+
{{ $t('login.modal.back') }}
|
|
75
|
+
</a-button>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<style scoped>
|
|
80
|
+
|
|
81
|
+
</style>
|
|
@@ -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>
|