@sendbird/uikit-utils 2.0.3 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/lib/commonjs/hooks/index.js +14 -1
  2. package/lib/commonjs/hooks/index.js.map +1 -1
  3. package/lib/commonjs/index.js +39 -2
  4. package/lib/commonjs/index.js.map +1 -1
  5. package/lib/commonjs/sendbird/channel.js +18 -6
  6. package/lib/commonjs/sendbird/channel.js.map +1 -1
  7. package/lib/commonjs/sendbird/message.js +12 -2
  8. package/lib/commonjs/sendbird/message.js.map +1 -1
  9. package/lib/commonjs/sendbird/user.js +23 -0
  10. package/lib/commonjs/sendbird/user.js.map +1 -0
  11. package/lib/commonjs/shared/bufferedRequest.js +38 -12
  12. package/lib/commonjs/shared/bufferedRequest.js.map +1 -1
  13. package/lib/commonjs/shared/regex.js +52 -6
  14. package/lib/commonjs/shared/regex.js.map +1 -1
  15. package/lib/commonjs/shared/replace.js +14 -0
  16. package/lib/commonjs/shared/replace.js.map +1 -0
  17. package/lib/commonjs/types.js +3 -1
  18. package/lib/commonjs/types.js.map +1 -1
  19. package/lib/commonjs/ui-format/common.js +17 -14
  20. package/lib/commonjs/ui-format/common.js.map +1 -1
  21. package/lib/commonjs/ui-format/groupChannel.js +7 -10
  22. package/lib/commonjs/ui-format/groupChannel.js.map +1 -1
  23. package/lib/module/hooks/index.js +10 -0
  24. package/lib/module/hooks/index.js.map +1 -1
  25. package/lib/module/index.js +4 -2
  26. package/lib/module/index.js.map +1 -1
  27. package/lib/module/sendbird/channel.js +14 -4
  28. package/lib/module/sendbird/channel.js.map +1 -1
  29. package/lib/module/sendbird/message.js +9 -3
  30. package/lib/module/sendbird/message.js.map +1 -1
  31. package/lib/module/sendbird/user.js +12 -0
  32. package/lib/module/sendbird/user.js.map +1 -0
  33. package/lib/module/shared/bufferedRequest.js +39 -12
  34. package/lib/module/shared/bufferedRequest.js.map +1 -1
  35. package/lib/module/shared/regex.js +43 -3
  36. package/lib/module/shared/regex.js.map +1 -1
  37. package/lib/module/shared/replace.js +6 -0
  38. package/lib/module/shared/replace.js.map +1 -0
  39. package/lib/module/types.js +1 -4
  40. package/lib/module/types.js.map +1 -1
  41. package/lib/module/ui-format/common.js +12 -7
  42. package/lib/module/ui-format/common.js.map +1 -1
  43. package/lib/module/ui-format/groupChannel.js +5 -4
  44. package/lib/module/ui-format/groupChannel.js.map +1 -1
  45. package/lib/typescript/src/hooks/index.d.ts +3 -2
  46. package/lib/typescript/src/index.d.ts +4 -2
  47. package/lib/typescript/src/sendbird/channel.d.ts +6 -1
  48. package/lib/typescript/src/sendbird/message.d.ts +4 -2
  49. package/lib/typescript/src/sendbird/user.d.ts +7 -0
  50. package/lib/typescript/src/shared/bufferedRequest.d.ts +6 -4
  51. package/lib/typescript/src/shared/logger.d.ts +1 -1
  52. package/lib/typescript/src/shared/pubsub.d.ts +2 -2
  53. package/lib/typescript/src/shared/regex.d.ts +8 -0
  54. package/lib/typescript/src/shared/replace.d.ts +2 -0
  55. package/lib/typescript/src/types.d.ts +42 -35
  56. package/lib/typescript/src/ui-format/common.d.ts +7 -6
  57. package/package.json +3 -3
  58. package/src/hooks/index.ts +11 -0
  59. package/src/index.ts +14 -2
  60. package/src/sendbird/channel.ts +11 -4
  61. package/src/sendbird/message.ts +13 -3
  62. package/src/sendbird/user.ts +21 -0
  63. package/src/shared/bufferedRequest.ts +37 -12
  64. package/src/shared/regex.ts +35 -0
  65. package/src/shared/replace.ts +5 -0
  66. package/src/types.ts +21 -3
  67. package/src/ui-format/common.ts +9 -7
  68. package/src/ui-format/groupChannel.ts +5 -4
@@ -56,6 +56,17 @@ export const useIsMountedRef = () => {
56
56
  return isMounted;
57
57
  };
58
58
 
59
+ export const useIsFirstMount = () => {
60
+ const isFirstMount = useRef(true);
61
+
62
+ if (isFirstMount.current) {
63
+ isFirstMount.current = false;
64
+ return true;
65
+ }
66
+
67
+ return isFirstMount.current;
68
+ };
69
+
59
70
  export const useFreshCallback = <T extends (...args: any[]) => any>(callback: T): T => {
60
71
  const ref = useRef<T>(callback);
61
72
  ref.current = callback;
package/src/index.ts CHANGED
@@ -15,8 +15,11 @@ export {
15
15
  normalizeFileName,
16
16
  emailRegex,
17
17
  phoneRegex,
18
+ replaceWithRegex,
19
+ createMentionTemplateRegex,
18
20
  } from './shared/regex';
19
21
  export { BufferedRequest } from './shared/bufferedRequest';
22
+ export { default as replace } from './shared/replace';
20
23
 
21
24
  export * from './hooks';
22
25
  export * from './ui-format/groupChannel';
@@ -24,6 +27,7 @@ export * from './ui-format/common';
24
27
  export * from './sendbird/channel';
25
28
  export * from './sendbird/message';
26
29
  export * from './sendbird/attrs';
30
+ export * from './sendbird/user';
27
31
 
28
32
  export const NOOP: () => void = () => void 0;
29
33
  export const ASYNC_NOOP = async () => void 0;
@@ -35,11 +39,14 @@ export const SBErrorCode = {
35
39
  };
36
40
  export const SBErrorMessage = {
37
41
  ACL:
38
- "An error occurred because you don't have access to the user list in your application.\n" +
39
- 'In order to gain access, you can turn on this attribute in the Access Control List settings on Sendbird Dashboard.',
42
+ 'Sendbird provides various access control options when using the Chat SDK.\n' +
43
+ 'By default, the Allow retrieving user list attribute is turned on to facilitate creating sample apps.\n' +
44
+ 'However, this may grant access to unwanted data or operations, leading to potential security concerns.\n' +
45
+ 'To manage your access control settings, you can turn on or off each setting on Sendbird Dashboard.',
40
46
  };
41
47
 
42
48
  export type {
49
+ UserStruct,
43
50
  FilterByValueType,
44
51
  UnionToIntersection,
45
52
  OmittedValues,
@@ -76,4 +83,9 @@ export type {
76
83
  SendbirdUserMessageUpdateParams,
77
84
  SendbirdFileMessageUpdateParams,
78
85
  SendbirdUserUpdateParams,
86
+ SendbirdRestrictedUser,
87
+ SendbirdReaction,
88
+ SendbirdEmojiContainer,
89
+ SendbirdEmoji,
90
+ SendbirdEmojiCategory,
79
91
  } from './types';
@@ -12,20 +12,23 @@ export function isDifferentChannel<T extends SendbirdBaseChannel>(a?: T, b?: T):
12
12
  return a.url !== b.url;
13
13
  }
14
14
 
15
- export const isGroupChannelChatUnavailable = (channel: SendbirdGroupChannel) => {
16
- return channel.myMutedState === 'muted' || (channel.isFrozen && channel.myRole !== 'operator');
15
+ export const getGroupChannelChatAvailableState = (channel: SendbirdGroupChannel) => {
16
+ const frozen = channel.isFrozen && channel.myRole !== 'operator';
17
+ const muted = channel.myMutedState === 'muted';
18
+ const disabled = frozen || muted;
19
+ return { disabled, frozen, muted };
17
20
  };
18
21
 
19
22
  export const confirmAndMarkAsRead = async (channels: SendbirdBaseChannel[]) => {
20
23
  channels
21
24
  .filter((it): it is SendbirdGroupChannel => it.isGroupChannel() && it.unreadMessageCount > 0)
22
- .forEach((it) => BufferedRequest.markAsRead.push(() => it.markAsRead()));
25
+ .forEach((it) => BufferedRequest.markAsRead.push(() => it.markAsRead(), it.url));
23
26
  };
24
27
 
25
28
  export const confirmAndMarkAsDelivered = async (channels: SendbirdBaseChannel[]) => {
26
29
  channels
27
30
  .filter((it): it is SendbirdGroupChannel => it.isGroupChannel() && it.unreadMessageCount > 0)
28
- .forEach((it) => BufferedRequest.markAsDelivered.push(() => it.markAsDelivered()));
31
+ .forEach((it) => BufferedRequest.markAsDelivered.push(() => it.markAsDelivered(), it.url));
29
32
  };
30
33
 
31
34
  export function isDefaultCoverImage(coverUrl: string) {
@@ -43,3 +46,7 @@ export function getGroupChannels(channels: SendbirdChannel[]): SendbirdGroupChan
43
46
  export function getOpenChannels(channels: SendbirdChannel[]): SendbirdOpenChannel[] {
44
47
  return channels.filter((c): c is SendbirdOpenChannel => c.isOpenChannel());
45
48
  }
49
+
50
+ export function getChannelUniqId(channel: SendbirdChannel) {
51
+ return channel.url;
52
+ }
@@ -1,11 +1,13 @@
1
1
  import type {
2
+ SendbirdBaseChannel,
2
3
  SendbirdBaseMessage,
3
4
  SendbirdDataPayload,
4
5
  SendbirdFileMessage,
5
6
  SendbirdMessage,
7
+ SendbirdReaction,
6
8
  SendbirdSendableMessage,
7
9
  } from '../types';
8
- import { messageTime } from '../ui-format/common';
10
+ import { getMessageTimeFormat } from '../ui-format/common';
9
11
 
10
12
  export function isNewMessage(msg: SendbirdMessage, currentUserId?: string) {
11
13
  const myMessage = isMyMessage(msg, currentUserId);
@@ -67,7 +69,7 @@ export function calcMessageGrouping(
67
69
  if (!prev) return false;
68
70
  if (curr.isAdminMessage()) return false;
69
71
  if (!hasSameSender(curr, prev)) return false;
70
- if (messageTime(new Date(curr.createdAt)) !== messageTime(new Date(prev.createdAt))) return false;
72
+ if (getMessageTimeFormat(new Date(curr.createdAt)) !== getMessageTimeFormat(new Date(prev.createdAt))) return false;
71
73
  return true;
72
74
  };
73
75
 
@@ -76,7 +78,7 @@ export function calcMessageGrouping(
76
78
  if (!next) return false;
77
79
  if (curr.isAdminMessage()) return false;
78
80
  if (!hasSameSender(curr, next)) return false;
79
- if (messageTime(new Date(curr.createdAt)) !== messageTime(new Date(next.createdAt))) return false;
81
+ if (getMessageTimeFormat(new Date(curr.createdAt)) !== getMessageTimeFormat(new Date(next.createdAt))) return false;
80
82
  return true;
81
83
  };
82
84
 
@@ -110,3 +112,11 @@ export function isSendbirdNotification(dataPayload?: {
110
112
  export function parseSendbirdNotification(dataPayload: RawSendbirdDataPayload): SendbirdDataPayload {
111
113
  return typeof dataPayload.sendbird === 'string' ? JSON.parse(dataPayload.sendbird) : dataPayload.sendbird;
112
114
  }
115
+
116
+ export function shouldRenderReaction(channel: SendbirdBaseChannel, reactionEnabled: boolean) {
117
+ return channel.isGroupChannel() && !channel.isBroadcast && !channel.isSuper && reactionEnabled;
118
+ }
119
+
120
+ export function getReactionCount(reaction: SendbirdReaction) {
121
+ return reaction.userIds.length;
122
+ }
@@ -0,0 +1,21 @@
1
+ import type { Role } from '@sendbird/chat';
2
+
3
+ import type { UserStruct } from '../types';
4
+
5
+ export function ifOperator<T>(role: Role, then: T): T | undefined;
6
+ export function ifOperator<T, V>(role: Role, then: T, or: V): T | V;
7
+ export function ifOperator(role: Role, then: unknown, or?: unknown) {
8
+ if (role === 'operator') return then;
9
+ return or;
10
+ }
11
+
12
+ export function ifMuted<T>(muted: boolean, then: T): T | undefined;
13
+ export function ifMuted<T, V>(muted: boolean, then: T, or: V): T | V;
14
+ export function ifMuted(muted: boolean, then: unknown, or?: unknown) {
15
+ if (muted) return then;
16
+ return or;
17
+ }
18
+
19
+ export function getUserUniqId<T extends UserStruct>(user: T) {
20
+ return user.userId;
21
+ }
@@ -5,10 +5,21 @@ let REQ_PER_TIMEOUT = 5;
5
5
  let TIMEOUT_MILLS = 1000;
6
6
  const SAFE_TIMEOUT_BUFFER = 100;
7
7
 
8
+ function generateRandomId() {
9
+ return Math.random().toString(16).slice(2);
10
+ }
11
+
8
12
  export class BufferedRequest {
9
13
  public static markAsRead = BufferedRequest.create();
10
14
  public static markAsDelivered = BufferedRequest.create();
11
15
 
16
+ public static updateMarkAsReadOptions(reqPerTimeout: number, timeoutMills: number) {
17
+ BufferedRequest.markAsRead = BufferedRequest.create(reqPerTimeout, timeoutMills);
18
+ }
19
+ public static updateMarkAsDeliveredOptions(reqPerTimeout: number, timeoutMills: number) {
20
+ BufferedRequest.markAsDelivered = BufferedRequest.create(reqPerTimeout, timeoutMills);
21
+ }
22
+
12
23
  public static get reqPerTimeout() {
13
24
  return REQ_PER_TIMEOUT;
14
25
  }
@@ -28,28 +39,33 @@ export class BufferedRequest {
28
39
  }
29
40
 
30
41
  public static create(reqPerTimeout = REQ_PER_TIMEOUT, timeoutMills = TIMEOUT_MILLS) {
31
- const waitQueue: Func[] = [];
32
- const nextQueue: Func[] = [];
42
+ const waitQueue = new Map<string, Func>();
43
+ const nextQueue = new Map<string, Func>();
33
44
 
34
45
  let state: State = 'idle';
35
46
  let timeout: NodeJS.Timeout | undefined;
36
47
 
37
48
  return {
38
- push(func: Func) {
39
- waitQueue.push(func);
49
+ push(func: Func, lane?: string) {
50
+ waitQueue.set(lane ?? generateRandomId(), func);
40
51
  this.invoke();
41
52
  },
42
53
  shift() {
43
- if (nextQueue.length < reqPerTimeout) {
44
- const nextRemains = Math.min(reqPerTimeout - nextQueue.length, waitQueue.length);
54
+ if (nextQueue.size < reqPerTimeout) {
55
+ const nextRemains = Math.min(reqPerTimeout - nextQueue.size, waitQueue.size);
56
+ const lanes = [...waitQueue.keys()];
45
57
  for (let n = 0; n < nextRemains; n++) {
46
- const func = waitQueue.shift();
47
- if (func) nextQueue.push(func);
58
+ const lane = lanes[n];
59
+ const func = waitQueue.get(lane);
60
+ if (func) {
61
+ waitQueue.delete(lane);
62
+ nextQueue.set(lane, func);
63
+ }
48
64
  }
49
65
  }
50
66
  },
51
67
  handleIdle() {
52
- if (0 < nextQueue.length) {
68
+ if (0 < nextQueue.size) {
53
69
  state = 'processing';
54
70
  this.invoke();
55
71
  }
@@ -59,15 +75,24 @@ export class BufferedRequest {
59
75
 
60
76
  timeout = setTimeout(() => {
61
77
  timeout = undefined;
62
- if (0 < nextQueue.length || 0 < waitQueue.length) {
78
+ if (0 < nextQueue.size || 0 < waitQueue.size) {
63
79
  this.invoke();
64
80
  } else {
65
81
  state = 'idle';
66
82
  }
67
83
  }, timeoutMills + SAFE_TIMEOUT_BUFFER);
68
84
 
69
- nextQueue.forEach((func) => func());
70
- nextQueue.length = 0;
85
+ let index = 0;
86
+ const nextRequestBaseTimeout = timeoutMills / nextQueue.size;
87
+ nextQueue.forEach((func) => {
88
+ setTimeout(() => {
89
+ func();
90
+ // TODO: Add retry
91
+ //.catch(() => waitQueue.set(lane, func));
92
+ }, nextRequestBaseTimeout * index);
93
+ index++;
94
+ });
95
+ nextQueue.clear();
71
96
  },
72
97
  async invoke() {
73
98
  this.shift();
@@ -9,6 +9,8 @@ export const phoneRegex = /[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,7}/
9
9
  export const emailRegex = /\S+@\S+\.\S+/;
10
10
  export const newLineRegex = /\r\n|\r|\n/g;
11
11
 
12
+ export const createMentionTemplateRegex = (trigger: string) => new RegExp(`(${trigger}[{])(.*?)([}])`, 'g');
13
+
12
14
  // const cases = [
13
15
  // {
14
16
  // type: 'urlStrict',
@@ -28,6 +30,39 @@ export const newLineRegex = /\r\n|\r|\n/g;
28
30
  // },
29
31
  // ];
30
32
 
33
+ export const replaceWithRegex = <T>(
34
+ text: string,
35
+ regex: RegExp,
36
+ replacer: (params: {
37
+ match: string;
38
+ groups: string[];
39
+ matchIndex: number | undefined;
40
+ index: number;
41
+ keyPrefix: string;
42
+ }) => T,
43
+ keyPrefix: string,
44
+ ) => {
45
+ const matches = [...text.matchAll(regex)];
46
+ const founds = matches.map((value) => {
47
+ const text = value[0];
48
+ const start = value.index ?? 0;
49
+ const end = start + text.length;
50
+ return { text, start, end, groups: value, matchIndex: value.index };
51
+ });
52
+
53
+ const items: Array<T | string> = [text];
54
+ let cursor = 0;
55
+ founds.forEach(({ text, start, end, groups, matchIndex }, index) => {
56
+ const restText = items.pop() as string;
57
+ const head = restText.slice(0, start - cursor);
58
+ const mid = replacer({ match: text, groups, matchIndex, index, keyPrefix });
59
+ const tail = restText.slice(end - cursor);
60
+ items.push(head, mid, tail);
61
+ cursor = end;
62
+ });
63
+ return items;
64
+ };
65
+
31
66
  export const replaceUrlAsComponents = <T>(originText: string, replacer: (url: string) => T, strict?: boolean) => {
32
67
  const matches = [...originText.matchAll(strict ? urlRegexStrict : urlRegexRough)];
33
68
  const founds = matches.map((value) => {
@@ -0,0 +1,5 @@
1
+ const replace = (original: string, start: number, end: number, str: string) => {
2
+ return original.slice(0, start) + str + original.slice(end);
3
+ };
4
+
5
+ export default replace;
package/src/types.ts CHANGED
@@ -4,7 +4,16 @@
4
4
  import type React from 'react';
5
5
 
6
6
  import type SendbirdChat from '@sendbird/chat';
7
- import type { BaseChannel, SendbirdError as SBError, User, UserUpdateParams } from '@sendbird/chat';
7
+ import type {
8
+ BaseChannel,
9
+ Emoji,
10
+ EmojiCategory,
11
+ EmojiContainer,
12
+ RestrictedUser,
13
+ SendbirdError as SBError,
14
+ User,
15
+ UserUpdateParams,
16
+ } from '@sendbird/chat';
8
17
  import type {
9
18
  GroupChannel,
10
19
  GroupChannelCollection,
@@ -23,14 +32,13 @@ import type {
23
32
  FileMessageCreateParams,
24
33
  FileMessageUpdateParams,
25
34
  PreviousMessageListQuery,
35
+ Reaction,
26
36
  UserMessage,
27
37
  UserMessageCreateParams,
28
38
  UserMessageUpdateParams,
29
39
  } from '@sendbird/chat/message';
30
40
  import type { OpenChannel, OpenChannelModule } from '@sendbird/chat/openChannel';
31
41
 
32
- import './';
33
-
34
42
  export type FilterByValueType<T extends object, Type> = {
35
43
  [K in keyof T as T[K] extends Type ? K : never]: T[K];
36
44
  };
@@ -57,6 +65,10 @@ export type Optional<T> = T | undefined;
57
65
 
58
66
  export type ContextValue<T extends React.Context<any>> = T extends React.Context<infer V> ? V : never;
59
67
 
68
+ export interface UserStruct {
69
+ userId: string;
70
+ }
71
+
60
72
  export type SendbirdChatSDK = SendbirdChat & ModuleNamespaces<[GroupChannelModule, OpenChannelModule]>;
61
73
  export type SendbirdMessage = BaseMessage | FileMessage | UserMessage | AdminMessage | SendableMessage;
62
74
  export type SendbirdChannel = BaseChannel | GroupChannel | OpenChannel;
@@ -73,11 +85,17 @@ export type SendbirdGroupChannelCreateParams = GroupChannelCreateParams;
73
85
  export type SendbirdGroupChannelUpdateParams = GroupChannelUpdateParams;
74
86
  export type SendbirdUserUpdateParams = UserUpdateParams;
75
87
  export type SendbirdUser = User;
88
+ export type SendbirdRestrictedUser = RestrictedUser;
76
89
  export type SendbirdMember = Member;
77
90
  export type SendbirdGroupChannel = GroupChannel;
78
91
  export type SendbirdBaseChannel = BaseChannel;
79
92
  export type SendbirdOpenChannel = OpenChannel;
80
93
 
94
+ export type SendbirdReaction = Reaction;
95
+ export type SendbirdEmoji = Emoji;
96
+ export type SendbirdEmojiCategory = EmojiCategory;
97
+ export type SendbirdEmojiContainer = EmojiContainer;
98
+
81
99
  export type SendbirdGroupChannelCollection = GroupChannelCollection;
82
100
  export type SendbirdGroupChannelListQuery = GroupChannelListQuery;
83
101
  export type SendbirdMessageCollection = MessageCollection;
@@ -1,5 +1,5 @@
1
1
  import type { Locale } from 'date-fns';
2
- import format from 'date-fns/format';
2
+ import { format, isThisYear } from 'date-fns';
3
3
 
4
4
  type TruncateMode = 'head' | 'mid' | 'tail';
5
5
  type TruncateOption = { mode: TruncateMode; maxLen: number; separator: string };
@@ -38,15 +38,16 @@ export const truncate = (str: string, opts: Partial<TruncateOption> = defaultOpt
38
38
  };
39
39
 
40
40
  /**
41
- * Badge count truncate util
41
+ * Count truncate util
42
42
  * If count exceed the limit, it comes in the form of "MAX+"
43
43
  *
44
44
  * @param {number} count
45
45
  * @param {number} MAX default 99
46
+ * @param {string} MAX_SUFFIX default +
46
47
  * @returns {string}
47
48
  * */
48
- export const truncatedBadgeCount = (count: number, MAX = 99) => {
49
- if (count >= MAX) return `${MAX}+`;
49
+ export const truncatedCount = (count: number, MAX = 99, MAX_SUFFIX = '+') => {
50
+ if (count >= MAX) return `${MAX}${MAX_SUFFIX}`;
50
51
  return `${count}`;
51
52
  };
52
53
 
@@ -57,8 +58,9 @@ export const truncatedBadgeCount = (count: number, MAX = 99) => {
57
58
  * @param {Locale} [locale]
58
59
  * @returns {string}
59
60
  * */
60
- export const dateSeparator = (date: Date, locale?: Locale): string => {
61
- return format(date, 'E, LLL dd', { locale });
61
+ export const getDateSeparatorFormat = (date: Date, locale?: Locale): string => {
62
+ if (isThisYear(date)) return format(date, 'MMM dd, yyyy', { locale });
63
+ return format(date, 'E, MMM dd', { locale });
62
64
  };
63
65
 
64
66
  /**
@@ -68,6 +70,6 @@ export const dateSeparator = (date: Date, locale?: Locale): string => {
68
70
  * @param {Locale} [locale]
69
71
  * @returns {string}
70
72
  * */
71
- export const messageTime = (date: Date, locale?: Locale): string => {
73
+ export const getMessageTimeFormat = (date: Date, locale?: Locale): string => {
72
74
  return format(date, 'p', { locale });
73
75
  };
@@ -1,7 +1,5 @@
1
1
  import type { Locale } from 'date-fns';
2
- import format from 'date-fns/format';
3
- import isToday from 'date-fns/isToday';
4
- import isYesterday from 'date-fns/isYesterday';
2
+ import { format, isThisYear, isToday, isYesterday } from 'date-fns';
5
3
 
6
4
  import type { SendbirdGroupChannel } from '../types';
7
5
  import { truncate } from './common';
@@ -23,9 +21,12 @@ export const getGroupChannelTitle = (
23
21
 
24
22
  export const getGroupChannelPreviewTime = (channel: SendbirdGroupChannel, locale?: Locale) => {
25
23
  const timestamp = channel.lastMessage?.createdAt || channel.joinedAt * 1000 || channel.createdAt;
24
+
26
25
  if (isToday(timestamp)) return format(timestamp, 'p', { locale });
27
26
  if (isYesterday(timestamp)) return 'Yesterday';
28
- return format(timestamp, 'MMM dd', { locale });
27
+ if (isThisYear(timestamp)) return format(timestamp, 'MMM dd', { locale });
28
+
29
+ return format(timestamp, 'yyyy/MM/dd', { locale });
29
30
  };
30
31
 
31
32
  export const getGroupChannelLastMessage = (channel: SendbirdGroupChannel, EMPTY_MESSAGE = '', MAX_LEN = 15) => {