Page MenuHomePhabricator

D13996.diff
No OneTemporary

D13996.diff

diff --git a/native/components/community-joiner-modal.react.js b/native/components/community-joiner-modal.react.js
new file mode 100644
--- /dev/null
+++ b/native/components/community-joiner-modal.react.js
@@ -0,0 +1,181 @@
+// @flow
+
+import * as React from 'react';
+import { View, Text } from 'react-native';
+import { TabView, SceneMap, TabBar } from 'react-native-tab-view';
+
+import { useThreadSearchIndex } from 'lib/selectors/nav-selectors.js';
+import { threadInfoFromRawThreadInfo } from 'lib/shared/thread-utils.js';
+import type { ClientCommunityInfoWithCommunityName } from 'lib/types/community-types.js';
+
+import Modal from './modal.react.js';
+import CommunityList from '../components/community-list.react.js';
+import type { RootNavigationProp } from '../navigation/root-navigator.react.js';
+import type { NavigationRoute } from '../navigation/route-names.js';
+import { useSelector } from '../redux/redux-utils.js';
+import { useColors, useStyles } from '../themes/colors.js';
+
+export type CommunityJoinerModalParams = {
+ +communities: $ReadOnlyArray<ClientCommunityInfoWithCommunityName>,
+};
+
+type Props = {
+ +navigation: RootNavigationProp<'CommunityJoinerModal'>,
+ +route: NavigationRoute<'CommunityJoinerModal'>,
+};
+
+const defaultCommunities: $ReadOnlyArray<ClientCommunityInfoWithCommunityName> =
+ [];
+
+// This should be updated with the names of the crypto communities on Comm
+const cryptoCommunityNames: $ReadOnlyArray<string> = [];
+
+function CommunityJoinerModal(props: Props): React.Node {
+ const { params } = props.route;
+ const communities = params?.communities ?? defaultCommunities;
+
+ const viewerID = useSelector(
+ state => state.currentUserInfo && state.currentUserInfo.id,
+ );
+ const userInfos = useSelector(state => state.userStore.userInfos);
+ const styles = useStyles(unboundStyles);
+
+ const generalCommunities = React.useMemo(
+ () =>
+ communities.filter(
+ community => !cryptoCommunityNames.includes(community.communityName),
+ ),
+ [communities],
+ );
+ const cryptoCommunities = React.useMemo(
+ () =>
+ communities.filter(community =>
+ cryptoCommunityNames.includes(community.communityName),
+ ),
+ [communities],
+ );
+
+ const generateThreadInfos = React.useCallback(
+ (communityList: $ReadOnlyArray<ClientCommunityInfoWithCommunityName>) =>
+ communityList
+ .map(community =>
+ community.threadInfo
+ ? threadInfoFromRawThreadInfo(
+ community.threadInfo,
+ viewerID,
+ userInfos,
+ )
+ : null,
+ )
+ .filter(Boolean),
+ [userInfos, viewerID],
+ );
+
+ const generalThreadInfos = React.useMemo(
+ () => generateThreadInfos(generalCommunities),
+ [generateThreadInfos, generalCommunities],
+ );
+
+ const cryptoThreadInfos = React.useMemo(
+ () => generateThreadInfos(cryptoCommunities),
+ [generateThreadInfos, cryptoCommunities],
+ );
+
+ const generalIndex = useThreadSearchIndex(generalThreadInfos);
+ const cryptoIndex = useThreadSearchIndex(cryptoThreadInfos);
+
+ const renderGeneralTab = () => (
+ <CommunityList
+ threadInfos={generalThreadInfos}
+ itemStyle={styles.threadListItem}
+ searchIndex={generalIndex}
+ />
+ );
+
+ const renderCryptoTab = () => (
+ <CommunityList
+ threadInfos={cryptoThreadInfos}
+ itemStyle={styles.threadListItem}
+ searchIndex={cryptoIndex}
+ />
+ );
+
+ const [index, setIndex] = React.useState(0);
+ const [routes] = React.useState([
+ { key: 'general', title: 'General' },
+ { key: 'crypto', title: 'Crypto' },
+ ]);
+
+ const renderScene = SceneMap({
+ general: renderGeneralTab,
+ crypto: renderCryptoTab,
+ });
+
+ const colors = useColors();
+ const { tabBarBackground, tabBarAccent } = colors;
+
+ const screenOptions = React.useMemo(
+ () => ({
+ tabBarShowIcon: true,
+ tabBarStyle: {
+ backgroundColor: tabBarBackground,
+ },
+ tabBarItemStyle: {
+ flexDirection: 'row',
+ },
+ tabBarIndicatorStyle: {
+ borderColor: tabBarAccent,
+ borderBottomWidth: 2,
+ },
+ }),
+ [tabBarAccent, tabBarBackground],
+ );
+
+ const renderTabBar = (tabBarProps: mixed) => (
+ <View style={styles.tabBarContainer}>
+ <TabBar
+ {...tabBarProps}
+ style={screenOptions.tabBarStyle}
+ indicatorStyle={screenOptions.tabBarIndicatorStyle}
+ />
+ </View>
+ );
+
+ return (
+ <Modal>
+ <View style={styles.headerContainer}>
+ <Text style={styles.headerText}>Discover communities</Text>
+ </View>
+ <TabView
+ navigationState={{ index, routes }}
+ renderScene={renderScene}
+ onIndexChange={setIndex}
+ initialLayout={{ width: 400 }}
+ renderTabBar={renderTabBar}
+ />
+ </Modal>
+ );
+}
+
+const unboundStyles = {
+ headerContainer: {
+ padding: 10,
+ paddingBottom: 0,
+ },
+ headerText: {
+ color: 'modalForegroundLabel',
+ fontSize: 20,
+ marginBottom: 8,
+ textAlign: 'center',
+ },
+ threadListItem: {
+ paddingLeft: 10,
+ paddingRight: 10,
+ paddingVertical: 2,
+ },
+ tabBarContainer: {
+ marginBottom: 15,
+ },
+};
+
+export default CommunityJoinerModal;
diff --git a/native/navigation/root-navigator.react.js b/native/navigation/root-navigator.react.js
--- a/native/navigation/root-navigator.react.js
+++ b/native/navigation/root-navigator.react.js
@@ -58,6 +58,7 @@
CreateMissingSIWEBackupMessageRouteName,
RestoreSIWEBackupRouteName,
LinkedDevicesBottomSheetRouteName,
+ CommunityJoinerModalRouteName,
} from './route-names.js';
import LoggedOutModal from '../account/logged-out-modal.react.js';
import CreateMissingSIWEBackupMessage from '../account/registration/missing-registration-data/missing-siwe-backup-message.react.js';
@@ -74,6 +75,7 @@
import SubchannelsListModal from '../chat/subchannels-list-modal.react.js';
import CommunityCreationNavigator from '../community-creation/community-creation-navigator.react.js';
import TagFarcasterChannelNavigator from '../community-settings/tag-farcaster-channel/tag-farcaster-channel-navigator.react.js';
+import CommunityJoinerModal from '../components/community-joiner-modal.react.js';
import ConnectFarcasterBottomSheet from '../components/connect-farcaster-bottom-sheet.react.js';
import DirectoryPromptBottomSheet from '../components/directory-prompt-bottom-sheet.react.js';
import InviteLinksNavigator from '../invite-links/invite-links-navigator.react.js';
@@ -311,6 +313,11 @@
component={DirectoryPromptBottomSheet}
options={modalOverlayScreenOptions}
/>
+ <Root.Screen
+ name={CommunityJoinerModalRouteName}
+ component={CommunityJoinerModal}
+ options={modalOverlayScreenOptions}
+ />
<Root.Screen
name={TagFarcasterChannelNavigatorRouteName}
component={TagFarcasterChannelNavigator}
diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js
--- a/native/navigation/route-names.js
+++ b/native/navigation/route-names.js
@@ -39,6 +39,7 @@
import type { TogglePinModalParams } from '../chat/toggle-pin-modal.react.js';
import type { TagFarcasterChannelByNameParams } from '../community-settings/tag-farcaster-channel/tag-farcaster-channel-by-name.react.js';
import type { TagFarcasterChannelParams } from '../community-settings/tag-farcaster-channel/tag-farcaster-channel.react.js';
+import type { CommunityJoinerModalParams } from '../components/community-joiner-modal.react.js';
import type { InviteLinksNavigatorParams } from '../invite-links/invite-links-navigator.react.js';
import type { ManagePublicLinkScreenParams } from '../invite-links/manage-public-link-screen.react.js';
import type { ViewInviteLinksScreenParams } from '../invite-links/view-invite-links-screen.react.js';
@@ -164,6 +165,7 @@
export const ConnectFarcasterBottomSheetRouteName =
'ConnectFarcasterBottomSheet';
export const DirectoryPromptBottomSheetRouteName = 'DirectoryPromptBottomSheet';
+export const CommunityJoinerModalRouteName = 'CommunityJoinerModal';
export const TagFarcasterChannelNavigatorRouteName =
'TagFarcasterChannelNavigator';
export const TagFarcasterChannelRouteName = 'TagFarcasterChannel';
@@ -201,6 +203,7 @@
+LinkedDevicesBottomSheet: LinkedDevicesBottomSheetParams,
+ConnectFarcasterBottomSheet: void,
+DirectoryPromptBottomSheet: void,
+ +CommunityJoinerModal: CommunityJoinerModalParams,
+TagFarcasterChannelNavigator: void,
+CreateMissingSIWEBackupMessage: void,
+RestoreSIWEBackup: RestoreSIWEBackupParams,

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 22, 9:05 PM (12 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2564953
Default Alt Text
D13996.diff (8 KB)

Event Timeline