Skip to content

Commit 2edd1f9

Browse files
authored
1 parent 022ef4b commit 2edd1f9

File tree

7 files changed

+226
-18
lines changed

7 files changed

+226
-18
lines changed

CHANGELOG.md

+150
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,155 @@
11
# Changelog - v3
22

3+
## [v3.4.0] (Mar 6 2023)
4+
5+
### Voice Message
6+
Voice message is a new type of message and feature that you can use in group channel. You can record your voice on the message input and send it to the channel. Also the messages will be displayed as a new design of the voice message. You are able to use this feature from this version.
7+
8+
#### How to turn on/off
9+
* You can turn this feature on/off using the props `isVoiceMessageEnabled` on the <App /> and <SendbirdProvider /> components. Here is an example.
10+
```javascript
11+
import App from '@sendbird/uikit-react/App'
12+
import SendbirdProvider from '@sendbird/uikit-react/SendbirdProvider'
13+
import { useEffect } from 'react'
14+
15+
const QuickStart = () => (<App isVoiceMessageEnabled />)
16+
const CustomApp = () => {
17+
const [useVoiceMessage, setUseVoiceMessage] = useEffect(true)
18+
return (
19+
<SendbirdProvider
20+
isVoiceMessageEnabled={useVoiceMessage}
21+
>
22+
{/* Implement your custom app here */}
23+
</SendbirdProvider>
24+
)
25+
}
26+
```
27+
28+
#### How to customize the voice message in Channel and Thread?
29+
You can identify the voice message to check if `message.type` includes `sbu_type=voice`. But you can use `isVoiceMessage` util function to do that.
30+
```javascript
31+
import Channel from '@sendbird/uikit-react/Channel'
32+
import isVoiceMessage from '@sendbird/uikit-react/utils/message/isVoiceMessage'
33+
34+
const CustomChannel = () => {
35+
return (
36+
<Channel
37+
renderMessage={({ message }) => {
38+
if (isVoiceMessage(message)) {
39+
// Return your custom voice message item component
40+
}
41+
return null
42+
}}
43+
/>
44+
)
45+
}
46+
```
47+
48+
#### Limitation & Next step
49+
* For now, it's not able to customize the inner components of VoiceMessageInput. We are going to provide an interface to customize it in the future. Until that time, you can replace the VoiceMessageInput component using the `renderVoiceMessageIcon` props of MessageInput component.
50+
51+
#### What has been changed?
52+
* Add props `isVoiceMessageEnabled` and `voiceRecord` props to the App, `SendbirdProvider`, and `MessageInput` components, to turn on/off the voice message recording feature
53+
```javascript
54+
import SendbirdProvider from '@sendbird/uikit-react/SendbirdProvider'
55+
const CustomApp = () => {
56+
return (
57+
<SendbirdProvider
58+
isVoiceMessageEnabled
59+
voiceRecord={{
60+
maxRecordingTime: 60000,
61+
minRecordingTime: 1000,
62+
}}
63+
>
64+
{/* implement custom application */}
65+
</SendbirdProvider>
66+
)
67+
}
68+
```
69+
* Add props `onVoiceMessageIconClick` to the `MessageInput` component
70+
* Add props `onBeforeSendVoiceMessage` to the `Channel` component
71+
* Fetch message list including `MetaArray` in the `Channel` and `Thread` modules
72+
* Provide new IconType `AudioOnLined` & new IconColor `Primary2` and `OnBackground4`
73+
* Provide new string sets
74+
```javascript
75+
import SendbirdProvider from '@sendbird/uikit-react/SendbirdProvider'
76+
const CustomApp = () => {
77+
return (
78+
<SendbirdProvider
79+
stringSet={{
80+
BUTTON__OK: 'OK',
81+
VOICE_MESSAGE: 'Voice Message',
82+
MODAL__VOICE_MESSAGE_INPUT_DISABLED__TITLE_MUTED: 'You\'re muted by the operator.',
83+
MODAL__VOICE_MESSAGE_INPUT_DISABLED__TITLE_FROZEN: 'Channel is frozen.',
84+
}}
85+
>
86+
{/* implement custom application */}
87+
</SendbirdProvider>
88+
)
89+
}
90+
```
91+
* `BUTTON__OK`: 'OK' → Used on the submit button of pop up modal
92+
* `MODAL__VOICE_MESSAGE_INPUT_DISABLED__TITLE_MUTED`: 'You\'re muted by the operator.' → Used in an alert pop-up modal
93+
* `MODAL__VOICE_MESSAGE_INPUT_DISABLED__TITLE_FROZEN`: 'Channel is frozen.' → Used in an alert pop-up modal
94+
* `VOICE_MESSAGE`: 'Voice Message' → Used in ChannelPreviewItem, QuoteMessage, and MessageSearch to appear that the message type is the voice## External Contributions
95+
96+
#### What has been added?
97+
* Install `lamejs` to convert the audio file to mp3 (iOS support)
98+
* UI components
99+
```javascript
100+
import PlaybackTime from "@sendbird/uikit-react/ui/PlaybackTime"
101+
import ProgressBar from "@sendbird/uikit-react/ui/ProgressBar"
102+
import VoiceMessageInput from "@sendbird/uikit-react/ui/VoiceMessageInput"
103+
import VoiceMessageItemBody from "@sendbird/uikit-react/ui/VoiceMessageItemBody"
104+
```
105+
* PlaybackTime: Display the current time in 00:00 format with the received millisecond value
106+
* ProgressBar: Display the current progress status with the received maxSize and currentSize of millisecond unit value
107+
* VoiceMessageInput: UI component for recording and playing a voice message
108+
* VoiceMessageItemBody: UI component for rendering a voice message also able to play voice message
109+
* VoiceRecorder
110+
```javascript
111+
import { VoiceRecorderProvider, useVoiceRecorderContext } from '@sendbird/uikit-react/VoiceRecorder/context'
112+
import useVoiceRecorder from '@sendbird/uikit-react/VoiceRecorder/useVoiceRecorder'
113+
```
114+
* VoiceRecorderProvider: A react context provider component providing `start`, and `stop` functions
115+
* useVoiceRecorderContext: A react useContext hook of VoiceRecorderProvider
116+
* useVoiceRecorder: A react hook that provides advanced context, `recordingLimit`, `recordingTime`, `recordingFile`, and `recordingStatus`. Recommend using this hook in the customized components.
117+
* VoicePlayer
118+
```javascript
119+
import { VoicePlayerProvider, useVoicePlayerContext } from '@sendbird/uikit-react/VoicePlayer/context'
120+
import useVoicePlayer from '@sendbird/uikit-react/VoicePlayer/useVoicePlayer'
121+
```
122+
* VoicePlayerProvider: A react context provider component providing `play`, and `pause` functions
123+
* useVoicePlayerContext: A react useContext hook of VoicePlayerProvider
124+
* useVoicePlayer: A react hook that provides advanced context, `playbackTime`, `duration`, and `playingStatus`. Recommend using this hook in the customized components.
125+
* utils/isVoiceMessage: A function that you can check if the given message is a voice message
126+
```javascript
127+
import isVoiceMessage from '@sendbird/uikit-react/utils/message/isVoiceMessage'
128+
const isVoiceMsg: boolean = isVoiceMessage(message);
129+
```
130+
131+
Features:
132+
* Add props `renderFileUploadIcon`, `renderVoiceMessageIcon`, and `renderSendMessageIcon` into the `Channel`, `ChannelUI`, and `MessageInput` component
133+
```javascript
134+
interface MessageInputProps {
135+
renderFileUploadIcon?: () => React.ReactElement;
136+
renderVoiceMessageIcon?: () => React.ReactElement;
137+
renderSendMessageIcon?: () => React.ReactElement;
138+
}
139+
```
140+
141+
Fixes:
142+
* Use ApplicationUserListQuery on ChannelSettings component
143+
* Fix some visual issues on the normal User Panel of ChannelSettings
144+
* Indentify faulty images in OG message
145+
* Add classname: sendbird-og-message-item-body__og-thumbnail__empty to identify faulty images in OG message
146+
Clients can use CSS to target this class~
147+
```css
148+
.sendbird-og-message-item-body__og-thumbnail__empty {
149+
display: none;
150+
}
151+
```
152+
3153
## [v3.3.7] (Feb 24 2023)
4154

5155
Features:

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sendbird/uikit-react",
3-
"version": "3.3.7",
3+
"version": "3.4.0",
44
"description": "React based UI kit for sendbird",
55
"main": "dist/index.js",
66
"style": "dist/index.css",

scripts/index_d_ts

+69-9
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ declare module "SendbirdUIKitGlobal" {
6666
config?: SendbirdProviderConfig;
6767
useReaction?: boolean;
6868
useMessageGrouping?: boolean;
69+
isVoiceMessageEnabled?: boolean;
70+
voiceRecord?: {
71+
maxRecordingTime?: number,
72+
minRecordingTime?: number,
73+
};
6974
stringSet?: Record<string, string>;
7075
colorSet?: Record<string, string>;
7176
imageCompression?: {
@@ -218,33 +223,35 @@ declare module "SendbirdUIKitGlobal" {
218223
userId: string;
219224
appId: string;
220225
accessToken?: string;
221-
configureSession?: (sdk: SendbirdGroupChat | SendbirdOpenChat) => SessionHandler;
226+
configureSession?: (sdk: SendbirdChat) => SessionHandler;
222227
customApiHost?: string,
223228
customWebSocketHost?: string,
224-
// mediaQueryBreakPoint?: string | boolean,
225-
children?: React.ReactNode | React.ReactElement;
229+
children?: React.ReactElement;
226230
theme?: 'light' | 'dark';
227231
nickname?: string;
228232
profileUrl?: string;
229233
dateLocale?: Locale;
230234
disableUserProfile?: boolean;
231235
disableMarkAsDelivered?: boolean;
232-
onUserProfileMessage?: (props: GroupChannel) => void;
233-
renderUserProfile?: (props: RenderUserProfileProps) => React.ReactNode | React.ReactElement;
236+
renderUserProfile?: (props: RenderUserProfileProps) => React.ReactElement;
234237
allowProfileEdit?: boolean;
235238
userListQuery?(): UserListQuery;
236239
config?: SendbirdProviderConfig;
237240
stringSet?: Record<string, string>;
238241
colorSet?: Record<string, string>;
239-
isMentionEnabled?: boolean;
240242
imageCompression?: {
241243
compressionRate?: number,
242244
resizingWidth?: number | string,
243245
resizingHeight?: number | string,
244246
};
245-
isReactionEnabled?: boolean,
246-
isTypingIndicatorEnabledOnChannelList?: boolean,
247-
isMessageReceiptStatusEnabledOnChannelList?: boolean,
247+
isMentionEnabled?: boolean;
248+
isVoiceMessageEnabled?: boolean;
249+
voiceRecord?: {
250+
maxRecordingTime?: number,
251+
minRecordingTime?: number,
252+
};
253+
isTypingIndicatorEnabledOnChannelList?: boolean;
254+
isMessageReceiptStatusEnabledOnChannelList?: boolean;
248255
}
249256

250257
export interface SendBirdStateConfig {
@@ -272,6 +279,11 @@ declare module "SendbirdUIKitGlobal" {
272279
resizingWidth?: number | string,
273280
resizingHeight?: number | string,
274281
};
282+
isVoiceMessageEnabled?: boolean;
283+
voiceRecord?: {
284+
maxRecordingTime?: number,
285+
minRecordingTime?: number,
286+
};
275287
isTypingIndicatorEnabledOnChannelList?: boolean;
276288
isMessageReceiptStatusEnabledOnChannelList?: boolean;
277289
replyType: ReplyType;
@@ -464,6 +476,14 @@ declare module "SendbirdUIKitGlobal" {
464476
onCancel: () => void;
465477
};
466478

479+
export enum VoicePlayerStatus {
480+
IDLE = 'IDLE',
481+
PREPARING = 'PREPARING',
482+
READY_TO_PLAY = 'READY_TO_PLAY',
483+
PLAYING = 'PLAYING',
484+
COMPLETED = 'COMPLETED',
485+
}
486+
467487
/**
468488
* Channel
469489
*/
@@ -1194,6 +1214,11 @@ declare module '@sendbird/uikit-react/utils/message/getOutgoingMessageState' {
11941214
): OutgoingMessageStates;
11951215
}
11961216

1217+
declare module '@sendbird/uikit-react/utils/message/isVoiceMessage' {
1218+
import type { FileMessage } from '@sendbird/chat/message';
1219+
export function isVoiceMessage(message: FileMessage): boolean;
1220+
}
1221+
11971222
/** ChannelList */
11981223
declare module '@sendbird/uikit-react/ChannelList' {
11991224
import SendbirdUIKitGlobal from 'SendbirdUIKitGlobal';
@@ -1839,7 +1864,17 @@ declare module '@sendbird/uikit-react/ui/FileMessageItemBody' {
18391864
}
18401865
const FileMessageItemBody: React.FC<FileMessageItemBodyProps>;
18411866
export default FileMessageItemBody;
1867+
}
18421868

1869+
declare module '@sendbird/uikit-react/ui/VoiceMessageItemBody' {
1870+
interface VoiceMessageItemBodyProps {
1871+
minRecordTime?: number;
1872+
maximumValue: number;
1873+
currentValue?: number;
1874+
currentType: VoicePlayerStatus;
1875+
}
1876+
type VoiceMessageItemBody = React.FC<VoiceMessageItemBodyProps>;
1877+
export default VoiceMessageItemBody;
18431878
}
18441879

18451880
declare module '@sendbird/uikit-react/ui/FileViewer' {
@@ -2005,6 +2040,7 @@ declare module '@sendbird/uikit-react/ui/MessageInput' {
20052040
className?: Array<string>,
20062041
isEdit?: boolean,
20072042
isMentionEnabled?: boolean;
2043+
isVoiceMessageEnabled?: boolean;
20082044
disabled?: boolean,
20092045
// value is removed when channelURL changes
20102046
value?: string,
@@ -2022,6 +2058,7 @@ declare module '@sendbird/uikit-react/ui/MessageInput' {
20222058
onMentionedUserIdsUpdated?: (userIds: Array<string>) => void,
20232059
onKeyUp?: (e: React.KeyboardEvent<HTMLDivElement>) => void,
20242060
onKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void,
2061+
onVoiceMessageIconClick?: () => void;
20252062
renderFileUploadIcon?: () => React.ReactElement;
20262063
renderVoiceMessageIcon?: () => React.ReactElement;
20272064
renderSendMessageIcon?: () => React.ReactElement;
@@ -2030,6 +2067,29 @@ declare module '@sendbird/uikit-react/ui/MessageInput' {
20302067
export default MessageInput;
20312068
}
20322069

2070+
declare module '@sendbird/uikit-react/ui/VoiceMessageInput' {
2071+
export enum VoiceMessageInputStatus {
2072+
READY_TO_RECORD = 'READY_TO_RECORD',
2073+
RECORDING = 'RECORDING',
2074+
READY_TO_PLAY = 'READY_TO_PLAY',
2075+
PLAYING = 'PLAYING',
2076+
}
2077+
interface VoiceMessageInputProps {
2078+
minRecordTime?: number;
2079+
maximumValue: number;
2080+
currentValue?: number;
2081+
currentType: VoiceMessageInputStatus;
2082+
onCancelClick?: () => void;
2083+
onControlClick?: (type: VoiceMessageInputStatus) => void;
2084+
onSubmitClick?: () => void;
2085+
renderCancelButton?: () => React.ReactElement;
2086+
renderControlButton?: (type: VoiceMessageInputStatus) => React.ReactElement;
2087+
renderSubmitButton?: () => React.ReactElement;
2088+
}
2089+
type VoiceMessageInput = React.FC<VoiceMessageInputProps>;
2090+
export default VoiceMessageInput;
2091+
}
2092+
20332093
declare module '@sendbird/uikit-react/ui/MessageItemMenu' {
20342094
import type { GroupChannel } from '@sendbird/chat/groupChannel';
20352095
import type { FileMessage, UserMessage } from '@sendbird/chat/message';

src/index.d.ts

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import {
4242
} from '@sendbird/chat/openChannel';
4343
import { UikitMessageHandler } from './lib/selectors';
4444
import { RenderCustomSeparatorProps } from './types';
45-
import { isVoiceMessage } from './utils';
4645

4746
type ReplyType = "NONE" | "QUOTE_REPLY" | "THREAD";
4847

src/utils/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ export const isVoiceMessage = (message: FileMessage): boolean => {
171171
return true;
172172
}
173173
// ex) message.metaArrays = [{ key: 'KEY_INTERNAL_MESSAGE_TYPE', value: ['voice/m4a'] }]
174-
return isVOICE_MESSAGE_MIME_TYPE(message.metaArrays.find((metaArray) => metaArray.key === 'KEY_INTERNAL_MESSAGE_TYPE')?.value?.[0]);
174+
return isVoiceMessageMimeType(message.metaArrays.find((metaArray) => metaArray.key === 'KEY_INTERNAL_MESSAGE_TYPE')?.value?.[0]);
175175
};
176-
export const isVOICE_MESSAGE_MIME_TYPE = (type: string): boolean => (/^voice\//.test(type));
176+
export const isVoiceMessageMimeType = (type: string): boolean => (/^voice\//.test(type));
177177

178178
export const isEditedMessage = (message: AdminMessage | UserMessage | FileMessage): boolean => isUserMessage(message) && (message?.updatedAt > 0);
179179
export const isEnabledOGMessage = (message: UserMessage): boolean => (

src/utils/isVoiceMessage.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { isVoiceMessage } from ".";
1+
import { isVoiceMessage as _isVoiceMessage } from ".";
22

3-
export default isVoiceMessage;
4-
// mentioned on docs
3+
export const isVoiceMessage = _isVoiceMessage;

0 commit comments

Comments
 (0)