diff --git a/src/app/i18n/en.ts b/src/app/i18n/en.ts
index 46dab19..5fa879a 100644
--- a/src/app/i18n/en.ts
+++ b/src/app/i18n/en.ts
@@ -82,8 +82,10 @@ export const en: Translations = {
creatingPayment: 'Creating payment...',
waitFewSeconds: 'Please wait a few seconds',
scanQr: 'Scan the QR code to pay',
+ choosePaymentMethod: 'Choose a payment method',
amountToPay: 'Amount due:',
waitingPayment: 'Waiting for payment...',
+ payByBankCard: 'Pay by bank card',
copied: '✓ Copied',
copyLink: 'Copy link',
openNewTab: 'Open in new tab',
diff --git a/src/app/i18n/hy.ts b/src/app/i18n/hy.ts
index 809a342..742c588 100644
--- a/src/app/i18n/hy.ts
+++ b/src/app/i18n/hy.ts
@@ -82,8 +82,10 @@ export const hy: Translations = {
creatingPayment: 'Վճարման ստեղծում...',
waitFewSeconds: 'Խնդրում ենք սպասել մի քանի վայրկյան',
scanQr: 'Սքանավորեք QR կոդը վճարման համար',
+ choosePaymentMethod: 'Ընտրեք վճարման եղանակը',
amountToPay: 'Վճարման գումար՝',
waitingPayment: 'Սպասում ենք վճարմանը...',
+ payByBankCard: 'Վճարել բանկային քարտով',
copied: '✓ Պատճենված է',
copyLink: 'Պատճենել հղումը',
openNewTab: 'Բացել նոր ներդիրում',
diff --git a/src/app/i18n/ru.ts b/src/app/i18n/ru.ts
index 8b38edf..c47829a 100644
--- a/src/app/i18n/ru.ts
+++ b/src/app/i18n/ru.ts
@@ -82,8 +82,10 @@ export const ru: Translations = {
creatingPayment: 'Создание платежа...',
waitFewSeconds: 'Подождите несколько секунд',
scanQr: 'Сканируйте QR-код для оплаты',
+ choosePaymentMethod: 'Выберите способ оплаты',
amountToPay: 'Сумма к оплате:',
waitingPayment: 'Ожидание оплаты...',
+ payByBankCard: 'Оплатить банковской картой',
copied: '✓ Скопировано',
copyLink: 'Скопировать ссылку',
openNewTab: 'Открыть в новой вкладке',
diff --git a/src/app/i18n/translations.ts b/src/app/i18n/translations.ts
index 094af77..07ada19 100644
--- a/src/app/i18n/translations.ts
+++ b/src/app/i18n/translations.ts
@@ -80,8 +80,10 @@ export interface Translations {
creatingPayment: string;
waitFewSeconds: string;
scanQr: string;
+ choosePaymentMethod: string;
amountToPay: string;
waitingPayment: string;
+ payByBankCard: string;
copied: string;
copyLink: string;
openNewTab: string;
diff --git a/src/app/pages/cart/cart.component.html b/src/app/pages/cart/cart.component.html
index 3b66bb1..c8f37c0 100644
--- a/src/app/pages/cart/cart.component.html
+++ b/src/app/pages/cart/cart.component.html
@@ -208,14 +208,16 @@
@if (paymentStatus() === 'waiting') {
-
{{ 'cart.scanQr' | translate }}
+
{{ qrCodeUrl() ? ('cart.scanQr' | translate) : ('cart.choosePaymentMethod' | translate) }}
-
-
-
![QR код для оплаты]()
-
+ @if (qrCodeUrl()) {
+
+
+
![QR код для оплаты]()
+
+
-
+ }
-
-
}
@@ -322,6 +332,19 @@
}
+
+ @if (showBankPaymentPopup() && bankPaymentFrameUrl()) {
+
+ }
}
diff --git a/src/app/pages/cart/cart.component.scss b/src/app/pages/cart/cart.component.scss
index 48eb235..36148da 100644
--- a/src/app/pages/cart/cart.component.scss
+++ b/src/app/pages/cart/cart.component.scss
@@ -1445,6 +1445,54 @@
}
}
}
+
+ .bank-payment-btn {
+ width: 100%;
+ padding: 14px 18px;
+ border: none;
+ border-radius: 10px;
+ background: #1f2937;
+ color: white;
+ font-weight: 700;
+ font-size: 1rem;
+ cursor: pointer;
+ transition: all 0.2s ease;
+
+ &:hover {
+ background: #111827;
+ transform: translateY(-1px);
+ box-shadow: 0 6px 16px rgba(31, 41, 55, 0.22);
+ }
+ }
+}
+
+.bank-payment-modal-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 1001;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 24px;
+ background: rgba(17, 24, 39, 0.55);
+}
+
+.bank-payment-modal {
+ position: relative;
+ width: min(960px, 92vw);
+ height: min(760px, 86vh);
+ padding: 56px 16px 16px;
+ background: white;
+ border-radius: 13px;
+ box-shadow: 0 18px 60px rgba(0, 0, 0, 0.28);
+}
+
+.bank-payment-frame {
+ width: 100%;
+ height: 100%;
+ border: 0;
+ border-radius: 8px;
+ background: white;
}
@keyframes pulse {
@@ -1623,6 +1671,16 @@
}
}
+ .bank-payment-modal-overlay {
+ padding: 12px;
+ }
+
+ .bank-payment-modal {
+ width: 94vw;
+ height: 82vh;
+ padding: 52px 10px 10px;
+ }
+
.payment-active h2 {
font-size: 1.25rem;
margin-bottom: 16px;
diff --git a/src/app/pages/cart/cart.component.ts b/src/app/pages/cart/cart.component.ts
index a21e108..1e01e95 100644
--- a/src/app/pages/cart/cart.component.ts
+++ b/src/app/pages/cart/cart.component.ts
@@ -2,6 +2,7 @@ import { Component, ChangeDetectionStrategy, signal, OnDestroy, inject } from '@
import { DecimalPipe } from '@angular/common';
import { Router, RouterLink } from '@angular/router';
import { FormsModule } from '@angular/forms';
+import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { CartService, ApiService, LanguageService, AuthService } from '../../services';
import { Item, CartItem, DeliveryOption } from '../../models';
import { interval, of, Subscription } from 'rxjs';
@@ -47,6 +48,9 @@ export class CartComponent implements OnDestroy {
paymentStatus = signal<'creating' | 'waiting' | 'success' | 'timeout' | 'error' | null>('creating');
qrCodeUrl = signal('');
paymentUrl = signal('');
+ bankPaymentUrl = signal('');
+ bankPaymentFrameUrl = signal(null);
+ showBankPaymentPopup = signal(false);
paymentId = signal('');
linkCopied = signal(false);
@@ -68,7 +72,8 @@ export class CartComponent implements OnDestroy {
private cartService: CartService,
private apiService: ApiService,
private router: Router,
- private langService: LanguageService
+ private langService: LanguageService,
+ private sanitizer: DomSanitizer
) {
this.items = this.cartService.items;
this.itemCount = this.cartService.itemCount;
@@ -175,6 +180,9 @@ export class CartComponent implements OnDestroy {
this.paymentId.set('');
this.qrCodeUrl.set('');
this.paymentUrl.set('');
+ this.bankPaymentUrl.set('');
+ this.bankPaymentFrameUrl.set(null);
+ this.showBankPaymentPopup.set(false);
this.linkCopied.set(false);
this.userEmail.set('');
this.userPhone.set('');
@@ -189,6 +197,7 @@ export class CartComponent implements OnDestroy {
closePaymentPopup(): void {
this.showPaymentPopup.set(false);
+ this.closeBankPaymentPopup();
this.stopPolling();
if (this.closeTimeout) {
clearTimeout(this.closeTimeout);
@@ -206,6 +215,9 @@ export class CartComponent implements OnDestroy {
this.paymentId.set('');
this.qrCodeUrl.set('');
this.paymentUrl.set('');
+ this.bankPaymentUrl.set('');
+ this.bankPaymentFrameUrl.set(null);
+ this.showBankPaymentPopup.set(false);
this.linkCopied.set(false);
this.createPayment();
}
@@ -228,9 +240,10 @@ export class CartComponent implements OnDestroy {
const qrId = this.apiService.resolvePaymentQrId(response);
const qrUrl = this.apiService.resolvePaymentQrUrl(response);
const paymentLink = this.apiService.resolvePaymentLink(response);
+ const bankUrl = this.apiService.resolveBankPaymentUrl(response);
- if (!qrId || !qrUrl) {
- console.error('Payment response missing qr fields:', response);
+ if (!qrId || (!qrUrl && !bankUrl)) {
+ console.error('Payment response missing payment fields:', response);
this.setPaymentError();
return;
}
@@ -238,6 +251,7 @@ export class CartComponent implements OnDestroy {
this.paymentId.set(qrId);
this.qrCodeUrl.set(qrUrl);
this.paymentUrl.set(paymentLink);
+ this.bankPaymentUrl.set(bankUrl);
this.paymentStatus.set('waiting');
this.startPolling();
@@ -280,6 +294,7 @@ export class CartComponent implements OnDestroy {
if (paymentStatus === 'FAILED' || paymentStatus === 'EXPIRED' || paymentStatus === 'CANCELLED' || paymentStatus === 'REJECTED') {
this.paymentStatus.set('timeout');
+ this.closeBankPaymentPopup();
this.stopPolling();
if (this.closeTimeout) clearTimeout(this.closeTimeout);
this.closeTimeout = setTimeout(() => {
@@ -291,6 +306,7 @@ export class CartComponent implements OnDestroy {
// Check if payment is successful
if (paymentStatus === 'COMPLETED' || paymentStatus === 'APPROVED' || paymentStatus === 'PAID' || paymentCode === 'SUCCESS') {
this.paymentStatus.set('success');
+ this.closeBankPaymentPopup();
this.stopPolling();
// Auto-submit purchase after 5 seconds
if (this.closeTimeout) clearTimeout(this.closeTimeout);
@@ -308,6 +324,7 @@ export class CartComponent implements OnDestroy {
// If all checks are done but payment not completed
if (this.paymentStatus() === 'waiting') {
this.paymentStatus.set('timeout');
+ this.closeBankPaymentPopup();
// Close popup after showing timeout message
if (this.closeTimeout) clearTimeout(this.closeTimeout);
this.closeTimeout = setTimeout(() => {
@@ -325,8 +342,24 @@ export class CartComponent implements OnDestroy {
}
}
+ openBankPaymentPopup(): void {
+ const bankUrl = this.bankPaymentUrl();
+ if (!bankUrl) {
+ return;
+ }
+
+ this.bankPaymentFrameUrl.set(this.sanitizer.bypassSecurityTrustResourceUrl(bankUrl));
+ this.showBankPaymentPopup.set(true);
+ }
+
+ closeBankPaymentPopup(): void {
+ this.showBankPaymentPopup.set(false);
+ this.bankPaymentFrameUrl.set(null);
+ }
+
private setPaymentError(): void {
this.paymentStatus.set('error');
+ this.closeBankPaymentPopup();
this.stopPolling();
if (this.closeTimeout) {
clearTimeout(this.closeTimeout);
diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts
index 14aa901..9f1ec88 100644
--- a/src/app/services/api.service.ts
+++ b/src/app/services/api.service.ts
@@ -23,6 +23,7 @@ export interface QrCreateResponse {
nspkID?: string;
nspkId?: string;
nspkurl?: string;
+ bankUrl?: string;
status?: string;
qrStatus?: string;
qrExpirationDate?: string;
@@ -543,6 +544,10 @@ export class ApiService {
return response.nspkurl ?? response.Payload ?? response.payload ?? response.qrUrl ?? '';
}
+ resolveBankPaymentUrl(response: QrCreateResponse): string {
+ return response.bankUrl ?? '';
+ }
+
resolvePaymentQrUrl(response: QrCreateResponse): string {
const paymentLink = this.resolvePaymentLink(response);
if (paymentLink) {