Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/utils/__tests__/cloneMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { cloneMessage } from '../cloneMessage';

describe('cloneMessage', () => {
it('Should return a clone message', () => {
const oldMessage = {
isAdminMessage: true,
isUserMessage: true,
isFileMessage: true,
isMultipleFilesMessage: true,
applyParentMessage: true,
applyReactionEvent: true,
applyThreadInfoUpdateEvent: true,
extraProps: {
field1: true,
field2: 'test',
field3: 42,
},
};

const newMessage = cloneMessage(oldMessage);

expect(newMessage).toEqual(oldMessage);
});
});
29 changes: 29 additions & 0 deletions src/utils/__tests__/color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { changeColorToClassName, Colors } from '../color';
import { truncateString } from '../index';

describe('color', () => {
it('check all color enum exist', () => {
expect(Colors.ONBACKGROUND_1).not.toBe(undefined);
expect(Colors.ONBACKGROUND_2).not.toBe(undefined);
expect(Colors.ONBACKGROUND_3).not.toBe(undefined);
expect(Colors.ONBACKGROUND_4).not.toBe(undefined);
expect(Colors.ONCONTENT_1).not.toBe(undefined);
expect(Colors.PRIMARY).not.toBe(undefined);
expect(Colors.ERROR).not.toBe(undefined);
});

it('change color enum to proper className', () => {
for (const color of Object.values(Colors)) {
expect(changeColorToClassName(color)).toBe(`sendbird-color--${color.toLowerCase().replace('_', '-')}`);
}

const nonColor = 'not-existing-color-enum-value';
expect(changeColorToClassName(nonColor)).toBe('');
});
});

describe('truncateString', () => {
it('truncate string properly by the given parameter', () => {
expect(truncateString('this is full string', 10)).toBe('this...ing');
});
});
48 changes: 48 additions & 0 deletions src/utils/__tests__/useDidMountEffect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { render, waitFor, screen } from '@testing-library/react';
import useDidMountEffect from '../useDidMountEffect';
import React, { useState } from 'react';

describe('useDidMountEffect', () => {
beforeEach(() => {
jest.restoreAllMocks();
});

it('ignore callback if didMount was false', () => {
const mockCallback = jest.fn();

const TestComponent = () => {
const [counter, setCounter] = useState(0);
useDidMountEffect(mockCallback, [counter]);
return (<button onClick={() => setCounter(counter + 1)}>increment</button>);
};

render(<TestComponent />);

expect(mockCallback).not.toHaveBeenCalled();
});

it('call callback if didMount was true', async () => {
const mockCallback = jest.fn();

const TestComponent = () => {
const [counter, setCounter] = useState(0);
useDidMountEffect(mockCallback, [counter]);
return (<button onClick={() => setCounter(counter + 1)}>increment</button>);
};

render(<TestComponent />);
const button = screen.getByText('increment');

await waitFor(() => {
button.click();
});

await waitFor(() => {
button.click();
});

await waitFor(() => {
expect(mockCallback).toHaveBeenCalledTimes(2);
});
});
});
40 changes: 36 additions & 4 deletions src/utils/__tests__/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
isFileMessage,
isUrl,
isUserMessage,
isMultipleFilesMessage, isDefaultChannelName, DEFAULT_GROUP_CHANNEL_NAME, DEFAULT_AI_CHATBOT_CHANNEL_NAME,
isMultipleFilesMessage, isDefaultChannelName, DEFAULT_GROUP_CHANNEL_NAME, DEFAULT_AI_CHATBOT_CHANNEL_NAME, arrayEqual,
} from '../index';
import { AdminMessage, FileMessage, MultipleFilesMessage, UserMessage } from '@sendbird/chat/message';
import { delay, deleteNullish } from '../utils';
Expand Down Expand Up @@ -237,6 +237,8 @@ describe('deleteNullish', () => {
});

describe('delay', () => {
const errorBound = 5;

it('should resolve after the specified time', async () => {
const start = Date.now();
const delayTime = 100;
Expand All @@ -247,7 +249,7 @@ describe('delay', () => {
const elapsed = end - start;

// Check if the elapsed time is at least the delay time
expect(elapsed).toBeGreaterThanOrEqual(delayTime);
expect(elapsed).toBeGreaterThanOrEqual(delayTime - errorBound);
});

it('should resolve immediately for 0 milliseconds', async () => {
Expand All @@ -259,7 +261,7 @@ describe('delay', () => {
const elapsed = end - start;

// Check if the elapsed time is very small
expect(elapsed).toBeLessThan(10);
expect(elapsed).toBeLessThan(errorBound);
});
it('should resolve immediately when no parameter is provided', async () => {
const start = Date.now();
Expand All @@ -269,7 +271,7 @@ describe('delay', () => {
const end = Date.now();
const elapsed = end - start;

expect(elapsed).toBeLessThan(10);
expect(elapsed).toBeLessThan(errorBound);
});
});

Expand Down Expand Up @@ -320,3 +322,33 @@ describe('isDefaultChannelName', () => {
expect(result).toBe(false);
});
});

describe('arrayEqual', () => {
it('return true if two arrays are equal', () => {
const arr1 = ['elem', 2, true];
const arr2 = ['elem', 2, true];

expect(arrayEqual(arr1, arr2)).toBe(true);
});

it('return false if two arrays are not equal', () => {
const arr1 = ['elem', 2, true];
const arr2 = ['elem', 42, false];

expect(arrayEqual(arr1, arr2)).toBe(false);
});

it('return false if two array doesn\'t have same length', () => {
const arr1 = ['elem', 2, true];
const arr2 = ['elem', 42];

expect(arrayEqual(arr1, arr2)).toBe(false);
});

it('return false if the one of parameter is not array', () => {
const arr1 = ['elem', 2, true];
const arr2 = {};

expect(arrayEqual(arr1, arr2)).toBe(false);
});
});
1 change: 0 additions & 1 deletion src/utils/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export enum Colors {
ONBACKGROUND_3 = 'ONBACKGROUND_3',
ONBACKGROUND_4 = 'ONBACKGROUND_4',
ONCONTENT_1 = 'ONCONTENT_1',
ONCONTENT_2 = 'ONCONTENT_2',
PRIMARY = 'PRIMARY',
ERROR = 'ERROR',
}
Expand Down
70 changes: 2 additions & 68 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import SendbirdChat, { Emoji, EmojiCategory, EmojiContainer, User } from '@sendbird/chat';
import { GroupChannel, Member, SendbirdGroupChat, GroupChannelListQuery, GroupChannelListOrder } from '@sendbird/chat/groupChannel';
import { Emoji, EmojiCategory, EmojiContainer, User } from '@sendbird/chat';
import { GroupChannel, Member, GroupChannelListQuery, GroupChannelListOrder } from '@sendbird/chat/groupChannel';
import {
AdminMessage,
BaseMessage,
Expand All @@ -10,7 +10,6 @@ import {
UploadedFileInfo,
UserMessage,
} from '@sendbird/chat/message';
import { OpenChannel, SendbirdOpenChat } from '@sendbird/chat/openChannel';
import { SendableMessage } from '@sendbird/chat/lib/__definition';

import { getOutgoingMessageState, OutgoingMessageStates } from './exports/getOutgoingMessageState';
Expand Down Expand Up @@ -217,13 +216,6 @@ const SendingMessageStatus: SendingMessageStatus = {
export type CoreMessageType = AdminMessage | UserMessage | FileMessage | MultipleFilesMessage;
export type SendableMessageType = UserMessage | FileMessage | MultipleFilesMessage;

export const isTextuallyNull = (text: string): boolean => {
if (text === '' || text === null) {
return true;
}
return false;
};

export const isMOVType = (type: string): boolean => type === 'video/quicktime';
/**
* @link: https://sendbird.atlassian.net/browse/SBISSUE-16031?focusedCommentId=270601
Expand Down Expand Up @@ -452,15 +444,6 @@ export const getClassName = (classNames: string | Array<string | Array<string>>)
: classNames
);

export const startsWithAtAndEndsWithBraces = (str: string) => {
const regex = /^\{@.*\}$/;
return regex.test(str);
};

export const removeAtAndBraces = (str: string) => {
return str.replace(/^\{@|}$/g, '');
};

export const isReactedBy = (userId: string, reaction: Reaction): boolean => (
reaction.userIds.some((reactorUserId: string): boolean => reactorUserId === userId)
);
Expand All @@ -480,33 +463,6 @@ export const getEmojiTooltipString = (reaction: Reaction, userId: string, member
.join(', ')}${you}`);
};

// TODO: Use the interface after language tranlsatation of Sendbird.js
interface UIKitStore {
stores: {
sdkStore: {
sdk: SendbirdChat | SendbirdOpenChat | SendbirdGroupChat,
},
userStore: {
user: User,
},
},
config: {
isReactionEnabled: boolean,
htmlTextDirection: HTMLTextDirection,
forceLeftToRightMessageLayout: boolean,
}
}
export const getCurrentUserId = (store: UIKitStore): string => (store?.stores?.userStore?.user?.userId);
export const getUseReaction = (store: UIKitStore, channel: GroupChannel | OpenChannel): boolean => {
if (!store?.config?.isReactionEnabled)
return false;
if (!store?.stores?.sdkStore?.sdk?.appInfo?.useReaction)
return false;
if (channel?.isGroupChannel())
return !((channel as GroupChannel).isBroadcast || (channel as GroupChannel).isSuper);
return store?.config?.isReactionEnabled;
};

export function getSuggestedReplies(message?: BaseMessage): string[] {
if (message?.extendedMessagePayload && Array.isArray(message?.extendedMessagePayload?.suggested_replies)) {
return message.extendedMessagePayload.suggested_replies;
Expand All @@ -515,22 +471,12 @@ export function getSuggestedReplies(message?: BaseMessage): string[] {
}
}

export const isMessageSentByMe = (
userId: string,
message: SendableMessageType,
): boolean => (
!!(userId && message?.sender?.userId && userId === message.sender.userId)
);

const URL_REG = /^((http|https):\/\/)?([a-z\d-]+\.)+[a-z]{2,}(\:[0-9]{1,5})?(\/[-a-zA-Z\d%_.~+&=]*)*(\?[;&a-zA-Z\d%_.~+=-]*)?(#\S*)?$/;
/** @deprecated
* URL detection in a message text will be handled in utils/tokens/tokenize.ts
*/
export const isUrl = (text: string): boolean => URL_REG.test(text);

const MENTION_TAG_REG = /\@\{.*?\}/i;
export const isMentionedText = (text: string): boolean => MENTION_TAG_REG.test(text);

export const truncateString = (fullStr: string, strLen?: number): string => {
if (!strLen) strLen = 40;
if (fullStr === null || fullStr === undefined) return '';
Expand Down Expand Up @@ -897,18 +843,6 @@ export const getChannelsWithUpsertedChannel = (
return sortChannelList(channels, order ?? GroupChannelListOrder.LATEST_LAST_MESSAGE);
};

export const getMatchedUserIds = (word: string, users: Array<User>, _template?: string): boolean => {
const template = _template || '@'; // Use global variable
// const matchedUserIds = [];
// users.map((user) => user?.userId).forEach((userId) => {
// if (word.indexOf(`${template}{${userId}}`) > -1) {
// matchedUserIds.push(userId);
// }
// });
// return matchedUserIds;
return users.map((user) => user?.userId).some((userId) => word.indexOf(`${template}{${userId}}`) > -1);
};

export enum StringObjType {
normal = 'normal',
mention = 'mention',
Expand Down
4 changes: 2 additions & 2 deletions src/utils/useDidMountEffect.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useEffect, useState } from 'react';

const useDidMountEffect = (func: () => void, deps: Array<unknown>): void => {
const [didMount, setDidmount] = useState(false);
const [didMount, setDidMount] = useState(false);
useEffect(() => {
if (didMount) {
func();
} else {
setDidmount(true);
setDidMount(true);
}
}, deps);
};
Expand Down