reset
This commit is contained in:
@@ -19,48 +19,92 @@ export class TelegramLoginComponent implements OnDestroy {
|
|||||||
webSessionID = signal('');
|
webSessionID = signal('');
|
||||||
qrStatus = signal<'loading' | 'ready' | 'expired' | 'error'>('loading');
|
qrStatus = signal<'loading' | 'ready' | 'expired' | 'error'>('loading');
|
||||||
encodedQrUrl = computed(() => encodeURIComponent(this.loginUrl()));
|
encodedQrUrl = computed(() => encodeURIComponent(this.loginUrl()));
|
||||||
|
awaitingTelegramReturn = signal(false);
|
||||||
|
|
||||||
private readonly pollIntervalMs = 5000;
|
private readonly pollIntervalMs = 5000;
|
||||||
private pollTimer?: ReturnType<typeof setInterval>;
|
private pollTimer?: ReturnType<typeof setInterval>;
|
||||||
|
private mobileFallbackTimeout?: ReturnType<typeof setTimeout>;
|
||||||
|
private launchFrame?: HTMLIFrameElement;
|
||||||
|
private readonly handleVisibilityChange = () => {
|
||||||
|
if (typeof document !== 'undefined' && document.visibilityState === 'hidden') {
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.checkLoginAfterReturn();
|
||||||
|
};
|
||||||
|
private readonly handleWindowFocus = () => {
|
||||||
|
this.checkLoginAfterReturn();
|
||||||
|
};
|
||||||
|
private readonly handlePageShow = () => {
|
||||||
|
this.checkLoginAfterReturn();
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
effect(() => {
|
effect(() => {
|
||||||
if (this.showDialog()) {
|
if (this.showDialog()) {
|
||||||
this.initQrLogin();
|
this.initQrLogin();
|
||||||
} else {
|
} else {
|
||||||
|
this.awaitingTelegramReturn.set(false);
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
document.addEventListener('visibilitychange', this.handleVisibilityChange);
|
||||||
|
window.addEventListener('focus', this.handleWindowFocus);
|
||||||
|
window.addEventListener('pageshow', this.handlePageShow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
this.awaitingTelegramReturn.set(false);
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
||||||
|
window.removeEventListener('focus', this.handleWindowFocus);
|
||||||
|
window.removeEventListener('pageshow', this.handlePageShow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(): void {
|
close(): void {
|
||||||
|
this.awaitingTelegramReturn.set(false);
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
this.authService.hideLogin();
|
this.authService.hideLogin();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
}
|
}
|
||||||
|
|
||||||
openTelegramLogin(): void {
|
openTelegramLogin(): void {
|
||||||
const url = this.loginUrl();
|
const url = this.loginUrl();
|
||||||
if (!url) return;
|
|
||||||
|
|
||||||
window.open(url, '_blank');
|
|
||||||
if (!this.pollTimer) {
|
|
||||||
const webSessionID = this.webSessionID();
|
const webSessionID = this.webSessionID();
|
||||||
if (webSessionID) {
|
if (!url || !webSessionID) return;
|
||||||
|
|
||||||
|
if (!this.pollTimer) {
|
||||||
this.startPolling(webSessionID);
|
this.startPolling(webSessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isMobileBrowser()) {
|
||||||
|
this.awaitingTelegramReturn.set(true);
|
||||||
|
this.launchTelegramApp(webSessionID);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.open(url, '_blank', 'noopener,noreferrer');
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshQr(): void {
|
refreshQr(): void {
|
||||||
|
this.awaitingTelegramReturn.set(false);
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
this.initQrLogin();
|
this.initQrLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
private initQrLogin(): void {
|
private initQrLogin(): void {
|
||||||
|
this.awaitingTelegramReturn.set(false);
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
this.qrStatus.set('loading');
|
this.qrStatus.set('loading');
|
||||||
this.loginUrl.set('');
|
this.loginUrl.set('');
|
||||||
this.webSessionID.set('');
|
this.webSessionID.set('');
|
||||||
@@ -94,6 +138,8 @@ export class TelegramLoginComponent implements OnDestroy {
|
|||||||
this.authService.checkSessionOnce(webSessionID).subscribe({
|
this.authService.checkSessionOnce(webSessionID).subscribe({
|
||||||
next: (session) => {
|
next: (session) => {
|
||||||
if (session?.active) {
|
if (session?.active) {
|
||||||
|
this.awaitingTelegramReturn.set(false);
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
this.authService.onTelegramLoginComplete();
|
this.authService.onTelegramLoginComplete();
|
||||||
}
|
}
|
||||||
@@ -111,4 +157,73 @@ export class TelegramLoginComponent implements OnDestroy {
|
|||||||
this.pollTimer = undefined;
|
this.pollTimer = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private checkLoginAfterReturn(): void {
|
||||||
|
if (!this.showDialog() || !this.awaitingTelegramReturn()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const webSessionID = this.webSessionID();
|
||||||
|
if (!webSessionID) {
|
||||||
|
this.awaitingTelegramReturn.set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.pollTimer) {
|
||||||
|
this.startPolling(webSessionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.authService.checkSessionOnce(webSessionID).subscribe(session => {
|
||||||
|
if (session?.active) {
|
||||||
|
this.awaitingTelegramReturn.set(false);
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
|
this.stopPolling();
|
||||||
|
this.authService.onTelegramLoginComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private launchTelegramApp(webSessionID: string): void {
|
||||||
|
if (typeof document === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clearMobileLaunchArtifacts();
|
||||||
|
|
||||||
|
this.launchFrame = document.createElement('iframe');
|
||||||
|
this.launchFrame.style.display = 'none';
|
||||||
|
this.launchFrame.setAttribute('aria-hidden', 'true');
|
||||||
|
this.launchFrame.setAttribute('tabindex', '-1');
|
||||||
|
this.launchFrame.src = this.authService.getTelegramAppLoginUrl(webSessionID);
|
||||||
|
document.body.appendChild(this.launchFrame);
|
||||||
|
|
||||||
|
this.mobileFallbackTimeout = setTimeout(() => {
|
||||||
|
this.removeLaunchFrame();
|
||||||
|
}, 1400);
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearMobileLaunchArtifacts(): void {
|
||||||
|
if (this.mobileFallbackTimeout) {
|
||||||
|
clearTimeout(this.mobileFallbackTimeout);
|
||||||
|
this.mobileFallbackTimeout = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeLaunchFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeLaunchFrame(): void {
|
||||||
|
this.launchFrame?.remove();
|
||||||
|
this.launchFrame = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isMobileBrowser(): boolean {
|
||||||
|
if (typeof navigator === 'undefined') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userAgent = navigator.userAgent || navigator.vendor;
|
||||||
|
const isTouchMac = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1;
|
||||||
|
|
||||||
|
return /Android|iPhone|iPad|iPod|IEMobile|Opera Mini/i.test(userAgent) || isTouchMac;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,10 +84,16 @@ export class AuthService {
|
|||||||
|
|
||||||
/** Generate the Telegram login URL for bot-based auth */
|
/** Generate the Telegram login URL for bot-based auth */
|
||||||
getTelegramLoginUrl(webSessionID = this.generateGuid()): string {
|
getTelegramLoginUrl(webSessionID = this.generateGuid()): string {
|
||||||
const botUsername = (environment as Record<string, unknown>)['telegramBot'] as string || 'DexarSupport_bot';
|
const botUsername = this.getTelegramBotUsername();
|
||||||
return `https://t.me/${botUsername}?start=${encodeURIComponent(webSessionID)}`;
|
return `https://t.me/${botUsername}?start=${encodeURIComponent(webSessionID)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Generate a Telegram app deep link for mobile login without opening a browser tab. */
|
||||||
|
getTelegramAppLoginUrl(webSessionID: string): string {
|
||||||
|
const botUsername = this.getTelegramBotUsername();
|
||||||
|
return `tg://resolve?domain=${encodeURIComponent(botUsername)}&start=${encodeURIComponent(webSessionID)}`;
|
||||||
|
}
|
||||||
|
|
||||||
/** Get QR code data URL for Telegram login */
|
/** Get QR code data URL for Telegram login */
|
||||||
getTelegramQrUrl(): string {
|
getTelegramQrUrl(): string {
|
||||||
return this.getTelegramLoginUrl();
|
return this.getTelegramLoginUrl();
|
||||||
@@ -348,4 +354,8 @@ export class AuthService {
|
|||||||
|
|
||||||
document.cookie = `${WEB_SESSION_COOKIE}=; Max-Age=0; Path=/; SameSite=Lax`;
|
document.cookie = `${WEB_SESSION_COOKIE}=; Max-Age=0; Path=/; SameSite=Lax`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getTelegramBotUsername(): string {
|
||||||
|
return (environment as Record<string, unknown>)['telegramBot'] as string || 'DexarSupport_bot';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user