diff --git a/ai-docs/DEPRECATED_API_REMOVAL_PLAN.md b/ai-docs/DEPRECATED_API_REMOVAL_PLAN.md new file mode 100644 index 0000000000..25c191345d --- /dev/null +++ b/ai-docs/DEPRECATED_API_REMOVAL_PLAN.md @@ -0,0 +1,117 @@ +# Deprecated API Removal Plan + +## Context + +The SDK (currently at v14 beta) has **31 deprecated items** accumulated over several major versions. Some have been deprecated since v10 ("will be removed in v11.0.0"). Since v14 is still in beta, now is the ideal time to clean these up before stable release. All removals are breaking changes, but they're expected in a major version bump. + +## Inventory + +| # | Deprecated Item | Replacement | Location | Status | +| ---------------------------------------------------------- | ---------------------------------------- | ------------------------------------------- | ----------------------------------------------------------- | ---------------- | +| **Pin Permissions (7 items)** | | | | | +| 1 | `pinPermissions` prop (MessageContext) | `channelCapabilities` | `src/context/MessageContext.tsx` | ✅ Done | +| 2 | `pinPermissions` prop (MessageProps) | `channelCapabilities` | `src/components/Message/types.ts` | ✅ Done | +| 3 | `pinPermissions` prop (MessageListProps) | `channelCapabilities` | `src/components/MessageList/MessageList.tsx` | ✅ Done | +| 4 | `PinEnabledUserRoles` type | `channelCapabilities` | `src/components/Message/hooks/usePinHandler.ts` | ✅ Done | +| 5 | `PinPermissions` type | `channelCapabilities` | `src/components/Message/hooks/usePinHandler.ts` | ✅ Done | +| 6 | `defaultPinPermissions` constant | `channelCapabilities` | `src/components/Message/utils.tsx` | ✅ Done | +| 7 | `_permissions` param in `usePinHandler` | `channelCapabilities` | `src/components/Message/hooks/usePinHandler.ts` | ✅ Done | +| **Pagination Renames (6 items, #1804)** | | | | | +| 8 | `hasMore` prop (InfiniteScroll) | `hasPreviousPage` | `src/components/InfiniteScrollPaginator/InfiniteScroll.tsx` | ✅ Done | +| 9 | `hasMoreNewer` prop (InfiniteScroll) | `hasNextPage` | `src/components/InfiniteScrollPaginator/InfiniteScroll.tsx` | ✅ Done | +| 10 | `loadMore` prop (InfiniteScroll) | `loadPreviousPage` | `src/components/InfiniteScrollPaginator/InfiniteScroll.tsx` | ✅ Done | +| 11 | `loadMoreNewer` prop (InfiniteScroll) | `loadNextPage` | `src/components/InfiniteScrollPaginator/InfiniteScroll.tsx` | ✅ Done | +| 12 | `refreshing` prop (LoadMoreButton) | `isLoading` | `src/components/LoadMore/LoadMoreButton.tsx` | ✅ Done | +| 13 | `refreshing` prop (PaginatorProps) | `isLoading` | `src/types/types.ts` | ✅ Done | +| **useUserRole (3 items)** | | | | | +| 14 | `isAdmin` return value | `channelCapabilities` | `src/components/Message/hooks/useUserRole.ts:13` | Pending | +| 15 | `isOwner` return value | `channelCapabilities` | `src/components/Message/hooks/useUserRole.ts:20` | Pending | +| 16 | `isModerator` return value | `channelCapabilities` | `src/components/Message/hooks/useUserRole.ts:26` | Pending | +| **VirtualizedMessageList (4 items, deprecated since v10)** | | | | | +| 17 | `defaultItemHeight` prop | `additionalVirtuosoProps.defaultItemHeight` | `VirtualizedMessageList.tsx:617` | Pending | +| 18 | `head` prop | `additionalVirtuosoProps.components.Header` | `VirtualizedMessageList.tsx:636` | Pending | +| 19 | `overscan` prop | `additionalVirtuosoProps.overscan` | `VirtualizedMessageList.tsx:663` | Pending | +| 20 | `scrollSeekPlaceHolder` prop | `additionalVirtuosoProps.scrollSeek*` | `VirtualizedMessageList.tsx:675` | Pending | +| **Other** | | | | | +| 21 | `StreamEmoji` component | (none) | `src/components/Reactions/StreamEmoji.tsx` | ✅ Done | +| 22 | `UploadButton` / `UploadButtonProps` | `FileInput` / `FileInputProps` | `src/components/ReactFileUtilities/UploadButton.tsx` | ✅ Done | +| 23 | `moveChannelUp` utility | `moveChannelUpwards` | `src/components/ChannelList/utils.ts` | ✅ Done | +| 24 | `latestMessage` prop | `latestMessagePreview` | `src/components/ChannelListItem/ChannelListItem.tsx` | ✅ Done | +| 25 | `total_unread_count` mock field | `unread_count` | `src/mock-builders/event/notificationMarkUnread.ts` | ✅ Done | +| 26 | `hasNotMoreMessages` function | `hasMoreMessagesProbably` | `src/components/MessageList/utils.ts` | ✅ Done | +| 27 | `popperOptions` prop (EmojiPicker) | `placement` | `src/plugins/Emojis/EmojiPicker.tsx` | ✅ Done | +| 28 | `useActionHandler` string overload | `FormData` object form | `src/components/Message/hooks/useActionHandler.ts:34` | Pending | +| 29 | `formatDate` prop (MessageProps) | (TBD) | `src/components/Message/types.ts:29` (`// todo: remove`) | Pending | +| 30 | `LegacyReactionOptions` array format | Object format `{ quick: {...} }` | `src/components/Reactions/reactionOptions.tsx:5` | Needs discussion | +| 31 | `LegacyThreadContext` | (internal plumbing, not public API) | `src/components/Thread/LegacyThreadContext.ts` | Needs discussion | + +## Bug Fix (not a removal) + +~~`MessageList.tsx:83` has a **wrong deprecation comment**: `loadMoreNewer` is labeled `@deprecated in favor of channelCapabilities` but it's a pagination callback, not related to capabilities. This comment was copy-pasted from pin permissions deprecation and should be removed.~~ ✅ Fixed + +## Also addressed + +- `deprecationAndReplacementWarning` utility deleted (zero callers remain after Batch 3) +- Tests updated: `InfiniteScroll.test.tsx`, `LoadMoreButton.test.tsx`, `LoadMorePaginator.test.tsx` +- Unused `fireEvent` import cleaned up in `InfiniteScroll.test.tsx` + +## Remaining Work + +### Batch 4 (remaining): useUserRole (items 14–16) + +**Risk: Medium** + +| Action | File | +| ----------------------------------------------------------------- | ------------------------------------------------------------- | +| Remove `isAdmin`, `isOwner`, `isModerator` computations + returns | `src/components/Message/hooks/useUserRole.ts` | +| Delete ~120 lines of tests for removed values | `src/components/Message/hooks/__tests__/useUserRole.test.tsx` | + +### Batch 5: VirtualizedMessageList Props (items 17–20) + +**Risk: Medium-High** — Deprecated since v10. The `head` prop needs care since it may affect thread rendering. + +| Action | File | +| ----------------------------------------------------------------------- | ------------------------------------------------------- | +| Remove `defaultItemHeight` prop + Virtuoso spread | `src/components/MessageList/VirtualizedMessageList.tsx` | +| Remove `head` prop + rendering logic (verify thread headers still work) | `src/components/MessageList/VirtualizedMessageList.tsx` | +| Remove `overscan` prop + Virtuoso prop | `src/components/MessageList/VirtualizedMessageList.tsx` | +| Remove `scrollSeekPlaceHolder` prop + Virtuoso config | `src/components/MessageList/VirtualizedMessageList.tsx` | + +### Batch 6: Misc Cleanup (items 28, 29) + +**Risk: Medium** + +| Action | File | +| ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | +| Remove string overload branch (`typeof dataOrName === 'string'`) | `src/components/Message/hooks/useActionHandler.ts` | +| Update `ActionHandlerReturnType` to only accept `FormData` | `src/components/Message/hooks/useActionHandler.ts` | +| Update tests if any use the string overload | `src/components/Message/hooks/__tests__/useActionHandler.test.tsx` | +| Remove `formatDate` prop from `MessageProps` and `MessageContextValue` (has `// todo: remove`) | `src/components/Message/types.ts`, `src/context/MessageContext.tsx` | +| Remove `formatDate` pass-through in Message component and i18n integration | `src/i18n/utils.ts`, `src/i18n/types.ts` | +| **Note:** `DateSeparator.formatDate` is a separate prop and should be kept | | + +### Batch 7: Legacy Formats (items 30, 31) — Needs Discussion + +**Risk: High** — These are not formally `@deprecated` but are named "Legacy" and have newer replacements. Removal is more invasive. + +| Item | Details | +| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `LegacyReactionOptions` array format | The `ReactionOptions` type is a union of `LegacyReactionOptions` (array) and the new object format. Removing the array branch requires updating `Array.isArray()` guards in `ReactionSelector.tsx`, `useProcessReactions.tsx`, `MessageReactionsDetail.tsx`, and tests. | +| `LegacyThreadContext` | Internal compatibility bridge used in `Thread.tsx`, `useMessageComposerController.ts`, `useNotificationTarget.ts`, and tests. Named "Legacy" explicitly. Not a public API — removal depends on whether the new thread model fully replaces it. | + +**Recommendation:** These warrant their own investigation before committing to removal in v14. They may be better suited for v15 unless the team confirms the newer alternatives fully cover all use cases. + +## Items to NOT Remove + +| Item | Reason | +| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| `hasMore`/`hasMoreNewer`/`loadMore`/`loadMoreNewer` on **MessageList** and **VirtualizedMessageList** | NOT deprecated — canonical API from ChannelStateContext/ChannelActionContext | +| `_componentName` params on context hooks | Backward-compatible call-site markers, no benefit to removing | + +## Verification (per batch) + +1. `yarn types` — No type errors from removed types/props +2. `yarn test` — Full test suite passes +3. `yarn build` — Build succeeds +4. `yarn lint-fix` — No lint issues +5. For Batch 5: manually verify thread rendering in the example app diff --git a/src/components/ChannelList/hooks/index.ts b/src/components/ChannelList/hooks/index.ts index ed5454b7ba..85c9bf0e04 100644 --- a/src/components/ChannelList/hooks/index.ts +++ b/src/components/ChannelList/hooks/index.ts @@ -1,15 +1,5 @@ -export * from './useChannelDeletedListener'; -export * from './useChannelHiddenListener'; -export * from './useChannelTruncatedListener'; -export * from './useChannelUpdatedListener'; -export * from './useChannelVisibleListener'; export * from './useConnectionRecoveredListener'; -export * from './useMessageNewListener'; export * from './useMobileNavigation'; -export * from './useNotificationAddedToChannelListener'; -export * from './useNotificationMessageNewListener'; -export * from './useNotificationRemovedFromChannelListener'; export * from './usePaginatedChannels'; -export * from './useUserPresenceChangedListener'; export * from './useChannelMembershipState'; export * from './useChannelMembersState'; diff --git a/src/components/ChannelList/hooks/useChannelDeletedListener.ts b/src/components/ChannelList/hooks/useChannelDeletedListener.ts deleted file mode 100644 index d95830cc67..0000000000 --- a/src/components/ChannelList/hooks/useChannelDeletedListener.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useEffect } from 'react'; -import type { Channel, Event } from 'stream-chat'; - -import { useChatContext } from '../../../context/ChatContext'; - -export const useChannelDeletedListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, -) => { - const { client } = useChatContext('useChannelDeletedListener'); - - useEffect(() => { - const handleEvent = (event: Event) => { - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } else { - setChannels((channels) => { - const channelIndex = channels.findIndex((channel) => channel.cid === event.cid); - - if (channelIndex < 0) return [...channels]; - - // Remove the deleted channel from the list - channels.splice(channelIndex, 1); - - return [...channels]; - }); - } - }; - - client.on('channel.deleted', handleEvent); - - return () => { - client.off('channel.deleted', handleEvent); - }; - }, [client, customHandler, setChannels]); -}; diff --git a/src/components/ChannelList/hooks/useChannelHiddenListener.ts b/src/components/ChannelList/hooks/useChannelHiddenListener.ts deleted file mode 100644 index 338c420dd8..0000000000 --- a/src/components/ChannelList/hooks/useChannelHiddenListener.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { useEffect } from 'react'; -import type { Channel, Event } from 'stream-chat'; - -import { useChatContext } from '../../../context/ChatContext'; - -export const useChannelHiddenListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, -) => { - const { client } = useChatContext('useChannelHiddenListener'); - - useEffect(() => { - const handleEvent = (event: Event) => { - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } else { - setChannels((channels) => { - const channelIndex = channels.findIndex((channel) => channel.cid === event.cid); - if (channelIndex < 0) return [...channels]; - - // Remove the hidden channel from the list.s - channels.splice(channelIndex, 1); - - return [...channels]; - }); - } - }; - - client.on('channel.hidden', handleEvent); - - return () => { - client.off('channel.hidden', handleEvent); - }; - }, [client, customHandler, setChannels]); -}; diff --git a/src/components/ChannelList/hooks/useChannelTruncatedListener.ts b/src/components/ChannelList/hooks/useChannelTruncatedListener.ts deleted file mode 100644 index a20fc8d2b4..0000000000 --- a/src/components/ChannelList/hooks/useChannelTruncatedListener.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { useEffect } from 'react'; - -import { useChatContext } from '../../../context/ChatContext'; - -import type { Channel, Event } from 'stream-chat'; - -export const useChannelTruncatedListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, - forceUpdate?: () => void, -) => { - const { client } = useChatContext('useChannelTruncatedListener'); - - useEffect(() => { - const handleEvent = (event: Event) => { - setChannels((channels) => [...channels]); - - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } - if (forceUpdate) { - forceUpdate(); - } - }; - - client.on('channel.truncated', handleEvent); - - return () => { - client.off('channel.truncated', handleEvent); - }; - }, [client, customHandler, forceUpdate, setChannels]); -}; diff --git a/src/components/ChannelList/hooks/useChannelUpdatedListener.ts b/src/components/ChannelList/hooks/useChannelUpdatedListener.ts deleted file mode 100644 index 0129763d51..0000000000 --- a/src/components/ChannelList/hooks/useChannelUpdatedListener.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { useEffect } from 'react'; - -import { useChatContext } from '../../../context/ChatContext'; - -import type { Channel, Event } from 'stream-chat'; - -export const useChannelUpdatedListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, - forceUpdate?: () => void, -) => { - const { client } = useChatContext('useChannelUpdatedListener'); - - useEffect(() => { - const handleEvent = (event: Event) => { - setChannels((channels) => { - const channelIndex = channels.findIndex( - (channel) => channel.cid === event.channel?.cid, - ); - - if (channelIndex > -1 && event.channel) { - const newChannels = channels; - newChannels[channelIndex].data = { - ...event.channel, - hidden: event.channel?.hidden ?? newChannels[channelIndex].data?.hidden, - own_capabilities: - event.channel?.own_capabilities ?? - newChannels[channelIndex].data?.own_capabilities, - }; - - return [...newChannels]; - } - - return channels; - }); - if (forceUpdate) { - forceUpdate(); - } - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } - }; - - client.on('channel.updated', handleEvent); - - return () => { - client.off('channel.updated', handleEvent); - }; - }, [client, customHandler, forceUpdate, setChannels]); -}; diff --git a/src/components/ChannelList/hooks/useChannelVisibleListener.ts b/src/components/ChannelList/hooks/useChannelVisibleListener.ts deleted file mode 100644 index c43ea1ed00..0000000000 --- a/src/components/ChannelList/hooks/useChannelVisibleListener.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useEffect } from 'react'; -import uniqBy from 'lodash.uniqby'; - -import { getChannel } from '../../../utils/getChannel'; - -import { useChatContext } from '../../../context/ChatContext'; - -import type { Channel, Event } from 'stream-chat'; - -export const useChannelVisibleListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, -) => { - const { client } = useChatContext('useChannelVisibleListener'); - - useEffect(() => { - const handleEvent = async (event: Event) => { - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } else if (event.type && event.channel_type && event.channel_id) { - const channel = await getChannel({ - client, - id: event.channel_id, - type: event.channel_type, - }); - setChannels((channels) => uniqBy([channel, ...channels], 'cid')); - } - }; - - client.on('channel.visible', handleEvent); - - return () => { - client.off('channel.visible', handleEvent); - }; - }, [client, customHandler, setChannels]); -}; diff --git a/src/components/ChannelList/hooks/useMessageNewListener.ts b/src/components/ChannelList/hooks/useMessageNewListener.ts deleted file mode 100644 index e21b7d180c..0000000000 --- a/src/components/ChannelList/hooks/useMessageNewListener.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { useEffect } from 'react'; -import uniqBy from 'lodash.uniqby'; - -import { moveChannelUp } from '../utils'; - -import { useChatContext } from '../../../context/ChatContext'; - -import type { Channel, Event } from 'stream-chat'; - -export const useMessageNewListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, - lockChannelOrder = false, - allowNewMessagesFromUnfilteredChannels = true, -) => { - const { client } = useChatContext('useMessageNewListener'); - - useEffect(() => { - const handleEvent = (event: Event) => { - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } else { - setChannels((channels) => { - const channelInList = - channels.filter((channel) => channel.cid === event.cid).length > 0; - - if ( - !channelInList && - allowNewMessagesFromUnfilteredChannels && - event.channel_type - ) { - const channel = client.channel(event.channel_type, event.channel_id); - return uniqBy([channel, ...channels], 'cid'); - } - - if (!lockChannelOrder) return moveChannelUp({ channels, cid: event.cid || '' }); - - return channels; - }); - } - }; - - client.on('message.new', handleEvent); - - return () => { - client.off('message.new', handleEvent); - }; - }, [ - allowNewMessagesFromUnfilteredChannels, - client, - customHandler, - lockChannelOrder, - setChannels, - ]); -}; diff --git a/src/components/ChannelList/hooks/useNotificationAddedToChannelListener.ts b/src/components/ChannelList/hooks/useNotificationAddedToChannelListener.ts deleted file mode 100644 index 90f74f2ce6..0000000000 --- a/src/components/ChannelList/hooks/useNotificationAddedToChannelListener.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { useEffect } from 'react'; -import uniqBy from 'lodash.uniqby'; - -import { getChannel } from '../../../utils/getChannel'; - -import { useChatContext } from '../../../context/ChatContext'; - -import type { Channel, Event } from 'stream-chat'; - -export const useNotificationAddedToChannelListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, - allowNewMessagesFromUnfilteredChannels = true, -) => { - const { client } = useChatContext('useNotificationAddedToChannelListener'); - - useEffect(() => { - const handleEvent = async (event: Event) => { - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } else if (allowNewMessagesFromUnfilteredChannels && event.channel?.type) { - const channel = await getChannel({ - client, - id: event.channel.id, - members: event.channel.members?.reduce((acc, { user, user_id }) => { - const userId = user_id || user?.id; - if (userId) { - acc.push(userId); - } - return acc; - }, []), - type: event.channel.type, - }); - setChannels((channels) => uniqBy([channel, ...channels], 'cid')); - } - }; - - client.on('notification.added_to_channel', handleEvent); - - return () => { - client.off('notification.added_to_channel', handleEvent); - }; - }, [allowNewMessagesFromUnfilteredChannels, client, customHandler, setChannels]); -}; diff --git a/src/components/ChannelList/hooks/useNotificationMessageNewListener.ts b/src/components/ChannelList/hooks/useNotificationMessageNewListener.ts deleted file mode 100644 index 464a124926..0000000000 --- a/src/components/ChannelList/hooks/useNotificationMessageNewListener.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { useEffect } from 'react'; -import uniqBy from 'lodash.uniqby'; - -import { getChannel } from '../../../utils/getChannel'; - -import { useChatContext } from '../../../context/ChatContext'; - -import type { Channel, Event } from 'stream-chat'; - -export const useNotificationMessageNewListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, - allowNewMessagesFromUnfilteredChannels = true, -) => { - const { client } = useChatContext('useNotificationMessageNewListener'); - - useEffect(() => { - const handleEvent = async (event: Event) => { - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } else if (allowNewMessagesFromUnfilteredChannels && event.channel?.type) { - const channel = await getChannel({ - client, - id: event.channel.id, - type: event.channel.type, - }); - setChannels((channels) => uniqBy([channel, ...channels], 'cid')); - } - }; - - client.on('notification.message_new', handleEvent); - - return () => { - client.off('notification.message_new', handleEvent); - }; - }, [allowNewMessagesFromUnfilteredChannels, client, customHandler, setChannels]); -}; diff --git a/src/components/ChannelList/hooks/useNotificationRemovedFromChannelListener.ts b/src/components/ChannelList/hooks/useNotificationRemovedFromChannelListener.ts deleted file mode 100644 index bfe1a85ee9..0000000000 --- a/src/components/ChannelList/hooks/useNotificationRemovedFromChannelListener.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useEffect } from 'react'; - -import { useChatContext } from '../../../context/ChatContext'; - -import type { Channel, Event } from 'stream-chat'; - -export const useNotificationRemovedFromChannelListener = ( - setChannels: React.Dispatch>>, - customHandler?: ( - setChannels: React.Dispatch>>, - event: Event, - ) => void, -) => { - const { client } = useChatContext('useNotificationRemovedFromChannelListener'); - - useEffect(() => { - const handleEvent = (event: Event) => { - if (customHandler && typeof customHandler === 'function') { - customHandler(setChannels, event); - } else { - setChannels((channels) => - channels.filter((channel) => channel.cid !== event.channel?.cid), - ); - } - }; - - client.on('notification.removed_from_channel', handleEvent); - - return () => { - client.off('notification.removed_from_channel', handleEvent); - }; - }, [client, customHandler, setChannels]); -}; diff --git a/src/components/ChannelList/hooks/useUserPresenceChangedListener.ts b/src/components/ChannelList/hooks/useUserPresenceChangedListener.ts deleted file mode 100644 index d7edb1171a..0000000000 --- a/src/components/ChannelList/hooks/useUserPresenceChangedListener.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { useEffect } from 'react'; - -import { useChatContext } from '../../../context/ChatContext'; - -import type { Channel, Event } from 'stream-chat'; - -export const useUserPresenceChangedListener = ( - setChannels: React.Dispatch>>, -) => { - const { client } = useChatContext('useUserPresenceChangedListener'); - - useEffect(() => { - const handleEvent = (event: Event) => { - setChannels((channels) => { - const newChannels = channels.map((channel) => { - if (!event.user?.id || !channel.state.members[event.user.id]) { - return channel; - } - - const newChannel = channel; // dumb workaround for linter - newChannel.state.members[event.user.id].user = event.user; - - return newChannel; - }); - - return [...newChannels]; - }); - }; - - client.on('user.presence.changed', handleEvent); - - return () => { - client.off('user.presence.changed', handleEvent); - }; - }, [client, setChannels]); -}; diff --git a/src/components/ChannelList/utils.ts b/src/components/ChannelList/utils.ts index b1b5dbe51c..3f1c5bde2b 100644 --- a/src/components/ChannelList/utils.ts +++ b/src/components/ChannelList/utils.ts @@ -1,29 +1,7 @@ -import uniqBy from 'lodash.uniqby'; import type { Channel, ChannelSort, ChannelSortBase } from 'stream-chat'; import type { ChannelListProps } from './ChannelList'; -type MoveChannelUpParams = { - channels: Array; - cid: string; - activeChannel?: Channel; -}; - -/** - * @deprecated - */ -export const moveChannelUp = ({ activeChannel, channels, cid }: MoveChannelUpParams) => { - // get index of channel to move up - const channelIndex = channels.findIndex((channel) => channel.cid === cid); - - if (!activeChannel && channelIndex <= 0) return channels; - - // get channel to move up - const channel = activeChannel || channels[channelIndex]; - - return uniqBy([channel, ...channels], 'cid'); -}; - /** * Expects channel array sorted by `{ pinned_at: -1 }`. * diff --git a/src/components/ChannelListItem/ChannelListItem.tsx b/src/components/ChannelListItem/ChannelListItem.tsx index 9ebf33bd66..1e54c96d26 100644 --- a/src/components/ChannelListItem/ChannelListItem.tsx +++ b/src/components/ChannelListItem/ChannelListItem.tsx @@ -27,8 +27,6 @@ export type ChannelListItemUIProps = ChannelListItemProps & { groupChannelDisplayInfo?: GroupChannelDisplayInfo; /** The last message received in a channel */ lastMessage?: LocalMessage; - /** @deprecated Use latestMessagePreview prop instead. */ - latestMessage?: ReactNode; /** Latest message preview to display, will be a string or JSX element supporting markdown. */ latestMessagePreview?: ReactNode; /** Status describing whether own message has been delivered or read by another. If the last message is not an own message, then the status is undefined. */ @@ -202,7 +200,6 @@ export const ChannelListItem = (props: ChannelListItemProps) => { displayTitle={displayTitle} groupChannelDisplayInfo={groupChannelDisplayInfo} lastMessage={lastMessage} - latestMessage={latestMessagePreview} latestMessagePreview={latestMessagePreview} messageDeliveryStatus={messageDeliveryStatus} muted={muted} diff --git a/src/components/InfiniteScrollPaginator/InfiniteScroll.tsx b/src/components/InfiniteScrollPaginator/InfiniteScroll.tsx index 0f1914d9cb..4b713d435f 100644 --- a/src/components/InfiniteScrollPaginator/InfiniteScroll.tsx +++ b/src/components/InfiniteScrollPaginator/InfiniteScroll.tsx @@ -1,7 +1,6 @@ import type { PropsWithChildren } from 'react'; import React, { useEffect, useRef, useState } from 'react'; import type { PaginatorProps } from '../../types/types'; -import { deprecationAndReplacementWarning } from '../../utils/deprecationWarning'; import { DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD } from '../../constants/limits'; /** @@ -17,32 +16,12 @@ const mousewheelListener = (event: Event) => { export type InfiniteScrollProps = PaginatorProps & { className?: string; element?: React.ElementType; - /** - * @desc Flag signalling whether more pages with older items can be loaded - * @deprecated Use hasPreviousPage prop instead. Planned for removal: https://github.com/GetStream/stream-chat-react/issues/1804 - */ - hasMore?: boolean; - /** - * @desc Flag signalling whether more pages with newer items can be loaded - * @deprecated Use hasNextPage prop instead. Planned for removal: https://github.com/GetStream/stream-chat-react/issues/1804 - */ - hasMoreNewer?: boolean; /** Element to be rendered at the top of the thread message list. By default, Message and ThreadStart components */ head?: React.ReactNode; initialLoad?: boolean; isLoading?: boolean; listenToScroll?: (offset: number, reverseOffset: number, threshold: number) => void; loader?: React.ReactNode; - /** - * @desc Function that loads previous page with older items - * @deprecated Use loadPreviousPage prop instead. Planned for removal: https://github.com/GetStream/stream-chat-react/issues/1804 - */ - loadMore?: () => void; - /** - * @desc Function that loads next page with newer items - * @deprecated Use loadNextPage prop instead. Planned for removal: https://github.com/GetStream/stream-chat-react/issues/1804 - */ - loadMoreNewer?: () => void; useCapture?: boolean; }; @@ -60,8 +39,6 @@ export const InfiniteScroll = (props: PropsWithChildren) => const { children, element: Component = 'div', - hasMore, - hasMoreNewer, hasNextPage, hasPreviousPage, head, @@ -69,8 +46,6 @@ export const InfiniteScroll = (props: PropsWithChildren) => isLoading, listenToScroll, loader, - loadMore, - loadMoreNewer, loadNextPage, loadPreviousPage, threshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD, @@ -78,11 +53,6 @@ export const InfiniteScroll = (props: PropsWithChildren) => ...elementProps } = props; - const loadNextPageFn = loadNextPage || loadMoreNewer; - const loadPreviousPageFn = loadPreviousPage || loadMore; - const hasNextPageFlag = hasNextPage || hasMoreNewer; - const hasPreviousPageFlag = hasPreviousPage || hasMore; - const [scrollComponent, setScrollComponent] = useState(null); const previousOffset = useRef(undefined); const previousReverseOffset = useRef(undefined); @@ -119,34 +89,17 @@ export const InfiniteScroll = (props: PropsWithChildren) => // FIXME: this triggers loadMore call when a user types messages in thread and the scroll container expands if ( reverseOffset < Number(threshold) && - typeof loadPreviousPageFn === 'function' && - hasPreviousPageFlag + typeof loadPreviousPage === 'function' && + hasPreviousPage ) { - loadPreviousPageFn(); + loadPreviousPage(); } - if ( - offset < Number(threshold) && - typeof loadNextPageFn === 'function' && - hasNextPageFlag - ) { - loadNextPageFn(); + if (offset < Number(threshold) && typeof loadNextPage === 'function' && hasNextPage) { + loadNextPage(); } }; - useEffect(() => { - deprecationAndReplacementWarning( - [ - [{ hasMoreNewer }, { hasNextPage }], - [{ loadMoreNewer }, { loadNextPage }], - [{ hasMore }, { hasPreviousPage }], - [{ loadMore }, { loadPreviousPage }], - ], - 'InfiniteScroll', - ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - useEffect(() => { const scrollElement = scrollComponent?.parentNode; diff --git a/src/components/InfiniteScrollPaginator/__tests__/InfiniteScroll.test.tsx b/src/components/InfiniteScrollPaginator/__tests__/InfiniteScroll.test.tsx index f30c10194a..83b7cb028a 100644 --- a/src/components/InfiniteScrollPaginator/__tests__/InfiniteScroll.test.tsx +++ b/src/components/InfiniteScrollPaginator/__tests__/InfiniteScroll.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, render } from '@testing-library/react'; +import { render } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { InfiniteScroll } from '../'; @@ -90,39 +90,6 @@ describe('InfiniteScroll', () => { }, ); - it.each([ - ['hasMoreNewer', 'loadMoreNewer', 'hasNextPage', 'loadNextPage'], - ['hasMore', 'loadMore', 'hasPreviousPage', 'loadPreviousPage'], - ])( - 'deprecates %s and %s in favor of %s and %s', - (deprecatedFlag, deprecatedLoader, newFlag, newLoader) => { - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => null); - const oldLoaderSpy = vi.fn(); - const newLoaderSpy = vi.fn(); - - const { scrollParent } = renderComponent({ - [deprecatedFlag]: false, - [deprecatedLoader]: oldLoaderSpy, - [newFlag]: true, - [newLoader]: newLoaderSpy, - threshold: Infinity, - }); - - Object.defineProperty(HTMLElement.prototype, 'offsetParent', { - get() { - return this.parentNode; - }, - }); - fireEvent.scroll(scrollParent); - - consoleWarnSpy.mockRestore(); - - expect(oldLoaderSpy).not.toHaveBeenCalled(); - - expect(newLoaderSpy).toHaveBeenCalled(); - }, - ); - describe('Rendering loader', () => { const getRenderResult = () => { const props = fromPartial({ diff --git a/src/components/LoadMore/LoadMoreButton.tsx b/src/components/LoadMore/LoadMoreButton.tsx index cf2fe421f1..acf11d0c3f 100644 --- a/src/components/LoadMore/LoadMoreButton.tsx +++ b/src/components/LoadMore/LoadMoreButton.tsx @@ -1,7 +1,6 @@ import type { PropsWithChildren } from 'react'; -import React, { useEffect } from 'react'; +import React from 'react'; import { LoadingIndicator } from '../Loading'; -import { deprecationAndReplacementWarning } from '../../utils/deprecationWarning'; import { useTranslationContext } from '../../context'; import { Button } from '../Button'; @@ -10,28 +9,16 @@ export type LoadMoreButtonProps = { onClick: React.MouseEventHandler; /** indicates whether a loading request is in progress */ isLoading?: boolean; - /** - * @desc If true, LoadingIndicator is displayed instead of button - * @deprecated Use loading prop instead of refreshing. Planned for removal: https://github.com/GetStream/stream-chat-react/issues/1804 - */ - refreshing?: boolean; }; const UnMemoizedLoadMoreButton = ({ children, isLoading, onClick, - refreshing, }: PropsWithChildren) => { const { t } = useTranslationContext('UnMemoizedLoadMoreButton'); const childrenOrDefaultString = children ?? t('Load more'); - const loading = typeof isLoading !== 'undefined' ? isLoading : refreshing; - - useEffect(() => { - deprecationAndReplacementWarning([[{ refreshing }, { isLoading }]], 'LoadMoreButton'); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); return (
@@ -39,12 +26,12 @@ const UnMemoizedLoadMoreButton = ({ appearance='ghost' aria-label={t('aria/Load More Channels')} data-testid='load-more-button' - disabled={loading} + disabled={isLoading} onClick={onClick} size='sm' variant='secondary' > - {loading ? : childrenOrDefaultString} + {isLoading ? : childrenOrDefaultString}
); diff --git a/src/components/LoadMore/LoadMorePaginator.tsx b/src/components/LoadMore/LoadMorePaginator.tsx index b3a48a0479..ec85f0757d 100644 --- a/src/components/LoadMore/LoadMorePaginator.tsx +++ b/src/components/LoadMore/LoadMorePaginator.tsx @@ -1,10 +1,9 @@ import type { PropsWithChildren } from 'react'; -import React, { useEffect } from 'react'; +import React from 'react'; import type { LoadMoreButtonProps } from './LoadMoreButton'; import { LoadMoreButton as DefaultLoadMoreButton } from './LoadMoreButton'; import type { PaginatorProps } from '../../types/types'; -import { deprecationAndReplacementWarning } from '../../utils/deprecationWarning'; export type LoadMorePaginatorProps = PaginatorProps & { /** A UI button component that handles pagination logic */ @@ -22,23 +21,13 @@ export const UnMemoizedLoadMorePaginator = ( isLoading, LoadMoreButton = DefaultLoadMoreButton, loadNextPage, - refreshing, reverse, } = props; - const loadingState = typeof isLoading !== 'undefined' ? isLoading : refreshing; - - useEffect(() => { - deprecationAndReplacementWarning( - [[{ refreshing }, { isLoading }]], - 'LoadMorePaginator', - ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); return ( <> {!reverse && children} - {hasNextPage && } + {hasNextPage && } {reverse && children} ); diff --git a/src/components/LoadMore/__tests__/LoadMoreButton.test.tsx b/src/components/LoadMore/__tests__/LoadMoreButton.test.tsx index a080d65f82..5325fd30a2 100644 --- a/src/components/LoadMore/__tests__/LoadMoreButton.test.tsx +++ b/src/components/LoadMore/__tests__/LoadMoreButton.test.tsx @@ -48,23 +48,6 @@ describe('LoadMoreButton', () => { expect(loadingIndicator).toBeInTheDocument(); }); - it('deprecates prop refreshing in favor of isLoading', () => { - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => null); - const onClickMock = vi.fn(); - - const { getByTestId } = render( - , - ); - - fireEvent.click(getByTestId('load-more-button')); - const loadingIndicator = getByTestId('load-more-button').querySelector( - '.str-chat__loading-indicator', - ); - - consoleWarnSpy.mockRestore(); - expect(loadingIndicator).not.toBeInTheDocument(); - }); - it('should display children', () => { const { getByText } = render( null}> diff --git a/src/components/LoadMore/__tests__/LoadMorePaginator.test.tsx b/src/components/LoadMore/__tests__/LoadMorePaginator.test.tsx index a7a77d4581..7f74308694 100644 --- a/src/components/LoadMore/__tests__/LoadMorePaginator.test.tsx +++ b/src/components/LoadMore/__tests__/LoadMorePaginator.test.tsx @@ -113,14 +113,13 @@ describe('LoadMorePaginator', () => { await waitFor(() => { expect(LoadMoreButton).toHaveBeenCalledWith( - { isLoading: undefined, onClick: undefined, refreshing: undefined }, + { isLoading: undefined, onClick: undefined }, undefined, ); }); }); it('should pass proper props to LoadMoreButton', async () => { - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => null); const LoadMoreButton = vi.fn(() =>
); const loadNextPage = vi.fn(); @@ -130,11 +129,9 @@ describe('LoadMorePaginator', () => { isLoading={false} LoadMoreButton={LoadMoreButton} loadNextPage={loadNextPage} - refreshing={true} />, ); - consoleWarnSpy.mockRestore(); await waitFor(() => { expect(LoadMoreButton).toHaveBeenCalledWith( { isLoading: false, onClick: loadNextPage }, diff --git a/src/components/Message/Message.tsx b/src/components/Message/Message.tsx index 020b30828c..5c9cd22d5d 100644 --- a/src/components/Message/Message.tsx +++ b/src/components/Message/Message.tsx @@ -207,7 +207,6 @@ export const Message = (props: MessageProps) => { onMentionsClick: propOnMentionsClick, onMentionsHover: propOnMentionsHover, openThread: propOpenThread, - pinPermissions, reactionDetailsSort, retrySendMessage: propRetrySendMessage, sortReactions, @@ -269,7 +268,7 @@ export const Message = (props: MessageProps) => { onMentionsHover: propOnMentionsHover, }); - const { canPin, handlePin } = usePinHandler(message, pinPermissions, { + const { canPin, handlePin } = usePinHandler(message, { getErrorNotification: getPinMessageErrorNotification, notify, }); @@ -309,7 +308,6 @@ export const Message = (props: MessageProps) => { onMentionsHoverMessage={onMentionsHover} onUserClick={props.onUserClick} onUserHover={props.onUserHover} - pinPermissions={props.pinPermissions} reactionDetailsSort={reactionDetailsSort} readBy={props.readBy} renderText={props.renderText} diff --git a/src/components/Message/hooks/usePinHandler.ts b/src/components/Message/hooks/usePinHandler.ts index 3f35bfbb93..7cc7bc4d37 100644 --- a/src/components/Message/hooks/usePinHandler.ts +++ b/src/components/Message/hooks/usePinHandler.ts @@ -1,4 +1,4 @@ -import { defaultPinPermissions, validateAndGetMessage } from '../utils'; +import { validateAndGetMessage } from '../utils'; import { useChannelActionContext } from '../../../context/ChannelActionContext'; import { useChannelStateContext } from '../../../context/ChannelStateContext'; @@ -8,33 +8,6 @@ import { useTranslationContext } from '../../../context/TranslationContext'; import type { LocalMessage } from 'stream-chat'; import type { ReactEventHandler } from '../types'; -// @deprecated in favor of `channelCapabilities` - TODO: remove in next major release -export type PinEnabledUserRoles = Partial< - Record -> & { - admin?: boolean; - anonymous?: boolean; - channel_member?: boolean; - channel_moderator?: boolean; - guest?: boolean; - member?: boolean; - moderator?: boolean; - owner?: boolean; - user?: boolean; -}; - -// @deprecated in favor of `channelCapabilities` - TODO: remove in next major release -export type PinPermissions< - T extends string = string, - U extends string = string, -> = Partial>> & { - commerce?: PinEnabledUserRoles; - gaming?: PinEnabledUserRoles; - livestream?: PinEnabledUserRoles; - messaging?: PinEnabledUserRoles; - team?: PinEnabledUserRoles; -}; - export type PinMessageNotifications = { getErrorNotification?: (message: LocalMessage) => string; notify?: (notificationText: string, type: 'success' | 'error') => void; @@ -42,8 +15,6 @@ export type PinMessageNotifications = { export const usePinHandler = ( message: LocalMessage, - // @deprecated in favor of `channelCapabilities` - TODO: remove in next major release - _permissions: PinPermissions = defaultPinPermissions, // eslint-disable-line notifications: PinMessageNotifications = {}, ) => { const { getErrorNotification, notify } = notifications; diff --git a/src/components/Message/types.ts b/src/components/Message/types.ts index 6a6a2a8482..93439a88ef 100644 --- a/src/components/Message/types.ts +++ b/src/components/Message/types.ts @@ -1,7 +1,7 @@ import type { ReactNode } from 'react'; import type { LocalMessage, ReactionSort, UserResponse } from 'stream-chat'; -import type { PinPermissions, UserEventHandler } from './hooks'; +import type { UserEventHandler } from './hooks'; import type { MessageActionsArray } from './utils'; import type { GroupStyle } from '../MessageList/utils'; import type { MessageComposerProps } from '../MessageComposer'; @@ -77,8 +77,6 @@ export type MessageProps = { onUserHover?: UserEventHandler; /** Custom open thread handler to override default in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */ openThread?: ChannelActionContextValue['openThread']; - /** @deprecated in favor of `channelCapabilities - The user roles allowed to pin messages in various channel types */ - pinPermissions?: PinPermissions; /** Sort options to provide to a reactions query */ reactionDetailsSort?: ReactionSort; /** A list of users that have read this Message if the message is the last one and was posted by my user */ diff --git a/src/components/Message/utils.tsx b/src/components/Message/utils.tsx index 255e0757c6..371de7862a 100644 --- a/src/components/Message/utils.tsx +++ b/src/components/Message/utils.tsx @@ -11,7 +11,6 @@ import type { StreamChat, UserResponse, } from 'stream-chat'; -import type { PinPermissions } from './hooks'; import type { MessageProps } from './types'; import type { MessageContextValue } from '../../context'; @@ -70,65 +69,6 @@ export type MessageActionsArray = Array< keyof typeof MESSAGE_ACTIONS | keyof typeof OPTIONAL_MESSAGE_ACTIONS | T >; -// @deprecated in favor of `channelCapabilities` - TODO: remove in next major release -export const defaultPinPermissions: PinPermissions = { - commerce: { - admin: true, - anonymous: false, - channel_member: false, - channel_moderator: true, - guest: false, - member: false, - moderator: true, - owner: true, - user: false, - }, - gaming: { - admin: true, - anonymous: false, - channel_member: false, - channel_moderator: true, - guest: false, - member: false, - moderator: true, - owner: false, - user: false, - }, - livestream: { - admin: true, - anonymous: false, - channel_member: false, - channel_moderator: true, - guest: false, - member: false, - moderator: true, - owner: true, - user: false, - }, - messaging: { - admin: true, - anonymous: false, - channel_member: true, - channel_moderator: true, - guest: false, - member: true, - moderator: true, - owner: true, - user: false, - }, - team: { - admin: true, - anonymous: false, - channel_member: true, - channel_moderator: true, - guest: false, - member: true, - moderator: true, - owner: true, - user: false, - }, -}; - export type Capabilities = { canDelete?: boolean; canEdit?: boolean; diff --git a/src/components/MessageList/MessageList.tsx b/src/components/MessageList/MessageList.tsx index 075b8f7189..fbb0119ee3 100644 --- a/src/components/MessageList/MessageList.tsx +++ b/src/components/MessageList/MessageList.tsx @@ -24,7 +24,7 @@ import { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyState import type { InfiniteScrollProps } from '../InfiniteScrollPaginator/InfiniteScroll'; import { InfiniteScroll } from '../InfiniteScrollPaginator/InfiniteScroll'; import { LoadingIndicator as DefaultLoadingIndicator } from '../Loading'; -import { defaultPinPermissions, MESSAGE_ACTIONS } from '../Message/utils'; +import { MESSAGE_ACTIONS } from '../Message/utils'; import { TypingIndicator as DefaultTypingIndicator } from '../TypingIndicator'; import { MessageListMainPanel as DefaultMessageListMainPanel } from './MessageListMainPanel'; @@ -80,13 +80,12 @@ const MessageListWithContext = (props: MessageListWithContextProps) => { } = {}, jumpToLatestMessage = () => Promise.resolve(), loadMore: loadMoreCallback, - loadMoreNewer: loadMoreNewerCallback, // @deprecated in favor of `channelCapabilities` - TODO: remove in next major release + loadMoreNewer: loadMoreNewerCallback, maxTimeBetweenGroupedMessages, messageActions = Object.keys(MESSAGE_ACTIONS), messageLimit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE, messages = [], noGroupByUser = false, - pinPermissions = defaultPinPermissions, reactionDetailsSort, renderMessages = defaultRenderMessages, returnAllReadData = false, @@ -226,7 +225,6 @@ const MessageListWithContext = (props: MessageListWithContextProps) => { onUserClick: props.onUserClick, onUserHover: props.onUserHover, openThread: props.openThread, - pinPermissions, reactionDetailsSort, renderText: props.renderText, retrySendMessage: props.retrySendMessage, @@ -492,7 +490,6 @@ type PropsDrilledToMessage = | 'onUserClick' | 'onUserHover' | 'openThread' - | 'pinPermissions' // @deprecated in favor of `channelCapabilities` - TODO: remove in next major release | 'reactionDetailsSort' | 'renderText' | 'retrySendMessage' diff --git a/src/components/MessageList/utils.ts b/src/components/MessageList/utils.ts index fbd0fbbc04..f0854027ed 100644 --- a/src/components/MessageList/utils.ts +++ b/src/components/MessageList/utils.ts @@ -318,10 +318,6 @@ export const getGroupStyles = ( export const hasMoreMessagesProbably = (returnedCountMessages: number, limit: number) => returnedCountMessages >= limit; -// @deprecated -export const hasNotMoreMessages = (returnedCountMessages: number, limit: number) => - returnedCountMessages < limit; - export function isIntroMessage(message: unknown): message is IntroMessage { return (message as IntroMessage).customType === CUSTOM_MESSAGE_TYPE.intro; } diff --git a/src/components/ReactFileUtilities/UploadButton.tsx b/src/components/ReactFileUtilities/UploadButton.tsx index 0132f41873..f2e13bd185 100644 --- a/src/components/ReactFileUtilities/UploadButton.tsx +++ b/src/components/ReactFileUtilities/UploadButton.tsx @@ -17,20 +17,13 @@ const attachmentManagerConfigStateSelector = (state: MessageComposerConfig) => ( maxNumberOfFilesPerMessage: state.attachments.maxNumberOfFilesPerMessage, }); -/** - * @deprecated Use FileInputProps instead. - */ -export type UploadButtonProps = { +export type FileInputProps = { onFileChange: (files: Array) => void; resetOnChange?: boolean; } & Omit, 'type' | 'onChange'>; -/** - * @deprecated Use FileInput instead - */ - -export const UploadButton = forwardRef(function UploadButton( - { onFileChange, resetOnChange = true, ...rest }: UploadButtonProps, +export const FileInput = forwardRef(function FileInput( + { onFileChange, resetOnChange = true, ...rest }: FileInputProps, ref: React.ForwardedRef, ) { const handleInputChange = useHandleFileChangeWrapper(resetOnChange, onFileChange); @@ -38,10 +31,6 @@ export const UploadButton = forwardRef(function UploadButton( return ; }); -export type FileInputProps = UploadButtonProps; - -export const FileInput = UploadButton; - export const UploadFileInput = forwardRef(function UploadFileInput( { className, diff --git a/src/components/Reactions/StreamEmoji.tsx b/src/components/Reactions/StreamEmoji.tsx deleted file mode 100644 index bad96e5c4f..0000000000 --- a/src/components/Reactions/StreamEmoji.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; - -import type { SpriteImageProps } from './SpriteImage'; -import { SpriteImage } from './SpriteImage'; - -import type { Readable } from '../../types/types'; - -const StreamSpriteEmojiPositions = { - angry: [1, 1], - haha: [1, 0], - like: [0, 0], - love: [1, 2], - sad: [0, 1], - wow: [0, 2], -}; - -type StreamEmojiType = keyof typeof StreamSpriteEmojiPositions; - -const STREAM_SPRITE_URL = 'https://getstream.imgix.net/images/emoji-sprite.png'; - -/** - * @deprecated - */ -export const StreamEmoji = ({ - fallback, - type, -}: Readable<{ type: StreamEmojiType } & Pick>) => { - const position = StreamSpriteEmojiPositions[type] as [number, number]; - return ( - - ); -}; diff --git a/src/components/Reactions/index.ts b/src/components/Reactions/index.ts index 116026e54f..d84a5c74dc 100644 --- a/src/components/Reactions/index.ts +++ b/src/components/Reactions/index.ts @@ -2,5 +2,4 @@ export * from './ReactionSelector'; export * from './MessageReactions'; export * from './MessageReactionsDetail'; export * from './SpriteImage'; -export * from './StreamEmoji'; export * from './reactionOptions'; diff --git a/src/components/index.ts b/src/components/index.ts index d9a04f6bb5..97dec10944 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -42,5 +42,5 @@ export * from './Tooltip'; export * from './TypingIndicator'; export * from './Window'; -export { UploadButton } from './ReactFileUtilities'; -export type { UploadButtonProps } from './ReactFileUtilities'; +export { FileInput } from './ReactFileUtilities'; +export type { FileInputProps } from './ReactFileUtilities'; diff --git a/src/context/MessageContext.tsx b/src/context/MessageContext.tsx index 818e9ac843..156dce8ef8 100644 --- a/src/context/MessageContext.tsx +++ b/src/context/MessageContext.tsx @@ -13,7 +13,6 @@ import type { import type { ChannelActionContextValue } from './ChannelActionContext'; import type { ActionHandlerReturnType } from '../components/Message/hooks/useActionHandler'; -import type { PinPermissions } from '../components/Message/hooks/usePinHandler'; import type { ReactEventHandler } from '../components/Message/types'; import type { MessageActionsArray } from '../components/Message/utils'; import type { GroupStyle } from '../components/MessageList/utils'; @@ -101,8 +100,6 @@ export type MessageContextValue = { messageListRect?: DOMRect; /** Array of muted users coming from [ChannelStateContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_state_context/#mutes) */ mutes?: Mute[]; - /** @deprecated in favor of `channelCapabilities - The user roles allowed to pin Messages in various channel types */ - pinPermissions?: PinPermissions; /** Sort options to provide to a reactions query */ reactionDetailsSort?: ReactionSort; /** A list of users that have read this Message */ diff --git a/src/mock-builders/event/notificationMarkUnread.ts b/src/mock-builders/event/notificationMarkUnread.ts index e6d6c5dc16..1e7d62bd4c 100644 --- a/src/mock-builders/event/notificationMarkUnread.ts +++ b/src/mock-builders/event/notificationMarkUnread.ts @@ -26,7 +26,6 @@ export default ({ // creation date of a message with last_read_message_id last_read_at: '2023-12-15T11:49:21.667730943Z', last_read_message_id: 'SmithAnne-jeIYWT39L56bs79f10Hao', - // @deprecated number of all unread messages across all my unread channels, equals unread_count total_unread_count: 19, type: 'notification.mark_unread', // number of all my channels with at least one unread message including the channel in this event diff --git a/src/plugins/Emojis/EmojiPicker.tsx b/src/plugins/Emojis/EmojiPicker.tsx index 14d4c53482..3e60cb3b38 100644 --- a/src/plugins/Emojis/EmojiPicker.tsx +++ b/src/plugins/Emojis/EmojiPicker.tsx @@ -28,10 +28,6 @@ export type EmojiPickerProps = { * Floating UI placement (default: 'top-end') for the picker popover */ placement?: PopperLikePlacement; - /** - * Deprecated: Popper options, use `placement` instead. - */ - popperOptions?: Partial<{ placement: PopperLikePlacement }>; }; const defaultButtonClassName = 'str-chat__emoji-picker-button'; diff --git a/src/types/types.ts b/src/types/types.ts index 241ae44ef0..26f55e2190 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -20,11 +20,6 @@ export type PaginatorProps = { LoadingIndicator?: React.ComponentType; /** callback to load the previous page */ loadPreviousPage?: () => void; - /** - * @desc indicates if there's currently any refreshing taking place - * @deprecated Use loading prop instead of refreshing. Planned for removal: https://github.com/GetStream/stream-chat-react/issues/1804 - */ - refreshing?: boolean; /** display the items in opposite order */ reverse?: boolean; /** Offset from when to start the loadNextPage call */ diff --git a/src/utils/deprecationWarning.ts b/src/utils/deprecationWarning.ts deleted file mode 100644 index 3fd07377d5..0000000000 --- a/src/utils/deprecationWarning.ts +++ /dev/null @@ -1,20 +0,0 @@ -export const deprecationAndReplacementWarning =

[][]>( - pairs: P, - component: string, -) => { - pairs.forEach((data) => { - const [[oldName, oldValue], [newName, newValue]] = [ - Object.entries(data[0])[0], - Object.entries(data[1])[0], - ]; - - if ( - (typeof oldValue !== 'undefined' && typeof newValue === 'undefined') || - (typeof oldValue !== 'undefined' && typeof newValue !== 'undefined') - ) { - console.warn( - `[Deprecation notice (${component})]: prefer using prop ${newName} instead of ${oldName}`, - ); - } - }); -};