From 15ab29e23f7e447026c6f90695ace5e46e9f84bf Mon Sep 17 00:00:00 2001 From: Andre Padez Date: Fri, 20 Feb 2026 21:52:07 +0000 Subject: [PATCH] Remove config module dependency from frontend - Delete unused useWebsockets.ts hook - Hardcode API URLs instead of using config module: - useClient.ts: default '/api' - useAuth.ts: '/api/auth' and '/api' - usePasskeys.ts: '/api/auth' - useImageLoader.ts: '/api' - useFiles.ts: '/api' - file-types.ts: '/api' - Remove useWebsockets export from hooks/index.ts --- src/workspaces/apps/FileBrowser/useFiles.ts | 7 +- src/workspaces/apps/FileViewer/file-types.ts | 7 +- src/workspaces/hooks/src/index.ts | 1 - src/workspaces/hooks/src/useAuth/useAuth.ts | 3 +- .../hooks/src/useAuth/usePasskeys.ts | 3 +- src/workspaces/hooks/src/useClient.ts | 5 +- src/workspaces/hooks/src/useImageLoader.ts | 3 +- src/workspaces/hooks/src/useWebsockets.ts | 111 ------------------ 8 files changed, 13 insertions(+), 127 deletions(-) delete mode 100644 src/workspaces/hooks/src/useWebsockets.ts diff --git a/src/workspaces/apps/FileBrowser/useFiles.ts b/src/workspaces/apps/FileBrowser/useFiles.ts index cc0ecafe..df55c642 100644 --- a/src/workspaces/apps/FileBrowser/useFiles.ts +++ b/src/workspaces/apps/FileBrowser/useFiles.ts @@ -1,5 +1,6 @@ import { useClient, getHeaders } from 'hooks/useClient'; -import { config } from 'config'; + +const API_URL = '/api'; export type DirEntry = { name: string; @@ -79,7 +80,7 @@ export const useFiles = (root: string = 'home') => { triggerBlobDownload(blob, isDir && !name.endsWith('.zip') ? `${name}.zip` : name); } else { const headers = getHeaders(); - const url = `${config.API_URL}/${withRoot('/file-browser/download').replace(/^\//, '')}`; + const url = `${API_URL}/${withRoot('/file-browser/download').replace(/^\//, '')}`; const res = await fetch(url, { method: 'POST', headers: { ...headers, 'Content-Type': 'application/json' }, @@ -98,7 +99,7 @@ export const useFiles = (root: string = 'home') => { formData.append('file', file, name); } const authHeaders = getHeaders(); - const url = withRoot(`${config.API_URL}/file-browser/upload?path=${encodeURIComponent(path)}`); + const url = withRoot(`${API_URL}/file-browser/upload?path=${encodeURIComponent(path)}`); return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); diff --git a/src/workspaces/apps/FileViewer/file-types.ts b/src/workspaces/apps/FileViewer/file-types.ts index d6228211..203386c9 100644 --- a/src/workspaces/apps/FileViewer/file-types.ts +++ b/src/workspaces/apps/FileViewer/file-types.ts @@ -1,5 +1,6 @@ import { getHeaders } from 'hooks/useClient'; -import { config } from 'config'; + +const API_URL = '/api'; export type FileType = 'markdown' | 'audio' | 'video' | 'image' | 'pdf' | 'code' | 'archive' | 'text'; @@ -143,14 +144,14 @@ export function getRawUrl(filePath: string, root?: string): string { const headers = getHeaders(); const token = headers['Authorization']?.replace('Bearer ', '') ?? ''; const rootParam = root && root !== 'home' ? `&root=${encodeURIComponent(root)}` : ''; - return `${config.API_URL}/file-browser/raw?path=${encodeURIComponent(filePath)}&token=${encodeURIComponent(token)}${rootParam}`; + return `${API_URL}/file-browser/raw?path=${encodeURIComponent(filePath)}&token=${encodeURIComponent(token)}${rootParam}`; } export function getTranscodeUrl(filePath: string, root?: string, t = '0'): string { const headers = getHeaders(); const token = headers['Authorization']?.replace('Bearer ', '') ?? ''; const rootParam = root && root !== 'home' ? `&root=${encodeURIComponent(root)}` : ''; - return `${config.API_URL}/file-browser/transcode?path=${encodeURIComponent(filePath)}&t=${encodeURIComponent(t)}&token=${encodeURIComponent(token)}${rootParam}`; + return `${API_URL}/file-browser/transcode?path=${encodeURIComponent(filePath)}&t=${encodeURIComponent(t)}&token=${encodeURIComponent(token)}${rootParam}`; } export function getArchiveBaseName(name: string): string { diff --git a/src/workspaces/hooks/src/index.ts b/src/workspaces/hooks/src/index.ts index d88e4d62..6790b5d3 100644 --- a/src/workspaces/hooks/src/index.ts +++ b/src/workspaces/hooks/src/index.ts @@ -12,7 +12,6 @@ export { usePopover } from './usePopover'; export { useQueryState } from './useQueryState'; export { useTimeout } from './useTimeout'; export { useTimer } from './useTimer'; -export { useWebsockets } from './useWebsockets'; export { useChatWebSocket } from './useChatWebSocket'; export { useDataControl } from './useDataControl'; export { useCustomSorter } from './useCustomSorter'; diff --git a/src/workspaces/hooks/src/useAuth/useAuth.ts b/src/workspaces/hooks/src/useAuth/useAuth.ts index 33f8b02b..8213af6e 100644 --- a/src/workspaces/hooks/src/useAuth/useAuth.ts +++ b/src/workspaces/hooks/src/useAuth/useAuth.ts @@ -3,13 +3,12 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useClient } from 'hooks/useClient'; import { useGlobal } from 'hooks/useGlobal'; import { usePasskeys } from './usePasskeys'; -import { config } from 'config'; type UseAuthProps = { authUrl?: string; apiUrl?: string } | undefined; export type UserWithToken = User & { token: string }; export const useAuth = (props: UseAuthProps = {}) => { - const { authUrl = config.AUTH_URL, apiUrl = config.API_URL } = props; + const { authUrl = '/api/auth', apiUrl = '/api' } = props; const queryClient = useQueryClient(); const [user, setUser, refreshUser] = useGlobal('CURRENT_USER', null); const authClient = useClient(authUrl); diff --git a/src/workspaces/hooks/src/useAuth/usePasskeys.ts b/src/workspaces/hooks/src/useAuth/usePasskeys.ts index 2c135216..116f5743 100644 --- a/src/workspaces/hooks/src/useAuth/usePasskeys.ts +++ b/src/workspaces/hooks/src/useAuth/usePasskeys.ts @@ -1,6 +1,5 @@ import { useQueryClient } from '@tanstack/react-query'; import { useClient } from 'hooks/useClient'; -import { config } from 'config'; import { startRegistration, startAuthentication } from '@simplewebauthn/browser'; import type { PublicKeyCredentialCreationOptionsJSON, @@ -16,7 +15,7 @@ type PasskeyUser = { export const usePasskeys = () => { const queryClient = useQueryClient(); - const authClient = useClient(config.AUTH_URL); + const authClient = useClient('/api/auth'); const createPasskeyCredentials = async (user: PasskeyUser) => { // Get registration options from server diff --git a/src/workspaces/hooks/src/useClient.ts b/src/workspaces/hooks/src/useClient.ts index d8398fb9..d32ef489 100644 --- a/src/workspaces/hooks/src/useClient.ts +++ b/src/workspaces/hooks/src/useClient.ts @@ -1,8 +1,7 @@ -import { config } from 'config'; import { useGlobal } from './useGlobal'; let theToken: string | null = null; -export const createClient = (baseUrl: string = config.API_URL) => { +export const createClient = (baseUrl: string = '/api') => { const lsToken = window.officerBearerToken || document.body.dataset['officerBearerToken'] || @@ -28,7 +27,7 @@ export const createClient = (baseUrl: string = config.API_URL) => { }; }; -export const useClient = (baseUrl: string = config.API_URL) => { +export const useClient = (baseUrl: string = '/api') => { const [apiError, setApiError] = useGlobal('API_ERROR', null); useClient.config.onError = (error) => { setApiError(error); diff --git a/src/workspaces/hooks/src/useImageLoader.ts b/src/workspaces/hooks/src/useImageLoader.ts index e55579c4..5d8cea06 100644 --- a/src/workspaces/hooks/src/useImageLoader.ts +++ b/src/workspaces/hooks/src/useImageLoader.ts @@ -1,8 +1,7 @@ import { useEffect, useRef } from 'react'; import { useClient } from 'hooks/useClient'; -import { config } from 'config'; -export const useImageLoader = (baseUrl: string = config.FILES_URL) => { +export const useImageLoader = (baseUrl: string = '/api') => { const listContainer = useRef(null); const filesClient = useClient(baseUrl); diff --git a/src/workspaces/hooks/src/useWebsockets.ts b/src/workspaces/hooks/src/useWebsockets.ts deleted file mode 100644 index 7ab3a9ce..00000000 --- a/src/workspaces/hooks/src/useWebsockets.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { useState, useEffect, useRef, useCallback } from 'react'; -import { config } from 'config'; -import type { WebSocketMessage } from './types'; - -type MessageHandler = (data: WebSocketMessage) => void; - -export const useWebsockets = (onMessage?: MessageHandler) => { - const [isOnline, setOnline] = useState(false); - const [userCount, setUserCount] = useState(0); - - const socketRef = useRef(null); - const retryRef = useRef(0); - const retryTimeoutRef = useRef(null); - const isCleaningUpRef = useRef(false); - - const connectSocket = useCallback(() => { - if (isCleaningUpRef.current) return; - if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) return; - - const socket = new WebSocket(config.WS_URL); - socketRef.current = socket; - - socket.addEventListener('open', () => { - setOnline(true); - retryRef.current = 0; - console.log('🟢 Connected to', config.WS_URL); - }); - - socket.addEventListener('message', (event) => { - try { - let data: WebSocketMessage; - - if (event.data instanceof ArrayBuffer) { - const text = new TextDecoder().decode(event.data); - data = JSON.parse(text) as WebSocketMessage; - } else if (typeof event.data === 'string') { - data = JSON.parse(event.data) as WebSocketMessage; - } else { - console.warn('⚠️ Unknown WS message type:', typeof event.data); - return; - } - - if ( - data && - typeof data === 'object' && - 'type' in data && - data.type === 'users' && - 'count' in data && - typeof data.count === 'number' - ) { - console.log('👥 Users online:', data.count); - setUserCount(data.count); - return; - } - - onMessage?.(data); - } catch (err) { - console.warn('⚠️ Failed to parse WS message:', event.data, err); - } - }); - - socket.addEventListener('close', () => { - if (isCleaningUpRef.current) return; - - setOnline(false); - console.log('🔴 Disconnected'); - - const retry = (retryRef.current ?? 0) + 1; - retryRef.current = retry; - const delay = Math.min(5000, 300 * retry); - retryTimeoutRef.current = window.setTimeout(connectSocket, delay); - }); - - socket.addEventListener('error', (err) => { - console.error('⚠️ WebSocket error', err); - socket.close(); - }); - }, [onMessage]); - - const send = useCallback((data: string | Record) => { - const socket = socketRef.current; - if (socket && socket.readyState === WebSocket.OPEN) { - socket.send(typeof data === 'string' ? data : JSON.stringify(data)); - } else { - console.warn('Cannot send message, socket not ready'); - } - }, []); - - useEffect(() => { - isCleaningUpRef.current = false; - connectSocket(); - - return () => { - isCleaningUpRef.current = true; - - if (retryTimeoutRef.current !== null) { - clearTimeout(retryTimeoutRef.current); - retryTimeoutRef.current = null; - } - - if (socketRef.current) { - socketRef.current.close(); - socketRef.current = null; - } - }; - }, [connectSocket]); - - return { isOnline, userCount, send }; -}; - -export type UseWebsocketsReturn = ReturnType;