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
@@ -203,7 +203,9 @@ const VideoCallView = React.memo(() => {
203
203
  BottombarProps: {},
204
204
  TopbarComponent: NavbarMobile,
205
205
  TopbarProps: {},
206
- VideocallWrapper: ContainerView,
206
+ VideocallWrapper: $config.ENABLE_CONVERSATIONAL_AI
207
+ ? ContainerView
208
+ : React.Fragment,
207
209
  };
208
210
  if (
209
211
  data?.components?.videoCall &&
@@ -254,7 +256,7 @@ const VideoCallView = React.memo(() => {
254
256
  });
255
257
 
256
258
  return (
257
- <>
259
+ <VideocallWrapper>
258
260
  <ToolbarProvider value={{position: ToolbarPosition.top}}>
259
261
  {Object.keys(TopbarProps)?.length ? (
260
262
  <TopbarComponent items={TopbarProps} includeDefaultItems={false} />
@@ -274,11 +276,20 @@ const VideoCallView = React.memo(() => {
274
276
  includeDefaultItems={false}
275
277
  />
276
278
  ) : (
277
- <BottombarComponent />
279
+ <>
280
+ <BottombarComponent />
281
+ <ActionSheet
282
+ includeDefaultItems={false}
283
+ items={{}}
284
+ hideDefaultActionSheet={
285
+ $config.ENABLE_CONVERSATIONAL_AI ? true : false
286
+ }
287
+ />
288
+ </>
278
289
  )}
279
290
  </ActionSheetProvider>
280
291
  </ToolbarProvider>
281
- </>
292
+ </VideocallWrapper>
282
293
  );
283
294
  });
284
295
 
@@ -286,7 +297,7 @@ export default VideoCallMobileView;
286
297
 
287
298
  const styles = StyleSheet.create({
288
299
  container: {
289
- paddingHorizontal: 16,
300
+ paddingHorizontal: $config.ENABLE_CONVERSATIONAL_AI ? 20 : 16,
290
301
  paddingVertical: 20,
291
302
  flex: 1,
292
303
  },
@@ -299,7 +310,7 @@ const styles = StyleSheet.create({
299
310
  paddingVertical: 2,
300
311
  },
301
312
  videoView: {
302
- flex: 0.85,
313
+ flex: $config.ENABLE_CONVERSATIONAL_AI ? (isMobileUA() ? 1 : 0.85) : 0.85,
303
314
  zIndex: 0,
304
315
  elevation: 0,
305
316
  },
@@ -264,7 +264,6 @@ const VideoCallScreen = () => {
264
264
  data?.components?.videoCall.virtualBackgroundPanel;
265
265
  }
266
266
 
267
- //todo hari - need to remove wrapper
268
267
  if (
269
268
  data?.components?.videoCall.wrapper &&
270
269
  typeof data?.components?.videoCall.wrapper !== 'object' &&
@@ -1,5 +1,5 @@
1
1
  import React, {useState, useRef, useContext, useEffect} from 'react';
2
- import {View, StyleSheet, useWindowDimensions} from 'react-native';
2
+ import {View, StyleSheet, useWindowDimensions, ViewStyle} from 'react-native';
3
3
  import {
4
4
  PropsContext,
5
5
  DispatchContext,
@@ -10,7 +10,13 @@ import {MaxVideoView} from '../../../agora-rn-uikit';
10
10
  import FallbackLogo from '../../subComponents/FallbackLogo';
11
11
  import NetworkQualityPill from '../../subComponents/NetworkQualityPill';
12
12
  import NameWithMicIcon from './NameWithMicIcon';
13
- import {useLayout, useContent, useRtc, customEvents} from 'customization-api';
13
+ import {
14
+ useLayout,
15
+ useContent,
16
+ useRtc,
17
+ useSpotlight,
18
+ customEvents,
19
+ } from 'customization-api';
14
20
  import {
15
21
  DefaultLayouts,
16
22
  getGridLayoutName,
@@ -39,15 +45,24 @@ import {
39
45
  } from '../../language/default-labels/videoCallScreenLabels';
40
46
  import {LogSource, logger} from '../../logger/AppBuilderLogger';
41
47
  import {useFullScreen} from '../../utils/useFullScreen';
48
+ import SpotlightHighligher from './SpotlightHighlighter';
42
49
  export interface VideoRendererProps {
43
50
  user: ContentInterface;
44
51
  isMax?: boolean;
45
52
  CustomChild?: React.ComponentType;
53
+ avatarRadius?: number;
54
+ hideMenuOptions?: boolean;
55
+ containerStyle?: ViewStyle;
56
+ innerContainerStyle?: ViewStyle;
46
57
  }
47
58
  const VideoRenderer: React.FC<VideoRendererProps> = ({
48
59
  user,
49
60
  isMax = false,
50
61
  CustomChild,
62
+ avatarRadius = 100,
63
+ hideMenuOptions = false,
64
+ containerStyle = {},
65
+ innerContainerStyle = {},
51
66
  }) => {
52
67
  const {height, width} = useWindowDimensions();
53
68
  const {requestFullscreen} = useFullScreen();
@@ -67,7 +82,7 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
67
82
  isHovered &&
68
83
  currentLayout === getPinnedLayoutName();
69
84
  const [videoTileWidth, setVideoTileWidth] = useState(0);
70
- const [avatarSize, setAvatarSize] = useState(100);
85
+ const [avatarSize, setAvatarSize] = useState(avatarRadius);
71
86
  const videoMoreMenuRef = useRef(null);
72
87
  const [actionMenuVisible, setActionMenuVisible] = React.useState(false);
73
88
  const {setVideoTileInViewPortState} = useVideoCall();
@@ -155,6 +170,7 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
155
170
  };
156
171
  });
157
172
  };
173
+ const {setSpotlightUid, spotlightUid} = useSpotlight();
158
174
 
159
175
  return (
160
176
  <>
@@ -170,6 +186,8 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
170
186
  user={user}
171
187
  btnRef={videoMoreMenuRef}
172
188
  from={'video-tile'}
189
+ setSpotlightUid={setSpotlightUid}
190
+ spotlightUid={spotlightUid}
173
191
  />
174
192
  <PlatformWrapper isHovered={isHovered} setIsHovered={setIsHovered}>
175
193
  <View
@@ -179,7 +197,9 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
179
197
  },
180
198
  }) => {
181
199
  setVideoTileWidth(width);
182
- setAvatarSize(Math.floor(width * 0.35));
200
+ setAvatarSize(
201
+ avatarRadius ? avatarRadius : Math.floor(width * 0.35),
202
+ );
183
203
  }}
184
204
  style={[
185
205
  maxStyle.container,
@@ -188,6 +208,7 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
188
208
  : user.video
189
209
  ? maxStyle.noVideoStyle
190
210
  : maxStyle.nonActiveContainerStyle,
211
+ containerStyle,
191
212
  ]}>
192
213
  {!showReplacePin && !showPinForMe && (
193
214
  <ScreenShareNotice uid={user.uid} isMax={isMax} />
@@ -329,6 +350,7 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
329
350
  landscapeMode && isScreenShareOnFullView ? width : '100%',
330
351
  borderRadius: 4,
331
352
  overflow: 'hidden',
353
+ ...innerContainerStyle,
332
354
  }}
333
355
  key={user.uid}
334
356
  landscapeMode={
@@ -359,8 +381,14 @@ const VideoRenderer: React.FC<VideoRendererProps> = ({
359
381
  ) : (
360
382
  <></>
361
383
  )}
384
+ {$config.ENABLE_SPOTLIGHT && spotlightUid === user.uid ? (
385
+ <SpotlightHighligher />
386
+ ) : (
387
+ <></>
388
+ )}
362
389
  {!(isScreenShareOnFullView || isWhiteboardOnFullScreen) &&
363
390
  // user.uid !== rtcProps?.screenShareUid &&
391
+ hideMenuOptions === false &&
364
392
  (isHovered || actionMenuVisible || isMobileUA()) ? (
365
393
  <MoreMenu
366
394
  videoMoreMenuRef={videoMoreMenuRef}
@@ -39,6 +39,7 @@ const WHITEBOARD_ACTIVE = 'WHITEBOARD_ACTIVE';
39
39
  const BOARD_COLOR_CHANGED = 'BOARD_COLOR_CHANGED';
40
40
  const WHITEBOARD_LAST_IMAGE_UPLOAD_POSITION = 'WHITEBOARD_L_I_U_P';
41
41
  const RECORDING_DELETED = 'RECORDING_DELETED';
42
+ const SPOTLIGHT_USER_CHANGED = 'SPOTLIGHT_USER_CHANGED';
42
43
  const EventNames = {
43
44
  RECORDING_STATE_ATTRIBUTE,
44
45
  RECORDING_STARTED_BY_ATTRIBUTE,
@@ -59,6 +60,7 @@ const EventNames = {
59
60
  BOARD_COLOR_CHANGED,
60
61
  WHITEBOARD_LAST_IMAGE_UPLOAD_POSITION,
61
62
  RECORDING_DELETED,
63
+ SPOTLIGHT_USER_CHANGED,
62
64
  };
63
65
  /** ***** EVENT NAMES ENDS ***** */
64
66
 
@@ -312,6 +312,7 @@ const ChatBubble = (props: ChatBubbleProps) => {
312
312
  scrollOffset,
313
313
  replyToMsgId,
314
314
  isLastMsg,
315
+ remoteUIConfig,
315
316
  } = props;
316
317
 
317
318
  const localUid = useLocalUid();
@@ -355,6 +356,18 @@ const ChatBubble = (props: ChatBubbleProps) => {
355
356
  //const remoteUserDefaultLabel = useString('remoteUserDefaultLabel')();
356
357
  const remoteUserDefaultLabel = useString(videoRoomUserFallbackText)();
357
358
 
359
+ const getUsername = () => {
360
+ if (isLocal) {
361
+ return 'You';
362
+ }
363
+ if (remoteUIConfig?.username) {
364
+ return trimText(remoteUIConfig?.username);
365
+ }
366
+ return defaultContent[uid]?.name
367
+ ? trimText(defaultContent[uid].name)
368
+ : remoteUserDefaultLabel;
369
+ };
370
+
358
371
  return props?.render ? (
359
372
  props.render(
360
373
  isLocal,
@@ -382,17 +395,21 @@ const ChatBubble = (props: ChatBubbleProps) => {
382
395
  style={{
383
396
  flexDirection: 'row',
384
397
  justifyContent: isLocal ? 'flex-end' : 'flex-start',
398
+ alignItems: 'center',
385
399
  marginBottom: 4,
386
400
  marginTop: 16,
387
401
  marginHorizontal: 12,
388
402
  }}>
389
- <Text style={style.userNameStyle}>
390
- {isLocal
391
- ? 'You'
392
- : defaultContent[uid]?.name
393
- ? trimText(defaultContent[uid].name)
394
- : remoteUserDefaultLabel}
395
- </Text>
403
+ {!isLocal && remoteUIConfig?.avatarIcon && (
404
+ <View style={{marginRight: 5}}>
405
+ <ImageIcon
406
+ iconType="plain"
407
+ iconSize={24}
408
+ icon={remoteUIConfig?.avatarIcon}
409
+ />
410
+ </View>
411
+ )}
412
+ <Text style={style.userNameStyle}>{getUsername()}</Text>
396
413
  <Text style={style.timestampStyle}>{time}</Text>
397
414
  </View>
398
415
  ) : (!isSameUser || forceShowUserNameandTimeStamp) &&
@@ -421,7 +438,10 @@ const ChatBubble = (props: ChatBubbleProps) => {
421
438
  style={[
422
439
  isLocal
423
440
  ? style.chatBubbleLocalView
424
- : style.chatBubbleRemoteView,
441
+ : {
442
+ ...style.chatBubbleRemoteView,
443
+ ...(remoteUIConfig?.bubbleStyleLayer1 || {}),
444
+ },
425
445
  isURL(message) ? {maxWidth: '88%'} : {},
426
446
  ]}>
427
447
  {isHovered && !isDeleted && (
@@ -438,7 +458,10 @@ const ChatBubble = (props: ChatBubbleProps) => {
438
458
  style={[
439
459
  isLocal
440
460
  ? style.chatBubbleLocalViewLayer2
441
- : style.chatBubbleRemoteViewLayer2,
461
+ : {
462
+ ...style.chatBubbleRemoteViewLayer2,
463
+ ...(remoteUIConfig?.bubbleStyleLayer2 || {}),
464
+ },
442
465
  type === ChatMessageType.IMAGE && style.chatBubbleViewImg,
443
466
  ]}>
444
467
  {isDeleted ? (
@@ -454,9 +477,7 @@ const ChatBubble = (props: ChatBubbleProps) => {
454
477
  style.messageStyle,
455
478
  {color: $config.SEMANTIC_NEUTRAL, marginLeft: 5},
456
479
  ]}>
457
- {chatMsgDeletedTxt(
458
- isLocal ? 'You' : defaultContent[uid]?.name,
459
- )}
480
+ {chatMsgDeletedTxt(getUsername())}
460
481
  </Text>
461
482
  </View>
462
483
  ) : (
@@ -530,9 +551,7 @@ const ChatBubble = (props: ChatBubbleProps) => {
530
551
  imageUrl={url}
531
552
  msgId={msgId}
532
553
  fileName={fileName}
533
- senderName={
534
- isLocal ? 'You' : defaultContent[uid]?.name
535
- }
554
+ senderName={getUsername()}
536
555
  timestamp={createdTimestamp}
537
556
  isLocal={isLocal}
538
557
  />
@@ -102,7 +102,9 @@ export default function FallbackLogo(
102
102
  const styles = StyleSheet.create({
103
103
  container: {
104
104
  flex: 1,
105
- backgroundColor: $config.VIDEO_AUDIO_TILE_COLOR,
105
+ backgroundColor: $config.ENABLE_CONVERSATIONAL_AI
106
+ ? '#333'
107
+ : $config.VIDEO_AUDIO_TILE_COLOR,
106
108
  justifyContent: 'center',
107
109
  },
108
110
  // activeSpeakerBg: {
@@ -49,6 +49,9 @@ export interface LocalAudioMuteProps {
49
49
  render?: (onPress: () => void, isAudioEnabled: boolean) => JSX.Element;
50
50
  disabled?: boolean;
51
51
  showWarningIcon?: boolean;
52
+ iconBGColor?: string;
53
+ iconSize?: number;
54
+ containerStyle?: object;
52
55
  }
53
56
 
54
57
  function LocalAudioMute(props: LocalAudioMuteProps) {
@@ -100,12 +103,25 @@ function LocalAudioMute(props: LocalAudioMuteProps) {
100
103
  ? micButtonLabel(I18nDeviceStatus.ON)
101
104
  : micButtonLabel(I18nDeviceStatus.OFF);
102
105
 
106
+ let iconSize = props?.iconSize
107
+ ? {
108
+ iconSize: props?.iconSize,
109
+ }
110
+ : {};
111
+
112
+ let containerStyle = props?.containerStyle
113
+ ? {
114
+ iconContainerStyle: props?.containerStyle,
115
+ }
116
+ : {};
117
+
103
118
  let iconProps: IconButtonProps['iconProps'] = {
104
119
  showWarningIcon: permissionDenied && showWarningIcon ? true : false,
105
120
  name: isAudioEnabled ? 'mic-on' : 'mic-off',
106
-
107
121
  iconBackgroundColor: isAudioEnabled
108
- ? $config.PRIMARY_ACTION_BRAND_COLOR
122
+ ? props?.iconBGColor
123
+ ? props.iconBGColor
124
+ : $config.PRIMARY_ACTION_BRAND_COLOR
109
125
  : '',
110
126
  tintColor: isAudioEnabled
111
127
  ? $config.PRIMARY_ACTION_TEXT_COLOR
@@ -117,6 +133,8 @@ function LocalAudioMute(props: LocalAudioMuteProps) {
117
133
  ...(props?.iconProps
118
134
  ? props.iconProps(isAudioEnabled, permissionDenied)
119
135
  : {}),
136
+ ...iconSize,
137
+ ...containerStyle,
120
138
  };
121
139
 
122
140
  let iconButtonProps: IconButtonProps = {
@@ -81,10 +81,9 @@ export function isURL(str) {
81
81
  if (!str) {
82
82
  return false;
83
83
  }
84
- var urlRegex =
85
- '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$';
86
- var url = new RegExp(urlRegex, 'i');
87
- return str.length < 2083 && url.test(str);
84
+ if (str?.indexOf('https') !== -1) {
85
+ return true;
86
+ }
88
87
  }
89
88
 
90
89
  export const base64ToUint8Array = (base64Str: string) => {
@@ -45,6 +45,13 @@ const JOIN_CHANNEL_PHRASE_AND_GET_USER = gql`
45
45
  rtm
46
46
  uid
47
47
  }
48
+ agents {
49
+ id
50
+ agent_type
51
+ model
52
+ agent_name
53
+ voice
54
+ }
48
55
  }
49
56
  getUser {
50
57
  name
@@ -88,6 +95,13 @@ const JOIN_CHANNEL_PHRASE = gql`
88
95
  rtm
89
96
  uid
90
97
  }
98
+ agents {
99
+ id
100
+ agent_type
101
+ model
102
+ agent_name
103
+ voice
104
+ }
91
105
  }
92
106
  }
93
107
  `;
@@ -0,0 +1,31 @@
1
+ import {DispatchContext, useContent} from 'customization-api';
2
+ import {useContext, useEffect} from 'react';
3
+ import {EventNames} from '../rtm-events';
4
+ import events from '../rtm-events-api';
5
+
6
+ export const useSpotlight = () => {
7
+ const {spotlightUid} = useContent();
8
+ const {dispatch} = useContext(DispatchContext);
9
+
10
+ useEffect(() => {
11
+ events.on(EventNames.SPOTLIGHT_USER_CHANGED, ({payload}) => {
12
+ if (payload) {
13
+ const data = JSON.parse(payload);
14
+ if (data && data?.user_id) {
15
+ setSpotlightUid(data?.user_id);
16
+ } else {
17
+ setSpotlightUid(0);
18
+ }
19
+ }
20
+ });
21
+ }, []);
22
+
23
+ const setSpotlightUid = (uid: number) => {
24
+ dispatch({
25
+ type: 'Spotlight',
26
+ value: [uid],
27
+ });
28
+ };
29
+
30
+ return {spotlightUid, setSpotlightUid};
31
+ };
@@ -1,30 +1,32 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  /* Basic Options */
4
- "target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
5
- "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
6
- "lib": ["es6", "DOM"], /* Specify library files to be included in the compilation. */
7
- "typeRoots": [
8
- "./global.d.ts"
9
- ],
10
- "allowJs": true, /* Allow javascript files to be compiled. */
4
+ "target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
5
+ "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
6
+ "lib": [
7
+ "es6",
8
+ "DOM",
9
+ "es2023"
10
+ ] /* Specify library files to be included in the compilation. */,
11
+ "typeRoots": ["./global.d.ts"],
12
+ "allowJs": true /* Allow javascript files to be compiled. */,
11
13
  // "checkJs": true, /* Report errors in .js files. */
12
- "jsx": "react-native", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
13
- "declaration": true, /* Generates corresponding '.d.ts' file. */
14
+ "jsx": "react-native" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
15
+ "declaration": true /* Generates corresponding '.d.ts' file. */,
14
16
  // "sourceMap": true, /* Generates corresponding '.map' file. */
15
17
  // "outFile": "./", /* Concatenate and emit output to single file. */
16
18
  // "outDir": "./", /* Redirect output structure to the directory. */
17
19
  // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
18
20
  // "removeComments": true, /* Do not emit comments to output. */
19
- "noEmit": false, /* Do not emit outputs. */
21
+ "noEmit": false /* Do not emit outputs. */,
20
22
  // "incremental": true, /* Enable incremental compilation */
21
23
  // "importHelpers": true, /* Import emit helpers from 'tslib'. */
22
24
  // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
23
- "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
25
+ "isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */,
24
26
 
25
27
  /* Strict Type-Checking Options */
26
- "strict": false, /* Enable all strict type-checking options. */
27
- "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
28
+ "strict": false /* Enable all strict type-checking options. */,
29
+ "noImplicitAny": false /* Raise error on expressions and declarations with an implied 'any' type. */,
28
30
  // "strictNullChecks": true, /* Enable strict null checks. */
29
31
  // "strictFunctionTypes": true, /* Enable strict checking of function types. */
30
32
  // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
@@ -38,15 +40,15 @@
38
40
  // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
39
41
 
40
42
  /* Module Resolution Options */
41
- "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
42
- "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
43
+ "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
44
+ "baseUrl": "./" /* Base directory to resolve non-absolute module names. */,
43
45
  "resolveJsonModule": true,
44
46
  // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
45
47
  // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
46
48
  // "typeRoots": [], /* List of folders to include type definitions from. */
47
49
  // "types": [], /* Type declaration files to be included in compilation. */
48
- "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
49
- "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
50
+ "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
51
+ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
50
52
  // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
51
53
 
52
54
  /* Source Map Options */
@@ -60,6 +62,9 @@
60
62
  // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
61
63
  },
62
64
  "exclude": [
63
- "node_modules", "babel.config.js", "metro.config.js", "jest.config.js"
65
+ "node_modules",
66
+ "babel.config.js",
67
+ "metro.config.js",
68
+ "jest.config.js"
64
69
  ]
65
70
  }