bank type added
This commit is contained in:
@@ -82,8 +82,10 @@ export const en: Translations = {
|
|||||||
creatingPayment: 'Creating payment...',
|
creatingPayment: 'Creating payment...',
|
||||||
waitFewSeconds: 'Please wait a few seconds',
|
waitFewSeconds: 'Please wait a few seconds',
|
||||||
scanQr: 'Scan the QR code to pay',
|
scanQr: 'Scan the QR code to pay',
|
||||||
|
choosePaymentMethod: 'Choose a payment method',
|
||||||
amountToPay: 'Amount due:',
|
amountToPay: 'Amount due:',
|
||||||
waitingPayment: 'Waiting for payment...',
|
waitingPayment: 'Waiting for payment...',
|
||||||
|
payByBankCard: 'Pay by bank card',
|
||||||
copied: '✓ Copied',
|
copied: '✓ Copied',
|
||||||
copyLink: 'Copy link',
|
copyLink: 'Copy link',
|
||||||
openNewTab: 'Open in new tab',
|
openNewTab: 'Open in new tab',
|
||||||
|
|||||||
@@ -82,8 +82,10 @@ export const hy: Translations = {
|
|||||||
creatingPayment: 'Վճարման ստեղծում...',
|
creatingPayment: 'Վճարման ստեղծում...',
|
||||||
waitFewSeconds: 'Խնդրում ենք սպասել մի քանի վայրկյան',
|
waitFewSeconds: 'Խնդրում ենք սպասել մի քանի վայրկյան',
|
||||||
scanQr: 'Սքանավորեք QR կոդը վճարման համար',
|
scanQr: 'Սքանավորեք QR կոդը վճարման համար',
|
||||||
|
choosePaymentMethod: 'Ընտրեք վճարման եղանակը',
|
||||||
amountToPay: 'Վճարման գումար՝',
|
amountToPay: 'Վճարման գումար՝',
|
||||||
waitingPayment: 'Սպասում ենք վճարմանը...',
|
waitingPayment: 'Սպասում ենք վճարմանը...',
|
||||||
|
payByBankCard: 'Վճարել բանկային քարտով',
|
||||||
copied: '✓ Պատճենված է',
|
copied: '✓ Պատճենված է',
|
||||||
copyLink: 'Պատճենել հղումը',
|
copyLink: 'Պատճենել հղումը',
|
||||||
openNewTab: 'Բացել նոր ներդիրում',
|
openNewTab: 'Բացել նոր ներդիրում',
|
||||||
|
|||||||
@@ -82,8 +82,10 @@ export const ru: Translations = {
|
|||||||
creatingPayment: 'Создание платежа...',
|
creatingPayment: 'Создание платежа...',
|
||||||
waitFewSeconds: 'Подождите несколько секунд',
|
waitFewSeconds: 'Подождите несколько секунд',
|
||||||
scanQr: 'Сканируйте QR-код для оплаты',
|
scanQr: 'Сканируйте QR-код для оплаты',
|
||||||
|
choosePaymentMethod: 'Выберите способ оплаты',
|
||||||
amountToPay: 'Сумма к оплате:',
|
amountToPay: 'Сумма к оплате:',
|
||||||
waitingPayment: 'Ожидание оплаты...',
|
waitingPayment: 'Ожидание оплаты...',
|
||||||
|
payByBankCard: 'Оплатить банковской картой',
|
||||||
copied: '✓ Скопировано',
|
copied: '✓ Скопировано',
|
||||||
copyLink: 'Скопировать ссылку',
|
copyLink: 'Скопировать ссылку',
|
||||||
openNewTab: 'Открыть в новой вкладке',
|
openNewTab: 'Открыть в новой вкладке',
|
||||||
|
|||||||
@@ -80,8 +80,10 @@ export interface Translations {
|
|||||||
creatingPayment: string;
|
creatingPayment: string;
|
||||||
waitFewSeconds: string;
|
waitFewSeconds: string;
|
||||||
scanQr: string;
|
scanQr: string;
|
||||||
|
choosePaymentMethod: string;
|
||||||
amountToPay: string;
|
amountToPay: string;
|
||||||
waitingPayment: string;
|
waitingPayment: string;
|
||||||
|
payByBankCard: string;
|
||||||
copied: string;
|
copied: string;
|
||||||
copyLink: string;
|
copyLink: string;
|
||||||
openNewTab: string;
|
openNewTab: string;
|
||||||
|
|||||||
@@ -208,14 +208,16 @@
|
|||||||
|
|
||||||
@if (paymentStatus() === 'waiting') {
|
@if (paymentStatus() === 'waiting') {
|
||||||
<div class="payment-active">
|
<div class="payment-active">
|
||||||
<h2>{{ 'cart.scanQr' | translate }}</h2>
|
<h2>{{ qrCodeUrl() ? ('cart.scanQr' | translate) : ('cart.choosePaymentMethod' | translate) }}</h2>
|
||||||
|
|
||||||
<div class="qr-section">
|
@if (qrCodeUrl()) {
|
||||||
<div class="qr-wrapper">
|
<div class="qr-section">
|
||||||
<img [src]="qrCodeUrl()" alt="QR код для оплаты" class="qr-code" />
|
<div class="qr-wrapper">
|
||||||
<div class="scan-line"></div>
|
<img [src]="qrCodeUrl()" alt="QR код для оплаты" class="qr-code" />
|
||||||
|
<div class="scan-line"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
|
|
||||||
<div class="payment-info">
|
<div class="payment-info">
|
||||||
<div class="payment-amount">
|
<div class="payment-amount">
|
||||||
@@ -229,13 +231,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="payment-actions">
|
@if (bankPaymentUrl()) {
|
||||||
<button class="copy-btn" (click)="copyPaymentLink()">
|
<button class="bank-payment-btn" (click)="openBankPaymentPopup()">
|
||||||
{{ linkCopied() ? ('cart.copied' | translate) : ('cart.copyLink' | translate) }}
|
{{ 'cart.payByBankCard' | translate }}
|
||||||
</button>
|
</button>
|
||||||
<a [href]="paymentUrl()" target="_blank" rel="noopener noreferrer" class="open-btn">
|
}
|
||||||
{{ 'cart.openNewTab' | translate }}
|
|
||||||
</a>
|
<div class="payment-actions">
|
||||||
|
@if (paymentUrl()) {
|
||||||
|
<button class="copy-btn" (click)="copyPaymentLink()">
|
||||||
|
{{ linkCopied() ? ('cart.copied' | translate) : ('cart.copyLink' | translate) }}
|
||||||
|
</button>
|
||||||
|
<a [href]="paymentUrl()" target="_blank" rel="noopener noreferrer" class="open-btn">
|
||||||
|
{{ 'cart.openNewTab' | translate }}
|
||||||
|
</a>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -322,6 +332,19 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (showBankPaymentPopup() && bankPaymentFrameUrl()) {
|
||||||
|
<div class="bank-payment-modal-overlay">
|
||||||
|
<div class="bank-payment-modal">
|
||||||
|
<button class="close-modal-btn" (click)="closeBankPaymentPopup()" [attr.aria-label]="'cart.close' | translate">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||||
|
<path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<iframe [src]="bankPaymentFrameUrl()" class="bank-payment-frame" title="Bank card payment"></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
@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 {
|
.payment-active h2 {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Component, ChangeDetectionStrategy, signal, OnDestroy, inject } from '@
|
|||||||
import { DecimalPipe } from '@angular/common';
|
import { DecimalPipe } from '@angular/common';
|
||||||
import { Router, RouterLink } from '@angular/router';
|
import { Router, RouterLink } from '@angular/router';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||||
import { CartService, ApiService, LanguageService, AuthService } from '../../services';
|
import { CartService, ApiService, LanguageService, AuthService } from '../../services';
|
||||||
import { Item, CartItem, DeliveryOption } from '../../models';
|
import { Item, CartItem, DeliveryOption } from '../../models';
|
||||||
import { interval, of, Subscription } from 'rxjs';
|
import { interval, of, Subscription } from 'rxjs';
|
||||||
@@ -47,6 +48,9 @@ export class CartComponent implements OnDestroy {
|
|||||||
paymentStatus = signal<'creating' | 'waiting' | 'success' | 'timeout' | 'error' | null>('creating');
|
paymentStatus = signal<'creating' | 'waiting' | 'success' | 'timeout' | 'error' | null>('creating');
|
||||||
qrCodeUrl = signal<string>('');
|
qrCodeUrl = signal<string>('');
|
||||||
paymentUrl = signal<string>('');
|
paymentUrl = signal<string>('');
|
||||||
|
bankPaymentUrl = signal<string>('');
|
||||||
|
bankPaymentFrameUrl = signal<SafeResourceUrl | null>(null);
|
||||||
|
showBankPaymentPopup = signal<boolean>(false);
|
||||||
paymentId = signal<string>('');
|
paymentId = signal<string>('');
|
||||||
linkCopied = signal<boolean>(false);
|
linkCopied = signal<boolean>(false);
|
||||||
|
|
||||||
@@ -68,7 +72,8 @@ export class CartComponent implements OnDestroy {
|
|||||||
private cartService: CartService,
|
private cartService: CartService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private langService: LanguageService
|
private langService: LanguageService,
|
||||||
|
private sanitizer: DomSanitizer
|
||||||
) {
|
) {
|
||||||
this.items = this.cartService.items;
|
this.items = this.cartService.items;
|
||||||
this.itemCount = this.cartService.itemCount;
|
this.itemCount = this.cartService.itemCount;
|
||||||
@@ -175,6 +180,9 @@ export class CartComponent implements OnDestroy {
|
|||||||
this.paymentId.set('');
|
this.paymentId.set('');
|
||||||
this.qrCodeUrl.set('');
|
this.qrCodeUrl.set('');
|
||||||
this.paymentUrl.set('');
|
this.paymentUrl.set('');
|
||||||
|
this.bankPaymentUrl.set('');
|
||||||
|
this.bankPaymentFrameUrl.set(null);
|
||||||
|
this.showBankPaymentPopup.set(false);
|
||||||
this.linkCopied.set(false);
|
this.linkCopied.set(false);
|
||||||
this.userEmail.set('');
|
this.userEmail.set('');
|
||||||
this.userPhone.set('');
|
this.userPhone.set('');
|
||||||
@@ -189,6 +197,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
|
|
||||||
closePaymentPopup(): void {
|
closePaymentPopup(): void {
|
||||||
this.showPaymentPopup.set(false);
|
this.showPaymentPopup.set(false);
|
||||||
|
this.closeBankPaymentPopup();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
if (this.closeTimeout) {
|
if (this.closeTimeout) {
|
||||||
clearTimeout(this.closeTimeout);
|
clearTimeout(this.closeTimeout);
|
||||||
@@ -206,6 +215,9 @@ export class CartComponent implements OnDestroy {
|
|||||||
this.paymentId.set('');
|
this.paymentId.set('');
|
||||||
this.qrCodeUrl.set('');
|
this.qrCodeUrl.set('');
|
||||||
this.paymentUrl.set('');
|
this.paymentUrl.set('');
|
||||||
|
this.bankPaymentUrl.set('');
|
||||||
|
this.bankPaymentFrameUrl.set(null);
|
||||||
|
this.showBankPaymentPopup.set(false);
|
||||||
this.linkCopied.set(false);
|
this.linkCopied.set(false);
|
||||||
this.createPayment();
|
this.createPayment();
|
||||||
}
|
}
|
||||||
@@ -228,9 +240,10 @@ export class CartComponent implements OnDestroy {
|
|||||||
const qrId = this.apiService.resolvePaymentQrId(response);
|
const qrId = this.apiService.resolvePaymentQrId(response);
|
||||||
const qrUrl = this.apiService.resolvePaymentQrUrl(response);
|
const qrUrl = this.apiService.resolvePaymentQrUrl(response);
|
||||||
const paymentLink = this.apiService.resolvePaymentLink(response);
|
const paymentLink = this.apiService.resolvePaymentLink(response);
|
||||||
|
const bankUrl = this.apiService.resolveBankPaymentUrl(response);
|
||||||
|
|
||||||
if (!qrId || !qrUrl) {
|
if (!qrId || (!qrUrl && !bankUrl)) {
|
||||||
console.error('Payment response missing qr fields:', response);
|
console.error('Payment response missing payment fields:', response);
|
||||||
this.setPaymentError();
|
this.setPaymentError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -238,6 +251,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
this.paymentId.set(qrId);
|
this.paymentId.set(qrId);
|
||||||
this.qrCodeUrl.set(qrUrl);
|
this.qrCodeUrl.set(qrUrl);
|
||||||
this.paymentUrl.set(paymentLink);
|
this.paymentUrl.set(paymentLink);
|
||||||
|
this.bankPaymentUrl.set(bankUrl);
|
||||||
|
|
||||||
this.paymentStatus.set('waiting');
|
this.paymentStatus.set('waiting');
|
||||||
this.startPolling();
|
this.startPolling();
|
||||||
@@ -280,6 +294,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
|
|
||||||
if (paymentStatus === 'FAILED' || paymentStatus === 'EXPIRED' || paymentStatus === 'CANCELLED' || paymentStatus === 'REJECTED') {
|
if (paymentStatus === 'FAILED' || paymentStatus === 'EXPIRED' || paymentStatus === 'CANCELLED' || paymentStatus === 'REJECTED') {
|
||||||
this.paymentStatus.set('timeout');
|
this.paymentStatus.set('timeout');
|
||||||
|
this.closeBankPaymentPopup();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
||||||
this.closeTimeout = setTimeout(() => {
|
this.closeTimeout = setTimeout(() => {
|
||||||
@@ -291,6 +306,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
// Check if payment is successful
|
// Check if payment is successful
|
||||||
if (paymentStatus === 'COMPLETED' || paymentStatus === 'APPROVED' || paymentStatus === 'PAID' || paymentCode === 'SUCCESS') {
|
if (paymentStatus === 'COMPLETED' || paymentStatus === 'APPROVED' || paymentStatus === 'PAID' || paymentCode === 'SUCCESS') {
|
||||||
this.paymentStatus.set('success');
|
this.paymentStatus.set('success');
|
||||||
|
this.closeBankPaymentPopup();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
// Auto-submit purchase after 5 seconds
|
// Auto-submit purchase after 5 seconds
|
||||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
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 all checks are done but payment not completed
|
||||||
if (this.paymentStatus() === 'waiting') {
|
if (this.paymentStatus() === 'waiting') {
|
||||||
this.paymentStatus.set('timeout');
|
this.paymentStatus.set('timeout');
|
||||||
|
this.closeBankPaymentPopup();
|
||||||
// Close popup after showing timeout message
|
// Close popup after showing timeout message
|
||||||
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
if (this.closeTimeout) clearTimeout(this.closeTimeout);
|
||||||
this.closeTimeout = setTimeout(() => {
|
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 {
|
private setPaymentError(): void {
|
||||||
this.paymentStatus.set('error');
|
this.paymentStatus.set('error');
|
||||||
|
this.closeBankPaymentPopup();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
if (this.closeTimeout) {
|
if (this.closeTimeout) {
|
||||||
clearTimeout(this.closeTimeout);
|
clearTimeout(this.closeTimeout);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export interface QrCreateResponse {
|
|||||||
nspkID?: string;
|
nspkID?: string;
|
||||||
nspkId?: string;
|
nspkId?: string;
|
||||||
nspkurl?: string;
|
nspkurl?: string;
|
||||||
|
bankUrl?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
qrStatus?: string;
|
qrStatus?: string;
|
||||||
qrExpirationDate?: string;
|
qrExpirationDate?: string;
|
||||||
@@ -543,6 +544,10 @@ export class ApiService {
|
|||||||
return response.nspkurl ?? response.Payload ?? response.payload ?? response.qrUrl ?? '';
|
return response.nspkurl ?? response.Payload ?? response.payload ?? response.qrUrl ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveBankPaymentUrl(response: QrCreateResponse): string {
|
||||||
|
return response.bankUrl ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
resolvePaymentQrUrl(response: QrCreateResponse): string {
|
resolvePaymentQrUrl(response: QrCreateResponse): string {
|
||||||
const paymentLink = this.resolvePaymentLink(response);
|
const paymentLink = this.resolvePaymentLink(response);
|
||||||
if (paymentLink) {
|
if (paymentLink) {
|
||||||
|
|||||||
Reference in New Issue
Block a user