diff --git a/apps/meteor/client/contexts/VideoConfContext.ts b/apps/meteor/client/contexts/VideoConfContext.ts index 2a4b2bd736fd..60932119f614 100644 --- a/apps/meteor/client/contexts/VideoConfContext.ts +++ b/apps/meteor/client/contexts/VideoConfContext.ts @@ -1,7 +1,6 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { createContext, useContext } from 'react'; -import type { Subscription } from 'use-subscription'; -import { useSubscription } from 'use-subscription'; +import { useSyncExternalStore } from 'use-sync-external-store'; import type { DirectCallData, ProviderCapabilities, CallPreferences, VideoConfManager } from '../lib/VideoConfManager'; @@ -22,11 +21,26 @@ type VideoConfContextValue = { rejectIncomingCall: (callId: string) => void; abortCall: () => void; setPreferences: (prefs: { mic?: boolean; cam?: boolean }) => void; - queryIncomingCalls: Subscription; - queryRinging: Subscription; - queryCalling: Subscription; - queryCapabilities: Subscription; - queryPreferences: Subscription; + queryIncomingCalls: { + subscribe: (cb: () => void) => () => void; + getSnapshot: () => DirectCallData[]; + }; + queryRinging: { + subscribe: (cb: () => void) => () => void; + getSnapshot: () => boolean; + }; + queryCalling: { + subscribe: (cb: () => void) => () => void; + getSnapshot: () => boolean; + }; + queryCapabilities: { + subscribe: (cb: () => void) => () => void; + getSnapshot: () => ProviderCapabilities; + }; + queryPreferences: { + subscribe: (cb: () => void) => () => void; + getSnapshot: () => CallPreferences; + }; }; export const VideoConfContext = createContext(undefined); @@ -49,24 +63,24 @@ export const useVideoConfAbortCall = (): VideoConfContextValue['abortCall'] => u export const useVideoConfRejectIncomingCall = (): VideoConfContextValue['rejectIncomingCall'] => useVideoConfContext().rejectIncomingCall; export const useVideoConfIncomingCalls = (): DirectCallData[] => { const { queryIncomingCalls } = useVideoConfContext(); - return useSubscription(queryIncomingCalls); + return useSyncExternalStore(queryIncomingCalls.subscribe, queryIncomingCalls.getSnapshot); }; export const useVideoConfSetPreferences = (): VideoConfContextValue['setPreferences'] => useVideoConfContext().setPreferences; export const useVideoConfIsRinging = (): boolean => { const { queryRinging } = useVideoConfContext(); - return useSubscription(queryRinging); + return useSyncExternalStore(queryRinging.subscribe, queryRinging.getSnapshot); }; export const useVideoConfIsCalling = (): boolean => { const { queryCalling } = useVideoConfContext(); - return useSubscription(queryCalling); + return useSyncExternalStore(queryCalling.subscribe, queryCalling.getSnapshot); }; export const useVideoConfCapabilities = (): ProviderCapabilities => { const { queryCapabilities } = useVideoConfContext(); - return useSubscription(queryCapabilities); + return useSyncExternalStore(queryCapabilities.subscribe, queryCapabilities.getSnapshot); }; export const useVideoConfPreferences = (): CallPreferences => { const { queryPreferences } = useVideoConfContext(); - return useSubscription(queryPreferences); + return useSyncExternalStore(queryPreferences.subscribe, queryPreferences.getSnapshot); }; export const useVideoConfManager = (): typeof VideoConfManager | undefined => useContext(VideoConfContext)?.manager; diff --git a/apps/meteor/client/providers/VideoConfProvider.tsx b/apps/meteor/client/providers/VideoConfProvider.tsx index 17cb5957ef4b..7553e4c52bfe 100644 --- a/apps/meteor/client/providers/VideoConfProvider.tsx +++ b/apps/meteor/client/providers/VideoConfProvider.tsx @@ -1,7 +1,6 @@ import type { IRoom } from '@rocket.chat/core-typings'; import type { ReactElement, ReactNode } from 'react'; import React, { useState, useMemo, useEffect } from 'react'; -import type { Unsubscribe } from 'use-subscription'; import type { VideoConfPopupPayload } from '../contexts/VideoConfContext'; import { VideoConfContext } from '../contexts/VideoConfContext'; @@ -42,24 +41,24 @@ const VideoConfContextProvider = ({ children }: { children: ReactNode }): ReactE abortCall: (): void => VideoConfManager.abortCall(), setPreferences: (prefs: Partial<(typeof VideoConfManager)['preferences']>): void => VideoConfManager.setPreferences(prefs), queryIncomingCalls: { - getCurrentValue: (): DirectCallData[] => VideoConfManager.getIncomingDirectCalls(), - subscribe: (cb: () => void): Unsubscribe => VideoConfManager.on('incoming/changed', cb), + getSnapshot: (): DirectCallData[] => VideoConfManager.getIncomingDirectCalls(), + subscribe: (cb: () => void) => VideoConfManager.on('incoming/changed', cb), }, queryRinging: { - getCurrentValue: (): boolean => VideoConfManager.isRinging(), - subscribe: (cb: () => void): Unsubscribe => VideoConfManager.on('ringing/changed', cb), + getSnapshot: (): boolean => VideoConfManager.isRinging(), + subscribe: (cb: () => void) => VideoConfManager.on('ringing/changed', cb), }, queryCalling: { - getCurrentValue: (): boolean => VideoConfManager.isCalling(), - subscribe: (cb: () => void): Unsubscribe => VideoConfManager.on('calling/changed', cb), + getSnapshot: (): boolean => VideoConfManager.isCalling(), + subscribe: (cb: () => void) => VideoConfManager.on('calling/changed', cb), }, queryCapabilities: { - getCurrentValue: (): ProviderCapabilities => VideoConfManager.capabilities, - subscribe: (cb: () => void): Unsubscribe => VideoConfManager.on('capabilities/changed', cb), + getSnapshot: (): ProviderCapabilities => VideoConfManager.capabilities, + subscribe: (cb: () => void) => VideoConfManager.on('capabilities/changed', cb), }, queryPreferences: { - getCurrentValue: (): CallPreferences => VideoConfManager.preferences, - subscribe: (cb: () => void): Unsubscribe => VideoConfManager.on('preference/changed', cb), + getSnapshot: (): CallPreferences => VideoConfManager.preferences, + subscribe: (cb: () => void) => VideoConfManager.on('preference/changed', cb), }, }), [], diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx index 1577cc50dc24..63e64b27e076 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx @@ -15,7 +15,7 @@ import { useTranslation, useUserPreference, useLayout, useSetting } from '@rocke import { useMutation } from '@tanstack/react-query'; import type { ReactElement, MouseEventHandler, FormEvent, ClipboardEventHandler, MouseEvent } from 'react'; import React, { memo, useRef, useReducer, useCallback } from 'react'; -import { useSubscription } from 'use-subscription'; +import { useSyncExternalStore } from 'use-sync-external-store'; import { createComposerAPI } from '../../../../../app/ui-message/client/messageBox/createComposerAPI'; import type { FormattingButton } from '../../../../../app/ui-message/client/messageBox/messageBoxFormatting'; @@ -248,30 +248,27 @@ const MessageBox = ({ onTyping?.(); }); - const isEditing = useSubscription({ - getCurrentValue: chat.composer?.editing.get ?? getEmptyFalse, - subscribe: chat.composer?.editing.subscribe ?? emptySubscribe, - }); + const isEditing = useSyncExternalStore(chat.composer?.editing.subscribe ?? emptySubscribe, chat.composer?.editing.get ?? getEmptyFalse); - const isRecordingAudio = useSubscription({ - getCurrentValue: chat.composer?.recording.get ?? getEmptyFalse, - subscribe: chat.composer?.recording.subscribe ?? emptySubscribe, - }); + const isRecordingAudio = useSyncExternalStore( + chat.composer?.recording.subscribe ?? emptySubscribe, + chat.composer?.recording.get ?? getEmptyFalse, + ); - const isMicrophoneDenied = useSubscription({ - getCurrentValue: chat.composer?.isMicrophoneDenied.get ?? getEmptyFalse, - subscribe: chat.composer?.isMicrophoneDenied.subscribe ?? emptySubscribe, - }); + const isMicrophoneDenied = useSyncExternalStore( + chat.composer?.isMicrophoneDenied.subscribe ?? emptySubscribe, + chat.composer?.isMicrophoneDenied.get ?? getEmptyFalse, + ); - const isRecordingVideo = useSubscription({ - getCurrentValue: chat.composer?.recordingVideo.get ?? getEmptyFalse, - subscribe: chat.composer?.recordingVideo.subscribe ?? emptySubscribe, - }); + const isRecordingVideo = useSyncExternalStore( + chat.composer?.recordingVideo.subscribe ?? emptySubscribe, + chat.composer?.recordingVideo.get ?? getEmptyFalse, + ); - const formatters = useSubscription({ - getCurrentValue: chat.composer?.formatters.get ?? getEmptyArray, - subscribe: chat.composer?.formatters.subscribe ?? emptySubscribe, - }); + const formatters = useSyncExternalStore( + chat.composer?.formatters.subscribe ?? emptySubscribe, + chat.composer?.formatters.get ?? getEmptyArray, + ); const isRecording = isRecordingAudio || isRecordingVideo; diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx b/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx index 9c52b78ca599..a68498bdee5a 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxReplies.tsx @@ -4,7 +4,7 @@ import { IconButton, Box, Margins } from '@rocket.chat/fuselage'; import { useSetting } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { memo } from 'react'; -import { useSubscription } from 'use-subscription'; +import { useSyncExternalStore } from 'use-sync-external-store'; import { getUserDisplayName } from '../../../../../lib/getUserDisplayName'; import { QuoteAttachment } from '../../../../components/message/content/attachments/QuoteAttachment'; @@ -18,10 +18,7 @@ const MessageBoxReplies = (): ReactElement | null => { throw new Error('Chat context not found'); } - const replies = useSubscription({ - getCurrentValue: chat.composer.quotedMessages.get, - subscribe: chat.composer.quotedMessages.subscribe, - }); + const replies = useSyncExternalStore(chat.composer.quotedMessages.subscribe, chat.composer.quotedMessages.get); const useRealName = Boolean(useSetting('UI_Use_Real_Name')); diff --git a/apps/meteor/package.json b/apps/meteor/package.json index c217605d1637..6d48ccde9994 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -154,7 +154,6 @@ "@types/supports-color": "~7.2.1", "@types/textarea-caret": "^3.0.3", "@types/ua-parser-js": "^0.7.39", - "@types/use-subscription": "^1.0.2", "@types/use-sync-external-store": "^0.0.6", "@types/uuid": "^8.3.4", "@types/xml-crypto": "~1.4.6", @@ -436,7 +435,6 @@ "underscore": "^1.13.7", "universal-perf-hooks": "^1.0.1", "url-polyfill": "^1.1.12", - "use-subscription": "~1.6.0", "use-sync-external-store": "^1.2.2", "uuid": "^8.3.2", "webdav": "^4.11.4", diff --git a/apps/uikit-playground/package.json b/apps/uikit-playground/package.json index a2bfd9d7de60..a485363e7a17 100644 --- a/apps/uikit-playground/package.json +++ b/apps/uikit-playground/package.json @@ -37,14 +37,12 @@ "react-router-dom": "^6.11.2", "react-split-pane": "^0.1.92", "react-virtuoso": "^4.7.1", - "reactflow": "^11.7.2", - "use-subscription": "^1.8.2" + "reactflow": "^11.7.2" }, "devDependencies": { "@types/react": "~17.0.80", "@types/react-beautiful-dnd": "^13.1.8", "@types/react-dom": "~17.0.25", - "@types/use-subscription": "^1.0.2", "@typescript-eslint/eslint-plugin": "~5.60.1", "@typescript-eslint/parser": "~5.60.1", "@vitejs/plugin-react": "^4.0.0", diff --git a/yarn.lock b/yarn.lock index 5dd4b180f75e..b4ed3718e3db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9063,7 +9063,6 @@ __metadata: "@types/supports-color": "npm:~7.2.1" "@types/textarea-caret": "npm:^3.0.3" "@types/ua-parser-js": "npm:^0.7.39" - "@types/use-subscription": "npm:^1.0.2" "@types/use-sync-external-store": "npm:^0.0.6" "@types/uuid": "npm:^8.3.4" "@types/xml-crypto": "npm:~1.4.6" @@ -9264,7 +9263,6 @@ __metadata: underscore: "npm:^1.13.7" universal-perf-hooks: "npm:^1.0.1" url-polyfill: "npm:^1.1.12" - use-subscription: "npm:~1.6.0" use-sync-external-store: "npm:^1.2.2" uuid: "npm:^8.3.2" webdav: "npm:^4.11.4" @@ -10169,7 +10167,6 @@ __metadata: "@types/react": "npm:~17.0.80" "@types/react-beautiful-dnd": "npm:^13.1.8" "@types/react-dom": "npm:~17.0.25" - "@types/use-subscription": "npm:^1.0.2" "@typescript-eslint/eslint-plugin": "npm:~5.60.1" "@typescript-eslint/parser": "npm:~5.60.1" "@vitejs/plugin-react": "npm:^4.0.0" @@ -10188,7 +10185,6 @@ __metadata: react-virtuoso: "npm:^4.7.1" reactflow: "npm:^11.7.2" typescript: "npm:~5.6.3" - use-subscription: "npm:^1.8.2" vite: "npm:^4.5.5" languageName: unknown linkType: soft @@ -13323,13 +13319,6 @@ __metadata: languageName: node linkType: hard -"@types/use-subscription@npm:^1.0.2": - version: 1.0.2 - resolution: "@types/use-subscription@npm:1.0.2" - checksum: 10/e547d8ffdf8410c985c271a30903cd754687a6514a67192378213590f707a0f516e0c11930cba10bd7e98dc4f7917e066b3b8d37a622d02b6fcf3c5df530e467 - languageName: node - linkType: hard - "@types/use-sync-external-store@npm:^0.0.6": version: 0.0.6 resolution: "@types/use-sync-external-store@npm:0.0.6" @@ -38012,26 +38001,6 @@ __metadata: languageName: node linkType: hard -"use-subscription@npm:^1.8.2": - version: 1.8.2 - resolution: "use-subscription@npm:1.8.2" - dependencies: - use-sync-external-store: "npm:^1.2.2" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 10/6b17f92a75405a4e6015d7762b459a43435f34d0bb9a72e512e305d6d3a61bd170e6666c3a62c2c3c7af1b7ba0b45c5a597b7eeea54c46e1cabf8ef0f971d44e - languageName: node - linkType: hard - -"use-subscription@npm:~1.6.0": - version: 1.6.0 - resolution: "use-subscription@npm:1.6.0" - peerDependencies: - react: ^18.0.0 - checksum: 10/afce4295e439069d6139079c7c3a12ac3e6c4e81cd9b1622e62934e007d8cf2885f6aae5bd8de4f031d3eb5bd3cea2fd83d9be8c3da9542d4ba0a9de170be274 - languageName: node - linkType: hard - "use-sync-external-store@npm:1.2.0": version: 1.2.0 resolution: "use-sync-external-store@npm:1.2.0"