agora-appbuilder-core 4.0.30 → 4.0.31-beta-2

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 (32) hide show
  1. package/package.json +1 -1
  2. package/template/customization-api/sub-components.ts +1 -0
  3. package/template/defaultConfig.js +2 -2
  4. package/template/package.json +1 -1
  5. package/template/src/components/ChatContext.ts +3 -0
  6. package/template/src/components/Controls.tsx +80 -18
  7. package/template/src/components/Navbar.tsx +29 -1
  8. package/template/src/components/chat/chatConfigure.native.tsx +85 -25
  9. package/template/src/components/chat/chatConfigure.tsx +99 -9
  10. package/template/src/components/chat-messages/useChatMessages.tsx +32 -39
  11. package/template/src/components/chat-ui/useChatUIControls.tsx +21 -0
  12. package/template/src/components/precall/joinWaitingRoomBtn.tsx +25 -6
  13. package/template/src/components/room-info/useRoomInfo.tsx +12 -0
  14. package/template/src/pages/Create.tsx +26 -1
  15. package/template/src/pages/video-call/VideoCallMobileView.tsx +3 -2
  16. package/template/src/pages/video-call/VideoCallScreen.tsx +3 -1
  17. package/template/src/subComponents/ChatBubble.tsx +388 -110
  18. package/template/src/subComponents/ChatContainer.tsx +76 -53
  19. package/template/src/subComponents/ChatInput.native.tsx +93 -14
  20. package/template/src/subComponents/ChatInput.tsx +41 -7
  21. package/template/src/subComponents/caption/Caption.tsx +14 -2
  22. package/template/src/subComponents/caption/CaptionContainer.tsx +24 -3
  23. package/template/src/subComponents/caption/CaptionText.tsx +13 -1
  24. package/template/src/subComponents/chat/ChatActionMenu.tsx +40 -3
  25. package/template/src/subComponents/chat/ChatAttachment.native.tsx +4 -2
  26. package/template/src/subComponents/chat/ChatEmoji.native.tsx +181 -22
  27. package/template/src/subComponents/chat/ChatEmoji.tsx +4 -3
  28. package/template/src/subComponents/chat/ChatQuickActionsMenu.tsx +70 -34
  29. package/template/src/subComponents/chat/ChatSendButton.tsx +42 -1
  30. package/template/src/subComponents/chat/PinnedMessage.tsx +207 -0
  31. package/template/src/utils/useCreateRoom.ts +23 -4
  32. package/template/src/utils/useJoinRoom.ts +76 -23
@@ -0,0 +1,207 @@
1
+ import {
2
+ Pressable,
3
+ StyleSheet,
4
+ Text,
5
+ TouchableOpacity,
6
+ View,
7
+ } from 'react-native';
8
+ import React, {useState} from 'react';
9
+ import ImageIcon from '../../../src/atoms/ImageIcon';
10
+ import hexadecimalTransparency from '../../../src/utils/hexadecimalTransparency';
11
+ import ThemeConfig from '../../theme';
12
+ import {
13
+ ChatMessageType,
14
+ useChatMessages,
15
+ } from '../../../src/components/chat-messages/useChatMessages';
16
+ import {useContent, useLocalUid, UidType} from 'customization-api';
17
+ import {trimText} from '../../../src/utils/common';
18
+ import {formatAMPM} from '../../../src/utils';
19
+ import {useChatConfigure} from '../../components/chat/chatConfigure';
20
+
21
+ interface PinnedMessageProps {
22
+ pinMsgId: string;
23
+ pinnedByUser: UidType;
24
+ }
25
+
26
+ const PinnedMessage: React.FC<PinnedMessageProps> = ({
27
+ pinMsgId,
28
+ pinnedByUser,
29
+ }) => {
30
+ const {messageStore} = useChatMessages();
31
+ const localUid = useLocalUid();
32
+ const {defaultContent} = useContent();
33
+ const [isExpanded, setIsExpanded] = useState(false);
34
+ const [showMoreIcon, setShowMoreIcon] = useState(false);
35
+ const {unPinMessage} = useChatConfigure();
36
+
37
+ const pinnedMsg = messageStore.filter(msg => msg.msgId === pinMsgId);
38
+ if (pinnedMsg.length === 0) return null;
39
+ const name =
40
+ localUid === pinnedMsg[0]?.uid
41
+ ? 'You'
42
+ : trimText(defaultContent[pinnedMsg[0]?.uid]?.name);
43
+ const msgPinnedUser =
44
+ localUid === pinnedByUser
45
+ ? 'You'
46
+ : trimText(defaultContent[pinnedByUser]?.name);
47
+ let time = formatAMPM(new Date(pinnedMsg[0]?.createdTimestamp));
48
+ const isAttachMsg = pinnedMsg[0].type !== ChatMessageType.TXT;
49
+ const fileExt = pinnedMsg[0].ext;
50
+ const fileName = pinnedMsg[0].fileName;
51
+
52
+ const toggleExpanded = () => {
53
+ setIsExpanded(prev => !prev);
54
+ };
55
+ const handleTextLayout = e => {
56
+ let textHeight = e.nativeEvent.layout?.height;
57
+ if (textHeight > 23) {
58
+ setShowMoreIcon(true);
59
+ } else {
60
+ setShowMoreIcon(false);
61
+ }
62
+ };
63
+
64
+ const handleMessageUnpin = () => {
65
+ unPinMessage(pinMsgId);
66
+ };
67
+
68
+ return (
69
+ <View
70
+ style={[styles.container, {overflow: isExpanded ? 'scroll' : 'hidden'}]}>
71
+ <View style={styles.pinUserContainer}>
72
+ <Pressable onPress={handleMessageUnpin}>
73
+ <ImageIcon
74
+ iconType="plain"
75
+ name="unpin-filled"
76
+ iconSize={20}
77
+ tintColor={$config.FONT_COLOR + hexadecimalTransparency['40%']}
78
+ />
79
+ </Pressable>
80
+ <Text style={styles.pinnedUser}> Pinned By {msgPinnedUser}</Text>
81
+ </View>
82
+
83
+ <View style={styles.msgContainer}>
84
+ <View
85
+ style={{
86
+ flexDirection: 'row',
87
+ gap: 8,
88
+ alignItems: 'flex-start',
89
+ width: '90%',
90
+ }}>
91
+ {isAttachMsg && (
92
+ <ImageIcon
93
+ base64={true}
94
+ iconSize={20}
95
+ iconType="plain"
96
+ name={
97
+ fileExt === 'pdf'
98
+ ? 'chat_attachment_pdf'
99
+ : fileExt === 'doc' || fileExt === 'docx'
100
+ ? 'chat_attachment_doc'
101
+ : pinnedMsg[0].type === ChatMessageType.IMAGE
102
+ ? 'chat_attachment_image'
103
+ : 'chat_attachment_unknown'
104
+ }
105
+ tintColor={$config.SEMANTIC_NEUTRAL}
106
+ />
107
+ )}
108
+ {/* Hidden Text to Measure */}
109
+ <Text
110
+ style={[styles.messageText, {position: 'absolute', opacity: 0}]}
111
+ numberOfLines={0}
112
+ onLayout={handleTextLayout}>
113
+ {isAttachMsg
114
+ ? pinnedMsg[0].msg
115
+ ? pinnedMsg[0].msg
116
+ : fileName
117
+ : pinnedMsg[0].msg}
118
+ </Text>
119
+ <Text
120
+ style={styles.messageText}
121
+ numberOfLines={isExpanded ? 0 : 1}
122
+ ellipsizeMode={'tail'}>
123
+ {isAttachMsg
124
+ ? pinnedMsg[0].msg
125
+ ? pinnedMsg[0].msg
126
+ : fileName
127
+ : pinnedMsg[0].msg}
128
+ </Text>
129
+ </View>
130
+
131
+ {showMoreIcon && (
132
+ <Pressable onPress={toggleExpanded}>
133
+ <ImageIcon
134
+ iconType="plain"
135
+ name={isExpanded ? 'arrow-up' : 'arrow-down'}
136
+ iconSize={20}
137
+ tintColor={$config.SECONDARY_ACTION_COLOR}
138
+ />
139
+ </Pressable>
140
+ )}
141
+ </View>
142
+
143
+ <Text style={styles.user}>
144
+ {name} <Text style={styles.pinnedUser}>sent at {time}</Text>
145
+ </Text>
146
+ </View>
147
+ );
148
+ };
149
+
150
+ export default PinnedMessage;
151
+
152
+ const styles = StyleSheet.create({
153
+ container: {
154
+ padding: 12,
155
+ backgroundColor: $config.CARD_LAYER_2_COLOR,
156
+ shadowColor: '#000',
157
+ shadowOffset: {
158
+ width: 0,
159
+ height: 4,
160
+ },
161
+ shadowOpacity: 0.25,
162
+ shadowRadius: 4,
163
+ elevation: 4,
164
+ margin: 8,
165
+ borderRadius: 8,
166
+ borderWidth: 1,
167
+ borderColor: $config.CARD_LAYER_1_COLOR,
168
+ flexDirection: 'column',
169
+ gap: 4,
170
+ alignItems: 'flex-start',
171
+ maxHeight: 120,
172
+ },
173
+ pinIcon: {
174
+ transform: [{rotate: '-45deg'}],
175
+ },
176
+ pinnedUser: {
177
+ fontFamily: ThemeConfig.FontFamily.sansPro,
178
+ fontWeight: '400',
179
+ fontSize: 12,
180
+ lineHeight: 12,
181
+ color: $config.FONT_COLOR + hexadecimalTransparency['40%'],
182
+ },
183
+ pinUserContainer: {
184
+ flexDirection: 'row',
185
+ alignItems: 'center',
186
+ },
187
+ user: {
188
+ fontFamily: ThemeConfig.FontFamily.sansPro,
189
+ color: $config.FONT_COLOR + hexadecimalTransparency['70%'],
190
+ fontSize: 12,
191
+ fontWeight: '600',
192
+ lineHeight: 12,
193
+ },
194
+ messageText: {
195
+ fontSize: 18,
196
+ fontWeight: '600',
197
+ fontFamily: ThemeConfig.FontFamily.sansPro,
198
+ color: $config.FONT_COLOR,
199
+ },
200
+ msgContainer: {
201
+ width: '100%',
202
+ flexDirection: 'row',
203
+ justifyContent: 'space-between',
204
+ alignItems: 'flex-start',
205
+ gap: 12,
206
+ },
207
+ });
@@ -18,6 +18,10 @@ const CREATE_CHANNEL = gql`
18
18
  pstn {
19
19
  number
20
20
  dtmf
21
+ error {
22
+ code
23
+ message
24
+ }
21
25
  }
22
26
  }
23
27
  }
@@ -118,10 +122,25 @@ export default function useCreateRoom(): createRoomFun {
118
122
  roomInfo.roomId.host = res.data.createChannel.passphrase.host;
119
123
  }
120
124
  if (enablePSTN === true && res?.data?.createChannel?.pstn) {
121
- roomInfo.pstn = {
122
- number: res.data.createChannel.pstn.number,
123
- pin: res.data.createChannel.pstn.dtmf,
124
- };
125
+ if (
126
+ res.data.createChannel.pstn?.error?.code ||
127
+ res.data.createChannel.pstn?.error?.message
128
+ ) {
129
+ roomInfo.pstn = {
130
+ number: '',
131
+ pin: '',
132
+ error: {
133
+ code: res.data.createChannel.pstn?.error?.code,
134
+ message: res.data.createChannel.pstn?.error?.message,
135
+ },
136
+ };
137
+ } else {
138
+ roomInfo.pstn = {
139
+ number: res.data.createChannel.pstn?.number,
140
+ pin: res.data.createChannel.pstn?.dtmf,
141
+ error: null,
142
+ };
143
+ }
125
144
  }
126
145
  logger.log(LogSource.Internals, 'CREATE_MEETING', 'Room created', {
127
146
  isHost: true,
@@ -21,6 +21,10 @@ const JOIN_CHANNEL_PHRASE_AND_GET_USER = gql`
21
21
  groupId
22
22
  userToken
23
23
  isGroupOwner
24
+ error {
25
+ code
26
+ message
27
+ }
24
28
  }
25
29
  secretSalt
26
30
  mainUser {
@@ -31,6 +35,10 @@ const JOIN_CHANNEL_PHRASE_AND_GET_USER = gql`
31
35
  whiteboard {
32
36
  room_uuid
33
37
  room_token
38
+ error {
39
+ code
40
+ message
41
+ }
34
42
  }
35
43
  screenShare {
36
44
  rtc
@@ -56,6 +64,10 @@ const JOIN_CHANNEL_PHRASE = gql`
56
64
  groupId
57
65
  userToken
58
66
  isGroupOwner
67
+ error {
68
+ code
69
+ message
70
+ }
59
71
  }
60
72
  secretSalt
61
73
  mainUser {
@@ -66,6 +78,10 @@ const JOIN_CHANNEL_PHRASE = gql`
66
78
  whiteboard {
67
79
  room_uuid
68
80
  room_token
81
+ error {
82
+ code
83
+ message
84
+ }
69
85
  }
70
86
  screenShare {
71
87
  rtc
@@ -236,19 +252,37 @@ export default function useJoinRoom() {
236
252
  : data.joinChannel.mainUser.rtm;
237
253
  }
238
254
  if (data?.joinChannel?.chat || data?.chat) {
239
- const chat: RoomInfoContextInterface['data']['chat'] = {
240
- user_token: isWaitingRoomEnabled
241
- ? data.chat.userToken
242
- : data?.joinChannel?.chat?.userToken,
243
- group_id: isWaitingRoomEnabled
244
- ? data.chat.groupId
245
- : data?.joinChannel?.chat?.groupId,
246
- is_group_owner: isWaitingRoomEnabled
247
- ? data.chat.isGroupOwner
248
- : data?.joinChannel?.chat?.isGroupOwner,
249
- };
250
-
251
- roomInfo.chat = chat;
255
+ const chatData = isWaitingRoomEnabled
256
+ ? data.chat
257
+ : data?.joinChannel?.chat;
258
+ if (
259
+ $config.CHAT &&
260
+ (chatData?.error?.code || chatData?.error?.message)
261
+ ) {
262
+ roomInfo.chat = {
263
+ user_token: '',
264
+ group_id: '',
265
+ is_group_owner: false,
266
+ error: {
267
+ code: chatData?.error?.code,
268
+ message: chatData?.error?.message,
269
+ },
270
+ };
271
+ } else {
272
+ const chat: RoomInfoContextInterface['data']['chat'] = {
273
+ user_token: isWaitingRoomEnabled
274
+ ? data.chat.userToken
275
+ : data?.joinChannel?.chat?.userToken,
276
+ group_id: isWaitingRoomEnabled
277
+ ? data.chat.groupId
278
+ : data?.joinChannel?.chat?.groupId,
279
+ is_group_owner: isWaitingRoomEnabled
280
+ ? data.chat.isGroupOwner
281
+ : data?.joinChannel?.chat?.isGroupOwner,
282
+ error: null,
283
+ };
284
+ roomInfo.chat = chat;
285
+ }
252
286
  }
253
287
 
254
288
  roomInfo.isHost = isWaitingRoomEnabled
@@ -261,16 +295,35 @@ export default function useJoinRoom() {
261
295
  : data.joinChannel.title;
262
296
  }
263
297
  if (data?.joinChannel?.whiteboard || data?.whiteboard) {
264
- const whiteboard: RoomInfoContextInterface['data']['whiteboard'] = {
265
- room_token: isWaitingRoomEnabled
266
- ? data.whiteboard.room_token
267
- : data?.joinChannel?.whiteboard?.room_token,
268
- room_uuid: isWaitingRoomEnabled
269
- ? data.whiteboard.room_uuid
270
- : data?.joinChannel?.whiteboard?.room_uuid,
271
- };
272
- if (whiteboard?.room_token && whiteboard?.room_uuid) {
273
- roomInfo.whiteboard = whiteboard;
298
+ const whiteboardData = isWaitingRoomEnabled
299
+ ? data.whiteboard
300
+ : data?.joinChannel?.whiteboard;
301
+ if (
302
+ $config.ENABLE_WHITEBOARD &&
303
+ (whiteboardData?.error?.code || whiteboardData?.error?.message)
304
+ ) {
305
+ roomInfo.whiteboard = {
306
+ room_token: '',
307
+ room_uuid: '',
308
+ error: {
309
+ code: whiteboardData?.error?.code,
310
+ message: whiteboardData?.error?.message,
311
+ },
312
+ };
313
+ } else {
314
+ const whiteboard: RoomInfoContextInterface['data']['whiteboard'] =
315
+ {
316
+ room_token: isWaitingRoomEnabled
317
+ ? data.whiteboard.room_token
318
+ : data?.joinChannel?.whiteboard?.room_token,
319
+ room_uuid: isWaitingRoomEnabled
320
+ ? data.whiteboard.room_uuid
321
+ : data?.joinChannel?.whiteboard?.room_uuid,
322
+ error: null,
323
+ };
324
+ if (whiteboard?.room_token && whiteboard?.room_uuid) {
325
+ roomInfo.whiteboard = whiteboard;
326
+ }
274
327
  }
275
328
  }
276
329
  //getUser is not available from backend