UNPKG

stream-chat-react

Version:

React components to create chat conversations or livestream style chat

123 lines (122 loc) 4.58 kB
import uniqBy from 'lodash.uniqby'; export const MAX_QUERY_CHANNELS_LIMIT = 30; /** * @deprecated */ export const moveChannelUp = ({ activeChannel, channels, cid }) => { // 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 }`. * * TODO: add support for the `{ pinned_at: 1 }` */ export function findLastPinnedChannelIndex({ channels }) { let lastPinnedChannelIndex = null; for (const channel of channels) { if (!isChannelPinned(channel)) break; if (typeof lastPinnedChannelIndex === 'number') { lastPinnedChannelIndex++; } else { lastPinnedChannelIndex = 0; } } return lastPinnedChannelIndex; } export const moveChannelUpwards = ({ channels, channelToMove, channelToMoveIndexWithinChannels, sort, }) => { // get index of channel to move up const targetChannelIndex = channelToMoveIndexWithinChannels ?? channels.findIndex((channel) => channel.cid === channelToMove.cid); const targetChannelExistsWithinList = targetChannelIndex >= 0; const targetChannelAlreadyAtTheTop = targetChannelIndex === 0; // pinned channels should not move within the list based on recent activity, channels which // receive messages and are not pinned should move upwards but only under the last pinned channel // in the list const considerPinnedChannels = shouldConsiderPinnedChannels(sort); const isTargetChannelPinned = isChannelPinned(channelToMove); if (targetChannelAlreadyAtTheTop || (considerPinnedChannels && isTargetChannelPinned)) { return channels; } const newChannels = [...channels]; // target channel index is known, remove it from the list if (targetChannelExistsWithinList) { newChannels.splice(targetChannelIndex, 1); } // as position of pinned channels has to stay unchanged, we need to // find last pinned channel in the list to move the target channel after let lastPinnedChannelIndex = null; if (considerPinnedChannels) { lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels }); } // re-insert it at the new place (to specific index if pinned channels are considered) newChannels.splice(typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0, 0, channelToMove); return newChannels; }; /** * Returns `true` only if object with `pinned_at` property is first within the `sort` array * or if `pinned_at` key of the `sort` object gets picked first when using `for...in` looping mechanism * and value of the `pinned_at` is either `1` or `-1`. */ export const shouldConsiderPinnedChannels = (sort) => { const value = extractSortValue({ atIndex: 0, sort, targetKey: 'pinned_at' }); if (typeof value !== 'number') return false; return Math.abs(value) === 1; }; export const extractSortValue = ({ atIndex, sort, targetKey, }) => { if (!sort) return null; let option = null; if (Array.isArray(sort)) { option = sort[atIndex] ?? null; } else { let index = 0; for (const key in sort) { if (index !== atIndex) { index++; continue; } if (key !== targetKey) { return null; } option = sort; break; } } return option?.[targetKey] ?? null; }; /** * Returns `true` only if `archived` property is of type `boolean` within `filters` object. */ export const shouldConsiderArchivedChannels = (filters) => { if (!filters) return false; return typeof filters.archived === 'boolean'; }; /** * Returns `true` only if `pinned_at` property is of type `string` within `membership` object. */ export const isChannelPinned = (channel) => { if (!channel) return false; const membership = channel.state.membership; return typeof membership.pinned_at === 'string'; }; /** * Returns `true` only if `archived_at` property is of type `string` within `membership` object. */ export const isChannelArchived = (channel) => { if (!channel) return false; const membership = channel.state.membership; return typeof membership.archived_at === 'string'; };