diff --git a/lib/utils/drawer-utils.react.js b/lib/utils/drawer-utils.react.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/drawer-utils.react.js
@@ -0,0 +1,79 @@
+// @flow
+
+import { threadIsChannel } from '../shared/thread-utils';
+import type { ThreadInfo } from '../types/thread-types';
+import { communitySubthreads } from '../types/thread-types';
+
+export type CommunityDrawerItemData<T> = {
+  +threadInfo: ThreadInfo,
+  +itemChildren?: $ReadOnlyArray<CommunityDrawerItemData<T>>,
+  +hasSubchannelsButton: boolean,
+  +labelStyle: T,
+};
+
+function createRecursiveDrawerItemsData<T>(
+  childThreadInfosMap: { +[id: string]: $ReadOnlyArray<ThreadInfo> },
+  communities: $ReadOnlyArray<ThreadInfo>,
+  labelStyles: $ReadOnlyArray<T>,
+  maxDepth: number,
+): $ReadOnlyArray<CommunityDrawerItemData<T>> {
+  const result = communities.map(community => ({
+    threadInfo: community,
+    itemChildren: [],
+    labelStyle: labelStyles[0],
+    hasSubchannelsButton: false,
+  }));
+  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),
+        }));
+      queue = queue.concat(
+        item.itemChildren.map(childItem => [childItem, lvl + 1]),
+      );
+    }
+  }
+  return result;
+}
+
+function threadHasSubchannels(
+  threadInfo: ThreadInfo,
+  childThreadInfosMap: { +[id: string]: $ReadOnlyArray<ThreadInfo> },
+): boolean {
+  if (!childThreadInfosMap[threadInfo.id]?.length) {
+    return false;
+  }
+  return childThreadInfosMap[threadInfo.id].some(thread =>
+    threadIsChannel(thread),
+  );
+}
+
+function appendSuffix(chats: $ReadOnlyArray<ThreadInfo>): ThreadInfo[] {
+  const result = [];
+  const names = new Map<string, number>();
+
+  for (const chat of chats) {
+    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;
+}
+
+export { createRecursiveDrawerItemsData, appendSuffix };
diff --git a/native/navigation/community-drawer-content.react.js b/native/navigation/community-drawer-content.react.js
--- a/native/navigation/community-drawer-content.react.js
+++ b/native/navigation/community-drawer-content.react.js
@@ -9,12 +9,13 @@
   childThreadInfos,
   communityThreadSelector,
 } from 'lib/selectors/thread-selectors';
-import { threadIsChannel } from 'lib/shared/thread-utils';
-import { type ThreadInfo, communitySubthreads } from 'lib/types/thread-types';
+import {
+  createRecursiveDrawerItemsData,
+  appendSuffix,
+} from 'lib/utils/drawer-utils.react';
 
 import { useNavigateToThread } from '../chat/message-list-types';
 import { useStyles } from '../themes/colors';
-import type { TextStyle } from '../types/styles';
 import CommunityDrawerItemCommunity from './community-drawer-item-cummunity.react';
 
 const maxDepth = 2;
@@ -43,18 +44,12 @@
 
   const renderItem = React.useCallback(
     ({ item }) => {
-      const itemData = {
-        threadInfo: item.threadInfo,
-        itemChildren: item.itemChildren,
-        labelStyle: item.labelStyle,
-        hasSubchannelsButton: item.subchannelsButton,
-      };
       return (
         <CommunityDrawerItemCommunity
-          key={item.key}
-          itemData={itemData}
+          key={item.threadInfo.id}
+          itemData={item}
           toggleExpanded={setOpenCommunnityOrClose}
-          expanded={itemData.threadInfo.id === openCommunity}
+          expanded={item.threadInfo.id === openCommunity}
           navigateToThread={navigateToThread}
         />
       );
@@ -78,6 +73,7 @@
         childThreadInfosMap,
         communitiesSuffixed,
         labelStyles,
+        maxDepth,
       ),
     [childThreadInfosMap, communitiesSuffixed, labelStyles],
   );
@@ -89,71 +85,6 @@
   );
 }
 
-function createRecursiveDrawerItemsData(
-  childThreadInfosMap: { +[id: string]: $ReadOnlyArray<ThreadInfo> },
-  communities: $ReadOnlyArray<ThreadInfo>,
-  labelStyles: $ReadOnlyArray<TextStyle>,
-) {
-  const result = communities.map(community => ({
-    key: community.id,
-    threadInfo: community,
-    itemChildren: [],
-    labelStyle: labelStyles[0],
-    subchannelsButton: false,
-  }));
-  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),
-        }));
-      queue = queue.concat(
-        item.itemChildren.map(childItem => [childItem, lvl + 1]),
-      );
-    }
-  }
-  return result;
-}
-
-function threadHasSubchannels(
-  threadInfo: ThreadInfo,
-  childThreadInfosMap: { +[id: string]: $ReadOnlyArray<ThreadInfo> },
-) {
-  if (!childThreadInfosMap[threadInfo.id]?.length) {
-    return false;
-  }
-  return childThreadInfosMap[threadInfo.id].some(thread =>
-    threadIsChannel(thread),
-  );
-}
-
-function appendSuffix(chats: $ReadOnlyArray<ThreadInfo>): ThreadInfo[] {
-  const result = [];
-  const names = new Map<string, number>();
-
-  for (const chat of chats) {
-    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;
-}
-
 const unboundStyles = {
   drawerContent: {
     flex: 1,
diff --git a/native/navigation/community-drawer-item.react.js b/native/navigation/community-drawer-item.react.js
--- a/native/navigation/community-drawer-item.react.js
+++ b/native/navigation/community-drawer-item.react.js
@@ -3,7 +3,7 @@
 import * as React from 'react';
 import { View, FlatList, TouchableOpacity } from 'react-native';
 
-import type { ThreadInfo } from 'lib/types/thread-types';
+import type { CommunityDrawerItemData } from 'lib/utils/drawer-utils.react';
 
 import type { MessageListParams } from '../chat/message-list-types';
 import { SingleLine } from '../components/single-line.react';
@@ -12,15 +12,8 @@
 import { ExpandButton, ExpandButtonDisabled } from './expand-buttons.react';
 import SubchannelsButton from './subchannels-button.react';
 
-export type CommunityDrawerItemData = {
-  +threadInfo: ThreadInfo,
-  +itemChildren?: $ReadOnlyArray<CommunityDrawerItemData>,
-  +labelStyle: TextStyle,
-  +hasSubchannelsButton: boolean,
-};
-
 export type DrawerItemProps = {
-  +itemData: CommunityDrawerItemData,
+  +itemData: CommunityDrawerItemData<TextStyle>,
   +toggleExpanded: (threadID: string) => void,
   +expanded: boolean,
   +navigateToThread: (params: MessageListParams) => void,
@@ -118,7 +111,7 @@
 };
 
 export type CommunityDrawerItemChatProps = {
-  +itemData: CommunityDrawerItemData,
+  +itemData: CommunityDrawerItemData<TextStyle>,
   +navigateToThread: (params: MessageListParams) => void,
 };