changes
This commit is contained in:
@@ -78,14 +78,14 @@ export const en: Translations = {
|
|||||||
privacyPolicy: 'privacy policy',
|
privacyPolicy: 'privacy policy',
|
||||||
and: 'and',
|
and: 'and',
|
||||||
checkout: 'Place order',
|
checkout: 'Place order',
|
||||||
|
payViaQr: 'Pay via QR',
|
||||||
|
payViaCard: 'Pay via card',
|
||||||
close: 'Close',
|
close: 'Close',
|
||||||
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',
|
||||||
|
|||||||
@@ -78,14 +78,14 @@ export const hy: Translations = {
|
|||||||
privacyPolicy: 'գաղտնիության քաղաքականության',
|
privacyPolicy: 'գաղտնիության քաղաքականության',
|
||||||
and: 'և',
|
and: 'և',
|
||||||
checkout: 'Ձևակերպել պատվերը',
|
checkout: 'Ձևակերպել պատվերը',
|
||||||
|
payViaQr: 'Վճարել QR-ով',
|
||||||
|
payViaCard: 'Վճարել քարտով',
|
||||||
close: 'Փակել',
|
close: 'Փակել',
|
||||||
creatingPayment: 'Վճարման ստեղծում...',
|
creatingPayment: 'Վճարման ստեղծում...',
|
||||||
waitFewSeconds: 'Խնդրում ենք սպասել մի քանի վայրկյան',
|
waitFewSeconds: 'Խնդրում ենք սպասել մի քանի վայրկյան',
|
||||||
scanQr: 'Սքանավորեք QR կոդը վճարման համար',
|
scanQr: 'Սքանավորեք QR կոդը վճարման համար',
|
||||||
choosePaymentMethod: 'Ընտրեք վճարման եղանակը',
|
|
||||||
amountToPay: 'Վճարման գումար՝',
|
amountToPay: 'Վճարման գումար՝',
|
||||||
waitingPayment: 'Սպասում ենք վճարմանը...',
|
waitingPayment: 'Սպասում ենք վճարմանը...',
|
||||||
payByBankCard: 'Վճարել բանկային քարտով',
|
|
||||||
copied: '✓ Պատճենված է',
|
copied: '✓ Պատճենված է',
|
||||||
copyLink: 'Պատճենել հղումը',
|
copyLink: 'Պատճենել հղումը',
|
||||||
openNewTab: 'Բացել նոր ներդիրում',
|
openNewTab: 'Բացել նոր ներդիրում',
|
||||||
|
|||||||
@@ -78,14 +78,14 @@ export const ru: Translations = {
|
|||||||
privacyPolicy: 'политикой конфиденциальности',
|
privacyPolicy: 'политикой конфиденциальности',
|
||||||
and: 'и',
|
and: 'и',
|
||||||
checkout: 'Оформить заказ',
|
checkout: 'Оформить заказ',
|
||||||
|
payViaQr: 'Оплатить через QR',
|
||||||
|
payViaCard: 'Оплатить картой',
|
||||||
close: 'Закрыть',
|
close: 'Закрыть',
|
||||||
creatingPayment: 'Создание платежа...',
|
creatingPayment: 'Создание платежа...',
|
||||||
waitFewSeconds: 'Подождите несколько секунд',
|
waitFewSeconds: 'Подождите несколько секунд',
|
||||||
scanQr: 'Сканируйте QR-код для оплаты',
|
scanQr: 'Сканируйте QR-код для оплаты',
|
||||||
choosePaymentMethod: 'Выберите способ оплаты',
|
|
||||||
amountToPay: 'Сумма к оплате:',
|
amountToPay: 'Сумма к оплате:',
|
||||||
waitingPayment: 'Ожидание оплаты...',
|
waitingPayment: 'Ожидание оплаты...',
|
||||||
payByBankCard: 'Оплатить банковской картой',
|
|
||||||
copied: '✓ Скопировано',
|
copied: '✓ Скопировано',
|
||||||
copyLink: 'Скопировать ссылку',
|
copyLink: 'Скопировать ссылку',
|
||||||
openNewTab: 'Открыть в новой вкладке',
|
openNewTab: 'Открыть в новой вкладке',
|
||||||
|
|||||||
@@ -76,14 +76,14 @@ export interface Translations {
|
|||||||
privacyPolicy: string;
|
privacyPolicy: string;
|
||||||
and: string;
|
and: string;
|
||||||
checkout: string;
|
checkout: string;
|
||||||
|
payViaQr: string;
|
||||||
|
payViaCard: string;
|
||||||
close: string;
|
close: string;
|
||||||
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;
|
||||||
|
|||||||
@@ -157,14 +157,25 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<div class="payment-method-actions">
|
||||||
class="checkout-btn"
|
<button
|
||||||
(click)="checkout()"
|
class="checkout-btn qr-payment-btn"
|
||||||
[class.disabled]="isCheckoutDisabled"
|
(click)="checkout('qr')"
|
||||||
[disabled]="isCheckoutDisabled"
|
[class.disabled]="isCheckoutDisabled"
|
||||||
>
|
[disabled]="isCheckoutDisabled"
|
||||||
{{ 'cart.checkout' | translate }}
|
>
|
||||||
</button>
|
{{ '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()) {
|
@if (!isAuthenticated()) {
|
||||||
<div class="cart-login-gate">
|
<div class="cart-login-gate">
|
||||||
@@ -208,7 +219,7 @@
|
|||||||
|
|
||||||
@if (paymentStatus() === 'waiting') {
|
@if (paymentStatus() === 'waiting') {
|
||||||
<div class="payment-active">
|
<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()) {
|
@if (qrCodeUrl()) {
|
||||||
<div class="qr-section">
|
<div class="qr-section">
|
||||||
@@ -231,12 +242,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (bankPaymentUrl()) {
|
|
||||||
<button class="bank-payment-btn" (click)="openBankPaymentPopup()">
|
|
||||||
{{ 'cart.payByBankCard' | translate }}
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
|
|
||||||
<div class="payment-actions">
|
<div class="payment-actions">
|
||||||
@if (paymentUrl()) {
|
@if (paymentUrl()) {
|
||||||
<button class="copy-btn" (click)="copyPaymentLink()">
|
<button class="copy-btn" (click)="copyPaymentLink()">
|
||||||
|
|||||||
@@ -724,6 +724,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.payment-method-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.checkout-btn {
|
.checkout-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@@ -736,7 +743,6 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
margin-top: 8px;
|
|
||||||
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15);
|
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15);
|
||||||
|
|
||||||
&:hover:not(:disabled) {
|
&: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
|
// 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 {
|
.checkout-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@@ -879,7 +901,6 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
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);
|
box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3);
|
||||||
|
|
||||||
&:hover:not(:disabled) {
|
&: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 {
|
.cart-login-gate {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
padding: 24px;
|
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 {
|
.bank-payment-modal-overlay {
|
||||||
@@ -1671,6 +1683,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.payment-method-actions {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.bank-payment-modal-overlay {
|
.bank-payment-modal-overlay {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import { TranslatePipe } from '../../i18n/translate.pipe';
|
|||||||
import { TranslateService } from '../../i18n/translate.service';
|
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';
|
import { PAYMENT_POLL_INTERVAL_MS, PAYMENT_MAX_CHECKS, PAYMENT_TIMEOUT_CLOSE_MS, LINK_COPIED_DURATION_MS } from '../../config/constants';
|
||||||
|
|
||||||
|
type PaymentMethod = 'qr' | 'card';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-cart',
|
selector: 'app-cart',
|
||||||
imports: [DecimalPipe, RouterLink, FormsModule, EmptyCartIconComponent, DeliverySelectorComponent, TelegramLoginComponent, LangRoutePipe, TranslatePipe],
|
imports: [DecimalPipe, RouterLink, FormsModule, EmptyCartIconComponent, DeliverySelectorComponent, TelegramLoginComponent, LangRoutePipe, TranslatePipe],
|
||||||
@@ -51,6 +53,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
bankPaymentUrl = signal<string>('');
|
bankPaymentUrl = signal<string>('');
|
||||||
bankPaymentFrameUrl = signal<SafeResourceUrl | null>(null);
|
bankPaymentFrameUrl = signal<SafeResourceUrl | null>(null);
|
||||||
showBankPaymentPopup = signal<boolean>(false);
|
showBankPaymentPopup = signal<boolean>(false);
|
||||||
|
selectedPaymentMethod = signal<PaymentMethod>('qr');
|
||||||
paymentId = signal<string>('');
|
paymentId = signal<string>('');
|
||||||
linkCopied = signal<boolean>(false);
|
linkCopied = signal<boolean>(false);
|
||||||
|
|
||||||
@@ -161,7 +164,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
this.cartService.setSelectedDelivery(itemID, selectedDelivery);
|
this.cartService.setSelectedDelivery(itemID, selectedDelivery);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkout(): void {
|
checkout(paymentMethod: PaymentMethod): void {
|
||||||
if (!this.allRequiredDeliveriesSelected()) {
|
if (!this.allRequiredDeliveriesSelected()) {
|
||||||
alert(this.i18n.t('cart.deliveryRequired'));
|
alert(this.i18n.t('cart.deliveryRequired'));
|
||||||
return;
|
return;
|
||||||
@@ -171,11 +174,12 @@ export class CartComponent implements OnDestroy {
|
|||||||
alert(this.i18n.t('cart.acceptTerms'));
|
alert(this.i18n.t('cart.acceptTerms'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.openPaymentPopup();
|
this.openPaymentPopup(paymentMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
openPaymentPopup(): void {
|
openPaymentPopup(paymentMethod: PaymentMethod): void {
|
||||||
this.showPaymentPopup.set(true);
|
this.showPaymentPopup.set(true);
|
||||||
|
this.selectedPaymentMethod.set(paymentMethod);
|
||||||
this.paymentStatus.set('creating');
|
this.paymentStatus.set('creating');
|
||||||
this.paymentId.set('');
|
this.paymentId.set('');
|
||||||
this.qrCodeUrl.set('');
|
this.qrCodeUrl.set('');
|
||||||
@@ -192,7 +196,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
this.phoneError.set('');
|
this.phoneError.set('');
|
||||||
this.emailSubmitting.set(false);
|
this.emailSubmitting.set(false);
|
||||||
this.paidItems = [...this.items()];
|
this.paidItems = [...this.items()];
|
||||||
this.createPayment();
|
this.createPayment(paymentMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
closePaymentPopup(): void {
|
closePaymentPopup(): void {
|
||||||
@@ -219,10 +223,10 @@ export class CartComponent implements OnDestroy {
|
|||||||
this.bankPaymentFrameUrl.set(null);
|
this.bankPaymentFrameUrl.set(null);
|
||||||
this.showBankPaymentPopup.set(false);
|
this.showBankPaymentPopup.set(false);
|
||||||
this.linkCopied.set(false);
|
this.linkCopied.set(false);
|
||||||
this.createPayment();
|
this.createPayment(this.selectedPaymentMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
createPayment(): void {
|
createPayment(paymentMethod: PaymentMethod): void {
|
||||||
const orderId = this.generateOrderId();
|
const orderId = this.generateOrderId();
|
||||||
const paymentPayload = {
|
const paymentPayload = {
|
||||||
amount: Number(this.totalWithDelivery()),
|
amount: Number(this.totalWithDelivery()),
|
||||||
@@ -231,6 +235,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
siteorderID: orderId,
|
siteorderID: orderId,
|
||||||
redirectUrl: '',
|
redirectUrl: '',
|
||||||
telegramUsername: this.getTelegramUsername(),
|
telegramUsername: this.getTelegramUsername(),
|
||||||
|
paymentMethod,
|
||||||
items: this.buildPaymentItems(),
|
items: this.buildPaymentItems(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -242,7 +247,7 @@ export class CartComponent implements OnDestroy {
|
|||||||
const paymentLink = this.apiService.resolvePaymentLink(response);
|
const paymentLink = this.apiService.resolvePaymentLink(response);
|
||||||
const bankUrl = this.apiService.resolveBankPaymentUrl(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);
|
console.error('Payment response missing payment fields:', response);
|
||||||
this.setPaymentError();
|
this.setPaymentError();
|
||||||
return;
|
return;
|
||||||
@@ -255,6 +260,9 @@ export class CartComponent implements OnDestroy {
|
|||||||
|
|
||||||
this.paymentStatus.set('waiting');
|
this.paymentStatus.set('waiting');
|
||||||
this.startPolling();
|
this.startPolling();
|
||||||
|
if (paymentMethod === 'card') {
|
||||||
|
this.openBankPaymentPopup();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error: (err) => {
|
error: (err) => {
|
||||||
console.error('Error creating payment:', err);
|
console.error('Error creating payment:', err);
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ export interface QrCreateResponse {
|
|||||||
nspkID?: string;
|
nspkID?: string;
|
||||||
nspkId?: string;
|
nspkId?: string;
|
||||||
nspkurl?: string;
|
nspkurl?: string;
|
||||||
|
orderID?: string;
|
||||||
|
url?: string;
|
||||||
bankUrl?: string;
|
bankUrl?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
qrStatus?: string;
|
qrStatus?: string;
|
||||||
@@ -43,6 +45,7 @@ export interface CartPaymentRequest {
|
|||||||
siteorderID: string;
|
siteorderID: string;
|
||||||
redirectUrl: string;
|
redirectUrl: string;
|
||||||
telegramUsername: string;
|
telegramUsername: string;
|
||||||
|
paymentMethod: 'qr' | 'card';
|
||||||
items: Array<{ itemID: number; price: number; name: string; quantity?: number; delivery?: DeliveryOption[] }>;
|
items: Array<{ itemID: number; price: number; name: string; quantity?: number; delivery?: DeliveryOption[] }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +540,7 @@ export class ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolvePaymentQrId(response: QrCreateResponse): string {
|
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 {
|
resolvePaymentLink(response: QrCreateResponse): string {
|
||||||
@@ -545,7 +548,7 @@ export class ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolveBankPaymentUrl(response: QrCreateResponse): string {
|
resolveBankPaymentUrl(response: QrCreateResponse): string {
|
||||||
return response.bankUrl ?? '';
|
return response.bankUrl ?? response.url ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvePaymentQrUrl(response: QrCreateResponse): string {
|
resolvePaymentQrUrl(response: QrCreateResponse): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user