diff --git a/src/app/i18n/en.ts b/src/app/i18n/en.ts index c8d811d..ae76e39 100644 --- a/src/app/i18n/en.ts +++ b/src/app/i18n/en.ts @@ -123,6 +123,9 @@ export const en: Translations = { emailNeedsAt: 'Email must contain @', emailNeedsDomain: 'Email must contain a domain (.com, .ru, etc.)', emailInvalid: 'Invalid email format', + telegramIdMissing: 'We could not identify your Telegram account, so we could not save your contact details. Your payment was still successful.', + emailPlaceholder: 'you@example.com', + phonePlaceholder: '+7 (___) ___-__-__', loginRequired: 'Log in to checkout', loginRequiredDesc: 'Please log in via Telegram to place your order', loginWithTelegram: 'Log in with Telegram', diff --git a/src/app/i18n/hy.ts b/src/app/i18n/hy.ts index 2d8c342..8c471d9 100644 --- a/src/app/i18n/hy.ts +++ b/src/app/i18n/hy.ts @@ -123,6 +123,9 @@ export const hy: Translations = { emailNeedsAt: 'Email-ը պետք է պարունակի @', emailNeedsDomain: 'Email-ը պետք է պարունակի դոմեյն (.com, .ru և այլն)', emailInvalid: 'Սխալ email ձևաչափ', + telegramIdMissing: 'Չհաջողվեց հաստատել ձեր Telegram հաշիվը, ուստի կոնտակտային տվյալները չեն պահպանվել։ Վճարումը հաջողությամբ կատարվել է։', + emailPlaceholder: 'you@example.com', + phonePlaceholder: '+7 (___) ___-__-__', loginRequired: 'Մուտք գործեք ձևակերպելու համար', loginRequiredDesc: 'Պատվեր ձևակերպելու համար մուտք գործեք Telegram-ով', loginWithTelegram: 'Մուտք Telegram-ով', diff --git a/src/app/i18n/ru.ts b/src/app/i18n/ru.ts index 5cdfdef..5f9d6dd 100644 --- a/src/app/i18n/ru.ts +++ b/src/app/i18n/ru.ts @@ -123,6 +123,9 @@ export const ru: Translations = { emailNeedsAt: 'Email должен содержать @', emailNeedsDomain: 'Email должен содержать домен (.com, .ru и т.д.)', emailInvalid: 'Некорректный формат email', + telegramIdMissing: 'Не удалось определить ваш Telegram-аккаунт, поэтому контактные данные не сохранены. Оплата прошла успешно.', + emailPlaceholder: 'you@example.com', + phonePlaceholder: '+7 (___) ___-__-__', loginRequired: 'Войдите для оформления', loginRequiredDesc: 'Для оформления заказа войдите через Telegram', loginWithTelegram: 'Войти через Telegram', diff --git a/src/app/i18n/translations.ts b/src/app/i18n/translations.ts index 8f8592d..2a9d780 100644 --- a/src/app/i18n/translations.ts +++ b/src/app/i18n/translations.ts @@ -121,6 +121,9 @@ export interface Translations { emailNeedsAt: string; emailNeedsDomain: string; emailInvalid: string; + telegramIdMissing: string; + emailPlaceholder: string; + phonePlaceholder: string; loginRequired: string; loginRequiredDesc: string; loginWithTelegram: string; diff --git a/src/app/pages/cart/cart.component.html b/src/app/pages/cart/cart.component.html index a6df206..2bfb1b9 100644 --- a/src/app/pages/cart/cart.component.html +++ b/src/app/pages/cart/cart.component.html @@ -271,6 +271,44 @@

{{ 'cart.paymentSuccess' | translate }}

+ @if (!purchaseSubmitted()) { +

{{ 'cart.paymentSuccessDesc' | translate }}

+
+ + + +
+ }
} diff --git a/src/app/pages/cart/cart.component.scss b/src/app/pages/cart/cart.component.scss index 3f1c608..759b0f8 100644 --- a/src/app/pages/cart/cart.component.scss +++ b/src/app/pages/cart/cart.component.scss @@ -722,6 +722,57 @@ color: white; margin: 0 auto 20px; } + + .contact-capture-form { + display: flex; + flex-direction: column; + gap: 12px; + margin-top: 16px; + text-align: left; + + label { + display: flex; + flex-direction: column; + gap: 4px; + } + + input { + padding: 10px 12px; + border: 1px solid var(--border-color); + border-radius: var(--radius-md, 8px); + font-size: var(--font-size-sm, 0.875rem); + color: var(--text-primary); + background: var(--surface-color, #fff); + + &[aria-invalid='true'] { + border-color: var(--error-color); + } + + &:disabled { + opacity: 0.6; + } + } + + .field-error { + font-size: var(--font-size-xs, 0.75rem); + color: var(--error-color); + } + + button { + padding: 10px 16px; + border: none; + border-radius: var(--radius-md, 8px); + background: var(--primary-color, #2563eb); + color: white; + font-weight: var(--font-weight-bold, 700); + cursor: pointer; + + &:disabled { + opacity: 0.6; + cursor: default; + } + } + } } &.error { diff --git a/src/app/pages/cart/cart.component.ts b/src/app/pages/cart/cart.component.ts index 77ec385..a5cb02d 100644 --- a/src/app/pages/cart/cart.component.ts +++ b/src/app/pages/cart/cart.component.ts @@ -71,6 +71,7 @@ export class CartComponent implements OnDestroy { emailError = signal(''); phoneError = signal(''); emailSubmitting = signal(false); + purchaseSubmitted = signal(false); paidItems: CartItem[] = []; maxChecks = Math.ceil(PAYMENT_MIN_POLL_SECONDS / (PAYMENT_POLL_INTERVAL_MS / 1000)); @@ -219,6 +220,7 @@ export class CartComponent implements OnDestroy { this.emailError.set(''); this.phoneError.set(''); this.emailSubmitting.set(false); + this.purchaseSubmitted.set(false); this.paidItems = [...this.items()]; this.createPayment(paymentMethod); } @@ -439,29 +441,39 @@ export class CartComponent implements OnDestroy { }); } + /** + * Fallback fired a few seconds after payment success if the user hasn't + * already submitted the email/phone form themselves (submitEmail()). + * Navigates home only once the submission result is known, never before - + * and sends whatever the user has typed so far instead of blank fields. + */ private autoSubmitPurchase(): void { - setTimeout(() => { - const lang = this.langService.currentLanguage(); - this.router.navigate([`/${lang}`]);}, 0); - const telegramUserId = this.getTelegramUserId(); - - // Telegram ID is mandatory - if (!telegramUserId) { - console.error('Cannot submit purchase: Telegram ID is required'); - this.emailSubmitting.set(false); + if (this.purchaseSubmitted()) { return; } - + + const telegramUserId = this.getTelegramUserId(); + + // Telegram ID is mandatory for submitPurchaseEmail. + if (!telegramUserId) { + this.notifications.show(this.i18n.t('cart.telegramIdMissing'), 'warning'); + this.emailSubmitting.set(false); + this.closePaymentPopup(); + const lang = this.langService.currentLanguage(); + this.router.navigate([`/${lang}`]); + return; + } + this.emailSubmitting.set(true); - + const emailData = { - email: '', - phone: '', + email: this.userEmail().trim(), + phone: this.userPhone().replace(/\D/g, ''), telegramUserId: telegramUserId, items: this.paidItems.map((item: CartItem) => ({ itemID: item.itemID, name: item.name, - price: item.discount > 0 + price: item.discount > 0 ? item.price * (1 - item.discount / 100) : item.price, currency: item.currency, @@ -469,9 +481,10 @@ export class CartComponent implements OnDestroy { ...(item.selectedDelivery ? { delivery: [item.selectedDelivery] } : {}) })) }; - + this.apiService.submitPurchaseEmail(emailData).subscribe({ next: () => { + this.purchaseSubmitted.set(true); this.emailSubmitting.set(false); this.closePaymentPopup(); const lang = this.langService.currentLanguage(); @@ -487,8 +500,6 @@ export class CartComponent implements OnDestroy { } }); this.paymentStatus.set(null); - - } copyPaymentLink(): void { @@ -541,6 +552,11 @@ export class CartComponent implements OnDestroy { this.apiService.submitPurchaseEmail(emailData).subscribe({ next: () => { + this.purchaseSubmitted.set(true); + if (this.closeTimeout) { + clearTimeout(this.closeTimeout); + this.closeTimeout = undefined; + } this.emailSubmitting.set(false); this.notifications.show(this.i18n.t('cart.emailSuccess'), 'success'); // Close popup and redirect to home page