changes
This commit is contained in:
248
src/app/auth-dialog/auth-dialog.ts
Normal file
248
src/app/auth-dialog/auth-dialog.ts
Normal file
@@ -0,0 +1,248 @@
|
||||
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 = 'DexarSupport_bot';
|
||||
private readonly sessionStorageKey = 'fc_session';
|
||||
private readonly maxPollAttempts = 100;
|
||||
|
||||
open = input(false);
|
||||
mode = input<AuthDialogMode>('login');
|
||||
processing = input(false);
|
||||
|
||||
authorized = output<AuthDialogAuthorizedEvent>();
|
||||
closed = output<void>();
|
||||
|
||||
state = signal<AuthDialogState>('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<typeof setInterval> | 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<WebSessionResponse>(`${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<WebSessionResponse>(`${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<WebSessionResponse>(`${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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user