diff --git a/lib/utils/drawer-utils.react.js b/lib/utils/drawer-utils.react.js index e332fd1e4..4944fa801 100644 --- a/lib/utils/drawer-utils.react.js +++ b/lib/utils/drawer-utils.react.js @@ -1,120 +1,129 @@ // @flow import * as React from 'react'; import { values } from './objects.js'; import { threadInFilterList, threadIsChannel } from '../shared/thread-utils.js'; import type { ResolvedThreadInfo, ThreadInfo, RawThreadInfo, } from '../types/minimally-encoded-thread-permissions-types.js'; import { communitySubthreads } from '../types/thread-types-enum.js'; type WritableCommunityDrawerItemData = { threadInfo: ResolvedThreadInfo, - itemChildren: $ReadOnlyArray>, + itemChildren: Array>, hasSubchannelsButton: boolean, labelStyle: T, }; -export type CommunityDrawerItemData = $ReadOnly< - WritableCommunityDrawerItemData, ->; +export type CommunityDrawerItemData = $ReadOnly<{ + ...WritableCommunityDrawerItemData, + +itemChildren: $ReadOnlyArray>, +}>; + +function compareCommunityDrawerItemData( + a: CommunityDrawerItemData, + b: CommunityDrawerItemData, +): number { + return a.threadInfo.uiName.localeCompare(b.threadInfo.uiName); +} function createRecursiveDrawerItemsData( childThreadInfosMap: { +[id: string]: $ReadOnlyArray, }, communities: $ReadOnlyArray, labelStyles: $ReadOnlyArray, maxDepth: number, ): $ReadOnlyArray> { - const result: $ReadOnlyArray< - WritableCommunityDrawerItemData, - > = communities.map(community => ({ - threadInfo: community, - itemChildren: [], - labelStyle: labelStyles[0], - hasSubchannelsButton: false, - })); + const result: Array> = + communities.map(community => ({ + threadInfo: community, + itemChildren: [], + labelStyle: labelStyles[0], + hasSubchannelsButton: false, + })); + result.sort(compareCommunityDrawerItemData); let queue = result.map(item => [item, 0]); for (let i = 0; i < queue.length; i++) { const [item, lvl] = queue[i]; const itemChildThreadInfos = childThreadInfosMap[item.threadInfo.id] ?? []; if (lvl < maxDepth) { item.itemChildren = itemChildThreadInfos .filter(childItem => communitySubthreads.includes(childItem.type)) .map(childItem => ({ threadInfo: childItem, itemChildren: [], labelStyle: labelStyles[Math.min(lvl + 1, labelStyles.length - 1)], hasSubchannelsButton: lvl + 1 === maxDepth && threadHasSubchannels(childItem, childThreadInfosMap), })); + item.itemChildren.sort(compareCommunityDrawerItemData); queue = queue.concat( item.itemChildren.map(childItem => [childItem, lvl + 1]), ); } } return result; } function threadHasSubchannels( threadInfo: ResolvedThreadInfo, childThreadInfosMap: { +[id: string]: $ReadOnlyArray, }, ): boolean { if (!childThreadInfosMap[threadInfo.id]?.length) { return false; } return childThreadInfosMap[threadInfo.id].some(thread => threadIsChannel(thread), ); } function useAppendCommunitySuffix( communities: $ReadOnlyArray, ): $ReadOnlyArray { return React.useMemo(() => { const result: ResolvedThreadInfo[] = []; const names = new Map(); for (const chat of communities) { let name = chat.uiName; const numberOfOccurrences = names.get(name); names.set(name, (numberOfOccurrences ?? 0) + 1); if (numberOfOccurrences) { name = `${name} (${numberOfOccurrences.toString()})`; } result.push({ ...chat, uiName: name }); } return result; }, [communities]); } function filterThreadIDsBelongingToCommunity( communityID: string, threadInfosObj: { +[id: string]: RawThreadInfo | ThreadInfo, }, ): $ReadOnlySet { const threadInfos = values(threadInfosObj); const threadIDs = threadInfos .filter( thread => (thread.community === communityID || thread.id === communityID) && threadInFilterList(thread), ) .map(item => item.id); return new Set(threadIDs); } export { createRecursiveDrawerItemsData, useAppendCommunitySuffix, filterThreadIDsBelongingToCommunity, };