QR login
This commit is contained in:
@@ -47,7 +47,11 @@ export class TelegramLoginComponent implements OnDestroy {
|
|||||||
openTelegramLogin(): void {
|
openTelegramLogin(): void {
|
||||||
window.open(this.loginUrl(), '_blank');
|
window.open(this.loginUrl(), '_blank');
|
||||||
if (!this.pollTimer) {
|
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: () => {
|
error: () => {
|
||||||
this.loginUrl.set(this.authService.getTelegramLoginUrl());
|
this.loginUrl.set(this.authService.getTelegramLoginUrl());
|
||||||
this.qrStatus.set('error');
|
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 {
|
private startPolling(token: string): void {
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
|
|||||||
@@ -671,6 +671,9 @@ function respond<T>(body: T, delayMs = 150) {
|
|||||||
return of(new HttpResponse({ status: 200, body })).pipe(delay(delayMs));
|
return of(new HttpResponse({ status: 200, body })).pipe(delay(delayMs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Mock Auth State ───
|
||||||
|
let mockQrPollCount = 0;
|
||||||
|
|
||||||
// ─── The Interceptor ───
|
// ─── The Interceptor ───
|
||||||
|
|
||||||
export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
||||||
@@ -685,6 +688,40 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
|||||||
return respond({ message: 'pong (mock)' });
|
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<string, unknown>)['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)
|
// ── GET /category (all categories flat list)
|
||||||
if (url.endsWith('/category') && req.method === 'GET') {
|
if (url.endsWith('/category') && req.method === 'GET') {
|
||||||
return respond(MOCK_CATEGORIES);
|
return respond(MOCK_CATEGORIES);
|
||||||
|
|||||||
@@ -60,6 +60,22 @@ export class AuthService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check session without updating internal state (for polling) */
|
||||||
|
checkSessionOnce(): Observable<AuthSession | null> {
|
||||||
|
return this.http.get<AuthSession>(`${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.
|
* Called after user completes Telegram login.
|
||||||
* The callback URL from Telegram will hit our backend which sets the cookie.
|
* The callback URL from Telegram will hit our backend which sets the cookie.
|
||||||
|
|||||||
Reference in New Issue
Block a user