import { Component, ChangeDetectionStrategy, inject, signal, computed, effect, OnDestroy } from '@angular/core'; import { AuthService } from '../../services/auth.service'; import { CartService } from '../../services/cart.service'; import { TranslatePipe } from '../../i18n/translate.pipe'; import { getDiscountedPrice } from '../../utils/item.utils'; @Component({ selector: 'app-telegram-login', imports: [TranslatePipe], templateUrl: './telegram-login.component.html', styleUrls: ['./telegram-login.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) export class TelegramLoginComponent implements OnDestroy { private authService = inject(AuthService); private cartService = inject(CartService); showDialog = this.authService.showLoginDialog; status = this.authService.status; loginUrl = signal(''); qrToken = signal(''); qrStatus = signal<'loading' | 'ready' | 'expired' | 'error'>('loading'); encodedQrUrl = computed(() => encodeURIComponent(this.loginUrl())); private pollTimer?: ReturnType; constructor() { effect(() => { if (this.showDialog()) { this.initQrLogin(); } else { this.stopPolling(); } }); } ngOnDestroy(): void { this.stopPolling(); } close(): void { this.authService.hideLogin(); this.stopPolling(); } openTelegramLogin(): void { window.open(this.loginUrl(), '_blank'); if (!this.pollTimer) { if (this.qrToken()) { this.startPolling(this.qrToken()); } else { this.startSessionPolling(); } } } refreshQr(): void { this.stopPolling(); this.initQrLogin(); } private initQrLogin(): void { this.qrStatus.set('loading'); this.authService.createQrToken().subscribe({ next: (res) => { this.loginUrl.set(res.url); this.qrToken.set(res.token); this.qrStatus.set('ready'); this.startPolling(res.token); }, error: () => { this.loginUrl.set(this.authService.getTelegramLoginUrl()); this.qrStatus.set('error'); this.startSessionPolling(); } }); } private startSessionPolling(): void { this.stopPolling(); let checks = 0; this.pollTimer = setInterval(() => { checks++; if (checks > 100) { this.stopPolling(); this.qrStatus.set('expired'); return; } this.authService.checkSessionOnce().subscribe(session => { if (session && session.active) { this.stopPolling(); this.syncCartAndComplete(session.sessionId); } }); }, 3000); } private startPolling(token: string): void { this.stopPolling(); if (!token) return; let checks = 0; this.pollTimer = setInterval(() => { checks++; if (checks > 100) { this.stopPolling(); this.qrStatus.set('expired'); return; } this.authService.pollQrToken(token).subscribe({ next: (res) => { switch (res.status) { case 'confirmed': this.stopPolling(); if (res.session) { this.syncCartAndComplete(res.session.sessionId); } else { this.authService.onTelegramLoginComplete(); } break; case 'expired': this.stopPolling(); this.qrStatus.set('expired'); break; } }, error: () => { // Network error — keep polling } }); }, 3000); } private syncCartAndComplete(sessionId: string): void { const cartItems = this.cartService.items().map(item => ({ itemID: item.itemID, quantity: item.quantity, colour: item.colour || '', size: item.size || '', price: item.discount > 0 ? item.price * (1 - item.discount / 100) : item.price, })); this.authService.syncCart(sessionId, cartItems).subscribe(() => { this.authService.onTelegramLoginComplete(); }); } private stopPolling(): void { if (this.pollTimer) { clearInterval(this.pollTimer); this.pollTimer = undefined; } } }