Skip to content

Commit ee63c40

Browse files
feat: message headers redesign (#3437)
This pull request makes several significant updates to the handling and display of message reminders and thread navigation in the sample app and core library. The main changes include refactoring the way message reminder headers are implemented, improving thread navigation (including scrolling to a targeted message), and exposing new header components for easier customization. Additionally, some code cleanup and minor UI improvements are included. **Message Reminder and Header Refactoring:** * Removed the custom `MessageReminderHeader` and related logic from the sample app, shifting responsibility for reminder headers to the core library and exposing them as customizable components (`MessageReminderHeader`, `MessageSavedForLaterHeader`, `SentToChannelHeader`). [[1]](diffhunk://#diff-e4b7ff703c5409150f35f3d93f9b4a6ca081dcc4bf8115f4fdb2a2d0439c6205L1-L92) [[2]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85R144-R146) [[3]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85R372-R374) [[4]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85R692-R694) [[5]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85R1954-R1956) [[6]](diffhunk://#diff-d3e4f4cdcef10807a38eab86f6ead6bbfe01980e7326f3cadfeb8186760d7af1R68-R70) [[7]](diffhunk://#diff-d3e4f4cdcef10807a38eab86f6ead6bbfe01980e7326f3cadfeb8186760d7af1R184-R186) * Updated the message actions to use the `Bell` icon directly from the core library instead of a local copy, and adjusted the icon prop to use `stroke` instead of `pathFill` for consistency. [[1]](diffhunk://#diff-3003c10c02dbe4fd6a088502b48ef3cf6b539a4c30704273f10482dbc8ae52a5R12-L13) [[2]](diffhunk://#diff-3003c10c02dbe4fd6a088502b48ef3cf6b539a4c30704273f10482dbc8ae52a5L97-R97) [[3]](diffhunk://#diff-550d274d1ba08f0f6b63d767444bd4f08e1e0e6daa758b818cc5cf213fda5c55L1-L22) **Thread Navigation and Targeted Message Scroll:** * Enhanced thread navigation by passing an optional `targetedMessageId` when navigating to the thread screen, allowing the UI to scroll directly to a specific message within a thread. [[1]](diffhunk://#diff-2335969a90d85933b956775f38af8bf0485cd538b0e73115b8087467d7ed116aL179-R179) [[2]](diffhunk://#diff-2335969a90d85933b956775f38af8bf0485cd538b0e73115b8087467d7ed116aR188) [[3]](diffhunk://#diff-f6f5acf3649a7159a27117d2ea15769405d09c079894eb8bc3a5e765cca5e9d8R43) [[4]](diffhunk://#diff-d205a2fd76b4c4f669af948205f8a5e11c6267f3e4e26dc91e3a6036cd87d606L77-R76) [[5]](diffhunk://#diff-d205a2fd76b4c4f669af948205f8a5e11c6267f3e4e26dc91e3a6036cd87d606L131-R147) * Added an `onBackPressThread` callback to the thread context and channel props, enabling the thread screen to return to the channel screen and optionally scroll to a targeted message. [[1]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85L407-R413) [[2]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85R716) [[3]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85R2000) [[4]](diffhunk://#diff-1c9dec060e52c82d28b7c313abbac01d23d19ddda8dc53cf82174b5432231231R15) [[5]](diffhunk://#diff-1c9dec060e52c82d28b7c313abbac01d23d19ddda8dc53cf82174b5432231231R43) [[6]](diffhunk://#diff-d205a2fd76b4c4f669af948205f8a5e11c6267f3e4e26dc91e3a6036cd87d606R119-R125) **Component and Prop Management:** * Removed direct usage of `MessageHeader` and `MessageReminderHeader` props in the sample app screens, relying on the core library's exposed components and context for message header rendering. [[1]](diffhunk://#diff-2335969a90d85933b956775f38af8bf0485cd538b0e73115b8087467d7ed116aL236) [[2]](diffhunk://#diff-d205a2fd76b4c4f669af948205f8a5e11c6267f3e4e26dc91e3a6036cd87d606L18-L23) [[3]](diffhunk://#diff-d205a2fd76b4c4f669af948205f8a5e11c6267f3e4e26dc91e3a6036cd87d606L90) [[4]](diffhunk://#diff-d205a2fd76b4c4f669af948205f8a5e11c6267f3e4e26dc91e3a6036cd87d606L131-R147) **Minor Improvements and Cleanup:** * Fixed a minor translation string in `ChannelPreviewMessage` to remove an unnecessary colon from the translation key. * Ensured the `onThreadSelect` prop is passed to the `MessageWithContext` component for better thread handling. These changes collectively improve the flexibility, maintainability, and user experience of message reminders and thread navigation in the app. --------- Co-authored-by: Ivan Sekovanikj <[email protected]>
1 parent 065306c commit ee63c40

38 files changed

+631
-150
lines changed

examples/SampleApp/src/components/Reminders/MessageReminderHeader.tsx

Lines changed: 0 additions & 92 deletions
This file was deleted.

examples/SampleApp/src/icons/Bell.tsx

Lines changed: 0 additions & 22 deletions
This file was deleted.

examples/SampleApp/src/screens/ChannelScreen.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import { useChannelMembersStatus } from '../hooks/useChannelMembersStatus';
2626
import type { StackNavigatorParamList } from '../types';
2727
import { NetworkDownIndicator } from '../components/NetworkDownIndicator';
2828
import { useCreateDraftFocusEffect } from '../utils/useCreateDraftFocusEffect.tsx';
29-
import { MessageHeader } from '../components/Reminders/MessageReminderHeader.tsx';
3029
import { channelMessageActions } from '../utils/messageActions.tsx';
3130
import { MessageLocation } from '../components/LocationSharing/MessageLocation.tsx';
3231
import { useStreamChatContext } from '../context/StreamChatContext.tsx';
@@ -174,7 +173,7 @@ export const ChannelScreen: React.FC<ChannelScreenProps> = ({
174173
};
175174

176175
const onThreadSelect = useCallback(
177-
(thread: LocalMessage | null) => {
176+
(thread: LocalMessage | null, targetedMessageId?: string) => {
178177
if (!thread || !channel) {
179178
return;
180179
}
@@ -183,6 +182,7 @@ export const ChannelScreen: React.FC<ChannelScreenProps> = ({
183182
navigation.navigate('ThreadScreen', {
184183
channel,
185184
thread,
185+
targetedMessageId,
186186
});
187187
},
188188
[channel, navigation, setThread],
@@ -230,7 +230,6 @@ export const ChannelScreen: React.FC<ChannelScreenProps> = ({
230230
initialScrollToFirstUnreadMessage
231231
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : -300}
232232
messageActions={messageActions}
233-
MessageHeader={MessageHeader}
234233
MessageLocation={MessageLocation}
235234
messageId={messageId}
236235
NetworkDownIndicator={() => null}

examples/SampleApp/src/screens/ThreadScreen.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@ import { useStateStore } from 'stream-chat-react-native';
1515

1616
import { ScreenHeader } from '../components/ScreenHeader';
1717

18-
import type { RouteProp } from '@react-navigation/native';
18+
import { type RouteProp } from '@react-navigation/native';
1919

2020
import type { StackNavigatorParamList } from '../types';
2121
import { LocalMessage, ThreadState, UserResponse } from 'stream-chat';
2222
import { useCreateDraftFocusEffect } from '../utils/useCreateDraftFocusEffect.tsx';
23-
import { MessageReminderHeader } from '../components/Reminders/MessageReminderHeader.tsx';
2423
import { channelMessageActions } from '../utils/messageActions.tsx';
2524
import { useStreamChatContext } from '../context/StreamChatContext.tsx';
2625
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
@@ -74,7 +73,7 @@ const ThreadHeader: React.FC<ThreadHeaderProps> = ({ thread }) => {
7473
export const ThreadScreen: React.FC<ThreadScreenProps> = ({
7574
navigation,
7675
route: {
77-
params: { channel, thread },
76+
params: { channel, thread, targetedMessageId },
7877
},
7978
}) => {
8079
const {
@@ -87,7 +86,6 @@ export const ThreadScreen: React.FC<ThreadScreenProps> = ({
8786
const { t } = useTranslationContext();
8887
const { setThread } = useStreamChatContext();
8988
const { messageInputFloating, messageListImplementation } = useAppContext();
90-
9189
const onPressMessage: NonNullable<React.ComponentProps<typeof Channel>['onPressMessage']> = (
9290
payload,
9391
) => {
@@ -118,6 +116,13 @@ export const ThreadScreen: React.FC<ThreadScreenProps> = ({
118116
setThread(null);
119117
}, [setThread]);
120118

119+
const onBackPressThread = useCallback(
120+
(messageId?: string) => {
121+
navigation.popTo('ChannelScreen', { messageId: messageId });
122+
},
123+
[navigation],
124+
);
125+
121126
return (
122127
<View style={[styles.container, { backgroundColor: white }]}>
123128
<Channel
@@ -128,14 +133,18 @@ export const ThreadScreen: React.FC<ThreadScreenProps> = ({
128133
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : -300}
129134
messageActions={messageActions}
130135
messageInputFloating={messageInputFloating}
131-
MessageHeader={MessageReminderHeader}
132136
MessageLocation={MessageLocation}
133137
onPressMessage={onPressMessage}
134138
thread={thread}
135139
threadList
140+
onBackPressThread={onBackPressThread}
141+
messageId={targetedMessageId}
136142
>
137143
<ThreadHeader thread={thread} />
138-
<Thread onThreadDismount={onThreadDismount} shouldUseFlashList={messageListImplementation === 'flashlist'} />
144+
<Thread
145+
onThreadDismount={onThreadDismount}
146+
shouldUseFlashList={messageListImplementation === 'flashlist'}
147+
/>
139148
</Channel>
140149
</View>
141150
);

examples/SampleApp/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export type StackNavigatorParamList = {
4040
ThreadScreen: {
4141
channel: Channel;
4242
thread: LocalMessage | ThreadType;
43+
targetedMessageId?: string;
4344
};
4445
};
4546

examples/SampleApp/src/utils/messageActions.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import {
99
MessageActionsParams,
1010
Time,
1111
TranslationContextValue,
12+
Bell,
1213
} from 'stream-chat-react-native';
13-
import { Bell } from '../icons/Bell';
1414
import { Theme } from 'stream-chat-react-native';
1515

1616
export function channelMessageActions({
@@ -94,7 +94,7 @@ export function channelMessageActions({
9494
},
9595
actionType: reminder ? 'remove-reminder' : 'remind-me',
9696
title: reminder ? 'Remove Reminder' : 'Remind Me',
97-
icon: <Bell height={20} width={20} pathFill={semantics.textSecondary} />,
97+
icon: <Bell height={20} width={20} stroke={semantics.textSecondary} />,
9898
type: 'standard',
9999
});
100100
actions.push({

package/src/components/Channel/Channel.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ import {
141141
} from '../KeyboardCompatibleView/KeyboardControllerAvoidingView';
142142
import { Message as MessageDefault } from '../Message/Message';
143143
import { MessagePinnedHeader as MessagePinnedHeaderDefault } from '../Message/MessageSimple/Headers/MessagePinnedHeader';
144+
import { MessageReminderHeader as MessageReminderHeaderDefault } from '../Message/MessageSimple/Headers/MessageReminderHeader';
145+
import { MessageSavedForLaterHeader as MessageSavedForLaterHeaderDefault } from '../Message/MessageSimple/Headers/MessageSavedForLaterHeader';
146+
import { SentToChannelHeader as SentToChannelHeaderDefault } from '../Message/MessageSimple/Headers/SentToChannelHeader';
144147
import { MessageAvatar as MessageAvatarDefault } from '../Message/MessageSimple/MessageAvatar';
145148
import { MessageBlocked as MessageBlockedDefault } from '../Message/MessageSimple/MessageBlocked';
146149
import { MessageBounce as MessageBounceDefault } from '../Message/MessageSimple/MessageBounce';
@@ -366,6 +369,9 @@ export type ChannelPropsWithContext = Pick<ChannelContextValue, 'channel'> &
366369
| 'MessageLocation'
367370
| 'MessageMenu'
368371
| 'MessagePinnedHeader'
372+
| 'MessageReminderHeader'
373+
| 'MessageSavedForLaterHeader'
374+
| 'SentToChannelHeader'
369375
| 'MessageReplies'
370376
| 'MessageRepliesAvatars'
371377
| 'MessageSimple'
@@ -404,7 +410,7 @@ export type ChannelPropsWithContext = Pick<ChannelContextValue, 'channel'> &
404410
>
405411
> &
406412
Partial<Pick<MessageContextValue, 'isMessageAIGenerated'>> &
407-
Partial<Pick<ThreadContextValue, 'allowThreadMessagesInChannel'>> & {
413+
Partial<Pick<ThreadContextValue, 'allowThreadMessagesInChannel' | 'onBackPressThread'>> & {
408414
shouldSyncChannel: boolean;
409415
thread: ThreadType;
410416
/**
@@ -683,6 +689,9 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
683689
MessageLocation,
684690
MessageMenu = MessageMenuDefault,
685691
MessagePinnedHeader = MessagePinnedHeaderDefault,
692+
MessageReminderHeader = MessageReminderHeaderDefault,
693+
MessageSavedForLaterHeader = MessageSavedForLaterHeaderDefault,
694+
SentToChannelHeader = SentToChannelHeaderDefault,
686695
MessageReactionPicker = MessageReactionPickerDefault,
687696
MessageReplies = MessageRepliesDefault,
688697
MessageRepliesAvatars = MessageRepliesAvatarsDefault,
@@ -704,6 +713,7 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
704713
onLongPressMessage,
705714
onPressInMessage,
706715
onPressMessage,
716+
onBackPressThread,
707717
openPollCreationDialog,
708718
overrideOwnCapabilities,
709719
PollContent,
@@ -1941,6 +1951,9 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
19411951
MessageLocation,
19421952
MessageMenu,
19431953
MessagePinnedHeader,
1954+
MessageReminderHeader,
1955+
MessageSavedForLaterHeader,
1956+
SentToChannelHeader,
19441957
MessageReactionPicker,
19451958
MessageReplies,
19461959
MessageRepliesAvatars,
@@ -1984,6 +1997,7 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
19841997

19851998
const threadContext = useCreateThreadContext({
19861999
allowThreadMessagesInChannel,
2000+
onBackPressThread,
19872001
closeThread,
19882002
loadMoreThread,
19892003
openThread,

package/src/components/Channel/hooks/useCreateMessagesContext.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ export const useCreateMessagesContext = ({
6565
MessageLocation,
6666
MessageMenu,
6767
MessagePinnedHeader,
68+
MessageReminderHeader,
69+
MessageSavedForLaterHeader,
70+
SentToChannelHeader,
6871
MessageReactionPicker,
6972
MessageReplies,
7073
MessageRepliesAvatars,
@@ -178,6 +181,9 @@ export const useCreateMessagesContext = ({
178181
MessageLocation,
179182
MessageMenu,
180183
MessagePinnedHeader,
184+
MessageReminderHeader,
185+
MessageSavedForLaterHeader,
186+
SentToChannelHeader,
181187
MessageReactionPicker,
182188
MessageReplies,
183189
MessageRepliesAvatars,

package/src/components/Channel/hooks/useCreateThreadContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const selector = (nextValue: ThreadState) =>
1212

1313
export const useCreateThreadContext = ({
1414
allowThreadMessagesInChannel,
15+
onBackPressThread,
1516
closeThread,
1617
loadMoreThread,
1718
openThread,
@@ -39,6 +40,7 @@ export const useCreateThreadContext = ({
3940

4041
return {
4142
allowThreadMessagesInChannel,
43+
onBackPressThread,
4244
closeThread,
4345
loadMoreThread,
4446
openThread,

package/src/components/ChannelPreview/ChannelPreviewMessage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export const ChannelPreviewMessage = (props: ChannelPreviewMessageProps) => {
7979
if (draftMessage) {
8080
return (
8181
<View style={styles.container}>
82-
<Text style={styles.draftText}>{t('Draft:')}</Text>
82+
<Text style={styles.draftText}>{t('Draft')}:</Text>
8383
{renderMessagePreview(draftMessage)}
8484
</View>
8585
);

0 commit comments

Comments
 (0)