This commit is contained in:
sdarbinyan
2026-06-29 00:06:18 +04:00
parent 3cf0ef87f8
commit 0977f302a4
8 changed files with 84 additions and 52 deletions

View File

@@ -78,14 +78,14 @@ export const en: Translations = {
privacyPolicy: 'privacy policy',
and: 'and',
checkout: 'Place order',
payViaQr: 'Pay via QR',
payViaCard: 'Pay via card',
close: 'Close',
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',

View File

@@ -78,14 +78,14 @@ export const hy: Translations = {
privacyPolicy: 'գաղտնիության քաղաքականության',
and: 'և',
checkout: 'Ձևակերպել պատվերը',
payViaQr: 'Վճարել QR-ով',
payViaCard: 'Վճարել քարտով',
close: 'Փակել',
creatingPayment: 'Վճարման ստեղծում...',
waitFewSeconds: 'Խնդրում ենք սպասել մի քանի վայրկյան',
scanQr: 'Սքանավորեք QR կոդը վճարման համար',
choosePaymentMethod: 'Ընտրեք վճարման եղանակը',
amountToPay: 'Վճարման գումար՝',
waitingPayment: 'Սպասում ենք վճարմանը...',
payByBankCard: 'Վճարել բանկային քարտով',
copied: '✓ Պատճենված է',
copyLink: 'Պատճենել հղումը',
openNewTab: 'Բացել նոր ներդիրում',

View File

@@ -78,14 +78,14 @@ export const ru: Translations = {
privacyPolicy: 'политикой конфиденциальности',
and: 'и',
checkout: 'Оформить заказ',
payViaQr: 'Оплатить через QR',
payViaCard: 'Оплатить картой',
close: 'Закрыть',
creatingPayment: 'Создание платежа...',
waitFewSeconds: 'Подождите несколько секунд',
scanQr: 'Сканируйте QR-код для оплаты',
choosePaymentMethod: 'Выберите способ оплаты',
amountToPay: 'Сумма к оплате:',
waitingPayment: 'Ожидание оплаты...',
payByBankCard: 'Оплатить банковской картой',
copied: '✓ Скопировано',
copyLink: 'Скопировать ссылку',
openNewTab: 'Открыть в новой вкладке',

View File

@@ -76,14 +76,14 @@ export interface Translations {
privacyPolicy: string;
and: string;
checkout: string;
payViaQr: string;
payViaCard: string;
close: string;
creatingPayment: string;
waitFewSeconds: string;
scanQr: string;
choosePaymentMethod: string;
amountToPay: string;
waitingPayment: string;
payByBankCard: string;
copied: string;
copyLink: string;
openNewTab: string;

View File

@@ -157,14 +157,25 @@
</label>
</div>
<button
class="checkout-btn"
(click)="checkout()"
[class.disabled]="isCheckoutDisabled"
[disabled]="isCheckoutDisabled"
>
{{ 'cart.checkout' | translate }}
</button>
<div class="payment-method-actions">
<button
class="checkout-btn qr-payment-btn"
(click)="checkout('qr')"
[class.disabled]="isCheckoutDisabled"
[disabled]="isCheckoutDisabled"
>
{{ 'cart.payViaQr' | translate }}
</button>
<button
class="checkout-btn card-payment-btn"
(click)="checkout('card')"
[class.disabled]="isCheckoutDisabled"
[disabled]="isCheckoutDisabled"
>
{{ 'cart.payViaCard' | translate }}
</button>
</div>
@if (!isAuthenticated()) {
<div class="cart-login-gate">
@@ -208,7 +219,7 @@
@if (paymentStatus() === 'waiting') {
<div class="payment-active">
<h2>{{ qrCodeUrl() ? ('cart.scanQr' | translate) : ('cart.choosePaymentMethod' | translate) }}</h2>
<h2>{{ selectedPaymentMethod() === 'card' ? ('cart.waitingPayment' | translate) : ('cart.scanQr' | translate) }}</h2>
@if (qrCodeUrl()) {
<div class="qr-section">
@@ -231,12 +242,6 @@
</div>
</div>
@if (bankPaymentUrl()) {
<button class="bank-payment-btn" (click)="openBankPaymentPopup()">
{{ 'cart.payByBankCard' | translate }}
</button>
}
<div class="payment-actions">
@if (paymentUrl()) {
<button class="copy-btn" (click)="copyPaymentLink()">

View File

@@ -724,6 +724,13 @@
}
}
.payment-method-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 8px;
}
.checkout-btn {
width: 100%;
padding: 16px;
@@ -736,7 +743,6 @@
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
margin-top: 8px;
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15);
&:hover:not(:disabled) {
@@ -810,6 +816,15 @@
}
}
}
.card-payment-btn {
background: #1f2937;
&:hover:not(:disabled) {
background: #111827;
box-shadow: 0 6px 16px rgba(31, 41, 55, 0.28);
}
}
}
// Novo Cart Summary - Green Modern
@@ -868,6 +883,13 @@
}
}
.payment-method-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 12px;
}
.checkout-btn {
width: 100%;
padding: 16px;
@@ -879,7 +901,6 @@
font-weight: 700;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
margin-top: 12px;
box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3);
&:hover:not(:disabled) {
@@ -897,6 +918,15 @@
}
}
.card-payment-btn {
background: linear-gradient(135deg, #1f2937 0%, #111827 100%);
box-shadow: 0 4px 16px rgba(31, 41, 55, 0.22);
&:hover:not(:disabled) {
box-shadow: 0 8px 24px rgba(31, 41, 55, 0.3);
}
}
.cart-login-gate {
margin-top: 20px;
padding: 24px;
@@ -1446,24 +1476,6 @@
}
}
.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 {
@@ -1671,6 +1683,10 @@
}
}
.payment-method-actions {
grid-template-columns: 1fr;
}
.bank-payment-modal-overlay {
padding: 12px;
}

View File

@@ -17,6 +17,8 @@ import { TranslatePipe } from '../../i18n/translate.pipe';
import { TranslateService } from '../../i18n/translate.service';
import { PAYMENT_POLL_INTERVAL_MS, PAYMENT_MAX_CHECKS, PAYMENT_TIMEOUT_CLOSE_MS, LINK_COPIED_DURATION_MS } from '../../config/constants';
type PaymentMethod = 'qr' | 'card';
@Component({
selector: 'app-cart',
imports: [DecimalPipe, RouterLink, FormsModule, EmptyCartIconComponent, DeliverySelectorComponent, TelegramLoginComponent, LangRoutePipe, TranslatePipe],
@@ -51,6 +53,7 @@ export class CartComponent implements OnDestroy {
bankPaymentUrl = signal<string>('');
bankPaymentFrameUrl = signal<SafeResourceUrl | null>(null);
showBankPaymentPopup = signal<boolean>(false);
selectedPaymentMethod = signal<PaymentMethod>('qr');
paymentId = signal<string>('');
linkCopied = signal<boolean>(false);
@@ -161,7 +164,7 @@ export class CartComponent implements OnDestroy {
this.cartService.setSelectedDelivery(itemID, selectedDelivery);
}
checkout(): void {
checkout(paymentMethod: PaymentMethod): void {
if (!this.allRequiredDeliveriesSelected()) {
alert(this.i18n.t('cart.deliveryRequired'));
return;
@@ -171,11 +174,12 @@ export class CartComponent implements OnDestroy {
alert(this.i18n.t('cart.acceptTerms'));
return;
}
this.openPaymentPopup();
this.openPaymentPopup(paymentMethod);
}
openPaymentPopup(): void {
openPaymentPopup(paymentMethod: PaymentMethod): void {
this.showPaymentPopup.set(true);
this.selectedPaymentMethod.set(paymentMethod);
this.paymentStatus.set('creating');
this.paymentId.set('');
this.qrCodeUrl.set('');
@@ -192,7 +196,7 @@ export class CartComponent implements OnDestroy {
this.phoneError.set('');
this.emailSubmitting.set(false);
this.paidItems = [...this.items()];
this.createPayment();
this.createPayment(paymentMethod);
}
closePaymentPopup(): void {
@@ -219,10 +223,10 @@ export class CartComponent implements OnDestroy {
this.bankPaymentFrameUrl.set(null);
this.showBankPaymentPopup.set(false);
this.linkCopied.set(false);
this.createPayment();
this.createPayment(this.selectedPaymentMethod());
}
createPayment(): void {
createPayment(paymentMethod: PaymentMethod): void {
const orderId = this.generateOrderId();
const paymentPayload = {
amount: Number(this.totalWithDelivery()),
@@ -231,6 +235,7 @@ export class CartComponent implements OnDestroy {
siteorderID: orderId,
redirectUrl: '',
telegramUsername: this.getTelegramUsername(),
paymentMethod,
items: this.buildPaymentItems(),
};
@@ -242,7 +247,7 @@ export class CartComponent implements OnDestroy {
const paymentLink = this.apiService.resolvePaymentLink(response);
const bankUrl = this.apiService.resolveBankPaymentUrl(response);
if (!qrId || (!qrUrl && !bankUrl)) {
if (!qrId || (paymentMethod === 'qr' && !qrUrl) || (paymentMethod === 'card' && !bankUrl)) {
console.error('Payment response missing payment fields:', response);
this.setPaymentError();
return;
@@ -255,6 +260,9 @@ export class CartComponent implements OnDestroy {
this.paymentStatus.set('waiting');
this.startPolling();
if (paymentMethod === 'card') {
this.openBankPaymentPopup();
}
},
error: (err) => {
console.error('Error creating payment:', err);

View File

@@ -23,6 +23,8 @@ export interface QrCreateResponse {
nspkID?: string;
nspkId?: string;
nspkurl?: string;
orderID?: string;
url?: string;
bankUrl?: string;
status?: string;
qrStatus?: string;
@@ -43,6 +45,7 @@ export interface CartPaymentRequest {
siteorderID: string;
redirectUrl: string;
telegramUsername: string;
paymentMethod: 'qr' | 'card';
items: Array<{ itemID: number; price: number; name: string; quantity?: number; delivery?: DeliveryOption[] }>;
}
@@ -537,7 +540,7 @@ export class ApiService {
}
resolvePaymentQrId(response: QrCreateResponse): string {
return response.qrId ?? response.qrID ?? response.nspkID ?? response.nspkId ?? '';
return response.qrId ?? response.qrID ?? response.nspkID ?? response.nspkId ?? response.orderID ?? '';
}
resolvePaymentLink(response: QrCreateResponse): string {
@@ -545,7 +548,7 @@ export class ApiService {
}
resolveBankPaymentUrl(response: QrCreateResponse): string {
return response.bankUrl ?? '';
return response.bankUrl ?? response.url ?? '';
}
resolvePaymentQrUrl(response: QrCreateResponse): string {