From 3cf0ef87f83298c3cb7e81d16bc389ddcddeb704 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Sun, 28 Jun 2026 22:18:35 +0400 Subject: [PATCH] bank type added --- src/app/i18n/en.ts | 2 + src/app/i18n/hy.ts | 2 + src/app/i18n/ru.ts | 2 + src/app/i18n/translations.ts | 2 + src/app/pages/cart/cart.component.html | 47 +++++++++++++++------ src/app/pages/cart/cart.component.scss | 58 ++++++++++++++++++++++++++ src/app/pages/cart/cart.component.ts | 39 +++++++++++++++-- src/app/services/api.service.ts | 5 +++ 8 files changed, 142 insertions(+), 15 deletions(-) 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 код для оплаты +
+
-
+ }
@@ -229,13 +231,21 @@
-
- - - {{ 'cart.openNewTab' | translate }} - + } + +
+ @if (paymentUrl()) { + + + {{ 'cart.openNewTab' | translate }} + + }
} @@ -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) {