159 lines
4.1 KiB
TypeScript
159 lines
4.1 KiB
TypeScript
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<typeof setInterval>;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|