Skip to content

Commit c450719

Browse files
committed
add inline date separators and move typing to own context
1 parent ad2d1aa commit c450719

18 files changed

Lines changed: 418 additions & 61 deletions

src/components/Channel/Channel.tsx

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { useCreateInputMessageInputContext } from './hooks/useCreateInputMessage
2727
import { useCreateMessagesContext } from './hooks/useCreateMessagesContext';
2828
import { useCreatePaginatedMessageListContext } from './hooks/useCreatePaginatedMessageListContext';
2929
import { useCreateThreadContext } from './hooks/useCreateThreadContext';
30+
import { useCreateTypingContext } from './hooks/useCreateTypingContext';
3031
import { useTargetedMessage } from './hooks/useTargetedMessage';
3132
import { heavyDebounce } from './utils/debounce';
3233
import { lightThrottle } from './utils/throttle';
@@ -111,6 +112,10 @@ import {
111112
TranslationContextValue,
112113
useTranslationContext,
113114
} from '../../contexts/translationContext/TranslationContext';
115+
import {
116+
TypingContextValue,
117+
TypingProvider,
118+
} from '../../contexts/typingContext/TypingContext';
114119
import {
115120
LOLReaction,
116121
LoveReaction,
@@ -188,6 +193,7 @@ export type ChannelPropsWithContext<
188193
| 'EmptyStateIndicator'
189194
| 'enforceUniqueReaction'
190195
| 'giphyEnabled'
196+
| 'hideDateSeparators'
191197
| 'LoadingIndicator'
192198
| 'NetworkDownIndicator'
193199
| 'StickyHeader'
@@ -442,6 +448,7 @@ const ChannelWithContext = <
442448
hasCommands = true,
443449
hasFilePicker = true,
444450
hasImagePicker = true,
451+
hideDateSeparators = false,
445452
ImageUploadPreview = ImageUploadPreviewDefault,
446453
initialScrollToFirstUnreadMessage = false,
447454
initialValue,
@@ -547,7 +554,7 @@ const ChannelWithContext = <
547554
ThreadContextValue<At, Ch, Co, Ev, Me, Re, Us>['threadMessages']
548555
>((threadProps?.id && channel?.state?.threads?.[threadProps.id]) || []);
549556
const [typing, setTyping] = useState<
550-
ChannelContextValue<At, Ch, Co, Ev, Me, Re, Us>['typing']
557+
TypingContextValue<At, Ch, Co, Ev, Me, Re, Us>['typing']
551558
>({});
552559
const [watcherCount, setWatcherCount] = useState<
553560
ChannelContextValue<At, Ch, Co, Ev, Me, Re, Us>['watcherCount']
@@ -1440,6 +1447,7 @@ const ChannelWithContext = <
14401447
!!(channel?.getConfig?.()?.commands || [])?.some(
14411448
(command) => command.name === 'giphy',
14421449
),
1450+
hideDateSeparators,
14431451
isAdmin,
14441452
isModerator,
14451453
isOwner,
@@ -1457,7 +1465,6 @@ const ChannelWithContext = <
14571465
setTargetedMessage,
14581466
StickyHeader,
14591467
targetedMessage,
1460-
typing,
14611468
watcherCount,
14621469
watchers,
14631470
});
@@ -1607,6 +1614,10 @@ const ChannelWithContext = <
16071614
threadMessages,
16081615
});
16091616

1617+
const typingContext = useCreateTypingContext({
1618+
typing,
1619+
});
1620+
16101621
if (!channel || error) {
16111622
return (
16121623
<LoadingErrorIndicator
@@ -1638,21 +1649,25 @@ const ChannelWithContext = <
16381649
{...additionalKeyboardAvoidingViewProps}
16391650
>
16401651
<ChannelProvider<At, Ch, Co, Ev, Me, Re, Us> value={channelContext}>
1641-
<PaginatedMessageListProvider<At, Ch, Co, Ev, Me, Re, Us>
1642-
value={messageListContext}
1643-
>
1644-
<MessagesProvider<At, Ch, Co, Ev, Me, Re, Us> value={messagesContext}>
1645-
<ThreadProvider<At, Ch, Co, Ev, Me, Re, Us> value={threadContext}>
1646-
<SuggestionsProvider<Co, Us> value={suggestionsContext}>
1647-
<MessageInputProvider<At, Ch, Co, Ev, Me, Re, Us>
1648-
value={messageInputContext}
1649-
>
1650-
<View style={{ height: '100%' }}>{children}</View>
1651-
</MessageInputProvider>
1652-
</SuggestionsProvider>
1653-
</ThreadProvider>
1654-
</MessagesProvider>
1655-
</PaginatedMessageListProvider>
1652+
<TypingProvider<At, Ch, Co, Ev, Me, Re, Us> value={typingContext}>
1653+
<PaginatedMessageListProvider<At, Ch, Co, Ev, Me, Re, Us>
1654+
value={messageListContext}
1655+
>
1656+
<MessagesProvider<At, Ch, Co, Ev, Me, Re, Us>
1657+
value={messagesContext}
1658+
>
1659+
<ThreadProvider<At, Ch, Co, Ev, Me, Re, Us> value={threadContext}>
1660+
<SuggestionsProvider<Co, Us> value={suggestionsContext}>
1661+
<MessageInputProvider<At, Ch, Co, Ev, Me, Re, Us>
1662+
value={messageInputContext}
1663+
>
1664+
<View style={{ height: '100%' }}>{children}</View>
1665+
</MessageInputProvider>
1666+
</SuggestionsProvider>
1667+
</ThreadProvider>
1668+
</MessagesProvider>
1669+
</PaginatedMessageListProvider>
1670+
</TypingProvider>
16561671
</ChannelProvider>
16571672
</KeyboardCompatibleView>
16581673
);

src/components/Channel/hooks/useCreateChannelContext.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const useCreateChannelContext = <
2727
enforceUniqueReaction,
2828
error,
2929
giphyEnabled,
30+
hideDateSeparators,
3031
isAdmin,
3132
isModerator,
3233
isOwner,
@@ -45,7 +46,6 @@ export const useCreateChannelContext = <
4546
setTargetedMessage,
4647
StickyHeader,
4748
targetedMessage,
48-
typing,
4949
typingEventsEnabled,
5050
watcherCount,
5151
watchers,
@@ -60,8 +60,6 @@ export const useCreateChannelContext = <
6060
.map(({ last_read }) => last_read.toISOString())
6161
.join();
6262

63-
const typingValue = Object.keys(typing).join();
64-
6563
const channelContext: ChannelContextValue<
6664
At,
6765
Ch,
@@ -78,6 +76,7 @@ export const useCreateChannelContext = <
7876
enforceUniqueReaction,
7977
error,
8078
giphyEnabled,
79+
hideDateSeparators,
8180
isAdmin,
8281
isModerator,
8382
isOwner,
@@ -96,7 +95,6 @@ export const useCreateChannelContext = <
9695
setTargetedMessage,
9796
StickyHeader,
9897
targetedMessage,
99-
typing,
10098
typingEventsEnabled,
10199
watcherCount,
102100
watchers,
@@ -113,7 +111,6 @@ export const useCreateChannelContext = <
113111
readUsersLastReads,
114112
targetedMessage,
115113
typingEventsEnabled,
116-
typingValue,
117114
watcherCount,
118115
],
119116
);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useMemo } from 'react';
2+
3+
import type { TypingContextValue } from '../../../contexts/typingContext/TypingContext';
4+
import type {
5+
DefaultAttachmentType,
6+
DefaultChannelType,
7+
DefaultCommandType,
8+
DefaultEventType,
9+
DefaultMessageType,
10+
DefaultReactionType,
11+
DefaultUserType,
12+
UnknownType,
13+
} from '../../../types/types';
14+
15+
export const useCreateTypingContext = <
16+
At extends UnknownType = DefaultAttachmentType,
17+
Ch extends UnknownType = DefaultChannelType,
18+
Co extends string = DefaultCommandType,
19+
Ev extends UnknownType = DefaultEventType,
20+
Me extends UnknownType = DefaultMessageType,
21+
Re extends UnknownType = DefaultReactionType,
22+
Us extends UnknownType = DefaultUserType
23+
>({
24+
typing,
25+
}: TypingContextValue<At, Ch, Co, Ev, Me, Re, Us>) => {
26+
const typingValue = Object.keys(typing).join();
27+
28+
const typingContext: TypingContextValue<At, Ch, Co, Ev, Me, Re, Us> = useMemo(
29+
() => ({
30+
typing,
31+
}),
32+
[typingValue],
33+
);
34+
35+
return typingContext;
36+
};

src/components/Message/Message.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ import type { Attachment, MessageResponse, Reaction } from 'stream-chat';
8585

8686
import {
8787
GroupType,
88-
isMessagesWithStylesAndReadBy,
88+
isMessagesWithStylesReadByAndDateSeparator,
8989
MessageType,
9090
} from '../MessageList/hooks/useMessageList';
9191

@@ -1183,8 +1183,10 @@ const areEqual = <
11831183

11841184
const messageEqual =
11851185
prevMessage.deleted_at === nextMessage.deleted_at &&
1186-
(isMessagesWithStylesAndReadBy(prevMessage) && prevMessage.readBy) ===
1187-
(isMessagesWithStylesAndReadBy(nextMessage) && nextMessage.readBy) &&
1186+
(isMessagesWithStylesReadByAndDateSeparator(prevMessage) &&
1187+
prevMessage.readBy) ===
1188+
(isMessagesWithStylesReadByAndDateSeparator(nextMessage) &&
1189+
nextMessage.readBy) &&
11881190
prevMessage.status === nextMessage.status &&
11891191
prevMessage.type === nextMessage.type &&
11901192
prevMessage.text === nextMessage.text &&

src/components/Message/MessageSimple/MessageStatus.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { StyleSheet, Text, View } from 'react-native';
33

4-
import { isMessagesWithStylesAndReadBy } from '../../MessageList/hooks/useMessageList';
4+
import { isMessagesWithStylesReadByAndDateSeparator } from '../../MessageList/hooks/useMessageList';
55

66
import {
77
MessageContextValue,
@@ -87,7 +87,7 @@ const MessageStatusWithContext = <
8787
}
8888

8989
if (
90-
isMessagesWithStylesAndReadBy(message) &&
90+
isMessagesWithStylesReadByAndDateSeparator(message) &&
9191
!threadList &&
9292
readEventsEnabled !== false
9393
) {
@@ -153,8 +153,10 @@ const areEqual = <
153153
const messageEqual =
154154
prevMessage.status === nextMessage.status &&
155155
prevMessage.type === nextMessage.type &&
156-
(isMessagesWithStylesAndReadBy(prevMessage) && prevMessage.readBy) ===
157-
(isMessagesWithStylesAndReadBy(nextMessage) && nextMessage.readBy);
156+
(isMessagesWithStylesReadByAndDateSeparator(prevMessage) &&
157+
prevMessage.readBy) ===
158+
(isMessagesWithStylesReadByAndDateSeparator(nextMessage) &&
159+
nextMessage.readBy);
158160
if (!messageEqual) return false;
159161

160162
return true;

src/components/Message/hooks/useCreateMessageContext.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useMemo } from 'react';
22

3-
import { isMessagesWithStylesAndReadBy } from '../../MessageList/hooks/useMessageList';
3+
import { isMessagesWithStylesReadByAndDateSeparator } from '../../MessageList/hooks/useMessageList';
44

55
import type { MessageContextValue } from '../../../contexts/messageContext/MessageContext';
66
import type {
@@ -60,7 +60,8 @@ export const useCreateMessageContext = <
6060
const latestReactions = message.latest_reactions
6161
? message.latest_reactions
6262
: undefined;
63-
const readBy = isMessagesWithStylesAndReadBy(message) && message.readBy;
63+
const readBy =
64+
isMessagesWithStylesReadByAndDateSeparator(message) && message.readBy;
6465
const messageValue = `${
6566
latestReactions ? latestReactions.map(({ type }) => type).join() : ''
6667
}${message.updated_at}${message.deleted_at}${readBy}${message.status}${
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React from 'react';
2+
import { StyleSheet, Text, View } from 'react-native';
3+
4+
import { useTheme } from '../../contexts/themeContext/ThemeContext';
5+
import {
6+
isDayOrMoment,
7+
useTranslationContext,
8+
} from '../../contexts/translationContext/TranslationContext';
9+
10+
const styles = StyleSheet.create({
11+
container: {
12+
alignItems: 'center',
13+
alignSelf: 'center',
14+
borderRadius: 8,
15+
height: 16,
16+
justifyContent: 'center',
17+
marginVertical: 4,
18+
paddingHorizontal: 8,
19+
},
20+
text: {
21+
fontSize: 12,
22+
textAlign: 'center',
23+
textAlignVertical: 'center',
24+
},
25+
});
26+
27+
export type InlineDateIndicatorProps = {
28+
date?: Date;
29+
};
30+
31+
export const InlineDateIndicator: React.FC<InlineDateIndicatorProps> = ({
32+
date,
33+
}) => {
34+
const {
35+
theme: {
36+
colors: { overlay_dark, white },
37+
inlineDateIndicator: { container, text },
38+
},
39+
} = useTheme();
40+
const { tDateTimeParser } = useTranslationContext();
41+
42+
if (!date) {
43+
return null;
44+
}
45+
46+
const dateFormat =
47+
date.getFullYear() === new Date().getFullYear() ? 'MMM D' : 'MMM D, YYYY';
48+
const tDate = tDateTimeParser(date);
49+
const dateString = isDayOrMoment(tDate)
50+
? tDate.format(dateFormat)
51+
: new Date(tDate).toDateString();
52+
53+
return (
54+
<View
55+
style={[styles.container, { backgroundColor: overlay_dark }, container]}
56+
>
57+
<Text style={[styles.text, { color: white }, text]}>{dateString}</Text>
58+
</View>
59+
);
60+
};

src/components/MessageList/MessageList.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import {
1010
} from 'react-native';
1111

1212
import {
13-
isMessagesWithStylesAndReadBy,
13+
isMessagesWithStylesReadByAndDateSeparator,
1414
MessageType,
1515
useMessageList,
1616
} from './hooks/useMessageList';
17+
import { InlineDateIndicator } from './InlineDateIndicator';
1718
import { InlineLoadingMoreIndicator } from './InlineLoadingMoreIndicator';
1819
import { InlineLoadingMoreRecentIndicator } from './InlineLoadingMoreRecentIndicator';
1920
import { InlineLoadingMoreThreadIndicator } from './InlineLoadingMoreThreadIndicator';
@@ -566,7 +567,7 @@ const MessageListWithContext = <
566567
<Message
567568
goToMessage={goToMessage}
568569
groupStyles={
569-
isMessagesWithStylesAndReadBy(message)
570+
isMessagesWithStylesReadByAndDateSeparator(message)
570571
? message.groupStyles
571572
: []
572573
}
@@ -581,6 +582,10 @@ const MessageListWithContext = <
581582
threadList={threadList}
582583
/>
583584
</ThemeProvider>
585+
{isMessagesWithStylesReadByAndDateSeparator(message) &&
586+
message.dateSeparator && (
587+
<InlineDateIndicator date={message.dateSeparator} />
588+
)}
584589
{/* Adding indicator below the messages, since the list is inverted */}
585590
{insertInlineUnreadIndicator && <InlineUnreadIndicator />}
586591
</>
@@ -591,7 +596,9 @@ const MessageListWithContext = <
591596
<Message
592597
goToMessage={goToMessage}
593598
groupStyles={
594-
isMessagesWithStylesAndReadBy(message) ? message.groupStyles : []
599+
isMessagesWithStylesReadByAndDateSeparator(message)
600+
? message.groupStyles
601+
: []
595602
}
596603
lastReceivedId={
597604
lastReceivedId === message.id ? lastReceivedId : undefined
@@ -603,6 +610,10 @@ const MessageListWithContext = <
603610
targetedMessage={targetedMessage === message.id}
604611
threadList={threadList}
605612
/>
613+
{isMessagesWithStylesReadByAndDateSeparator(message) &&
614+
message.dateSeparator && (
615+
<InlineDateIndicator date={message.dateSeparator} />
616+
)}
606617
{/* Adding indicator below the messages, since the list is inverted */}
607618
{insertInlineUnreadIndicator && <InlineUnreadIndicator />}
608619
</>

0 commit comments

Comments
 (0)