import { Component, computed, inject, signal } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { Router, RouterLink } from '@angular/router'; import { HttpClient } from '@angular/common/http'; import { FastcheckService } from '../../fastcheck.service'; import { FASTCHECK_API } from '../../api'; interface WebSessionResponse { sessionId: string; userId: string; expires: string; userSessionId: string; Status: boolean; } @Component({ selector: 'app-fastcheck-page', imports: [FormsModule, RouterLink], templateUrl: './fastcheck-page.html', styleUrl: './fastcheck-page.scss' }) export class FastcheckPage { private http = inject(HttpClient); private store = inject(FastcheckService); private router = inject(Router); // Telegram bot used for the sign-in deep link. private readonly telegramBot = 'DexarSupport_bot'; fastcheckNumber = signal(''); fastcheckAmount = signal(null); fastcheckCode = signal(''); error = signal(''); popupOpen = signal(false); popupLoading = signal(false); popupError = signal(''); webSessionId = signal(''); paid = signal(false); private pollHandle: ReturnType | null = null; telegramLink = computed(() => { const sid = this.webSessionId(); return sid ? `https://t.me/${this.telegramBot}?start=${encodeURIComponent(sid)}` : `https://t.me/${this.telegramBot}`; }); qrUrl = computed(() => { const link = this.telegramLink(); return `https://api.qrserver.com/v1/create-qr-code/?size=240x240&margin=8&data=${encodeURIComponent(link)}`; }); constructor() { // Pull autofill data left over by the create page. const created = this.store.consume(); if (created) { this.fastcheckNumber.set(created.fastcheck); this.fastcheckAmount.set(created.amount); this.fastcheckCode.set(created.code); } } pay(): void { if (!this.fastcheckNumber().trim()) { this.error.set('Введите номер Фастчека'); return; } if (!this.fastcheckCode().trim()) { this.error.set('Введите код Фастчека'); return; } this.error.set(''); this.openPopup(); } private openPopup(): void { this.popupOpen.set(true); this.popupError.set(''); this.paid.set(false); this.popupLoading.set(true); this.http.get(`${FASTCHECK_API}/websession`).subscribe({ next: (res) => { this.popupLoading.set(false); this.webSessionId.set(res.sessionId); this.startPolling(res.sessionId); }, error: () => { this.popupLoading.set(false); this.popupError.set('Не удалось создать сессию. Попробуйте ещё раз.'); } }); } closePopup(): void { this.popupOpen.set(false); this.stopPolling(); if (this.webSessionId()) { // Best-effort logout; ignore errors. this.http .request('DELETE', `${FASTCHECK_API}/websession/${this.webSessionId()}`, { body: { sessionId: this.webSessionId() } }) .subscribe({ error: () => undefined }); } this.webSessionId.set(''); } private startPolling(sessionId: string): void { this.stopPolling(); this.pollHandle = setInterval(() => { this.http .get(`${FASTCHECK_API}/websession/${sessionId}`) .subscribe({ next: (res) => { if (res?.Status) { this.stopPolling(); this.acceptFastcheck(sessionId); } }, error: () => undefined }); }, 3000); } private stopPolling(): void { if (this.pollHandle !== null) { clearInterval(this.pollHandle); this.pollHandle = null; } } private acceptFastcheck(sessionId: string): void { this.popupLoading.set(true); this.http .post( `${FASTCHECK_API}/fastcheck`, { fastcheck: this.fastcheckNumber().trim(), code: this.fastcheckCode().trim() }, { headers: { Authorization: JSON.stringify({ sessionID: sessionId }) } } ) .subscribe({ next: () => { this.popupLoading.set(false); this.paid.set(true); // Fire-and-forget merchant callback if a return_url is on the page. this.fireMerchantCallback(); }, error: () => { this.popupLoading.set(false); this.popupError.set('Не удалось принять Фастчек.'); } }); } private fireMerchantCallback(): void { const params = new URLSearchParams(window.location.search); const returnUrl = params.get('return_url'); if (returnUrl) { setTimeout(() => { window.location.href = `${returnUrl}${returnUrl.includes('?') ? '&' : '?'}fastcheck=${encodeURIComponent( this.fastcheckNumber() )}&status=ok`; }, 1500); } } onAmountChange(value: number | null): void { this.fastcheckAmount.set(value); } }