agora-appbuilder-core 4.0.35 → 4.1.0-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 (75) hide show
  1. package/package.json +2 -2
  2. package/template/agora-rn-uikit/README.md +1 -40
  3. package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +1 -0
  4. package/template/agora-rn-uikit/src/Contexts/RtcContext.tsx +1 -0
  5. package/template/agora-rn-uikit/src/Reducer/Spotlight.ts +11 -0
  6. package/template/agora-rn-uikit/src/Reducer/index.ts +1 -0
  7. package/template/agora-rn-uikit/src/RtcConfigure.tsx +7 -0
  8. package/template/bridge/rtc/webNg/RtcEngine.ts +4 -1
  9. package/template/customization-api/app-state.ts +11 -7
  10. package/template/customization-api/{customize.ts → customize.tsx} +116 -11
  11. package/template/customization-api/sub-components.ts +4 -0
  12. package/template/customization-api/temp.ts +2 -0
  13. package/template/customization-api/typeDefinition.ts +2 -1
  14. package/template/customization-api/utils.ts +6 -1
  15. package/template/defaultConfig.js +4 -2
  16. package/template/global.d.ts +2 -0
  17. package/template/src/AppRoutes.tsx +15 -5
  18. package/template/src/ai-agent/components/AgentControls/AgentContext.tsx +163 -0
  19. package/template/src/ai-agent/components/AgentControls/LeaveCall.png +0 -0
  20. package/template/src/ai-agent/components/AgentControls/Vector.svg +3 -0
  21. package/template/src/ai-agent/components/AgentControls/const.ts +58 -0
  22. package/template/src/ai-agent/components/AgentControls/index.tsx +293 -0
  23. package/template/src/ai-agent/components/AudioVisualizer.tsx +91 -0
  24. package/template/src/ai-agent/components/Bottombar.tsx +91 -0
  25. package/template/src/ai-agent/components/CustomCreate.tsx +279 -0
  26. package/template/src/ai-agent/components/CustomCreateNative.tsx +265 -0
  27. package/template/src/ai-agent/components/CustomSidePanel.tsx +135 -0
  28. package/template/src/ai-agent/components/FallbackLogo.tsx +80 -0
  29. package/template/src/ai-agent/components/LocalAudioWave.tsx +171 -0
  30. package/template/src/ai-agent/components/agent-chat-panel/agent-chat-ui.tsx +82 -0
  31. package/template/src/ai-agent/components/icons.tsx +227 -0
  32. package/template/src/ai-agent/components/mobile/Bottombar.tsx +47 -0
  33. package/template/src/ai-agent/components/mobile/MobileLayoutComponent.tsx +106 -0
  34. package/template/src/ai-agent/components/mobile/Topbar.tsx +62 -0
  35. package/template/src/ai-agent/components/react-audio-visualize/LiveAudioVisualizer/LiveAudioVisualizer.tsx +173 -0
  36. package/template/src/ai-agent/components/react-audio-visualize/LiveAudioVisualizer/index.ts +1 -0
  37. package/template/src/ai-agent/components/react-audio-visualize/LiveAudioVisualizer/utils.ts +102 -0
  38. package/template/src/ai-agent/components/react-audio-visualize/index.ts +1 -0
  39. package/template/src/ai-agent/components/utils.ts +15 -0
  40. package/template/src/ai-agent/index.tsx +301 -0
  41. package/template/src/ai-agent/routes/CustomLoginRoute.tsx +25 -0
  42. package/template/src/ai-agent/routes/CustomValidateRoute.tsx +25 -0
  43. package/template/src/ai-agent/utils.ts +78 -0
  44. package/template/src/assets/font-styles.css +4 -0
  45. package/template/src/assets/fonts/icomoon.ttf +0 -0
  46. package/template/src/assets/selection.json +1 -1
  47. package/template/src/atoms/CustomIcon.tsx +1 -0
  48. package/template/src/atoms/ImageIcon.tsx +3 -0
  49. package/template/src/atoms/ToolbarItem.tsx +0 -2
  50. package/template/src/components/ChatContext.ts +7 -0
  51. package/template/src/components/Controls.tsx +6 -1
  52. package/template/src/components/ErrorBoundary.tsx +37 -0
  53. package/template/src/components/ErrorBoundaryFallback.tsx +44 -0
  54. package/template/src/components/RTMConfigure.tsx +25 -20
  55. package/template/src/components/participants/Participant.tsx +4 -0
  56. package/template/src/components/participants/UserActionMenuOptions.tsx +34 -1
  57. package/template/src/components/precall/PermissionHelper.tsx +11 -8
  58. package/template/src/language/default-labels/videoCallScreenLabels.ts +8 -0
  59. package/template/src/logger/AppBuilderLogger.tsx +4 -1
  60. package/template/src/pages/Create.tsx +11 -12
  61. package/template/src/pages/VideoCall.tsx +1 -0
  62. package/template/src/pages/video-call/ActionSheet.tsx +33 -29
  63. package/template/src/pages/video-call/SidePanelHeader.tsx +8 -3
  64. package/template/src/pages/video-call/SpotlightHighlighter.tsx +91 -0
  65. package/template/src/pages/video-call/VideoCallMobileView.tsx +17 -6
  66. package/template/src/pages/video-call/VideoCallScreen.tsx +0 -1
  67. package/template/src/pages/video-call/VideoRenderer.tsx +32 -4
  68. package/template/src/rtm-events/constants.ts +2 -0
  69. package/template/src/subComponents/ChatBubble.tsx +34 -15
  70. package/template/src/subComponents/FallbackLogo.tsx +3 -1
  71. package/template/src/subComponents/LocalAudioMute.tsx +20 -2
  72. package/template/src/utils/index.tsx +3 -4
  73. package/template/src/utils/useJoinRoom.ts +14 -0
  74. package/template/src/utils/useSpotlight.ts +31 -0
  75. package/template/tsconfig.json +23 -18
@@ -152,4 +152,5 @@ export interface IconsInterface {
152
152
  'recording-status': string;
153
153
  fullscreen: string;
154
154
  add_reaction: string;
155
+ spotlight: string;
155
156
  }
@@ -31,6 +31,7 @@ export interface ImageIconProps {
31
31
  // hoverEffect?: boolean;
32
32
  // hoverEffectStyle?: ViewStyle;
33
33
  showWarningIcon?: boolean;
34
+ iconParentContainerStyle?: ViewStyle;
34
35
  }
35
36
 
36
37
  const ImageIcon = (props: ImageIconProps) => {
@@ -46,6 +47,7 @@ const ImageIcon = (props: ImageIconProps) => {
46
47
  base64TintColor = '',
47
48
  iconType = 'round',
48
49
  iconContainerStyle,
50
+ iconParentContainerStyle = {},
49
51
  isHovered,
50
52
  } = props;
51
53
  return (
@@ -57,6 +59,7 @@ const ImageIcon = (props: ImageIconProps) => {
57
59
  ? {backgroundColor: props.iconBackgroundColor}
58
60
  : {}
59
61
  : {backgroundColor: 'transparent', borderRadius: 0},
62
+ iconParentContainerStyle,
60
63
  ]}>
61
64
  <View
62
65
  style={[
@@ -21,8 +21,6 @@ const ToolbarItem = (props: ToolbarItemProps) => {
21
21
  const {isHorizontal, position} = useToolbar();
22
22
  //isHorizontal true -> top/bottom bar
23
23
  //isHorizontal false -> left/right bar
24
- // todo hari - first item shouldnot contain the margin right
25
- // todo hari - last item shouldnot contain the margin right
26
24
 
27
25
  //action sheet
28
26
  if (isMobileUA() && position === ToolbarPosition.bottom) {
@@ -15,6 +15,7 @@ import {createContext, SetStateAction} from 'react';
15
15
 
16
16
  import {ChatMessageType, Reaction} from './chat-messages/useChatMessages';
17
17
  import {createHook} from 'customization-implementation';
18
+ import {ViewStyle} from 'react-native';
18
19
 
19
20
  export interface ChatBubbleProps {
20
21
  isLocal: boolean;
@@ -35,6 +36,12 @@ export interface ChatBubbleProps {
35
36
  scrollOffset?: number;
36
37
  replyToMsgId?: string;
37
38
  isLastMsg?: boolean;
39
+ remoteUIConfig?: {
40
+ username?: string; // Custom username for remote user
41
+ avatarIcon?: string;
42
+ bubbleStyleLayer1?: ViewStyle;
43
+ bubbleStyleLayer2?: ViewStyle;
44
+ };
38
45
 
39
46
  render?: (
40
47
  isLocal: boolean,
@@ -1029,7 +1029,12 @@ export const RaiseHandToolbarItem = props => {
1029
1029
  export const LocalAudioToolbarItem = props => {
1030
1030
  return (
1031
1031
  <ToolbarItem testID="localAudio-btn" toolbarProps={props}>
1032
- <LocalAudioMute showToolTip={true} />
1032
+ <LocalAudioMute
1033
+ showToolTip={true}
1034
+ iconBGColor={props?.iconBGColor}
1035
+ iconSize={props?.iconSize}
1036
+ containerStyle={props?.containerStyle}
1037
+ />
1033
1038
  </ToolbarItem>
1034
1039
  );
1035
1040
  };
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import {logger, LogSource} from '../logger/AppBuilderLogger';
3
+
4
+ class ErrorBoundary extends React.Component<{fallback: JSX.Element}> {
5
+ constructor(props) {
6
+ super(props);
7
+ this.state = {hasError: false};
8
+ }
9
+
10
+ static getDerivedStateFromError(error) {
11
+ // Update state so the next render will show the fallback UI.
12
+ return {hasError: true};
13
+ }
14
+
15
+ componentDidCatch(error, info) {
16
+ logger.error(
17
+ LogSource.Internals,
18
+ 'VIDEO_CALL_ROOM',
19
+ 'Application crashed',
20
+ {
21
+ errorMessage: error?.message,
22
+ errorStack: info?.componentStack,
23
+ },
24
+ );
25
+ }
26
+
27
+ render() {
28
+ if (this.state.hasError) {
29
+ // You can render any custom fallback UI
30
+ return this.props.fallback;
31
+ }
32
+
33
+ return this.props.children;
34
+ }
35
+ }
36
+
37
+ export default ErrorBoundary;
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import {Text, View, StyleSheet, ScrollView} from 'react-native';
3
+ import Card from '../atoms/Card';
4
+ import ThemeConfig from '../theme';
5
+
6
+ export const ErrorBoundaryFallback = () => {
7
+ return (
8
+ <View style={style.root}>
9
+ <ScrollView contentContainerStyle={style.main}>
10
+ <Card>
11
+ <View>
12
+ <Text style={style.text}>
13
+ An unexpected error occurred. Please try again.
14
+ </Text>
15
+ </View>
16
+ </Card>
17
+ </ScrollView>
18
+ </View>
19
+ );
20
+ };
21
+
22
+ const style = StyleSheet.create({
23
+ logoContainerStyle: {
24
+ flexDirection: 'row',
25
+ justifyContent: 'space-between',
26
+ alignItems: 'center',
27
+ },
28
+ root: {
29
+ flex: 1,
30
+ },
31
+ main: {
32
+ flexGrow: 1,
33
+ flexDirection: 'row',
34
+ justifyContent: 'center',
35
+ },
36
+ text: {
37
+ fontSize: ThemeConfig.FontSize.large,
38
+ fontWeight: '400',
39
+ lineHeight: ThemeConfig.FontSize.large,
40
+ color: $config.FONT_COLOR,
41
+ fontFamily: ThemeConfig.FontFamily.sansPro,
42
+ opacity: ThemeConfig.EmphasisOpacity.high,
43
+ },
44
+ });
@@ -114,29 +114,34 @@ const RtmConfigure = (props: any) => {
114
114
  }, [defaultContent]);
115
115
 
116
116
  React.useEffect(() => {
117
- const handBrowserClose = ev => {
118
- ev.preventDefault();
119
- return (ev.returnValue = 'Are you sure you want to exit?');
120
- };
121
- const logoutRtm = () => {
122
- engine.current.leaveChannel(rtcProps.channel);
123
- };
124
-
125
- if (!isWebInternal()) return;
126
- window.addEventListener(
127
- 'beforeunload',
128
- isWeb() && !isSDK() ? handBrowserClose : () => {},
129
- );
130
-
131
- window.addEventListener('pagehide', logoutRtm);
132
- // cleanup this component
133
- return () => {
134
- window.removeEventListener(
117
+ if (!$config.ENABLE_CONVERSATIONAL_AI) {
118
+ const handBrowserClose = ev => {
119
+ ev.preventDefault();
120
+ window.setTimeout(function () {
121
+ window.location = `${window.location.origin}/create`;
122
+ }, 0);
123
+ return false;
124
+ };
125
+ const logoutRtm = () => {
126
+ engine.current.leaveChannel(rtcProps.channel);
127
+ };
128
+
129
+ if (!isWebInternal()) return;
130
+ window.addEventListener(
135
131
  'beforeunload',
136
132
  isWeb() && !isSDK() ? handBrowserClose : () => {},
137
133
  );
138
- window.removeEventListener('pagehide', logoutRtm);
139
- };
134
+
135
+ window.addEventListener('pagehide', logoutRtm);
136
+ // cleanup this component
137
+ return () => {
138
+ window.removeEventListener(
139
+ 'beforeunload',
140
+ isWeb() && !isSDK() ? handBrowserClose : () => {},
141
+ );
142
+ window.removeEventListener('pagehide', logoutRtm);
143
+ };
144
+ }
140
145
  }, []);
141
146
 
142
147
  const doLoginAndSetupRTM = async () => {
@@ -42,6 +42,7 @@ import {
42
42
  useLayout,
43
43
  useContent,
44
44
  useSidePanel,
45
+ useSpotlight,
45
46
  } from 'customization-api';
46
47
  import {getPinnedLayoutName} from '../../pages/video-call/DefaultLayouts';
47
48
  import UserActionMenuOptionsOptions from './UserActionMenuOptions';
@@ -96,6 +97,7 @@ const Participant = (props: ParticipantInterface) => {
96
97
  const showModal = () => {
97
98
  setActionMenuVisible(state => !state);
98
99
  };
100
+ const {setSpotlightUid, spotlightUid} = useSpotlight();
99
101
 
100
102
  return (
101
103
  <>
@@ -105,6 +107,8 @@ const Participant = (props: ParticipantInterface) => {
105
107
  user={props.user}
106
108
  btnRef={moreIconRef}
107
109
  from={'partcipant'}
110
+ spotlightUid={spotlightUid}
111
+ setSpotlightUid={setSpotlightUid}
108
112
  />
109
113
  <PlatformWrapper showModal={showModal} setIsHovered={setIsHovered}>
110
114
  <View style={styles.container} ref={usercontainerRef}>
@@ -57,6 +57,7 @@ import {
57
57
  moreBtnRemoveFromRoom,
58
58
  moreBtnRemoveFromTop,
59
59
  moreBtnRemoveScreenShare,
60
+ moreBtnSpotlight,
60
61
  moreBtnStopScreenShare,
61
62
  moreBtnVideo,
62
63
  moreBtnViewInLarge,
@@ -64,6 +65,7 @@ import {
64
65
  userRemovedFromTheRoomToastHeading,
65
66
  } from '../../language/default-labels/videoCallScreenLabels';
66
67
  import {isAndroid, isIOS} from '../../utils/common';
68
+ import {EventNames} from '../../rtm-events';
67
69
 
68
70
  interface UserActionMenuOptionsOptionsProps {
69
71
  user: ContentInterface;
@@ -71,6 +73,8 @@ interface UserActionMenuOptionsOptionsProps {
71
73
  setActionMenuVisible: (actionMenuVisible: boolean) => void;
72
74
  btnRef: any;
73
75
  from: 'partcipant' | 'screenshare-participant' | 'video-tile';
76
+ spotlightUid?: UidType;
77
+ setSpotlightUid?: (uid: UidType) => void;
74
78
  }
75
79
  export default function UserActionMenuOptionsOptions(
76
80
  props: UserActionMenuOptionsOptionsProps,
@@ -85,7 +89,7 @@ export default function UserActionMenuOptionsOptions(
85
89
  useState(false);
86
90
  const [actionMenuitems, setActionMenuitems] = useState<ActionMenuItem[]>([]);
87
91
  const {setSidePanel} = useSidePanel();
88
- const {user, actionMenuVisible, setActionMenuVisible} = props;
92
+ const {user, actionMenuVisible, setActionMenuVisible, spotlightUid} = props;
89
93
  const {currentLayout} = useLayout();
90
94
  const {pinnedUid, activeUids, customContent, secondaryPinnedUid} =
91
95
  useContent();
@@ -122,6 +126,7 @@ export default function UserActionMenuOptionsOptions(
122
126
  const stopScreenShareLabel = useString(moreBtnStopScreenShare)();
123
127
  const removeScreenShareLabel = useString(moreBtnRemoveScreenShare)();
124
128
  const removeFromRoomLabel = useString(moreBtnRemoveFromRoom)();
129
+ const moreBtnSpotlightLabel = useString(moreBtnSpotlight);
125
130
 
126
131
  useEffect(() => {
127
132
  customEvents.on('DisableChat', data => {
@@ -212,6 +217,33 @@ export default function UserActionMenuOptionsOptions(
212
217
  }
213
218
  }
214
219
 
220
+ if ($config.ENABLE_SPOTLIGHT && isHost && user.type === 'rtc') {
221
+ items.push({
222
+ icon: 'spotlight',
223
+ title: moreBtnSpotlightLabel(user.uid == props?.spotlightUid),
224
+ iconColor: $config.SECONDARY_ACTION_COLOR,
225
+ textColor: $config.SECONDARY_ACTION_COLOR,
226
+ onPress: () => {
227
+ if (user.uid == props?.spotlightUid) {
228
+ props?.setSpotlightUid(0);
229
+ events.send(
230
+ EventNames.SPOTLIGHT_USER_CHANGED,
231
+ JSON.stringify({user_id: 0}),
232
+ PersistanceLevel.Session,
233
+ );
234
+ } else {
235
+ props?.setSpotlightUid(user.uid);
236
+ events.send(
237
+ EventNames.SPOTLIGHT_USER_CHANGED,
238
+ JSON.stringify({user_id: user.uid}),
239
+ PersistanceLevel.Session,
240
+ );
241
+ }
242
+ setActionMenuVisible(false);
243
+ },
244
+ });
245
+ }
246
+
215
247
  /**
216
248
  * Below menu items for remote user with type rtc(not for screenshare)
217
249
  */
@@ -399,6 +431,7 @@ export default function UserActionMenuOptionsOptions(
399
431
  disableChatUids,
400
432
  secondaryPinnedUid,
401
433
  currentLayout,
434
+ spotlightUid,
402
435
  ]);
403
436
 
404
437
  const {width: globalWidth, height: globalHeight} = useWindowDimensions();
@@ -44,8 +44,11 @@ const PermissionHelper = () => {
44
44
  ),
45
45
  ])
46
46
  .then(([cameraResult, micResult]) => {
47
+ const conditionCheck = $config.AUDIO_ROOM
48
+ ? micResult.state !== 'granted'
49
+ : cameraResult.state !== 'granted' || micResult.state !== 'granted';
47
50
  // Chrome
48
- if (cameraResult.state !== 'granted' || micResult.state !== 'granted') {
51
+ if (conditionCheck) {
49
52
  setShowPopup(true);
50
53
  const onChangeFunc = () => {
51
54
  if (
@@ -59,15 +62,15 @@ const PermissionHelper = () => {
59
62
  }
60
63
  })
61
64
  .catch(e => {
62
- // Firefox
63
- setTimeout(() => {
64
- setShowPopup(true);
65
- }, 1000);
65
+ // Firefox and chrome
66
+ setShowPopup(true);
66
67
  });
67
68
  //If permission already given it will take few milliseconds to resolve the promise. it will show the popup which not required. so added timeout
68
- // setTimeout(() => {
69
- // setShowPopup(true);
70
- // }, 1000);
69
+ setTimeout(() => {
70
+ if (permissionStatus === PermissionState.REQUESTED) {
71
+ setShowPopup(true);
72
+ }
73
+ }, 1000);
71
74
  }, []);
72
75
  //todo hari update the modal message based the veritical
73
76
  return (
@@ -267,6 +267,7 @@ export const moreBtnRemoveFromLarge = 'moreBtnRemoveFromLarge';
267
267
  export const moreBtnPinToTop = 'moreBtnPinToTop';
268
268
  export const moreBtnRemoveFromTop = 'moreBtnRemoveFromTop';
269
269
  export const moreBtnMessagePrivately = 'moreBtnMessagePrivately';
270
+ export const moreBtnSpotlight = 'moreBtnSpotlight';
270
271
 
271
272
  export const moreBtnAudio = 'moreBtnAudio';
272
273
  export const moreBtnVideo = 'moreBtnVideo';
@@ -380,6 +381,8 @@ export const livestreamPromoteAsCoHostToastHeading =
380
381
  export const livestreamRequestAlreadyProcessed =
381
382
  'livestreamRequestAlreadyProcessed';
382
383
 
384
+ export const videoRoomInTheSpotlightText =
385
+ `video${room}InTheSpotlightText` as const;
383
386
  export const videoRoomUserFallbackText =
384
387
  `video${room}UserFallbackText` as const;
385
388
 
@@ -682,6 +685,8 @@ export interface I18nVideoCallScreenLabelsInterface {
682
685
  [moreBtnChangeName]?: I18nBaseType;
683
686
  [moreBtnStopScreenShare]?: I18nBaseType;
684
687
  [moreBtnRemoveScreenShare]?: I18nBaseType;
688
+ [moreBtnSpotlight]?: I18nConditionalType;
689
+ [videoRoomInTheSpotlightText]?: I18nBaseType;
685
690
 
686
691
  [muteAllConfirmationPopoverContent]?: I18nBaseType<I18nMuteType>;
687
692
  [muteAllConfirmationPopoverPrimaryBtnText]?: I18nBaseType;
@@ -1080,6 +1085,9 @@ export const VideoCallScreenLabels: I18nVideoCallScreenLabelsInterface = {
1080
1085
  [moreBtnChangeName]: 'Change Name',
1081
1086
  [moreBtnStopScreenShare]: 'Stop Screenshare',
1082
1087
  [moreBtnRemoveScreenShare]: 'Remove Screenshare',
1088
+ [moreBtnSpotlight]: spotlightOn =>
1089
+ spotlightOn ? 'Remove Spotlight' : 'Spotlight',
1090
+ [videoRoomInTheSpotlightText]: 'In the Spotlight',
1083
1091
 
1084
1092
  [muteAllConfirmationPopoverContent]: (type: I18nMuteType) =>
1085
1093
  `Mute everyone's ${type} on the call?`,
@@ -105,7 +105,10 @@ type LogType = {
105
105
  | 'recordings_get'
106
106
  | 'recording_delete';
107
107
  [LogSource.Events]: 'CUSTOM_EVENTS' | 'RTM_EVENTS';
108
- [LogSource.CustomizationAPI]: 'Log';
108
+ [LogSource.CustomizationAPI]:
109
+ | 'Log'
110
+ | 'AI_AGENT_CUSTOMIZATION'
111
+ | 'EXTERNAL_CUSTOMIZATION';
109
112
  [LogSource.SDK]: 'Log' | 'Event';
110
113
  };
111
114
 
@@ -22,6 +22,7 @@ import {
22
22
  maxInputLimit,
23
23
  isMobileUA,
24
24
  trimText,
25
+ isValidReactComponent,
25
26
  } from '../utils/common';
26
27
  import {useCustomization} from 'customization-implementation';
27
28
  import {useString} from '../utils/useString';
@@ -62,24 +63,22 @@ import {
62
63
  createRoomSuccessToastSubHeading,
63
64
  } from '../language/default-labels/createScreenLabels';
64
65
  import {LogSource, logger} from '../logger/AppBuilderLogger';
65
- import {backendErrorCode} from 'src/utils/BackendErrorCode';
66
66
 
67
67
  const Create = () => {
68
68
  const {CreateComponent} = useCustomization(data => {
69
69
  let components: {
70
70
  CreateComponent?: React.ElementType;
71
71
  } = {};
72
- // commented for v1 release
73
- // if (
74
- // data?.components?.create &&
75
- // typeof data?.components?.create !== 'object'
76
- // ) {
77
- // if (
78
- // data?.components?.create &&
79
- // isValidReactComponent(data?.components?.create)
80
- // )
81
- // components.CreateComponent = data?.components?.create;
82
- // }
72
+ if (
73
+ data?.components?.create &&
74
+ typeof data?.components?.create !== 'object'
75
+ ) {
76
+ if (
77
+ data?.components?.create &&
78
+ isValidReactComponent(data?.components?.create)
79
+ )
80
+ components.CreateComponent = data?.components?.create;
81
+ }
83
82
  return components;
84
83
  });
85
84
 
@@ -398,6 +398,7 @@ const VideoCall: React.FC = () => {
398
398
  // }
399
399
  // },
400
400
  EndCall: () => {
401
+ debugger;
401
402
  clearState('join');
402
403
  setTimeout(() => {
403
404
  // TODO: These callbacks are being called twice
@@ -47,7 +47,7 @@ const ActionSheet = props => {
47
47
  }
48
48
  }
49
49
  });
50
- const {snapPointsMinMax = [100, 400]} = props;
50
+ const {snapPointsMinMax = [100, 400], hideDefaultActionSheet = false} = props;
51
51
  const {setActionSheetVisible} = useToast();
52
52
  const [isExpanded, setIsExpanded] = React.useState(false);
53
53
  const [isChatOpen, setIsChatOpen] = React.useState(false);
@@ -74,7 +74,7 @@ const ActionSheet = props => {
74
74
  const {sidePanel, setSidePanel} = useSidePanel();
75
75
  const [showOverlay, setShowOverlay] = React.useState(false);
76
76
  const handleSheetChanges = useCallback((index: number) => {
77
- bottomSheetRef.current?.snapTo(({snapPoints}) => snapPoints[index]);
77
+ bottomSheetRef?.current?.snapTo(({snapPoints}) => snapPoints[index]);
78
78
  index === 0 ? setIsExpanded(false) : setIsExpanded(true);
79
79
  }, []);
80
80
 
@@ -161,7 +161,7 @@ const ActionSheet = props => {
161
161
  };
162
162
  const handleSpringEnd = (event: SpringEvent) => {
163
163
  if (event.type == 'SNAP') {
164
- const isMinmized = bottomSheetRef.current.height === 100;
164
+ const isMinmized = bottomSheetRef?.current?.height === 100;
165
165
  isMinmized && setShowOverlay(false);
166
166
  if (event.source === 'dragging') {
167
167
  if (isMinmized) {
@@ -203,32 +203,36 @@ const ActionSheet = props => {
203
203
  <View>
204
204
  {/* Controls Action Sheet */}
205
205
 
206
- <BottomSheet
207
- scrollLocking={false}
208
- ref={bottomSheetRef}
209
- open={true}
210
- onSpringStart={handleSpringStart}
211
- onSpringEnd={handleSpringEnd}
212
- // skipInitialTransition={true}
213
- expandOnContentDrag={true}
214
- snapPoints={({maxHeight}) => snapPointsMinMax}
215
- defaultSnap={({lastSnap, snapPoints}) =>
216
- lastSnap ?? Math.min(...snapPoints)
217
- }
218
- header={
219
- <>
220
- <ActionSheetHandle sidePanel={SidePanelType.None} />
221
- <Spacer size={12} />
222
- </>
223
- }
224
- blocking={false}>
225
- <ActionSheetContent
226
- handleSheetChanges={handleSheetChanges}
227
- isExpanded={isExpanded}
228
- native={false}
229
- {...props}
230
- />
231
- </BottomSheet>
206
+ {!hideDefaultActionSheet ? (
207
+ <BottomSheet
208
+ scrollLocking={false}
209
+ ref={bottomSheetRef}
210
+ open={true}
211
+ onSpringStart={handleSpringStart}
212
+ onSpringEnd={handleSpringEnd}
213
+ // skipInitialTransition={true}
214
+ expandOnContentDrag={true}
215
+ snapPoints={({maxHeight}) => snapPointsMinMax}
216
+ defaultSnap={({lastSnap, snapPoints}) =>
217
+ lastSnap ?? Math.min(...snapPoints)
218
+ }
219
+ header={
220
+ <>
221
+ <ActionSheetHandle sidePanel={SidePanelType.None} />
222
+ <Spacer size={12} />
223
+ </>
224
+ }
225
+ blocking={false}>
226
+ <ActionSheetContent
227
+ handleSheetChanges={handleSheetChanges}
228
+ isExpanded={isExpanded}
229
+ native={false}
230
+ {...props}
231
+ />
232
+ </BottomSheet>
233
+ ) : (
234
+ <></>
235
+ )}
232
236
  {/* Chat Action Sheet */}
233
237
  <BottomSheet
234
238
  sibling={ToastComponentRender}
@@ -22,7 +22,7 @@ import {numFormatter} from '../../utils';
22
22
  import ChatContext from '../../components/ChatContext';
23
23
  import {useCaption} from '../../subComponents/caption/useCaption';
24
24
  import ActionMenu, {ActionMenuItem} from '../../atoms/ActionMenu';
25
- import {calculatePosition} from '../../utils/common';
25
+ import {calculatePosition, isMobileUA} from '../../utils/common';
26
26
  import LanguageSelectorPopup from '../../subComponents/caption/LanguageSelectorPopup';
27
27
  import useSTTAPI from '../../subComponents/caption/useSTTAPI';
28
28
  import useGetName from '../../utils/useGetName';
@@ -56,7 +56,13 @@ export const SettingsHeader = props => {
56
56
  centerComponent={
57
57
  <Text style={SidePanelStyles.heading}>{settingsLabel}</Text>
58
58
  }
59
- trailingIconName="close"
59
+ trailingIconName={
60
+ $config.ENABLE_CONVERSATIONAL_AI
61
+ ? isMobileUA()
62
+ ? 'close'
63
+ : ''
64
+ : 'close'
65
+ }
60
66
  trailingIconOnPress={() => {
61
67
  props.handleClose && props.handleClose();
62
68
  setSidePanel(SidePanelType.None);
@@ -119,7 +125,6 @@ export const ChatHeader = () => {
119
125
  return (
120
126
  <SidePanelHeader
121
127
  isChat={true}
122
- showTintedOverlay={showEmojiPicker}
123
128
  leadingIconName={isPrivateActive ? 'back-btn' : null}
124
129
  leadingIconOnPress={
125
130
  isPrivateActive
@@ -0,0 +1,91 @@
1
+ import React from 'react';
2
+ import {View, StyleSheet, Text} from 'react-native';
3
+ import ThemeConfig from '../../theme';
4
+ import ImageIcon from '../../atoms/ImageIcon';
5
+ import {useLayout, useContent} from 'customization-api';
6
+ import {isMobileUA, isWeb} from '../../utils/common';
7
+ import {getGridLayoutName} from './DefaultLayouts';
8
+ import hexadecimalTransparency from '../../utils/hexadecimalTransparency';
9
+ import {useString} from '../../utils/useString';
10
+
11
+ const SpotlightHighligher = () => {
12
+ const {activeUids, customContent} = useContent();
13
+ const {currentLayout} = useLayout();
14
+ const activeUidsLen = activeUids?.filter(i => !customContent[i])?.length;
15
+ const reduceSpace =
16
+ isMobileUA() &&
17
+ activeUids.length > 4 &&
18
+ currentLayout === getGridLayoutName();
19
+ const spotlightText = useString('videoRoomInTheSpotlightText')();
20
+
21
+ return (
22
+ <View
23
+ style={[
24
+ style.container,
25
+ reduceSpace ? {left: 2, bottom: 2} : {},
26
+ reduceSpace && activeUidsLen > 12 ? {padding: 2} : {},
27
+ ]}>
28
+ <ImageIcon
29
+ iconType="plain"
30
+ name={'spotlight'}
31
+ tintColor={$config.PRIMARY_ACTION_BRAND_COLOR}
32
+ iconSize={20}
33
+ />
34
+ <PlatformWrapper>
35
+ <Text
36
+ numberOfLines={1}
37
+ textBreakStrategy="simple"
38
+ ellipsizeMode="tail"
39
+ style={[style.name]}>
40
+ {spotlightText}
41
+ </Text>
42
+ </PlatformWrapper>
43
+ </View>
44
+ );
45
+ };
46
+ const PlatformWrapper = ({children}) => {
47
+ return isWeb() ? (
48
+ <div
49
+ style={{
50
+ userSelect: 'none',
51
+ MozUserSelect: 'none',
52
+ WebkitUserSelect: 'none',
53
+ msUserSelect: 'none',
54
+ alignSelf: 'center',
55
+ overflow: 'hidden',
56
+ textOverflow: 'ellipsis',
57
+ color: $config.VIDEO_AUDIO_TILE_TEXT_COLOR,
58
+ }}>
59
+ {children}
60
+ </div>
61
+ ) : (
62
+ <>{children}</>
63
+ );
64
+ };
65
+
66
+ const style = StyleSheet.create({
67
+ container: {
68
+ backgroundColor:
69
+ $config.VIDEO_AUDIO_TILE_OVERLAY_COLOR + hexadecimalTransparency['25%'],
70
+ position: 'absolute',
71
+ alignItems: 'center',
72
+ padding: 8,
73
+ top: 8,
74
+ left: 8,
75
+ borderRadius: 4,
76
+ flexDirection: 'row',
77
+ zIndex: 999,
78
+ elevation: 5,
79
+ },
80
+ name: {
81
+ color: $config.VIDEO_AUDIO_TILE_TEXT_COLOR,
82
+ fontSize: ThemeConfig.FontSize.small,
83
+ fontWeight: '600',
84
+ fontFamily: ThemeConfig.FontFamily.sansPro,
85
+ flexShrink: 1,
86
+ marginLeft: 4,
87
+ marginRight: 2,
88
+ },
89
+ });
90
+
91
+ export default SpotlightHighligher;