Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
379eab3
refactor: add members button is a separate component now
szuperaz Jun 18, 2026
991d7cc
refactor: simplify add member and edit details contexts
szuperaz Jun 18, 2026
6d322f9
refactor: split up the ChannelDetails context
szuperaz Jun 18, 2026
6d405f0
refactor: move channel into context
szuperaz Jun 19, 2026
f450bcf
fix: edit button size in expo sample app
szuperaz Jun 22, 2026
6363ad8
fix: padding fixes
szuperaz Jun 22, 2026
14a2981
fix: member section header
szuperaz Jun 22, 2026
ec5915d
fix: missing modal padding on Android in edge-to-edge mode
szuperaz Jun 22, 2026
9d9975e
refactor: remove value wrapper from channel details context
szuperaz Jun 22, 2026
58d1ade
fix: add back onPress for edit button; export store related hooks
szuperaz Jun 23, 2026
1e4e00c
refactor: move isDirect logic outside of edit button
szuperaz Jun 23, 2026
34305e0
refactor: simplify form submission for edit channel and add members
szuperaz Jun 23, 2026
afed116
fix: unit test
szuperaz Jun 23, 2026
8fa95b7
refactor: rename misleading hook for channel details edit
szuperaz Jun 24, 2026
47592d3
feat: allow passing custom searchSource for channel details components
szuperaz Jun 24, 2026
1e49cf1
refactor: move useCanEdit to src/hooks
szuperaz Jun 24, 2026
7a2f81c
refactor: move and rename canEdit and canAddMembers hook
szuperaz Jun 24, 2026
6ad200b
refactor: create proper hoc for add members and edit channel
szuperaz Jun 24, 2026
5413495
feat: add signal store to close any open channel details modal
szuperaz Jun 24, 2026
d78d55a
refactor: don't expose ChannelAllMembersModal
szuperaz Jun 24, 2026
4945b36
fix: lint error
szuperaz Jun 24, 2026
d985750
refactor: remove channel from contexts used under channel details
szuperaz Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/ExpoMessaging/app/channel/[cid]/details/files.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function ChannelFilesScreen() {
return (
<>
<Stack.Screen options={{ contentStyle: { backgroundColor: semantics.backgroundCoreApp } }} />
<ChannelDetailsContextProvider value={{ channel }}>
<ChannelDetailsContextProvider channel={channel}>
<FileAttachmentList />
</ChannelDetailsContextProvider>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function ChannelImagesScreen() {
return (
<>
<Stack.Screen options={{ contentStyle: { backgroundColor: semantics.backgroundCoreApp } }} />
<ChannelDetailsContextProvider value={{ channel }}>
<ChannelDetailsContextProvider channel={channel}>
<MediaList />
</ChannelDetailsContextProvider>
</>
Expand Down
75 changes: 46 additions & 29 deletions examples/ExpoMessaging/app/channel/[cid]/details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import React, { useCallback, useContext, useState } from 'react';
import { Stack, useRouter } from 'expo-router';

import {
ChannelAddMembersModal,
ChannelAllMembersModal,
ChannelDetails,
ChannelDetailsActionsSection,
ChannelDetailsContextProvider,
ChannelDetailsMemberSection,
ChannelDetailsNavigationSection,
ChannelDetailsNavigationSectionType,
GetChannelDetailsNavigationItems,
GetChannelMemberActionItems,
ChannelDetailsEditButton,
useCanEditChannel,
useIsDirectChat,
WithComponents,
} from 'stream-chat-expo';

Expand All @@ -23,13 +27,16 @@ const navigationItems: {
files: 'files',
};

const Header = () => {
const EmptyHeader = () => {
return null;
};

export default function ChannelDetailsScreen() {
const router = useRouter();
const { channel } = useContext(AppContext);
const canEdit = useCanEditChannel(channel);
const isDirect = useIsDirectChat(channel);
const isEditButtonVisible = canEdit && !isDirect;

const getNavigationItems = useCallback<GetChannelDetailsNavigationItems>(
({ defaultItems }) =>
Expand All @@ -48,20 +55,33 @@ export default function ChannelDetailsScreen() {

const popToRoot = useCallback(() => router.replace('/'), [router]);

const [isAddMembersVisible, setAddMembersVisible] = useState(false);
const handleAddMembersClose = useCallback(() => setAddMembersVisible(false), []);
const handleAddMembersPress = useCallback(() => {
setAllMembersVisible(false);
setAddMembersVisible(true);
}, []);

const [isAllMembersVisible, setAllMembersVisible] = useState(false);
const handleAllMembersClose = useCallback(() => setAllMembersVisible(false), []);
const handleAllMembersPress = useCallback(() => setAllMembersVisible(true), []);

const getChannelMemberActionItems = useCallback<GetChannelMemberActionItems>(
({ defaultItems }) => defaultItems,
[],
const NavigationSection = useCallback(
() => <ChannelDetailsNavigationSection getNavigationItems={getNavigationItems} />,
[getNavigationItems],
);

const MemberSection = useCallback(
() => <ChannelDetailsMemberSection onViewAllMembersPress={handleAllMembersPress} />,
[handleAllMembersPress],
);

const renderHeaderRight = useCallback(
() =>
channel ? (
<ChannelDetailsContextProvider channel={channel}>
<ChannelDetailsEditButton style={{ flexShrink: 0, width: 'auto' }} />
</ChannelDetailsContextProvider>
) : null,
[channel],
);

const ActionsSection = useCallback(
() => <ChannelDetailsActionsSection onChannelDismiss={popToRoot} />,
[popToRoot],
);

if (!channel) {
Expand All @@ -73,24 +93,21 @@ export default function ChannelDetailsScreen() {
<Stack.Screen
options={{
title: 'Channel details',
headerRight: isEditButtonVisible ? renderHeaderRight : undefined,
}}
/>
<WithComponents overrides={{ ChannelDetailsNavHeader: Header }}>
<ChannelDetails
channel={channel}
getChannelMemberActionItems={getChannelMemberActionItems}
getNavigationItems={getNavigationItems}
onChannelDismiss={popToRoot}
onViewAllMembersPress={handleAllMembersPress}
/>
</WithComponents>
<ChannelDetailsContextProvider value={{ channel, getChannelMemberActionItems }}>
<ChannelAllMembersModal
onClose={handleAllMembersClose}
visible={isAllMembersVisible}
onAddMembersPress={handleAddMembersPress}
/>
<ChannelAddMembersModal onClose={handleAddMembersClose} visible={isAddMembersVisible} />
<ChannelDetailsContextProvider channel={channel}>
<WithComponents
overrides={{
ChannelDetailsActionsSection: ActionsSection,
ChannelDetailsMemberSection: MemberSection,
ChannelDetailsNavHeader: EmptyHeader,
ChannelDetailsNavigationSection: NavigationSection,
}}
>
<ChannelDetails />
<ChannelAllMembersModal onClose={handleAllMembersClose} visible={isAllMembersVisible} />
</WithComponents>
</ChannelDetailsContextProvider>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default function ChannelPinnedMessagesScreen() {
return (
<>
<Stack.Screen options={{ contentStyle: { backgroundColor: semantics.backgroundCoreApp } }} />
<ChannelDetailsContextProvider value={{ channel }}>
<ChannelDetailsContextProvider channel={channel}>
<WithComponents overrides={{ PinnedMessageItem: PinnedMessage }}>
<PinnedMessageList />
</WithComponents>
Expand Down
97 changes: 58 additions & 39 deletions examples/SampleApp/src/screens/ChannelDetailsScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import React, { useCallback, useState } from 'react';
import React, { useCallback } from 'react';

import type { RouteProp } from '@react-navigation/native';
import { useNavigation, type RouteProp } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';

import {
ChannelDetails,
ChannelDetailsActionsSection,
ChannelDetailsNavigationSection,
GetChannelDetailsNavigationItems,
GetChannelMemberActionItems,
ChannelAddMembersModal,
ChannelAllMembersModal,
ChannelDetailsContextProvider,
ChannelDetailsNavigationSectionType,
ChannelMemberActionsSheet,
WithComponents,
ChannelDetailsActionsSectionProps,
useChannelDetailsContext,
} from 'stream-chat-react-native';

import { SendDirectMessage } from '../icons/SendDirectMessage';
Expand Down Expand Up @@ -40,12 +44,10 @@ const navigationItems: {
files: 'ChannelFilesScreen',
};

export const ChannelDetailsScreen: React.FC<Props> = ({
navigation,
route: {
params: { channel },
},
}) => {
const ChannelDetailsScreenInner = () => {
const navigation = useNavigation<ChannelDetailsScreenNavigationProp>();
const { channel, closeModals } = useChannelDetailsContext();

const onBack = useCallback(() => navigation.goBack(), [navigation]);
const getNavigationItems = useCallback<GetChannelDetailsNavigationItems>(
({ defaultItems }) =>
Expand All @@ -65,15 +67,13 @@ export const ChannelDetailsScreen: React.FC<Props> = ({
}),
[navigation],
);
const [isAddMembersVisible, setAddMembersVisible] = useState(false);
const handleAddMembersClose = useCallback(() => setAddMembersVisible(false), []);
const handleAddMembersPress = useCallback(() => {
setAllMembersVisible(false);
setAddMembersVisible(true);
}, []);
const [isAllMembersVisible, setAllMembersVisible] = useState(false);
const handleAllMembersClose = useCallback(() => setAllMembersVisible(false), []);
const handleAllMembersPress = useCallback(() => setAllMembersVisible(true), []);

const ActionsSection = useCallback(
(props: ChannelDetailsActionsSectionProps) => (
<ChannelDetailsActionsSection {...props} onChannelDismiss={popToRoot} />
),
[popToRoot],
);

const getChannelMemberActionItems = useCallback<GetChannelMemberActionItems>(
({ context, defaultItems }) => {
Expand All @@ -85,7 +85,7 @@ export const ChannelDetailsScreen: React.FC<Props> = ({
return [
{
action: () => {
setAllMembersVisible(false);
closeModals();
navigation.navigate('NewDirectMessagingScreen', { initialUser: user });
return Promise.resolve();
},
Expand All @@ -97,28 +97,47 @@ export const ChannelDetailsScreen: React.FC<Props> = ({
...defaultItems,
];
},
[navigation],
[navigation, closeModals],
);

return (
<>
<ChannelDetails
channel={channel}
const NavigationSection = useCallback(
(props: Parameters<typeof ChannelDetailsNavigationSection>[0]) => (
<ChannelDetailsNavigationSection {...props} getNavigationItems={getNavigationItems} />
),
[getNavigationItems],
);

const MemberActionsSheet = useCallback(
(props: Parameters<typeof ChannelMemberActionsSheet>[0]) => (
<ChannelMemberActionsSheet
{...props}
getChannelMemberActionItems={getChannelMemberActionItems}
getNavigationItems={getNavigationItems}
onBack={onBack}
onChannelDismiss={popToRoot}
// Handler view all members modal so we can close it after navigation is triggered by our custom action
onViewAllMembersPress={handleAllMembersPress}
/>
<ChannelDetailsContextProvider value={{ channel, getChannelMemberActionItems }}>
<ChannelAllMembersModal
onClose={handleAllMembersClose}
visible={isAllMembersVisible}
onAddMembersPress={handleAddMembersPress}
/>
<ChannelAddMembersModal onClose={handleAddMembersClose} visible={isAddMembersVisible} />
</ChannelDetailsContextProvider>
</>
),
[getChannelMemberActionItems],
);

return (
<WithComponents
overrides={{
ChannelDetailsActionsSection: ActionsSection,
ChannelDetailsNavigationSection: NavigationSection,
ChannelMemberActionsSheet: MemberActionsSheet,
}}
>
<ChannelDetails onBack={onBack} />
</WithComponents>
);
};

export const ChannelDetailsScreen: React.FC<Props> = ({
route: {
params: { channel },
},
}) => {
return (
<ChannelDetailsContextProvider channel={channel}>
<ChannelDetailsScreenInner />
</ChannelDetailsContextProvider>
);
};
2 changes: 1 addition & 1 deletion examples/SampleApp/src/screens/ChannelFilesScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const ChannelFilesScreen: React.FC<ChannelFilesScreenProps> = ({
return (
<View style={[styles.flex]}>
<ScreenHeader titleText='Files' />
<ChannelDetailsContextProvider value={{ channel }}>
<ChannelDetailsContextProvider channel={channel}>
<FileAttachmentList />
</ChannelDetailsContextProvider>
</View>
Expand Down
2 changes: 1 addition & 1 deletion examples/SampleApp/src/screens/ChannelImagesScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const ChannelImagesScreen: React.FC<ChannelImagesScreenProps> = ({
return (
<View style={[styles.flex]}>
<ScreenHeader titleText='Photos and Videos' />
<ChannelDetailsContextProvider value={{ channel }}>
<ChannelDetailsContextProvider channel={channel}>
<MediaList />
</ChannelDetailsContextProvider>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export const ChannelPinnedMessagesScreen: React.FC<ChannelPinnedMessagesScreenPr
return (
<View style={[styles.flex]}>
<ScreenHeader titleText='Pinned Messages' />
<ChannelDetailsContextProvider value={{ channel }}>
<ChannelDetailsContextProvider channel={channel}>
<WithComponents overrides={{ PinnedMessageItem: PinnedMessage }}>
<PinnedMessageList />
</WithComponents>
Expand Down
Loading
Loading