import { HttpClient } from '@angular/common/http'; import { Component, computed, effect, inject, input, output, signal } from '@angular/core'; import { FASTCHECK_API } from '../api'; import { TranslatePipe } from '../translate/translate.pipe'; interface WebSessionResponse { sessionId: string; userId: string; expires: string; userSessionId: string; Status: boolean; } export type AuthDialogMode = 'payment' | 'login' | 'new'; export interface AuthDialogAuthorizedEvent { sessionId: string; userId: string; userSessionId: string; } type AuthDialogState = 'loading' | 'ready' | 'checking' | 'expired' | 'error'; @Component({ selector: 'app-auth-dialog', imports: [TranslatePipe], templateUrl: './auth-dialog.html', styleUrl: './auth-dialog.scss' }) export class AuthDialogComponent { private readonly http = inject(HttpClient); private readonly telegramBot = 'myAMLKYCBOT'; private readonly sessionStorageKey = 'fc_session'; private readonly maxPollAttempts = 100; open = input(false); mode = input('login'); processing = input(false); authorized = output(); closed = output(); state = signal('loading'); webSessionId = signal(''); messageKey = signal(''); telegramLink = computed(() => { const sessionId = this.webSessionId(); return sessionId ? `https://t.me/${this.telegramBot}?start=${encodeURIComponent(sessionId)}` : `https://t.me/${this.telegramBot}`; }); qrUrl = computed(() => { const link = this.telegramLink(); return `https://api.qrserver.com/v1/create-qr-code/?size=180x180&data=${encodeURIComponent(link)}`; }); get isMobile(): boolean { return typeof window !== 'undefined' && window.innerWidth < 768; } private pollHandle: ReturnType | null = null; private pollAttempts = 0; private wasOpen = false; private authenticated = false; constructor() { effect(() => { const isOpen = this.open(); if (isOpen && !this.wasOpen) { this.wasOpen = true; this.startAuthFlow(); return; } if (!isOpen && this.wasOpen) { this.wasOpen = false; this.finishFlow(); } }); effect(() => { if (!this.open()) return; if (!this.processing()) return; this.state.set('checking'); }); } requestClose(): void { this.closed.emit(); } openTelegram(): void { const link = this.telegramLink(); if (!link) return; window.open(link, '_blank', 'noopener'); } refreshQr(): void { this.cleanupSession(false); this.startAuthFlow(); } private startAuthFlow(): void { this.stopPolling(); this.authenticated = false; this.pollAttempts = 0; this.messageKey.set(''); this.webSessionId.set(''); this.state.set('checking'); const existingSession = localStorage.getItem(this.sessionStorageKey) ?? ''; if (existingSession) { this.checkExistingSession(existingSession); return; } this.createSession(); } private checkExistingSession(sessionId: string): void { this.http.get(`${FASTCHECK_API}/websession/${sessionId}`).subscribe({ next: (response) => { if (response?.Status) { this.webSessionId.set(sessionId); this.handleAuthorized(response, sessionId); return; } localStorage.removeItem(this.sessionStorageKey); this.createSession(); }, error: () => { localStorage.removeItem(this.sessionStorageKey); this.createSession(); } }); } private createSession(): void { this.state.set('loading'); this.http.get(`${FASTCHECK_API}/websession`).subscribe({ next: (response) => { const sessionId = response?.sessionId ?? ''; if (!sessionId) { this.messageKey.set('auth.session_failed'); this.state.set('error'); return; } this.webSessionId.set(sessionId); if (this.isMobile) { this.state.set('checking'); window.location.href = this.telegramLink(); this.startPolling(sessionId); return; } this.state.set('ready'); this.startPolling(sessionId); }, error: () => { this.messageKey.set('auth.session_failed'); this.state.set('error'); } }); } private startPolling(sessionId: string): void { this.stopPolling(); this.pollAttempts = 0; this.pollHandle = setInterval(() => { this.pollAttempts += 1; if (this.pollAttempts >= this.maxPollAttempts) { this.stopPolling(); this.messageKey.set('auth.expired'); this.state.set('expired'); return; } this.http.get(`${FASTCHECK_API}/websession/${sessionId}`).subscribe({ next: (response) => { if (!response?.Status) return; this.handleAuthorized(response, sessionId); }, error: () => undefined }); }, 5000); } private handleAuthorized(response: WebSessionResponse, sessionId: string): void { if (this.authenticated) return; this.authenticated = true; this.stopPolling(); this.webSessionId.set(sessionId); this.state.set('checking'); this.authorized.emit({ sessionId, userId: response.userId ?? '', userSessionId: response.userSessionId ?? '' }); } private finishFlow(): void { const shouldPersistSession = this.authenticated && (this.mode() === 'login' || this.mode() === 'new'); this.cleanupSession(shouldPersistSession); this.messageKey.set(''); this.webSessionId.set(''); this.state.set('loading'); this.authenticated = false; this.pollAttempts = 0; } private cleanupSession(persistSession: boolean): void { this.stopPolling(); const sessionId = this.webSessionId(); if (!sessionId) { if (!persistSession) { localStorage.removeItem(this.sessionStorageKey); } return; } if (persistSession) { localStorage.setItem(this.sessionStorageKey, sessionId); return; } this.http .request('DELETE', `${FASTCHECK_API}/websession/${sessionId}`, { body: { sessionId } }) .subscribe({ error: () => undefined }); localStorage.removeItem(this.sessionStorageKey); } private stopPolling(): void { if (this.pollHandle === null) return; clearInterval(this.pollHandle); this.pollHandle = null; } }