Files
marketplaces/src/app/components/telegram-login/telegram-login.component.ts

159 lines
4.1 KiB
TypeScript
Raw Normal View History

2026-03-25 15:32:50 +04:00
import { Component, ChangeDetectionStrategy, inject, signal, computed, effect, OnDestroy } from '@angular/core';
2026-02-28 17:18:24 +04:00
import { AuthService } from '../../services/auth.service';
2026-03-25 15:32:50 +04:00
import { CartService } from '../../services/cart.service';
2026-02-28 17:18:24 +04:00
import { TranslatePipe } from '../../i18n/translate.pipe';
2026-03-25 15:32:50 +04:00
import { getDiscountedPrice } from '../../utils/item.utils';
2026-02-28 17:18:24 +04:00
@Component({
selector: 'app-telegram-login',
imports: [TranslatePipe],
templateUrl: './telegram-login.component.html',
styleUrls: ['./telegram-login.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
2026-03-25 15:32:50 +04:00
export class TelegramLoginComponent implements OnDestroy {
2026-02-28 17:18:24 +04:00
private authService = inject(AuthService);
2026-03-25 15:32:50 +04:00
private cartService = inject(CartService);
2026-02-28 17:18:24 +04:00
showDialog = this.authService.showLoginDialog;
status = this.authService.status;
2026-03-25 15:32:50 +04:00
2026-02-28 17:18:24 +04:00
loginUrl = signal('');
2026-03-25 15:32:50 +04:00
qrToken = signal('');
qrStatus = signal<'loading' | 'ready' | 'expired' | 'error'>('loading');
encodedQrUrl = computed(() => encodeURIComponent(this.loginUrl()));
2026-02-28 17:18:24 +04:00
private pollTimer?: ReturnType<typeof setInterval>;
2026-03-25 15:32:50 +04:00
constructor() {
effect(() => {
if (this.showDialog()) {
this.initQrLogin();
} else {
this.stopPolling();
}
});
2026-02-28 17:18:24 +04:00
}
ngOnDestroy(): void {
this.stopPolling();
}
close(): void {
this.authService.hideLogin();
this.stopPolling();
}
openTelegramLogin(): void {
window.open(this.loginUrl(), '_blank');
2026-03-25 15:32:50 +04:00
if (!this.pollTimer) {
2026-04-14 23:14:26 +04:00
if (this.qrToken()) {
this.startPolling(this.qrToken());
} else {
this.startSessionPolling();
}
2026-03-25 15:32:50 +04:00
}
2026-02-28 17:18:24 +04:00
}
2026-03-25 15:32:50 +04:00
refreshQr(): void {
2026-02-28 17:18:24 +04:00
this.stopPolling();
2026-03-25 15:32:50 +04:00
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');
2026-04-14 23:14:26 +04:00
this.startSessionPolling();
2026-03-25 15:32:50 +04:00
}
});
}
2026-04-14 23:14:26 +04:00
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);
}
2026-03-25 15:32:50 +04:00
private startPolling(token: string): void {
this.stopPolling();
if (!token) return;
2026-02-28 17:18:24 +04:00
let checks = 0;
this.pollTimer = setInterval(() => {
checks++;
2026-03-25 15:32:50 +04:00
if (checks > 100) {
2026-02-28 17:18:24 +04:00
this.stopPolling();
2026-03-25 15:32:50 +04:00
this.qrStatus.set('expired');
2026-02-28 17:18:24 +04:00
return;
}
2026-03-25 15:32:50 +04:00
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
}
});
2026-02-28 17:18:24 +04:00
}, 3000);
}
2026-03-25 15:32:50 +04:00
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();
});
}
2026-02-28 17:18:24 +04:00
private stopPolling(): void {
if (this.pollTimer) {
clearInterval(this.pollTimer);
this.pollTimer = undefined;
}
}
}