diff --git a/src/services/sockets/socket.service.test.ts b/src/services/sockets/socket.service.test.ts index d1e75e2f1..4e979eb24 100644 --- a/src/services/sockets/socket.service.test.ts +++ b/src/services/sockets/socket.service.test.ts @@ -95,11 +95,13 @@ describe('RealtimeService', () => { test.each([ { isProduction: true, reconnection: true, withCredentials: true, logs: false }, - { isProduction: false, reconnection: true, withCredentials: false, logs: true }, + { isProduction: false, reconnection: false, withCredentials: false, logs: true }, ])( 'When running in isProduction=$isProduction environment, then it adjusts reconnection=$reconnection, withCredentials=$withCredentials and logging=$logs', ({ isProduction, reconnection, withCredentials, logs }) => { vi.spyOn(envService, 'isProduction').mockReturnValue(isProduction); + (RealtimeService as unknown as { instance: RealtimeService | undefined }).instance = undefined; + service = RealtimeService.getInstance(); service.init(); @@ -118,6 +120,64 @@ describe('RealtimeService', () => { ); }); + describe('Logging behavior', () => { + const resetServiceWithProduction = (isProduction: boolean) => { + vi.spyOn(envService, 'isProduction').mockReturnValue(isProduction); + (RealtimeService as unknown as { instance: RealtimeService | undefined }).instance = undefined; + return RealtimeService.getInstance(); + }; + + test('When not in production, then it logs on connect event', () => { + service = resetServiceWithProduction(false); + service.init(); + const connectHandler = mockSocket.on.mock.calls.find((call) => call[0] === 'connect')?.[1]; + connectHandler?.(); + expect(consoleLogSpy).toHaveBeenCalledWith('[REALTIME]: CONNECTED WITH ID', mockSocket.id); + }); + + test('When in production, then it does not log on connect event', () => { + service = resetServiceWithProduction(true); + service.init(); + const connectHandler = mockSocket.on.mock.calls.find((call) => call[0] === 'connect')?.[1]; + connectHandler?.(); + expect(consoleLogSpy).not.toHaveBeenCalledWith('[REALTIME]: CONNECTED WITH ID', mockSocket.id); + }); + + test('When not in production, then it logs on disconnect event', () => { + service = resetServiceWithProduction(false); + service.init(); + const disconnectHandler = mockSocket.on.mock.calls.find((call) => call[0] === 'disconnect')?.[1]; + disconnectHandler?.('transport close'); + expect(consoleLogSpy).toHaveBeenCalledWith('[REALTIME] DISCONNECTED:', 'transport close'); + }); + + test('When in production, then it does not log on disconnect event', () => { + service = resetServiceWithProduction(true); + service.init(); + const disconnectHandler = mockSocket.on.mock.calls.find((call) => call[0] === 'disconnect')?.[1]; + disconnectHandler?.('transport close'); + expect(consoleLogSpy).not.toHaveBeenCalledWith('[REALTIME] DISCONNECTED:', 'transport close'); + }); + + test('When not in production, then it logs errors on connect_error event', () => { + service = resetServiceWithProduction(false); + service.init(); + const connectErrorHandler = mockSocket.on.mock.calls.find((call) => call[0] === 'connect_error')?.[1]; + const error = new Error('connection refused'); + connectErrorHandler?.(error); + expect(consoleErrorSpy).toHaveBeenCalledWith('[REALTIME] CONNECTION ERROR:', error); + }); + + test('When in production, then it does not log errors on connect_error event', () => { + service = resetServiceWithProduction(true); + service.init(); + const connectErrorHandler = mockSocket.on.mock.calls.find((call) => call[0] === 'connect_error')?.[1]; + const error = new Error('connection refused'); + connectErrorHandler?.(error); + expect(consoleErrorSpy).not.toHaveBeenCalledWith('[REALTIME] CONNECTION ERROR:', error); + }); + }); + describe('Retrieving connection identifier', () => { test('When getting the client Id after initialization, then it provides a unique identifier', () => { service.init(); diff --git a/src/services/sockets/socket.service.ts b/src/services/sockets/socket.service.ts index 8f590fee8..a15800a8e 100644 --- a/src/services/sockets/socket.service.ts +++ b/src/services/sockets/socket.service.ts @@ -8,6 +8,7 @@ export default class RealtimeService { private socket?: Socket; private static instance: RealtimeService; private readonly eventHandlers: Set<(data: EventData) => void> = new Set(); + private readonly isProduction = envService.isProduction(); static getInstance(): RealtimeService { if (!this.instance) { @@ -18,7 +19,7 @@ export default class RealtimeService { } init(onConnected?: () => void): void { - if (!envService.isProduction()) { + if (!this.isProduction) { console.log('[REALTIME]: CONNECTING...'); } @@ -26,12 +27,12 @@ export default class RealtimeService { auth: { token: getToken(), }, - reconnection: true, - withCredentials: envService.isProduction(), + reconnection: this.isProduction, + withCredentials: this.isProduction, }); this.socket.on('connect', () => { - if (!envService.isProduction()) { + if (!this.isProduction) { console.log('[REALTIME]: CONNECTED WITH ID', this.socket?.id); } onConnected?.(); @@ -50,13 +51,13 @@ export default class RealtimeService { }); this.socket.on('disconnect', (reason) => { - if (!envService.isProduction()) { + if (!this.isProduction) { console.log('[REALTIME] DISCONNECTED:', reason); } }); this.socket.on('connect_error', (error) => { - if (!envService.isProduction()) console.error('[REALTIME] CONNECTION ERROR:', error); + if (!this.isProduction) console.error('[REALTIME] CONNECTION ERROR:', error); }); } @@ -68,14 +69,14 @@ export default class RealtimeService { } onEvent(cb: (data: any) => void): () => void { - if (!envService.isProduction()) { + if (!this.isProduction) { console.log('[REALTIME] Registering event handler. Total handlers:', this.eventHandlers.size + 1); } this.eventHandlers.add(cb); return () => { - if (!envService.isProduction()) { + if (!this.isProduction) { console.log('[REALTIME] Removing event handler. Remaining handlers:', this.eventHandlers.size - 1); } this.eventHandlers.delete(cb); @@ -83,7 +84,7 @@ export default class RealtimeService { } removeAllListeners() { - if (!envService.isProduction()) { + if (!this.isProduction) { console.log('[REALTIME] Clearing all event handlers'); } this.eventHandlers.clear(); diff --git a/src/views/Drive/components/DriveExplorer/DriveExplorer.tsx b/src/views/Drive/components/DriveExplorer/DriveExplorer.tsx index d93a3c926..26590fe2c 100644 --- a/src/views/Drive/components/DriveExplorer/DriveExplorer.tsx +++ b/src/views/Drive/components/DriveExplorer/DriveExplorer.tsx @@ -416,6 +416,13 @@ const DriveExplorer = (props: DriveExplorerProps): JSX.Element => { } }; + const onTrashCleared = useCallback(() => { + dispatch(storageActions.resetTrash()); + paginationState.setHasMoreItems(false); + setHasMoreTrashFolders(false); + onItemsDeleted?.(); + }, [onItemsDeleted]); + const onCloseEditItemDialog = (newItem) => { if (newItem && editNameItem) { if (isFileViewerOpen) { @@ -530,7 +537,7 @@ const DriveExplorer = (props: DriveExplorerProps): JSX.Element => { }} isTrash={isTrash} /> - + diff --git a/src/views/Drive/hooks/usePaginationState.ts b/src/views/Drive/hooks/usePaginationState.ts index 121444ee9..3d205ba42 100644 --- a/src/views/Drive/hooks/usePaginationState.ts +++ b/src/views/Drive/hooks/usePaginationState.ts @@ -19,7 +19,7 @@ export const usePaginationState = ({ isTrash, hasMoreFiles, hasMoreFolders }: Us }, [hasMoreFiles, isTrash]); useEffect(() => { - if (hasMoreFiles && hasMoreFolders) { + if (!isTrash && hasMoreFiles && hasMoreFolders) { setHasMoreItems(true); } }, [hasMoreFiles, hasMoreFolders]);