Skip to content

Commit 4922d04

Browse files
authored
feature: Add string set for date format (#1221)
[CLNP-5163](https://sendbird.atlassian.net/browse/CLNP-5163) [SBISSUE-17143](https://sendbird.atlassian.net/browse/SBISSUE-17143) #### ChangeLog ##### Features - Added stringSet for date format and applied them | Key | Value | | --- | ----- | | DATE_FORMAT__MESSAGE_CREATED_AT | `'p'` | | DATE_FORMAT__UNREAD_SINCE | `'p MMM dd'` | | DATE_FORMAT__LAST_MESSAGE_CREATED_AT__TODAY | `'p'` | | DATE_FORMAT__LAST_MESSAGE_CREATED_AT__THIS_YEAR | `'MMM d'` | | DATE_FORMAT__LAST_MESSAGE_CREATED_AT__PREVIOUS_YEAR | `'yyyy/M/d'` | [CLNP-5163]: https://sendbird.atlassian.net/browse/CLNP-5163?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [SBISSUE-17143]: https://sendbird.atlassian.net/browse/SBISSUE-17143?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
1 parent 95aeac7 commit 4922d04

File tree

22 files changed

+114
-45
lines changed

22 files changed

+114
-45
lines changed

src/modules/Channel/context/dux/__tests__/reducers.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ import * as actionTypes from '../actionTypes';
77
import reducers from '../reducers';
88
import initialState from '../initialState';
99
import { uuidv4 } from '../../../../../utils/uuid';
10+
import { useLocalization } from '../../../../../lib/LocalizationContext';
11+
12+
jest.mock('../../../../../lib/LocalizationContext', () => ({
13+
...jest.requireActual('../../../../../lib/LocalizationContext'),
14+
useLocalization: jest.fn(),
15+
}));
1016

1117
const getLastMessageOf = (messageList) => messageList[messageList.length - 1];
1218

@@ -15,6 +21,16 @@ describe('Messages-Reducers', () => {
1521
...initialState,
1622
currentGroupChannel: { url: generateMockChannel().currentGroupChannel.url },
1723
};
24+
25+
beforeEach(() => {
26+
jest.clearAllMocks();
27+
useLocalization.mockReturnValue({
28+
stringSet: {
29+
DATE_FORMAT__UNREAD_SINCE: 'p MMM dd',
30+
},
31+
});
32+
});
33+
1834
it('should setloading true FETCH_INITIAL_MESSAGES_START', () => {
1935
const nextState = reducers(initialState, {
2036
type: actionTypes.FETCH_INITIAL_MESSAGES_START,

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
isSendableMessage,
1818
} from '../../../../utils';
1919
import { ChannelInitialStateType } from './initialState';
20+
import { useLocalization } from '../../../../lib/LocalizationContext';
2021

2122
const getOldestMessageTimeStamp = (messages: CoreMessageType[] = []) => {
2223
const oldestMessage = messages[0];
@@ -37,6 +38,8 @@ export default function channelReducer(
3738
state: ChannelInitialStateType,
3839
action: ChannelActionTypes,
3940
): ChannelInitialStateType {
41+
const { stringSet } = useLocalization();
42+
4043
return match(action)
4144
.with({ type: channelActions.RESET_MESSAGES }, () => {
4245
return {
@@ -268,7 +271,7 @@ export default function channelReducer(
268271
return {
269272
...state,
270273
currentGroupChannel: channel,
271-
unreadSince: state.unreadSince ?? format(new Date(), 'p MMM dd'),
274+
unreadSince: state.unreadSince ?? format(new Date(), stringSet.DATE_FORMAT__UNREAD_SINCE),
272275
unreadSinceDate: state.unreadSinceDate ?? new Date(),
273276
allMessages: passUnsuccessfullMessages(state.allMessages, message),
274277
};

src/modules/Channel/context/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import format from 'date-fns/format';
55

66
import { CoreMessageType, SendableMessageType } from '../../../utils';
77
import { BaseMessage, SendingStatus } from '@sendbird/chat/message';
8+
import { useLocalization } from '../../../lib/LocalizationContext';
89

910
export const scrollToRenderedMessage = (
1011
scrollRef: React.RefObject<HTMLElement>,
@@ -115,7 +116,10 @@ export const mergeAndSortMessages = (oldMessages: BaseMessage[], newMessages: Ba
115116
return sortByCreatedAt(unique);
116117
};
117118

118-
export const getMessageCreatedAt = (message: BaseMessage) => format(message.createdAt, 'p');
119+
export const getMessageCreatedAt = (message: BaseMessage) => {
120+
const { stringSet } = useLocalization();
121+
return format(message.createdAt, stringSet.DATE_FORMAT__MESSAGE_CREATED_AT);
122+
};
119123

120124
export const passUnsuccessfullMessages = (
121125
allMessages: (CoreMessageType | SendableMessageType)[],

src/modules/GroupChannel/components/MessageList/__test__/getMessagePartsInfo.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
import { useLocalization } from "../../../../../lib/LocalizationContext";
12
import { getMessagePartsInfo } from "../getMessagePartsInfo";
23

4+
jest.mock('../../../../../lib/LocalizationContext', () => ({
5+
...jest.requireActual('../../../../../lib/LocalizationContext'),
6+
useLocalization: jest.fn(),
7+
}));
8+
39
const mockChannel = {
410
isGroupChannel: () => true,
511
getUnreadMemberCount: () => 0,
@@ -40,6 +46,14 @@ const messageGroup3 = [1, 2, 3].map((n, i) => ({
4046
}));
4147

4248
describe('getMessagePartsInfo', () => {
49+
beforeEach(() => {
50+
jest.clearAllMocks();
51+
useLocalization.mockReturnValue({
52+
stringSet: {
53+
DATE_FORMAT__MESSAGE_CREATED_AT: 'p',
54+
},
55+
});
56+
});
4357
it('should group messages that are sent at same time', () => {
4458
const defaultSetting = {
4559
allMessages: messageGroup1,

src/modules/GroupChannelList/components/GroupChannelListItem/utils.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ export const getLastMessageCreatedAt = ({ channel, locale, stringSet = LabelStri
2929
return '';
3030
}
3131
if (isToday(createdAt)) {
32-
return format(createdAt, 'p', optionalParam);
32+
return format(createdAt, stringSet.DATE_FORMAT__LAST_MESSAGE_CREATED_AT__TODAY, optionalParam);
3333
}
3434
if (isYesterday(createdAt)) {
3535
return stringSet.MESSAGE_STATUS__YESTERDAY || 'Yesterday';
3636
}
3737
if (isThisYear(createdAt)) {
38-
return format(createdAt, 'MMM d', optionalParam);
38+
return format(createdAt, stringSet.DATE_FORMAT__LAST_MESSAGE_CREATED_AT__THIS_YEAR, optionalParam);
3939
}
40-
return format(createdAt, 'yyyy/M/d', optionalParam);
40+
return format(createdAt, stringSet.DATE_FORMAT__LAST_MESSAGE_CREATED_AT__PREVIOUS_YEAR, optionalParam);
4141
};
4242

4343
export const getTotalMembers = (channel?: GroupChannel) => (channel?.memberCount ? channel.memberCount : 0);

src/modules/OpenChannel/context/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ import format from 'date-fns/format';
55

66
import { Logger } from '../../../lib/SendbirdState';
77
import { SendableMessageType } from '../../../utils';
8+
import { useLocalization } from '../../../lib/LocalizationContext';
89

9-
export const getMessageCreatedAt = (message: SendableMessageType): string => format(message.createdAt, 'p');
10+
export const getMessageCreatedAt = (message: SendableMessageType): string => {
11+
const { stringSet } = useLocalization();
12+
return format(message.createdAt, stringSet.DATE_FORMAT__MESSAGE_CREATED_AT);
13+
};
1014

1115
export const shouldFetchMore = (messageLength: number, maxMessages?: number): boolean => {
1216
if (typeof maxMessages !== 'number') {

src/modules/Thread/components/ParentMessageInfo/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export default function ParentMessageInfo({
4747
const { stores, config } = useSendbirdStateContext();
4848
const { isOnline, userMention, logger, groupChannel } = config;
4949
const userId = stores.userStore.user?.userId ?? '';
50-
const { dateLocale } = useLocalization();
50+
const { dateLocale, stringSet } = useLocalization();
5151
const {
5252
currentChannel,
5353
parentMessage,
@@ -301,7 +301,7 @@ export default function ParentMessageInfo({
301301
type={LabelTypography.CAPTION_3}
302302
color={LabelColors.ONBACKGROUND_2}
303303
>
304-
{format(parentMessage?.createdAt || 0, 'p', { locale: dateLocale })}
304+
{format(parentMessage?.createdAt || 0, stringSet.DATE_FORMAT__MESSAGE_CREATED_AT, { locale: dateLocale })}
305305
</Label>
306306
</div>
307307
{/* message content body */}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export default function ThreadListItemContent(props: ThreadListItemContentProps)
9898
} = deleteNullish(props);
9999

100100
const { isMobile } = useMediaQueryContext();
101-
const { dateLocale } = useLocalization();
101+
const { dateLocale, stringSet } = useLocalization();
102102
const { config, eventHandlers } = useSendbirdStateContext?.() || {};
103103
const { logger } = config;
104104
const onPressUserProfileHandler = eventHandlers?.reaction?.onPressUserProfile;
@@ -272,7 +272,7 @@ export default function ThreadListItemContent(props: ThreadListItemContentProps)
272272
type={LabelTypography.CAPTION_3}
273273
color={LabelColors.ONBACKGROUND_2}
274274
>
275-
{format(message?.createdAt || 0, 'p', {
275+
{format(message?.createdAt || 0, stringSet.DATE_FORMAT__MESSAGE_CREATED_AT, {
276276
locale: dateLocale,
277277
})}
278278
</Label>

src/modules/Thread/context/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import format from 'date-fns/format';
22
import { GroupChannel, Member } from '@sendbird/chat/groupChannel';
33
import { getOutgoingMessageState, OutgoingMessageStates } from '../../../utils/exports/getOutgoingMessageState';
44
import { SendableMessageType } from '../../../utils';
5+
import { useLocalization } from '../../../lib/LocalizationContext';
56

67
export const getNicknamesMapFromMembers = (members: Member[] = []): Map<string, string> => {
78
const nicknamesMap = new Map();
@@ -57,7 +58,10 @@ export function compareIds(a: number | string, b: number | string): boolean {
5758
return aString === bString;
5859
}
5960

60-
export const getMessageCreatedAt = (message: SendableMessageType): string => format(message.createdAt, 'p');
61+
export const getMessageCreatedAt = (message: SendableMessageType): string => {
62+
const { stringSet } = useLocalization();
63+
return format(message.createdAt, stringSet.DATE_FORMAT__MESSAGE_CREATED_AT);
64+
};
6165
export const isReadMessage = (channel: GroupChannel, message: SendableMessageType): boolean => (
6266
getOutgoingMessageState(channel, message) === OutgoingMessageStates.READ
6367
);

src/ui/Label/stringSet.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,11 @@ const stringSet = {
217217
DATE_FORMAT__MESSAGE_LIST__NOTIFICATION__UNREAD_SINCE: 'p \'on\' MMM dd',
218218
DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR: 'MMMM dd, yyyy',
219219
DATE_FORMAT__THREAD_LIST__DATE_SEPARATOR: 'MMM dd, yyyy',
220+
DATE_FORMAT__MESSAGE_CREATED_AT: 'p',
221+
DATE_FORMAT__UNREAD_SINCE: 'p MMM dd',
222+
DATE_FORMAT__LAST_MESSAGE_CREATED_AT__TODAY: 'p',
223+
DATE_FORMAT__LAST_MESSAGE_CREATED_AT__THIS_YEAR: 'MMM d',
224+
DATE_FORMAT__LAST_MESSAGE_CREATED_AT__PREVIOUS_YEAR: 'yyyy/M/d',
220225
// File upload
221226
FILE_UPLOAD_NOTIFICATION__COUNT_LIMIT: 'Up to %d files can be attached.',
222227
FILE_UPLOAD_NOTIFICATION__SIZE_LIMIT: 'The maximum size per file is %d MB.',

src/ui/MessageContent/__tests__/MessageContent.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ describe('ui/MessageContent', () => {
7171
};
7272
const localeContextValue = {
7373
dateLocale: {},
74+
stringSet: {
75+
DATE_FORMAT__MESSAGE_CREATED_AT: 'p',
76+
},
7477
};
7578
const messageContextValue = {
7679
message: {},

src/ui/MessageContent/index.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { ReactElement, ReactNode, useContext, useMemo, useRef, useState } from 'react';
1+
import React, { ReactElement, ReactNode, useMemo, useRef, useState } from 'react';
22
import format from 'date-fns/format';
33
import './index.scss';
44

@@ -25,7 +25,7 @@ import {
2525
SendableMessageType,
2626
UI_CONTAINER_TYPES,
2727
} from '../../utils';
28-
import { LocalizationContext, useLocalization } from '../../lib/LocalizationContext';
28+
import { useLocalization } from '../../lib/LocalizationContext';
2929
import useSendbirdStateContext from '../../hooks/useSendbirdStateContext';
3030
import { GroupChannel } from '@sendbird/chat/groupChannel';
3131
import { type EmojiCategory, EmojiContainer } from '@sendbird/chat';
@@ -137,7 +137,7 @@ export function MessageContent(props: MessageContentProps): ReactElement {
137137
renderMobileMenuOnLongPress = (props: MobileBottomSheetProps) => <MobileMenu {...props} />,
138138
} = deleteNullish(props);
139139

140-
const { dateLocale } = useLocalization();
140+
const { dateLocale, stringSet } = useLocalization();
141141
const { config, eventHandlers } = useSendbirdStateContext();
142142
const { logger } = config;
143143
const onPressUserProfileHandler = eventHandlers?.reaction?.onPressUserProfile;
@@ -176,8 +176,6 @@ export function MessageContent(props: MessageContentProps): ReactElement {
176176
}
177177
};
178178

179-
const { stringSet } = useContext(LocalizationContext);
180-
181179
const isByMe = (userId === (message as SendableMessageType)?.sender?.userId)
182180
|| ((message as SendableMessageType)?.sendingStatus === 'pending')
183181
|| ((message as SendableMessageType)?.sendingStatus === 'failed');
@@ -448,7 +446,7 @@ export function MessageContent(props: MessageContentProps): ReactElement {
448446
color={LabelColors.ONBACKGROUND_2}
449447
ref={timestampRef}
450448
>
451-
{format(message?.createdAt || 0, 'p', {
449+
{format(message?.createdAt || 0, stringSet.DATE_FORMAT__MESSAGE_CREATED_AT, {
452450
locale: dateLocale,
453451
})}
454452
</Label>

src/ui/MessageSearchFileItem/__tests__/MessageSearchFileItem.spec.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ import { getCreatedAt } from '../utils';
1414
jest.useFakeTimers();
1515
jest.setSystemTime(new Date('January 23, 2022 17:17:52'));
1616

17+
const stringSet = {
18+
DATE_FORMAT__LAST_MESSAGE_CREATED_AT__TODAY: 'p',
19+
MESSAGE_STATUS__YESTERDAY: 'Yesterday',
20+
DATE_FORMAT__LAST_MESSAGE_CREATED_AT__THIS_YEAR: 'MMM d',
21+
DATE_FORMAT__LAST_MESSAGE_CREATED_AT__PREVIOUS_YEAR: 'yyyy/M/dd',
22+
};
23+
1724
describe('ui/MessageSearchFileItem', () => {
1825
// should add test cases for each file types
1926
// define id for each icon svg files first
@@ -34,15 +41,15 @@ describe('ui/MessageSearchFileItem', () => {
3441
const nowTime = new Date(Date.now());
3542
const isPM = nowTime?.getHours() > 12;
3643
expect(
37-
getCreatedAt({ createdAt: nowTime })
44+
getCreatedAt({ createdAt: nowTime, stringSet })
3845
).toBe(`${nowTime?.getHours() - (isPM ? 12 : 0)}:${nowTime?.getMinutes()} ${isPM ? 'PM' : 'AM'}`);
3946
});
4047

4148
test('utils/getCreatedAt returns "Yesterday" if ts is created yesterday', () => {
4249
const nowTime = new Date(Date.now());
4350
nowTime.setDate(nowTime.getDate() - 1);
4451
expect(
45-
getCreatedAt({ createdAt: nowTime })
52+
getCreatedAt({ createdAt: nowTime, stringSet })
4653
).toBe("Yesterday");
4754
})
4855

@@ -51,21 +58,21 @@ describe('ui/MessageSearchFileItem', () => {
5158
nowTime.setDate(nowTime.getDate() - 2);
5259
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
5360
expect(
54-
getCreatedAt({ createdAt: nowTime })
61+
getCreatedAt({ createdAt: nowTime, stringSet })
5562
).toBe(`${months[nowTime?.getMonth()]} ${nowTime?.getDate()}`);
5663
expect(
57-
getCreatedAt({ createdAt: nowTime })
64+
getCreatedAt({ createdAt: nowTime, stringSet })
5865
).toBe('Jan 21');
5966
});
6067

6168
test('utils/getCreatedAt returns year, month, and date if ts is created last year', () => {
6269
const nowTime = new Date(Date.now());
6370
nowTime.setFullYear(nowTime.getFullYear() - 1);
6471
expect(
65-
getCreatedAt({ createdAt: nowTime })
72+
getCreatedAt({ createdAt: nowTime, stringSet })
6673
).toBe(`${nowTime?.getFullYear()}/${nowTime?.getMonth() + 1}/${nowTime?.getDate()}`);
6774
expect(
68-
getCreatedAt({ createdAt: nowTime })
75+
getCreatedAt({ createdAt: nowTime, stringSet })
6976
).toBe('2021/1/23');
7077
});
7178
});

src/ui/MessageSearchFileItem/utils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { Types } from '../Icon/type';
1313
export interface GetCreatedAtProps {
1414
createdAt: number;
1515
locale?: Locale;
16-
stringSet?: Record<string, string>;
16+
stringSet: Record<string, string>;
1717
}
1818

1919
export function getCreatedAt({ createdAt, locale, stringSet }: GetCreatedAtProps): string {
@@ -22,15 +22,15 @@ export function getCreatedAt({ createdAt, locale, stringSet }: GetCreatedAtProps
2222
return '';
2323
}
2424
if (isToday(createdAt)) {
25-
return format(createdAt, 'p', optionalParam);
25+
return format(createdAt, stringSet.DATE_FORMAT__LAST_MESSAGE_CREATED_AT__TODAY, optionalParam);
2626
}
2727
if (isYesterday(createdAt)) {
28-
return stringSet?.MESSAGE_STATUS__YESTERDAY || 'Yesterday';
28+
return stringSet.MESSAGE_STATUS__YESTERDAY;
2929
}
3030
if (isThisYear(createdAt)) {
31-
return format(createdAt, 'MMM d', optionalParam);
31+
return format(createdAt, stringSet.DATE_FORMAT__LAST_MESSAGE_CREATED_AT__THIS_YEAR, optionalParam);
3232
}
33-
return format(createdAt, 'yyyy/M/d', optionalParam);
33+
return format(createdAt, stringSet.DATE_FORMAT__LAST_MESSAGE_CREATED_AT__PREVIOUS_YEAR, optionalParam);
3434
}
3535

3636
export function getIconOfFileType(message: FileMessage | MultipleFilesMessage): Types {

0 commit comments

Comments
 (0)