From 6e5fb3b86a89d9a47938c247eee9a57cd70b1178 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Tue, 14 Apr 2026 23:14:26 +0400 Subject: [PATCH] QR login --- .../telegram-login.component.ts | 26 ++++++++++++- src/app/interceptors/mock-data.interceptor.ts | 37 +++++++++++++++++++ src/app/services/auth.service.ts | 16 ++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/app/components/telegram-login/telegram-login.component.ts b/src/app/components/telegram-login/telegram-login.component.ts index 20287fe..e716cdd 100644 --- a/src/app/components/telegram-login/telegram-login.component.ts +++ b/src/app/components/telegram-login/telegram-login.component.ts @@ -47,7 +47,11 @@ export class TelegramLoginComponent implements OnDestroy { openTelegramLogin(): void { window.open(this.loginUrl(), '_blank'); if (!this.pollTimer) { - this.startPolling(this.qrToken()); + if (this.qrToken()) { + this.startPolling(this.qrToken()); + } else { + this.startSessionPolling(); + } } } @@ -68,10 +72,30 @@ export class TelegramLoginComponent implements OnDestroy { 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; diff --git a/src/app/interceptors/mock-data.interceptor.ts b/src/app/interceptors/mock-data.interceptor.ts index 8575414..83e522d 100644 --- a/src/app/interceptors/mock-data.interceptor.ts +++ b/src/app/interceptors/mock-data.interceptor.ts @@ -671,6 +671,9 @@ function respond(body: T, delayMs = 150) { return of(new HttpResponse({ status: 200, body })).pipe(delay(delayMs)); } +// ─── Mock Auth State ─── +let mockQrPollCount = 0; + // ─── The Interceptor ─── export const mockDataInterceptor: HttpInterceptorFn = (req, next) => { @@ -685,6 +688,40 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => { return respond({ message: 'pong (mock)' }); } + // ── GET /auth/session + if (url.includes('/auth/session') && req.method === 'GET') { + return respond({ active: false }, 100); + } + + // ── POST /auth/qr/create + if (url.includes('/auth/qr/create') && req.method === 'POST') { + const token = 'mock-qr-token-' + Date.now(); + const botUsername = (environment as Record)['telegramBot'] as string || 'DexarSupport_bot'; + mockQrPollCount = 0; + return respond({ + token, + url: `https://t.me/${botUsername}?start=qr_${token}` + }, 200); + } + + // ── GET /auth/qr/poll + if (url.includes('/auth/qr/poll') && req.method === 'GET') { + mockQrPollCount++; + // Simulate confirmed after 3 polls (~9 seconds) + if (mockQrPollCount >= 3) { + return respond({ + status: 'confirmed', + session: { + sessionId: 'mock-session-' + Date.now(), + active: true, + displayName: 'Telegram User', + expiresAt: new Date(Date.now() + 3600000).toISOString() + } + }, 200); + } + return respond({ status: 'pending' }, 200); + } + // ── GET /category (all categories flat list) if (url.endsWith('/category') && req.method === 'GET') { return respond(MOCK_CATEGORIES); diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index de5f470..c9b65f3 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -60,6 +60,22 @@ export class AuthService { }); } + /** Check session without updating internal state (for polling) */ + checkSessionOnce(): Observable { + return this.http.get(`${this.apiUrl}/auth/session`, { + withCredentials: true + }).pipe( + tap(session => { + if (session && session.active) { + this.sessionSignal.set(session); + this.statusSignal.set('authenticated'); + this.scheduleSessionRefresh(session.expiresAt); + } + }), + catchError(() => of(null)) + ); + } + /** * Called after user completes Telegram login. * The callback URL from Telegram will hit our backend which sets the cookie.