From ccf876b635d802e178102c7ba85c1470d5c3f9ea Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Wed, 28 Jan 2026 06:08:04 +0530 Subject: [PATCH] Refactor TelegramConnectionModal and update ConnectStep imports - Cleaned up whitespace in TelegramConnectionModal for improved code readability. - Updated import paths in ConnectStep to align with the new asset structure, ensuring consistency across components. - Enhanced the structure of reducers in the Telegram state management to improve clarity and maintainability. These changes streamline the codebase and enhance the overall organization of the Telegram integration within the application. --- src/components/TelegramConnectionModal.tsx | 356 ++++++++++----------- src/pages/onboarding/steps/ConnectStep.tsx | 8 +- src/store/telegram/reducers.ts | 106 ++++-- 3 files changed, 263 insertions(+), 207 deletions(-) diff --git a/src/components/TelegramConnectionModal.tsx b/src/components/TelegramConnectionModal.tsx index 973a13e8f..ce590cd61 100644 --- a/src/components/TelegramConnectionModal.tsx +++ b/src/components/TelegramConnectionModal.tsx @@ -125,7 +125,7 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec } resolve(password.trim()); }; - + // Set a timeout to prevent hanging forever setTimeout(() => { if (passwordResolverRef.current) { @@ -139,7 +139,7 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec async (err) => { // Handle errors const errorMessage = err.message || 'Authentication error'; - + // Check if it's a 2FA password needed error if (errorMessage.includes('SESSION_PASSWORD_NEEDED') || errorMessage.includes('PASSWORD')) { // This should trigger the password callback, but if it doesn't, handle it here @@ -178,7 +178,7 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec } catch (err) { setIsAuthenticating(false); const errorMessage = err instanceof Error ? err.message : 'Authentication failed'; - + // If it's a password needed error, we should already be on the 2FA step // Don't show it as an error, just log it if (errorMessage.includes('SESSION_PASSWORD_NEEDED')) { @@ -190,7 +190,7 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec } return; // Don't show error, password callback should handle it } - + setError(errorMessage); setCurrentStep('error'); dispatch(setAuthError(errorMessage)); @@ -207,7 +207,7 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec const updateTimer = () => { const remaining = Math.max(0, Math.floor((qrCodeExpires * 1000 - Date.now()) / 1000)); setTimeRemaining(remaining); - + // If timer reaches 0 and we're on QR step, reload the QR code if (remaining === 0 && currentStep === 'qr' && !isAuthenticating) { startQrCodeFlow(); @@ -235,7 +235,7 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec if (!client) return; const isAuthorized = await client.checkAuthorization(); - + if (isAuthorized) { // User is authenticated - check if we need password try { @@ -277,12 +277,12 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec const handle2FASubmit = async () => { const passwordValue = password.trim(); - + if (!passwordValue) { setError('Please enter your password'); return; } - + if (!passwordResolverRef.current) { console.error('Password resolver is null - password callback may not be active'); setError('Authentication session expired. Please try again.'); @@ -298,10 +298,10 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec // This will pass the password to the Telegram library const resolver = passwordResolverRef.current; passwordResolverRef.current = null; // Clear before resolving to prevent double calls - + console.log('Resolving password promise - sending password to Telegram'); resolver(passwordValue); - + // The authentication will continue in the background via signInWithQrCode // The success/error will be handled by the signInWithQrCode promise // We keep isAuthenticating true until the promise resolves or rejects @@ -340,9 +340,9 @@ const TelegramConnectionModal = ({ isOpen, onClose, onComplete }: TelegramConnec if (!isOpen) return null; const modalContent = ( -
-
- {/* Close button */} - + {/* Close button */} + - {currentStep === 'loading' ? ( -
-
-

Initializing Telegram connection...

+ {currentStep === 'loading' ? ( +
+
+

Initializing Telegram connection...

+
+ ) : currentStep === 'error' ? ( + <> + {/* Error Screen */} +
+
+ + + +
+

Connection Error

+

{error || 'An error occurred'}

+
+ + +
- ) : currentStep === 'error' ? ( - <> - {/* Error Screen */} -
-
- - - -
-

Connection Error

-

{error || 'An error occurred'}

-
- - + + ) : currentStep === 'qr' ? ( + <> + {/* QR Code Screen */} +
+ {/* QR Code Container */} +
+
+ {qrCodeUrl ? ( +
+ +
+ ) : ( +
+ {isAuthenticating ? ( +
+
+

Generating QR code...

+
+ ) : ( +

Loading QR code...

+ )} +
+ )}
- - ) : currentStep === 'qr' ? ( - <> - {/* QR Code Screen */} -
- {/* QR Code Container */} -
-
- {qrCodeUrl ? ( -
- -
- ) : ( -
- {isAuthenticating ? ( -
-
-

Generating QR code...

-
- ) : ( -

Loading QR code...

- )} -
- )} -
-
- {qrCodeExpires && timeRemaining > 0 && ( -

- This code expires in {timeRemaining} seconds -

- )} - - {error && ( -
-

{error}

-
- )} - - {/* Instructions */} -
-
-
- 1 -
-

Open Telegram on your phone

-
- -
-
- 2 -
-

Go to Settings > Devices > Link Desktop Device

-
- -
-
- 3 -
-

Point your phone at this screen to confirm login

-
-
-
- - ) : ( - <> - {/* 2FA Screen */} -
-

Enter Your Password

-

- {passwordHint - ? `Your account is protected with two-step verification. Hint: ${passwordHint}` - : 'Your account is protected with two-step verification. Please enter your password to continue.'} + {qrCodeExpires && timeRemaining > 0 && ( +

+ This code expires in {timeRemaining} seconds

+ )} - {error && ( -
-

{error}

+ {error && ( +
+

{error}

+
+ )} + + {/* Instructions */} +
+
+
+ 1
- )} - - {/* Password input */} -
- setPassword(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter' && password.trim() && !isAuthenticating) { - handle2FASubmit(); - } - }} - placeholder="Enter your password" - className="w-full px-4 py-3 bg-black/50 border border-stone-700 rounded-xl text-white placeholder-opacity-50 focus:outline-none focus:border-primary-500 transition-colors" - autoComplete="off" - data-form-type="other" - data-lpignore="true" - data-1p-ignore="true" - data-bwignore="true" - data-dashlane-ignore="true" - data-bitwarden-watching="false" - autoFocus - disabled={isAuthenticating} - /> +

Open Telegram on your phone

- {/* Action buttons */} -
- - +
+
+ 2 +
+

Go to Settings > Devices > Link Desktop Device

+
+ +
+
+ 3 +
+

Point your phone at this screen to confirm login

- - )} -
+
+ + ) : ( + <> + {/* 2FA Screen */} +
+

Enter Your Password

+

+ {passwordHint + ? `Your account is protected with two-step verification. Hint: ${passwordHint}` + : 'Your account is protected with two-step verification. Please enter your password to continue.'} +

+ + {error && ( +
+

{error}

+
+ )} + + {/* Password input */} +
+ setPassword(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter' && password.trim() && !isAuthenticating) { + handle2FASubmit(); + } + }} + placeholder="Enter your password" + className="w-full px-4 py-3 bg-black/50 border border-stone-700 rounded-xl text-white placeholder-opacity-50 focus:outline-none focus:border-primary-500 transition-colors" + autoComplete="off" + data-form-type="other" + data-lpignore="true" + data-1p-ignore="true" + data-bwignore="true" + data-dashlane-ignore="true" + data-bitwarden-watching="false" + autoFocus + disabled={isAuthenticating} + /> +
+ + {/* Action buttons */} +
+ + +
+
+ + )} +
); diff --git a/src/pages/onboarding/steps/ConnectStep.tsx b/src/pages/onboarding/steps/ConnectStep.tsx index 9f6a78472..1a4e06c9e 100644 --- a/src/pages/onboarding/steps/ConnectStep.tsx +++ b/src/pages/onboarding/steps/ConnectStep.tsx @@ -2,10 +2,10 @@ import { useState } from 'react'; import GoogleIcon from '../../../assets/icons/GoogleIcon'; import TelegramConnectionModal from '../../../components/TelegramConnectionModal'; -import BinanceIcon from './icons/binance.svg'; -import NotionIcon from './icons/notion.svg'; -import TelegramIcon from './icons/telegram.svg'; -import MetamaskIcon from './icons/metamask.svg'; +import BinanceIcon from '../../../assets/icons/binance.svg'; +import NotionIcon from '../../../assets/icons/notion.svg'; +import TelegramIcon from '../../../assets/icons/telegram.svg'; +import MetamaskIcon from '../../../assets/icons/metamask.svg'; interface ConnectStepProps { diff --git a/src/store/telegram/reducers.ts b/src/store/telegram/reducers.ts index e4b3e6842..93e6db5a9 100644 --- a/src/store/telegram/reducers.ts +++ b/src/store/telegram/reducers.ts @@ -1,4 +1,4 @@ -import { PayloadAction } from '@reduxjs/toolkit'; +import { PayloadAction } from "@reduxjs/toolkit"; import type { TelegramState, TelegramConnectionStatus, @@ -7,50 +7,74 @@ import type { TelegramChat, TelegramMessage, TelegramThread, -} from './types'; +} from "./types"; export const reducers = { // Connection actions - setConnectionStatus: (state: TelegramState, action: PayloadAction) => { + setConnectionStatus: ( + state: TelegramState, + action: PayloadAction, + ) => { state.connectionStatus = action.payload; - if (action.payload !== 'error') { + if (action.payload !== "error") { state.connectionError = null; } }, - setConnectionError: (state: TelegramState, action: PayloadAction) => { + setConnectionError: ( + state: TelegramState, + action: PayloadAction, + ) => { state.connectionError = action.payload; if (action.payload) { - state.connectionStatus = 'error'; + state.connectionStatus = "error"; } }, // Authentication actions - setAuthStatus: (state: TelegramState, action: PayloadAction) => { + setAuthStatus: ( + state: TelegramState, + action: PayloadAction, + ) => { state.authStatus = action.payload; - if (action.payload !== 'error') { + if (action.payload !== "error") { state.authError = null; } }, - setAuthError: (state: TelegramState, action: PayloadAction) => { + setAuthError: ( + state: TelegramState, + action: PayloadAction, + ) => { state.authError = action.payload; if (action.payload) { - state.authStatus = 'error'; + state.authStatus = "error"; } }, - setPhoneNumber: (state: TelegramState, action: PayloadAction) => { + setPhoneNumber: ( + state: TelegramState, + action: PayloadAction, + ) => { state.phoneNumber = action.payload; }, - setSessionString: (state: TelegramState, action: PayloadAction) => { + setSessionString: ( + state: TelegramState, + action: PayloadAction, + ) => { state.sessionString = action.payload; }, // User actions - setCurrentUser: (state: TelegramState, action: PayloadAction) => { + setCurrentUser: ( + state: TelegramState, + action: PayloadAction, + ) => { state.currentUser = action.payload; }, // Chat actions - setChats: (state: TelegramState, action: PayloadAction>) => { + setChats: ( + state: TelegramState, + action: PayloadAction>, + ) => { state.chats = action.payload; }, addChat: (state: TelegramState, action: PayloadAction) => { @@ -60,7 +84,10 @@ export const reducers = { state.chatsOrder.unshift(chat.id); } }, - updateChat: (state: TelegramState, action: PayloadAction & { id: string }>) => { + updateChat: ( + state: TelegramState, + action: PayloadAction & { id: string }>, + ) => { const { id, ...updates } = action.payload; if (state.chats[id]) { state.chats[id] = { ...state.chats[id], ...updates }; @@ -74,7 +101,10 @@ export const reducers = { state.selectedChatId = null; } }, - setSelectedChat: (state: TelegramState, action: PayloadAction) => { + setSelectedChat: ( + state: TelegramState, + action: PayloadAction, + ) => { state.selectedChatId = action.payload; // Clear selected thread when changing chat if (action.payload !== state.selectedChatId) { @@ -86,7 +116,10 @@ export const reducers = { }, // Message actions - addMessage: (state: TelegramState, action: PayloadAction) => { + addMessage: ( + state: TelegramState, + action: PayloadAction, + ) => { const message = action.payload; const { chatId, id } = message; @@ -100,7 +133,10 @@ export const reducers = { state.messagesOrder[chatId].push(id); } }, - addMessages: (state: TelegramState, action: PayloadAction<{ chatId: string; messages: TelegramMessage[] }>) => { + addMessages: ( + state: TelegramState, + action: PayloadAction<{ chatId: string; messages: TelegramMessage[] }>, + ) => { const { chatId, messages } = action.payload; if (!state.messages[chatId]) { @@ -117,7 +153,11 @@ export const reducers = { }, updateMessage: ( state: TelegramState, - action: PayloadAction<{ chatId: string; messageId: string; updates: Partial }> + action: PayloadAction<{ + chatId: string; + messageId: string; + updates: Partial; + }>, ) => { const { chatId, messageId, updates } = action.payload; if (state.messages[chatId]?.[messageId]) { @@ -127,12 +167,15 @@ export const reducers = { }; } }, - removeMessage: (state: TelegramState, action: PayloadAction<{ chatId: string; messageId: string }>) => { + removeMessage: ( + state: TelegramState, + action: PayloadAction<{ chatId: string; messageId: string }>, + ) => { const { chatId, messageId } = action.payload; if (state.messages[chatId]?.[messageId]) { delete state.messages[chatId][messageId]; state.messagesOrder[chatId] = state.messagesOrder[chatId].filter( - (id) => id !== messageId + (id) => id !== messageId, ); } }, @@ -159,7 +202,11 @@ export const reducers = { }, updateThread: ( state: TelegramState, - action: PayloadAction<{ chatId: string; threadId: string; updates: Partial }> + action: PayloadAction<{ + chatId: string; + threadId: string; + updates: Partial; + }>, ) => { const { chatId, threadId, updates } = action.payload; if (state.threads[chatId]?.[threadId]) { @@ -169,15 +216,24 @@ export const reducers = { }; } }, - setSelectedThread: (state: TelegramState, action: PayloadAction) => { + setSelectedThread: ( + state: TelegramState, + action: PayloadAction, + ) => { state.selectedThreadId = action.payload; }, // Search actions - setSearchQuery: (state: TelegramState, action: PayloadAction) => { + setSearchQuery: ( + state: TelegramState, + action: PayloadAction, + ) => { state.searchQuery = action.payload; }, - setFilteredChatIds: (state: TelegramState, action: PayloadAction) => { + setFilteredChatIds: ( + state: TelegramState, + action: PayloadAction, + ) => { state.filteredChatIds = action.payload; },