adata-ui 3.1.49 → 3.1.51

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 (44) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +14 -1
  3. package/dist/runtime/components/SidePanel.vue +370 -0
  4. package/dist/runtime/components/SidePanel.vue.d.ts +68 -0
  5. package/dist/runtime/components/header/ProductMenu.vue +6 -6
  6. package/dist/runtime/components/mobile-navigation/MobileProductMenu.vue +5 -5
  7. package/dist/runtime/components/payment/process/PaymentKaspiQrSidePanel.vue +148 -0
  8. package/dist/runtime/components/payment/process/PaymentKaspiQrSidePanel.vue.d.ts +21 -0
  9. package/dist/runtime/components/payment/process/PaymentKaspiRedirectSidePanel.vue +97 -0
  10. package/dist/runtime/components/payment/process/PaymentKaspiRedirectSidePanel.vue.d.ts +20 -0
  11. package/dist/runtime/components/payment/process/PaymentMethodSidePanel.vue +106 -0
  12. package/dist/runtime/components/payment/process/PaymentMethodSidePanel.vue.d.ts +21 -0
  13. package/dist/runtime/components/payment/process/PaymentProcess.vue +112 -0
  14. package/dist/runtime/components/payment/process/PaymentProcess.vue.d.ts +2 -0
  15. package/dist/runtime/components/payment/process/PaymentTopUpSidePanel.vue +117 -0
  16. package/dist/runtime/components/payment/process/PaymentTopUpSidePanel.vue.d.ts +15 -0
  17. package/dist/runtime/composables/useAdaptive.d.ts +8 -0
  18. package/dist/runtime/composables/useAdaptive.js +27 -0
  19. package/dist/runtime/composables/usePayment.d.ts +8 -0
  20. package/dist/runtime/composables/usePayment.js +66 -0
  21. package/dist/runtime/i18n/i18n.config.d.ts +120 -0
  22. package/dist/runtime/icons/chevron/chevron-down.vue +16 -0
  23. package/dist/runtime/icons/chevron/chevron-down.vue.d.ts +2 -0
  24. package/dist/runtime/icons/chevron/chevron-left.vue +5 -0
  25. package/dist/runtime/icons/chevron/chevron-left.vue.d.ts +2 -0
  26. package/dist/runtime/icons/chevron/chevron-right.vue +5 -0
  27. package/dist/runtime/icons/chevron/chevron-right.vue.d.ts +2 -0
  28. package/dist/runtime/icons/chevron/chevron-up.vue +5 -0
  29. package/dist/runtime/icons/chevron/chevron-up.vue.d.ts +2 -0
  30. package/dist/runtime/icons/chevron/double-chevron-right.vue +12 -0
  31. package/dist/runtime/icons/chevron/double-chevron-right.vue.d.ts +2 -0
  32. package/dist/runtime/icons/kaspi-qr.vue +13 -0
  33. package/dist/runtime/icons/kaspi-qr.vue.d.ts +2 -0
  34. package/dist/runtime/icons/payment/payment-card.vue +6 -0
  35. package/dist/runtime/icons/payment/payment-card.vue.d.ts +2 -0
  36. package/dist/runtime/icons/payment/payment-kaspi.vue +11 -0
  37. package/dist/runtime/icons/payment/payment-kaspi.vue.d.ts +2 -0
  38. package/dist/runtime/lang/en.js +40 -0
  39. package/dist/runtime/lang/kk.js +40 -0
  40. package/dist/runtime/lang/ru.d.ts +40 -0
  41. package/dist/runtime/lang/ru.js +40 -0
  42. package/dist/runtime/plugins/toast.d.ts +24 -24
  43. package/dist/runtime/public/kaspi/logo.svg +4 -0
  44. package/package.json +4 -2
package/dist/module.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "nuxt": ">=3.16.0"
6
6
  },
7
7
  "failOnWarn": false,
8
- "version": "3.1.49",
8
+ "version": "3.1.51",
9
9
  "builder": {
10
10
  "@nuxt/module-builder": "1.0.1",
11
11
  "unbuild": "3.5.0"
package/dist/module.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defu } from 'defu';
2
- import { defineNuxtModule, createResolver, addVitePlugin, addComponentsDir, addPlugin, installModule, addImportsDir, hasNuxtModule } from '@nuxt/kit';
2
+ import { defineNuxtModule, createResolver, addVitePlugin, addComponentsDir, addPlugin, installModule, addImportsDir, extendViteConfig, setGlobalHead, hasNuxtModule } from '@nuxt/kit';
3
3
 
4
4
  const module = defineNuxtModule({
5
5
  meta: {
@@ -73,6 +73,19 @@ const module = defineNuxtModule({
73
73
  });
74
74
  addPlugin(resolver.resolve("./runtime/i18n"));
75
75
  addImportsDir(resolver.resolve("./runtime/composables"));
76
+ extendViteConfig((config) => {
77
+ config.optimizeDeps.include ||= ["qrcode"];
78
+ });
79
+ setGlobalHead({
80
+ script: [
81
+ {
82
+ src: "https://widget.tiptoppay.kz/bundles/widget.js",
83
+ defer: true,
84
+ async: true,
85
+ onerror: `console.error("Failed to load script: https://widget.tiptoppay.kz/bundles/widget.js");`
86
+ }
87
+ ]
88
+ });
76
89
  }
77
90
  });
78
91
 
@@ -0,0 +1,370 @@
1
+ <script setup>
2
+ import { disableBodyScroll, enableBodyScroll } from "body-scroll-lock";
3
+ import { useAdaptive } from "#adata-ui/composables/useAdaptive";
4
+ import { ref, useAttrs, onMounted, onBeforeUnmount, watch, computed } from "#imports";
5
+ const props = defineProps({
6
+ idName: { type: String, required: false, default: "vsp-container" },
7
+ hideCloseBtn: { type: Boolean, required: false },
8
+ noClose: { type: Boolean, required: false },
9
+ side: { type: String, required: false, default: "right" },
10
+ rerender: { type: Boolean, required: false },
11
+ zIndex: { type: [Number, String], required: false, default: "auto" },
12
+ width: { type: String, required: false, default: "auto" },
13
+ height: { type: String, required: false, default: "auto" },
14
+ lockScroll: { type: Boolean, required: false, default: true },
15
+ lockScrollHtml: { type: Boolean, required: false },
16
+ hideScrollbar: { type: Boolean, required: false, default: false },
17
+ overlayColor: { type: String, required: false, default: "black" },
18
+ overlayOpacity: { type: Number, required: false, default: 0.5 },
19
+ overlayDuration: { type: Number, required: false, default: 500 },
20
+ panelColor: { type: String, required: false, default: "bg-white dark:bg-gray-900" },
21
+ panelDuration: { type: Number, required: false, default: 300 },
22
+ transitionName: { type: String, required: false },
23
+ headerClass: { type: String, required: false },
24
+ bodyClass: { type: String, required: false },
25
+ footerClass: { type: String, required: false }
26
+ });
27
+ defineEmits(["opened", "closed"]);
28
+ const modelValue = defineModel();
29
+ let teleportContainer = void 0;
30
+ const panel = ref(null);
31
+ const overlay = ref(null);
32
+ const footer = ref(null);
33
+ const header = ref(null);
34
+ const body = ref(null);
35
+ const panelSide = ref(props.side);
36
+ const device = useAdaptive();
37
+ const zIndex = ref();
38
+ const isBodyAlreadyLocked = ref(false);
39
+ const attrs = useAttrs();
40
+ const closePanel = () => modelValue.value = false;
41
+ const lockUnlockBodyScroll = (elem, lock) => {
42
+ if (lock) {
43
+ setTimeout(() => {
44
+ disableBodyScroll(elem, {
45
+ reserveScrollBarGap: true,
46
+ allowTouchMove: elem && elem !== document.body
47
+ });
48
+ disableBodyScroll(elem, { reserveScrollBarGap: true });
49
+ if (props.lockScrollHtml) document.documentElement.style.overflow = "hidden";
50
+ }, 0);
51
+ return;
52
+ }
53
+ enableBodyScroll(elem);
54
+ if (props.lockScrollHtml) document.documentElement.style.removeProperty("overflow");
55
+ };
56
+ const getMaxZIndex = () => Math.max(
57
+ ...Array.from(
58
+ document.querySelectorAll("body *"),
59
+ (el) => Number.parseFloat(window.getComputedStyle(el).zIndex)
60
+ ).filter((zIndex2) => !Number.isNaN(zIndex2)),
61
+ 0
62
+ );
63
+ onMounted(() => {
64
+ zIndex.value = props.zIndex === "auto" ? getMaxZIndex() : props.zIndex;
65
+ const alreadyCreatedTarget = document.getElementById(props.idName);
66
+ if (alreadyCreatedTarget) return;
67
+ teleportContainer = document.createElement("div");
68
+ teleportContainer.setAttribute("id", props.idName);
69
+ document.body.appendChild(teleportContainer);
70
+ });
71
+ onBeforeUnmount(() => {
72
+ if (props.lockScroll && panel.value && modelValue.value) lockUnlockBodyScroll(panel.value, false);
73
+ if (teleportContainer) document.body.removeChild(teleportContainer);
74
+ });
75
+ watch(() => device.value, () => {
76
+ panelSide.value = device.value.isTablet || device.value.isSmallTablet ? "bottom" : props.side;
77
+ }, { immediate: true });
78
+ watch(() => [modelValue.value, panel.value], (newP, oldP) => {
79
+ const wasShown = oldP ? oldP[0] : false;
80
+ const [isShown, panelEl] = newP;
81
+ const isOpening = isShown;
82
+ const isClosing = wasShown && !isShown;
83
+ if (!panelEl) return;
84
+ if (isShown) {
85
+ if (props.lockScroll) lockUnlockBodyScroll(panelEl, true);
86
+ return;
87
+ }
88
+ if (!props.lockScroll || !isClosing || isBodyAlreadyLocked.value) return;
89
+ setTimeout(() => {
90
+ if (panelEl) lockUnlockBodyScroll(panelEl, false);
91
+ }, props.panelDuration);
92
+ }, { immediate: true });
93
+ const roundedClass = computed(() => {
94
+ const classes = {
95
+ left: "rounded-r-xl",
96
+ right: "rounded-l-xl",
97
+ top: "rounded-b-xl",
98
+ bottom: "rounded-t-xl"
99
+ };
100
+ return classes[panelSide.value];
101
+ });
102
+ const overlayStyles = computed(() => ({
103
+ "zIndex": zIndex.value,
104
+ "animationDuration": `${props.overlayDuration}ms`,
105
+ "--overlay-opacity": props.overlayOpacity,
106
+ "opacity": modelValue.value ? props.overlayOpacity : 0,
107
+ "backgroundColor": props.overlayColor,
108
+ "pointerEvents": !modelValue.value ? "none" : "all"
109
+ }));
110
+ const panelStyles = computed(() => ({
111
+ width: ["left", "right"].includes(panelSide.value) ? props.width : void 0,
112
+ maxWidth: "100%",
113
+ ...["top", "bottom"].includes(panelSide.value) ? {
114
+ height: device.value.isSmallTablet || device.value.isTablet ? "100%" : props.height,
115
+ maxHeight: device.value.isMobile ? "90%" : "100%"
116
+ } : {},
117
+ zIndex: zIndex.value,
118
+ animationDuration: `${props.panelDuration}ms`,
119
+ ...Object.assign({}, attrs.style)
120
+ }));
121
+ const positionStart = ref(0);
122
+ const isClose = ref(false);
123
+ const modalHeight = ref(0);
124
+ const touchstart = (event) => {
125
+ isClose.value = false;
126
+ positionStart.value = event.touches[0].clientY;
127
+ modalHeight.value = panel.value?.offsetHeight || 0;
128
+ };
129
+ const touchmove = (event) => {
130
+ if (!device.value.isSmallTablet && !device.value.isTablet) return;
131
+ event.preventDefault();
132
+ const touchPosition = event.touches[0].clientY;
133
+ const step = touchPosition - positionStart.value;
134
+ if (step < 0) return;
135
+ const newHeight = modalHeight.value - step;
136
+ panel.value.style.height = `${newHeight}px`;
137
+ isClose.value = step > 65;
138
+ };
139
+ const touchend = () => {
140
+ if (isClose.value) {
141
+ closePanel();
142
+ } else {
143
+ panel.value.style.height = `${modalHeight.value}px`;
144
+ }
145
+ };
146
+ </script>
147
+
148
+ <template>
149
+ <client-only>
150
+ <Teleport :to="`#${idName}`">
151
+ <div
152
+ class="vsp-wrapper"
153
+ :class="[modelValue && 'vsp-wrapper--active']"
154
+ >
155
+ <Transition name="overlay">
156
+ <div
157
+ v-show="modelValue"
158
+ ref="overlay"
159
+ class="vsp-overlay fixed top-0 left-0 w-full h-full"
160
+ :style="overlayStyles"
161
+ @click="() => noClose ? void 0 : closePanel()"
162
+ />
163
+ </Transition>
164
+ <Transition
165
+ :name="transitionName || `slide-${panelSide}`"
166
+ @after-enter="$emit('opened')"
167
+ @after-leave="$emit('closed')"
168
+ >
169
+ <div
170
+ v-if="rerender ? modelValue : true"
171
+ v-show="rerender ? true : modelValue"
172
+ ref="panel"
173
+ class="vsp fixed flex flex-col"
174
+ :class="[`vsp--${panelSide}-side`, $attrs.class, roundedClass, panelColor]"
175
+ :style="panelStyles"
176
+ >
177
+ <div
178
+ class="w-full flex justify-center items-center mt-1 lg:hidden"
179
+ @touchmove="touchmove"
180
+ @touchstart="touchstart"
181
+ @touchend="touchend"
182
+ >
183
+ <div class="h-1 w-10 bg-[#D9D9D9] rounded m-1" />
184
+ </div>
185
+ <div
186
+ v-if="!hideCloseBtn"
187
+ :class="roundedClass"
188
+ class="absolute w-8 px-2 py-4 bg-blue-700 text-white -left-8 top-8 cursor-pointer lg:block hidden"
189
+ @click="closePanel"
190
+ >
191
+ <i-x-mark />
192
+ </div>
193
+ <div
194
+ v-if="!!$slots.header"
195
+ ref="header"
196
+ :class="[headerClass, 'vsp__header border-b border-deepblue-100 dark:border-[#E3E5E80D] lg:px-8 p-4']"
197
+ @touchmove="touchmove"
198
+ @touchstart="touchstart"
199
+ @touchend="touchend"
200
+ >
201
+ <slot
202
+ name="header"
203
+ :close="closePanel"
204
+ />
205
+ </div>
206
+ <div
207
+ ref="body"
208
+ :class="[
209
+ bodyClass,
210
+ 'vsp__body overflow-y-auto relative flex-grow-1 h-full lg:px-8 p-4',
211
+ hideScrollbar ? 'vsp__body--hide-scroll' : ''
212
+ ]"
213
+ >
214
+ <slot
215
+ name="default"
216
+ :close="closePanel"
217
+ />
218
+ </div>
219
+ <div
220
+ v-if="!!$slots.footer"
221
+ ref="footer"
222
+ :class="[footerClass, 'vsp__footer border-t border-deepblue-100 dark:border-[#E3E5E80D] lg:px-8 p-4']"
223
+ >
224
+ <slot name="footer" />
225
+ </div>
226
+ </div>
227
+ </Transition>
228
+ </div>
229
+ </Teleport>
230
+ </client-only>
231
+ </template>
232
+
233
+ <style scoped>
234
+ .vsp-wrapper .vsp--right-side, .vsp-wrapper .vsp--left-side {
235
+ top: 0;
236
+ height: 100%;
237
+ }
238
+ .vsp-wrapper .vsp--right-side {
239
+ right: 0;
240
+ left: unset;
241
+ }
242
+ .vsp-wrapper .vsp--left-side {
243
+ right: unset;
244
+ left: 0;
245
+ }
246
+ .vsp-wrapper .vsp--bottom-side, .vsp-wrapper .vsp--top-side {
247
+ left: 0;
248
+ width: 100%;
249
+ }
250
+ .vsp-wrapper .vsp--bottom-side {
251
+ bottom: 0;
252
+ }
253
+ .vsp-wrapper .vsp--top-side {
254
+ top: 0;
255
+ }
256
+ .vsp-wrapper .vsp__body.overflow-y-auto::-webkit-scrollbar {
257
+ width: 8px;
258
+ }
259
+ .vsp-wrapper .vsp__body.overflow-y-auto::-webkit-scrollbar-thumb {
260
+ background: rgba(44, 62, 80, 0.2);
261
+ border-radius: 6px;
262
+ }
263
+ .vsp-wrapper .vsp__body.vsp__body--hide-scroll {
264
+ scrollbar-width: none;
265
+ }
266
+ .vsp-wrapper .vsp__body.vsp__body--hide-scroll::-webkit-scrollbar {
267
+ width: 0;
268
+ height: 0;
269
+ }
270
+ .vsp-wrapper .overlay-enter-active,
271
+ .vsp-wrapper .overlay-leave-active {
272
+ animation: overlay-transition;
273
+ }
274
+ .vsp-wrapper .overlay-leave-active {
275
+ animation-direction: reverse;
276
+ }
277
+ .vsp-wrapper .slide-right-enter-active,
278
+ .vsp-wrapper .slide-right-leave-active {
279
+ animation: slide-right;
280
+ }
281
+ .vsp-wrapper .slide-right-leave-active {
282
+ animation-direction: reverse;
283
+ }
284
+ .vsp-wrapper .slide-left-enter-active,
285
+ .vsp-wrapper .slide-left-leave-active {
286
+ animation: slide-left;
287
+ }
288
+ .vsp-wrapper .slide-left-leave-active {
289
+ animation-direction: reverse;
290
+ }
291
+ .vsp-wrapper .slide-top-enter-active,
292
+ .vsp-wrapper .slide-top-leave-active {
293
+ animation: slide-left;
294
+ }
295
+ .vsp-wrapper .slide-top-leave-active {
296
+ animation-direction: reverse;
297
+ }
298
+ .vsp-wrapper .slide-top-enter-active,
299
+ .vsp-wrapper .slide-top-leave-active {
300
+ animation: slide-top;
301
+ }
302
+ .vsp-wrapper .slide-top-leave-active {
303
+ animation-direction: reverse;
304
+ }
305
+ .vsp-wrapper .slide-bottom-enter-active,
306
+ .vsp-wrapper .slide-bottom-leave-active {
307
+ animation: slide-bottom;
308
+ }
309
+ .vsp-wrapper .slide-bottom-leave-active {
310
+ animation-direction: reverse;
311
+ }
312
+ @keyframes slide-right {
313
+ 0% {
314
+ transform: translateX(100%);
315
+ opacity: 0;
316
+ }
317
+ 100% {
318
+ transform: translateX(0);
319
+ opacity: 1;
320
+ }
321
+ }
322
+ @keyframes slide-left {
323
+ 0% {
324
+ transform: translateX(-100%);
325
+ opacity: 0;
326
+ }
327
+ 100% {
328
+ transform: translateX(0);
329
+ opacity: 1;
330
+ }
331
+ }
332
+ @keyframes slide-bottom {
333
+ 0% {
334
+ transform: translateY(100%);
335
+ opacity: 0;
336
+ }
337
+ 100% {
338
+ transform: translateY(0);
339
+ opacity: 1;
340
+ }
341
+ }
342
+ @keyframes slide-top {
343
+ 0% {
344
+ transform: translateY(-100%);
345
+ opacity: 0;
346
+ }
347
+ 100% {
348
+ transform: translateY(0);
349
+ opacity: 1;
350
+ }
351
+ }
352
+ @keyframes slide-top {
353
+ 0% {
354
+ transform: translateY(-100%);
355
+ opacity: 0;
356
+ }
357
+ 100% {
358
+ transform: translateY(0);
359
+ opacity: 1;
360
+ }
361
+ }
362
+ @keyframes overlay-transition {
363
+ 0% {
364
+ opacity: 0;
365
+ }
366
+ 100% {
367
+ opacity: var(--overlay-opacity);
368
+ }
369
+ }
370
+ </style>
@@ -0,0 +1,68 @@
1
+ type Side = 'top' | 'right' | 'bottom' | 'left';
2
+ type __VLS_Props = {
3
+ idName?: string;
4
+ hideCloseBtn?: boolean;
5
+ noClose?: boolean;
6
+ side?: Side;
7
+ rerender?: boolean;
8
+ zIndex?: number | 'auto';
9
+ width?: string;
10
+ height?: string;
11
+ lockScroll?: boolean;
12
+ lockScrollHtml?: boolean;
13
+ hideScrollbar?: boolean;
14
+ overlayColor?: string;
15
+ overlayOpacity?: number;
16
+ overlayDuration?: number;
17
+ panelColor?: string;
18
+ panelDuration?: number;
19
+ transitionName?: string;
20
+ headerClass?: string;
21
+ bodyClass?: string;
22
+ footerClass?: string;
23
+ };
24
+ type __VLS_PublicProps = __VLS_Props & {
25
+ modelValue?: any;
26
+ };
27
+ declare var __VLS_27: {
28
+ close: any;
29
+ }, __VLS_29: {
30
+ close: any;
31
+ }, __VLS_31: {};
32
+ type __VLS_Slots = {} & {
33
+ header?: (props: typeof __VLS_27) => any;
34
+ } & {
35
+ default?: (props: typeof __VLS_29) => any;
36
+ } & {
37
+ footer?: (props: typeof __VLS_31) => any;
38
+ };
39
+ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
40
+ "update:modelValue": (value: any) => any;
41
+ } & {
42
+ opened: () => any;
43
+ closed: () => any;
44
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
45
+ "onUpdate:modelValue"?: ((value: any) => any) | undefined;
46
+ onOpened?: (() => any) | undefined;
47
+ onClosed?: (() => any) | undefined;
48
+ }>, {
49
+ side: Side;
50
+ width: string;
51
+ idName: string;
52
+ zIndex: number | "auto";
53
+ height: string;
54
+ lockScroll: boolean;
55
+ hideScrollbar: boolean;
56
+ overlayColor: string;
57
+ overlayOpacity: number;
58
+ overlayDuration: number;
59
+ panelColor: string;
60
+ panelDuration: number;
61
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
62
+ declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
63
+ export default _default;
64
+ type __VLS_WithSlots<T, S> = T & {
65
+ new (): {
66
+ $slots: S;
67
+ };
68
+ };
@@ -160,18 +160,18 @@ const filteredItems = computed(() => [
160
160
  link: `https://tnved.${mode}.kz` + PAGES.fea.main,
161
161
  icon: IGlobe,
162
162
  items: [
163
+ {
164
+ title: t("header.products.fea.items.o.t"),
165
+ subtitle: t("header.products.fea.items.o.st"),
166
+ icon: ISviazi,
167
+ to: `https://tnved.${mode}.kz` + PAGES.fea.o
168
+ },
163
169
  {
164
170
  title: t("header.products.fea.items.i.t"),
165
171
  subtitle: t("header.products.fea.items.i.st"),
166
172
  icon: IHandshake,
167
173
  to: `https://tnved.${mode}.kz` + PAGES.fea.t
168
174
  },
169
- {
170
- title: t("header.products.fea.items.o.t"),
171
- subtitle: t("header.products.fea.items.o.st"),
172
- icon: ISviazi,
173
- to: `https://tnved.${mode}.kz`
174
- },
175
175
  {
176
176
  title: t("header.products.fea.items.cp.t"),
177
177
  subtitle: t("header.products.fea.items.cp.st"),
@@ -211,16 +211,16 @@ const sideLinks = {
211
211
  }
212
212
  ],
213
213
  fea: [
214
- {
215
- label: "header.products.fea.items.i.t",
216
- icon: ISearch,
217
- link: `https://tnved.${mode}.kz` + PAGES.fea.t
218
- },
219
214
  {
220
215
  label: "header.products.fea.items.o.t",
221
216
  icon: ISviazi,
222
217
  link: `https://tnved.${mode}.kz` + PAGES.fea.o
223
218
  },
219
+ {
220
+ label: "header.products.fea.items.i.t",
221
+ icon: ISearch,
222
+ link: `https://tnved.${mode}.kz` + PAGES.fea.t
223
+ },
224
224
  {
225
225
  label: "header.products.fea.items.cp.t",
226
226
  icon: IFile,
@@ -0,0 +1,148 @@
1
+ <script setup>
2
+ import { toCanvas } from "qrcode";
3
+ import { removeTrailingSlash } from "#adata-ui/utils/removeTrailingSlash";
4
+ import { watch, ref, nextTick } from "vue";
5
+ import { useAppConfig, useColorMode, useCookie, useI18n } from "#imports";
6
+ const props = defineProps({
7
+ requestUrl: { type: String, required: true },
8
+ requestId: { type: Number, required: true }
9
+ });
10
+ const emit = defineEmits(["back", "updateUserRate"]);
11
+ const isOpen = defineModel({ default: false });
12
+ const { t, locale } = useI18n();
13
+ const { commonAuth } = useAppConfig();
14
+ const accessToken = useCookie("accessToken");
15
+ const colorMode = useColorMode();
16
+ const userApiURL = commonAuth.userApiURL;
17
+ const paymentSuccess = ref(false);
18
+ let intervalId = null;
19
+ function onBack() {
20
+ emit("back", "kaspi");
21
+ }
22
+ async function checkPayment() {
23
+ try {
24
+ const { data } = await $fetch(`${removeTrailingSlash(userApiURL)}/user/kaspi-balance/invoice-status`, {
25
+ method: "GET",
26
+ credentials: "include",
27
+ headers: {
28
+ Authorization: `Bearer ${accessToken.value}`,
29
+ lang: locale.value
30
+ },
31
+ params: {
32
+ request_id: props.requestId,
33
+ initial: 0
34
+ }
35
+ });
36
+ if (data.status === "completed") {
37
+ paymentSuccess.value = true;
38
+ }
39
+ } catch (e) {
40
+ console.error(e);
41
+ }
42
+ }
43
+ watch(isOpen, async (value) => {
44
+ if (!value) {
45
+ if (intervalId) {
46
+ clearInterval(intervalId);
47
+ }
48
+ return;
49
+ }
50
+ await nextTick();
51
+ const canvas = document.getElementById("kaspiQr");
52
+ if (!canvas) return;
53
+ toCanvas(
54
+ canvas,
55
+ props.requestUrl,
56
+ {
57
+ errorCorrectionLevel: "H",
58
+ width: 300,
59
+ margin: 0,
60
+ color: {
61
+ dark: colorMode.value === "dark" ? "#FFFFFF" : "#000000",
62
+ // квадраты
63
+ light: colorMode.value === "dark" ? "#000000" : "#FFFFFF"
64
+ // фон
65
+ }
66
+ },
67
+ (error) => {
68
+ if (error) {
69
+ console.error(error);
70
+ return;
71
+ }
72
+ const ctx = canvas.getContext("2d");
73
+ if (!ctx) return;
74
+ const logo = new Image();
75
+ logo.src = "/adata-ui/kaspi/logo.svg";
76
+ logo.onload = () => {
77
+ const size = canvas.width * 0.2;
78
+ const x = (canvas.width - size) / 2;
79
+ const y = (canvas.height - size) / 2;
80
+ ctx.fillStyle = colorMode.value === "dark" ? "#000000" : "#fff";
81
+ ctx.fillRect(x - 6, y - 6, size + 12, size + 12);
82
+ ctx.drawImage(logo, x, y, size, size);
83
+ };
84
+ }
85
+ );
86
+ intervalId = setInterval(() => {
87
+ if (paymentSuccess.value && intervalId) {
88
+ clearInterval(intervalId);
89
+ emit("updateUserRate");
90
+ return;
91
+ }
92
+ checkPayment();
93
+ }, 1e3);
94
+ });
95
+ </script>
96
+
97
+ <template>
98
+ <adt-side-panel
99
+ v-model="isOpen"
100
+ width="484px"
101
+ >
102
+ <template #header>
103
+ <div class="flex items-center gap-2">
104
+ <button @click="onBack">
105
+ <i-chevron-left class="size-6" />
106
+ </button>
107
+ <p class="text-xl font-semibold">
108
+ {{ t("payment.kaspi.title") }}
109
+ </p>
110
+ </div>
111
+ </template>
112
+
113
+ <div class="flex flex-col gap-6">
114
+ <div class="flex flex-col items-center text-center text-black dark:text-white">
115
+ <p class="mb-4 font-semibold text-sm">
116
+ {{ t("payment.kaspi.description") }}
117
+ </p>
118
+
119
+ <div class="flex gap-3 items-center">
120
+ <i-kaspi-qr class="size-16" />
121
+ <span class="font-bold text-[44px]">
122
+ {{ t("payment.kaspi.qr") }}
123
+ </span>
124
+ </div>
125
+
126
+ <p class="mt-5 font-bold text-2xl">
127
+ {{ t("payment.kaspi.scan") }}
128
+ </p>
129
+
130
+ <canvas
131
+ id="kaspiQr"
132
+ class="mt-5"
133
+ />
134
+
135
+ <p class="mt-10 text-lg">
136
+ {{ t("payment.kaspi.adata") }}
137
+ </p>
138
+ </div>
139
+
140
+ <adt-button
141
+ view="outline"
142
+ @click="onBack"
143
+ >
144
+ {{ t("payment.kaspi.changeMethod") }}
145
+ </adt-button>
146
+ </div>
147
+ </adt-side-panel>
148
+ </template>
@@ -0,0 +1,21 @@
1
+ type __VLS_Props = {
2
+ requestUrl: string;
3
+ requestId: number;
4
+ };
5
+ declare const __VLS_defaults: {
6
+ modelValue: boolean;
7
+ };
8
+ type __VLS_PublicProps = __VLS_Props & {
9
+ modelValue?: typeof __VLS_defaults['modelValue'];
10
+ };
11
+ declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
12
+ "update:modelValue": (value: boolean) => any;
13
+ } & {
14
+ back: (type: "kaspi") => any;
15
+ updateUserRate: () => any;
16
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
17
+ "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
18
+ onBack?: ((type: "kaspi") => any) | undefined;
19
+ onUpdateUserRate?: (() => any) | undefined;
20
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ export default _default;