Skip to content

Commit 575be99

Browse files
authored
feat(CLNP-1344): add date format string set (#823)
## Description Add `DATE_FORMAT__THREAD_LIST__DATE_SEPARATOR` to customize date format of `DateSeparator` Add `DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR` to customize date format of `DateSeparator` > ![image](https://github.com/sendbird/sendbird-uikit-react/assets/26326015/3a66f7af-080b-4036-a7ae-492aba38a76b) Add `DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE` to customize date format of `UnreadCount` > ![image](https://github.com/sendbird/sendbird-uikit-react/assets/26326015/02936378-88f5-4a2d-b343-47e6785a4bfe) ## Changelogs * Provide new string sets, you can directly customize the date format of `DateSeparator` and `UnreadCount`. - `DATE_FORMAT__THREAD_LIST__DATE_SEPARATOR`: 'MMM dd, yyyy' → Used on the date separator of thread list - `DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR`: 'MMMM dd, yyyy' → Used on the date separator of message list - `DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE`: 'p \'on\' MMM dd' → Used on the unread notification of message list ```javascript import SendbirdProvider from '@sendbird/uikit-react/SendbirdProvider' const CustomApp = () => { return ( <SendbirdProvider stringSet={{ DATE_FORMAT__THREAD_LIST__DATE_SEPARATOR: 'MMM dd, yyyy', DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR: 'MMMM dd, yyyy', DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE: 'p \'on\' MMM dd', }} > {/* implement custom application */} </SendbirdProvider> ) } ``` * Deprecate a `CHANNEL__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE_FORMAT`, please use `DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE` instead. ## ticket: [CLNP-1344] [CLNP-1344]: https://sendbird.atlassian.net/browse/CLNP-1344?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
1 parent 9cb5b96 commit 575be99

File tree

10 files changed

+50
-21
lines changed

10 files changed

+50
-21
lines changed

src/modules/App/stories/index.stories.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ export const Korean = () => fitPageSize(
257257
MESSAGE_INPUT__PLACE_HOLDER: '메시지 보내기',
258258
MESSAGE_INPUT__PLACE_HOLDER__DISABLED: '입력이 불가능 합니다',
259259
MESSAGE_INPUT__PLACE_HOLDER__MUTED: '음소거 되었습니다',
260+
DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR: "yyyy'년' MMMM do '('ccc')'",
261+
DATE_FORMAT__THREAD_LIST__DATE_SEPARATOR: "yyyy'년' MMM do '('ccc')'",
262+
DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE: "p '의' MMM dd",
260263
}}
261264
isMentionEnabled
262265
isTypingIndicatorEnabledOnChannelList

src/modules/Channel/components/Message/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const Message = ({
5454
renderMessage,
5555
renderMessageContent,
5656
}: MessageUIProps): React.ReactElement => {
57-
const { dateLocale } = useLocalization();
57+
const { dateLocale, stringSet } = useLocalization();
5858
const globalStore = useSendbirdStateContext();
5959

6060
const {
@@ -234,7 +234,7 @@ const Message = ({
234234
hasSeparator && (renderedCustomSeparator || (
235235
<DateSeparator>
236236
<Label type={LabelTypography.CAPTION_2} color={LabelColors.ONBACKGROUND_2}>
237-
{format(message.createdAt, 'MMMM dd, yyyy', {
237+
{format(message.createdAt, stringSet.DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR, {
238238
locale: dateLocale,
239239
})}
240240
</Label>
@@ -347,7 +347,7 @@ const Message = ({
347347
hasSeparator && (renderedCustomSeparator || (
348348
<DateSeparator>
349349
<Label type={LabelTypography.CAPTION_2} color={LabelColors.ONBACKGROUND_2}>
350-
{format(message.createdAt, 'MMMM dd, yyyy', {
350+
{format(message.createdAt, stringSet.DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR, {
351351
locale: dateLocale,
352352
})}
353353
</Label>

src/modules/Channel/components/MessageList/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const MessageList: React.FC<MessageListProps> = ({
5858
loading,
5959
isScrolled,
6060
unreadSince,
61+
unreadSinceDate,
6162
} = useChannelContext();
6263

6364
const store = useSendbirdStateContext();
@@ -244,11 +245,12 @@ const MessageList: React.FC<MessageListProps> = ({
244245
{currentGroupChannel?.isFrozen && (
245246
<FrozenNotification className="sendbird-conversation__messages__notification" />
246247
)}
247-
{unreadSince && (
248+
{(unreadSince || unreadSinceDate) && (
248249
<UnreadCount
249250
className="sendbird-conversation__messages__notification"
250251
count={currentGroupChannel?.unreadMessageCount}
251252
time={unreadSince}
253+
lastReadAt={unreadSinceDate}
252254
onClick={() => {
253255
if (scrollRef?.current?.scrollTop) {
254256
scrollRef.current.scrollTop = (scrollRef?.current?.scrollHeight ?? 0) - (scrollRef?.current?.offsetHeight ?? 0);

src/modules/Channel/components/UnreadCount/index.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,39 @@
1-
import React, { useContext } from 'react';
1+
import React, { useContext, useMemo } from 'react';
22

33
import './unread-count.scss';
44
import { LocalizationContext } from '../../../../lib/LocalizationContext';
55
import Label, { LabelTypography, LabelColors } from '../../../../ui/Label';
66
import Icon, { IconTypes, IconColors } from '../../../../ui/Icon';
7+
import format from 'date-fns/format';
78

89
export interface UnreadCountProps {
910
className?: string;
1011
count: number | undefined;
11-
time: string;
1212
onClick(): void;
13+
lastReadAt?: Date | null;
14+
/** @deprecated Please use `lastReadAt` instead * */
15+
time?: string;
1316
}
1417

1518
const UnreadCount: React.FC<UnreadCountProps> = ({
1619
className = '',
1720
count = 0,
1821
time = '',
1922
onClick,
23+
lastReadAt,
2024
}: UnreadCountProps) => {
2125
const { stringSet } = useContext(LocalizationContext);
22-
const timeArray = time?.toString?.()?.split(' ') || [];
23-
timeArray?.splice(-2, 0, stringSet.CHANNEL__MESSAGE_LIST__NOTIFICATION__ON);
26+
27+
const unreadSince = useMemo(() => {
28+
// TODO: Remove this on v4
29+
if (stringSet.CHANNEL__MESSAGE_LIST__NOTIFICATION__ON !== 'on') {
30+
const timeArray = time?.toString?.()?.split(' ') || [];
31+
timeArray?.splice(-2, 0, stringSet.CHANNEL__MESSAGE_LIST__NOTIFICATION__ON);
32+
return timeArray.join(' ');
33+
} else if (lastReadAt) {
34+
return format(lastReadAt, stringSet.DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE);
35+
}
36+
}, [time, lastReadAt]);
2437

2538
return (
2639
<div
@@ -30,7 +43,7 @@ const UnreadCount: React.FC<UnreadCountProps> = ({
3043
<Label className="sendbird-notification__text" color={LabelColors.ONCONTENT_1} type={LabelTypography.CAPTION_2}>
3144
{`${count} `}
3245
{stringSet.CHANNEL__MESSAGE_LIST__NOTIFICATION__NEW_MESSAGE}
33-
{` ${timeArray.join(' ')}`}
46+
{` ${unreadSince}`}
3447
</Label>
3548
<Icon
3649
width="24px"

src/modules/Channel/context/ChannelProvider.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ interface MessageStoreInterface {
109109
localMessages: CoreMessageType[];
110110
loading: boolean;
111111
initialized: boolean;
112+
/** @deprecated Please use `unreadSinceDate` instead * */
112113
unreadSince: string;
114+
unreadSinceDate: Date | null;
113115
isInvalid: boolean;
114116
currentGroupChannel: Nullable<GroupChannel>;
115117
hasMorePrev: boolean;
@@ -241,6 +243,7 @@ const ChannelProvider: React.FC<ChannelContextProps> = (props: ChannelContextPro
241243
loading,
242244
initialized,
243245
unreadSince,
246+
unreadSinceDate,
244247
isInvalid,
245248
currentGroupChannel,
246249
hasMorePrev,
@@ -473,6 +476,7 @@ const ChannelProvider: React.FC<ChannelContextProps> = (props: ChannelContextPro
473476
loading,
474477
initialized,
475478
unreadSince,
479+
unreadSinceDate,
476480
isInvalid,
477481
currentGroupChannel,
478482
hasMorePrev,

src/modules/Channel/context/dux/initialState.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ export interface ChannelInitialStateType {
88
localMessages: (SendableMessageType | CoreMessageType)[];
99
loading: boolean;
1010
initialized: boolean;
11+
/** @deprecated Please use `unreadSinceDate` instead. * */
1112
unreadSince: string;
13+
unreadSinceDate: Date | null;
1214
isInvalid: boolean;
1315
currentGroupChannel: GroupChannel | null;
1416
hasMorePrev: boolean;
@@ -39,11 +41,13 @@ const initialState: ChannelInitialStateType = {
3941
hasMoreNext: false,
4042
latestMessageTimeStamp: 0,
4143
emojiContainer: { emojiCategories: [], emojiHash: '' },
44+
/** @deprecated Please use `unreadSinceDate` instead. * */
4245
unreadSince: null,
4346
/**
44-
* unreadSince is a formatted date information string
45-
* It's used only for the {unreadSince && <UnreadCount time={unreadSince} />}
47+
* unreadSinceDate is a date information about message unread.
48+
* It's used only for the {unreadSinceDate && <UnreadCount unreadSinceDate={unreadSinceDate} />}
4649
*/
50+
unreadSinceDate: null,
4751
isInvalid: false,
4852
readStatus: null,
4953
messageListParams: null,

src/modules/Channel/context/dux/reducers.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export default function channelReducer(
208208
const { channel, message } = action.payload;
209209
const { members } = channel;
210210
const { sender } = message;
211-
const { currentGroupChannel, unreadSince } = state;
211+
const { currentGroupChannel } = state;
212212

213213
const currentGroupChannelUrl = currentGroupChannel?.url;
214214

@@ -257,9 +257,8 @@ export default function channelReducer(
257257
return {
258258
...state,
259259
currentGroupChannel: channel,
260-
unreadSince: state?.unreadSince
261-
? unreadSince
262-
: format(new Date(), 'p MMM dd'),
260+
unreadSince: state.unreadSince ?? format(new Date(), 'p MMM dd'),
261+
unreadSinceDate: state.unreadSinceDate ?? new Date(),
263262
allMessages: passUnsuccessfullMessages(state.allMessages, message),
264263
};
265264
})
@@ -334,6 +333,7 @@ export default function channelReducer(
334333
return {
335334
...state,
336335
unreadSince: null,
336+
unreadSinceDate: null,
337337
};
338338
})
339339
.with({ type: channelActions.ON_MESSAGE_DELETED }, (action) => {

src/modules/OpenChannel/components/OpenChannelMessage/index.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export default function MessagOpenChannelMessageeHoc(props: OpenChannelMessagePr
5656
updateMessage,
5757
resendMessage,
5858
} = useOpenChannelContext();
59-
const { dateLocale } = useLocalization();
59+
const { dateLocale, stringSet } = useLocalization();
6060
const editDisabled = currentOpenChannel?.isFrozen;
6161

6262
const globalState = useSendbirdStateContext();
@@ -126,9 +126,7 @@ export default function MessagOpenChannelMessageeHoc(props: OpenChannelMessagePr
126126
(hasSeparator && message?.createdAt) && (
127127
<DateSeparator>
128128
<Label type={LabelTypography.CAPTION_2} color={LabelColors.ONBACKGROUND_2}>
129-
{format(message?.createdAt, 'MMMM dd, yyyy', {
130-
locale: dateLocale,
131-
})}
129+
{format(message?.createdAt, stringSet.DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR, { locale: dateLocale })}
132130
</Label>
133131
</DateSeparator>
134132
)

src/modules/Thread/components/ThreadList/ThreadListItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default function ThreadListItem({
4848
logger,
4949
} = config;
5050
const userId = stores?.userStore?.user?.userId;
51-
const { dateLocale } = useLocalization();
51+
const { dateLocale, stringSet } = useLocalization();
5252
const threadContext = useThreadContext?.();
5353
const {
5454
currentChannel,
@@ -226,7 +226,7 @@ export default function ThreadListItem({
226226
type={LabelTypography.CAPTION_2}
227227
color={LabelColors.ONBACKGROUND_2}
228228
>
229-
{format(message?.createdAt, 'MMM dd, yyyy', { locale: dateLocale })}
229+
{format(message?.createdAt, stringSet.DATE_FORMAT__THREAD_LIST__DATE_SEPARATOR, { locale: dateLocale })}
230230
</Label>
231231
</DateSeparator>
232232
))

src/ui/Label/stringSet.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const stringSet = {
1111
// Group Channel - Conversation
1212
MESSAGE_STATUS__YESTERDAY: 'Yesterday',
1313
CHANNEL__MESSAGE_LIST__NOTIFICATION__NEW_MESSAGE: 'new message(s) since',
14+
/** @deprecated Please use `DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE` instead * */
1415
CHANNEL__MESSAGE_LIST__NOTIFICATION__ON: 'on',
1516
// Channel List
1617
CHANNEL_PREVIEW_MOBILE_LEAVE: 'Leave channel',
@@ -201,6 +202,10 @@ const stringSet = {
201202
CHANNEL_PREVIEW_LAST_MESSAGE_FILE_TYPE_AUDIO: 'Audio',
202203
CHANNEL_PREVIEW_LAST_MESSAGE_FILE_TYPE_VOICE_MESSAGE: 'Voice message',
203204
CHANNEL_PREVIEW_LAST_MESSAGE_FILE_TYPE_GENERAL: 'File',
205+
// Date format
206+
DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE: 'p \'on\' MMM dd',
207+
DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR: 'MMMM dd, yyyy',
208+
DATE_FORMAT__THREAD_LIST__DATE_SEPARATOR: 'MMM dd, yyyy',
204209
},
205210
};
206211

0 commit comments

Comments
 (0)