@tellescope/react-components 1.240.0 → 1.242.0

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 (76) hide show
  1. package/lib/cjs/Forms/inputs.d.ts +1 -1
  2. package/lib/cjs/TwilioVideo/TwilioControls.d.ts +8 -0
  3. package/lib/cjs/TwilioVideo/TwilioControls.d.ts.map +1 -0
  4. package/lib/cjs/TwilioVideo/TwilioControls.js +57 -0
  5. package/lib/cjs/TwilioVideo/TwilioControls.js.map +1 -0
  6. package/lib/cjs/TwilioVideo/TwilioLocalPreview.d.ts +6 -0
  7. package/lib/cjs/TwilioVideo/TwilioLocalPreview.d.ts.map +1 -0
  8. package/lib/cjs/TwilioVideo/TwilioLocalPreview.js +173 -0
  9. package/lib/cjs/TwilioVideo/TwilioLocalPreview.js.map +1 -0
  10. package/lib/cjs/TwilioVideo/TwilioParticipant.d.ts +11 -0
  11. package/lib/cjs/TwilioVideo/TwilioParticipant.d.ts.map +1 -0
  12. package/lib/cjs/TwilioVideo/TwilioParticipant.js +98 -0
  13. package/lib/cjs/TwilioVideo/TwilioParticipant.js.map +1 -0
  14. package/lib/cjs/TwilioVideo/TwilioVideoContext.d.ts +28 -0
  15. package/lib/cjs/TwilioVideo/TwilioVideoContext.d.ts.map +1 -0
  16. package/lib/cjs/TwilioVideo/TwilioVideoContext.js +222 -0
  17. package/lib/cjs/TwilioVideo/TwilioVideoContext.js.map +1 -0
  18. package/lib/cjs/TwilioVideo/TwilioVideoRoom.d.ts +10 -0
  19. package/lib/cjs/TwilioVideo/TwilioVideoRoom.d.ts.map +1 -0
  20. package/lib/cjs/TwilioVideo/TwilioVideoRoom.js +49 -0
  21. package/lib/cjs/TwilioVideo/TwilioVideoRoom.js.map +1 -0
  22. package/lib/cjs/TwilioVideo/hooks.d.ts +44 -0
  23. package/lib/cjs/TwilioVideo/hooks.d.ts.map +1 -0
  24. package/lib/cjs/TwilioVideo/hooks.js +232 -0
  25. package/lib/cjs/TwilioVideo/hooks.js.map +1 -0
  26. package/lib/cjs/TwilioVideo/index.d.ts +7 -0
  27. package/lib/cjs/TwilioVideo/index.d.ts.map +1 -0
  28. package/lib/cjs/TwilioVideo/index.js +19 -0
  29. package/lib/cjs/TwilioVideo/index.js.map +1 -0
  30. package/lib/cjs/index.d.ts +1 -0
  31. package/lib/cjs/index.d.ts.map +1 -1
  32. package/lib/cjs/index.js +1 -0
  33. package/lib/cjs/index.js.map +1 -1
  34. package/lib/esm/Forms/inputs.d.ts +1 -1
  35. package/lib/esm/TwilioVideo/TwilioControls.d.ts +8 -0
  36. package/lib/esm/TwilioVideo/TwilioControls.d.ts.map +1 -0
  37. package/lib/esm/TwilioVideo/TwilioControls.js +53 -0
  38. package/lib/esm/TwilioVideo/TwilioControls.js.map +1 -0
  39. package/lib/esm/TwilioVideo/TwilioLocalPreview.d.ts +6 -0
  40. package/lib/esm/TwilioVideo/TwilioLocalPreview.d.ts.map +1 -0
  41. package/lib/esm/TwilioVideo/TwilioLocalPreview.js +166 -0
  42. package/lib/esm/TwilioVideo/TwilioLocalPreview.js.map +1 -0
  43. package/lib/esm/TwilioVideo/TwilioParticipant.d.ts +11 -0
  44. package/lib/esm/TwilioVideo/TwilioParticipant.d.ts.map +1 -0
  45. package/lib/esm/TwilioVideo/TwilioParticipant.js +94 -0
  46. package/lib/esm/TwilioVideo/TwilioParticipant.js.map +1 -0
  47. package/lib/esm/TwilioVideo/TwilioVideoContext.d.ts +28 -0
  48. package/lib/esm/TwilioVideo/TwilioVideoContext.d.ts.map +1 -0
  49. package/lib/esm/TwilioVideo/TwilioVideoContext.js +214 -0
  50. package/lib/esm/TwilioVideo/TwilioVideoContext.js.map +1 -0
  51. package/lib/esm/TwilioVideo/TwilioVideoRoom.d.ts +10 -0
  52. package/lib/esm/TwilioVideo/TwilioVideoRoom.d.ts.map +1 -0
  53. package/lib/esm/TwilioVideo/TwilioVideoRoom.js +45 -0
  54. package/lib/esm/TwilioVideo/TwilioVideoRoom.js.map +1 -0
  55. package/lib/esm/TwilioVideo/hooks.d.ts +44 -0
  56. package/lib/esm/TwilioVideo/hooks.d.ts.map +1 -0
  57. package/lib/esm/TwilioVideo/hooks.js +226 -0
  58. package/lib/esm/TwilioVideo/hooks.js.map +1 -0
  59. package/lib/esm/TwilioVideo/index.d.ts +7 -0
  60. package/lib/esm/TwilioVideo/index.d.ts.map +1 -0
  61. package/lib/esm/TwilioVideo/index.js +7 -0
  62. package/lib/esm/TwilioVideo/index.js.map +1 -0
  63. package/lib/esm/index.d.ts +1 -0
  64. package/lib/esm/index.d.ts.map +1 -1
  65. package/lib/esm/index.js +1 -0
  66. package/lib/esm/index.js.map +1 -1
  67. package/lib/tsconfig.tsbuildinfo +1 -1
  68. package/package.json +12 -11
  69. package/src/TwilioVideo/TwilioControls.tsx +110 -0
  70. package/src/TwilioVideo/TwilioLocalPreview.tsx +151 -0
  71. package/src/TwilioVideo/TwilioParticipant.tsx +136 -0
  72. package/src/TwilioVideo/TwilioVideoContext.tsx +198 -0
  73. package/src/TwilioVideo/TwilioVideoRoom.tsx +98 -0
  74. package/src/TwilioVideo/hooks.ts +159 -0
  75. package/src/TwilioVideo/index.ts +19 -0
  76. package/src/index.ts +2 -1
@@ -0,0 +1,98 @@
1
+ import React from 'react'
2
+ import { Box, Grid } from '@mui/material'
3
+ import { useTwilioVideo } from './TwilioVideoContext'
4
+ import { TwilioParticipant } from './TwilioParticipant'
5
+ import { TwilioControlBar } from './TwilioControls'
6
+
7
+ export interface TwilioVideoRoomProps {
8
+ onLeave?: () => void
9
+ onEndForAll?: () => void
10
+ style?: React.CSSProperties
11
+ /** Resolve participant identity to a display label. Defaults to empty string. */
12
+ resolveIdentity?: (identity: string) => string
13
+ }
14
+
15
+ export const TwilioVideoRoom: React.FC<TwilioVideoRoomProps> = ({
16
+ onLeave,
17
+ onEndForAll,
18
+ style,
19
+ resolveIdentity,
20
+ }) => {
21
+ const { room, participants } = useTwilioVideo()
22
+
23
+ if (!room) return null
24
+
25
+ const localParticipant = room.localParticipant
26
+ const hasRemoteParticipants = participants.length > 0
27
+
28
+ return (
29
+ <Box
30
+ sx={{
31
+ display: 'flex',
32
+ flexDirection: 'column',
33
+ height: '100%',
34
+ width: '100%',
35
+ backgroundColor: '#1a1a1a',
36
+ ...style,
37
+ }}
38
+ >
39
+ {/* Video grid */}
40
+ <Box
41
+ sx={{
42
+ flex: 1,
43
+ position: 'relative',
44
+ overflow: 'hidden',
45
+ }}
46
+ >
47
+ {/* Remote participants */}
48
+ {hasRemoteParticipants ? (
49
+ <Grid
50
+ container
51
+ sx={{
52
+ height: '100%',
53
+ width: '100%',
54
+ }}
55
+ >
56
+ {participants.map((participant) => (
57
+ <Grid
58
+ item
59
+ key={participant.sid}
60
+ xs={participants.length === 1 ? 12 : 6}
61
+ sx={{ height: participants.length <= 2 ? '100%' : '50%' }}
62
+ >
63
+ <TwilioParticipant participant={participant} resolveIdentity={resolveIdentity} />
64
+ </Grid>
65
+ ))}
66
+ </Grid>
67
+ ) : (
68
+ // When alone, show local video larger
69
+ <Box sx={{ height: '100%', width: '100%' }}>
70
+ <TwilioParticipant participant={localParticipant} isLocal resolveIdentity={resolveIdentity} />
71
+ </Box>
72
+ )}
73
+
74
+ {/* Local participant (small, corner) - only when there are remote participants */}
75
+ {hasRemoteParticipants && (
76
+ <Box
77
+ sx={{
78
+ position: 'absolute',
79
+ top: 16,
80
+ right: 16,
81
+ width: 200,
82
+ height: 150,
83
+ zIndex: 10,
84
+ borderRadius: 1,
85
+ overflow: 'hidden',
86
+ boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
87
+ }}
88
+ >
89
+ <TwilioParticipant participant={localParticipant} isLocal resolveIdentity={resolveIdentity} />
90
+ </Box>
91
+ )}
92
+ </Box>
93
+
94
+ {/* Control bar */}
95
+ <TwilioControlBar onLeave={onLeave} onEndForAll={onEndForAll} />
96
+ </Box>
97
+ )
98
+ }
@@ -0,0 +1,159 @@
1
+ import { useCallback, useState } from 'react'
2
+ import { useResolvedSession, useSession } from '../authentication'
3
+ import { useCalendarEvents, useMeetings } from '../state'
4
+ import { useTwilioVideo } from './TwilioVideoContext'
5
+ import { CalendarEvent } from '@tellescope/types-client'
6
+ import { AttendeeInfo } from '@tellescope/types-models'
7
+
8
+ /**
9
+ * Hook for hosts to start a Twilio Video call for a calendar event
10
+ */
11
+ export const useStartTwilioVideoCall = (calendarEventId?: string) => {
12
+ const session = useSession()
13
+ const { connect, disconnect, setIsHost, room, isConnected } = useTwilioVideo()
14
+ const [, { updateLocalElement: updateLocalEvent }] = useCalendarEvents()
15
+ const [starting, setStarting] = useState(false)
16
+ const [ending, setEnding] = useState(false)
17
+
18
+ const startMeeting = useCallback(async (eventId?: string) => {
19
+ const targetEventId = eventId || calendarEventId
20
+ if (!targetEventId) {
21
+ throw new Error('No calendar event ID provided')
22
+ }
23
+
24
+ setStarting(true)
25
+ try {
26
+ // Call backend to create Twilio room and get access token
27
+ const response = await session.api.meetings.start_meeting_for_event({
28
+ calendarEventId: targetEventId,
29
+ })
30
+
31
+ // Update local event with meetingId
32
+ updateLocalEvent(targetEventId, { meetingId: response.id })
33
+
34
+ // The host info contains the Twilio token (mapped to JoinToken field)
35
+ const hostInfo = response.host.info as AttendeeInfo
36
+ const roomName = response.meeting.Meeting.ExternalMeetingId || response.id
37
+
38
+ setIsHost(true)
39
+ await connect(hostInfo.JoinToken, roomName)
40
+
41
+ return response.id
42
+ } catch (err) {
43
+ console.error('Failed to start Twilio meeting:', err)
44
+ throw err
45
+ } finally {
46
+ setStarting(false)
47
+ }
48
+ }, [session, calendarEventId, connect, setIsHost, updateLocalEvent])
49
+
50
+ const endMeeting = useCallback(async (meetingId: string) => {
51
+ setEnding(true)
52
+ try {
53
+ await session.api.meetings.end_meeting({ id: meetingId })
54
+ disconnect()
55
+ } catch (err) {
56
+ console.error('Failed to end Twilio meeting:', err)
57
+ throw err
58
+ } finally {
59
+ setEnding(false)
60
+ }
61
+ }, [session, disconnect])
62
+
63
+ return {
64
+ starting,
65
+ ending,
66
+ room,
67
+ isConnected,
68
+ startMeeting,
69
+ endMeeting,
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Hook for participants to join a Twilio Video call
75
+ */
76
+ export const useJoinTwilioVideoCall = () => {
77
+ const session = useResolvedSession()
78
+ const { connect, disconnect, room, isConnected } = useTwilioVideo()
79
+ const [joining, setJoining] = useState(false)
80
+
81
+ const joinMeeting = useCallback(async (calendarEventId: string) => {
82
+ setJoining(true)
83
+ try {
84
+ // Call backend to get access token for the room
85
+ const response = await session.api.meetings.join_meeting_for_event({
86
+ calendarEventId,
87
+ })
88
+
89
+ const attendeeInfo = response.attendee.info as AttendeeInfo
90
+ const roomName = response.meeting.Meeting.ExternalMeetingId || response.id
91
+
92
+ await connect(attendeeInfo.JoinToken, roomName)
93
+ } catch (err) {
94
+ console.error('Failed to join Twilio meeting:', err)
95
+ throw err
96
+ } finally {
97
+ setJoining(false)
98
+ }
99
+ }, [session, connect])
100
+
101
+ const leaveMeeting = useCallback(() => {
102
+ disconnect()
103
+ }, [disconnect])
104
+
105
+ return {
106
+ joining,
107
+ room,
108
+ isConnected,
109
+ joinMeeting,
110
+ leaveMeeting,
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Hook for calendar event-based Twilio Video calls
116
+ * Combines start and join functionality with meeting status polling
117
+ */
118
+ export const useTwilioMeetingForCalendarEvent = (calendarEventId: string) => {
119
+ const session = useResolvedSession()
120
+ const { room, isConnected } = useTwilioVideo()
121
+ const { startMeeting, starting } = useStartTwilioVideoCall(calendarEventId)
122
+ const { joinMeeting, joining } = useJoinTwilioVideoCall()
123
+ const [, { findById: findEvent }] = useCalendarEvents()
124
+ const [, { findById: findMeeting }] = useMeetings()
125
+
126
+ const event = findEvent(calendarEventId)
127
+ const meeting = event?.meetingId ? findMeeting(event.meetingId) : undefined
128
+
129
+ const startAndJoinMeeting = useCallback(async () => {
130
+ await startMeeting(calendarEventId)
131
+ }, [startMeeting, calendarEventId])
132
+
133
+ const join = useCallback(async () => {
134
+ await joinMeeting(calendarEventId)
135
+ }, [joinMeeting, calendarEventId])
136
+
137
+ const isHost = session.userInfo.id === event?.creator
138
+
139
+ return {
140
+ event,
141
+ meeting,
142
+ room,
143
+ isConnected,
144
+ isHost,
145
+ starting,
146
+ joining,
147
+ startAndJoinMeeting,
148
+ joinMeeting: join,
149
+ meetingStatus: (
150
+ event?.videoIntegration !== 'Twilio'
151
+ ? 'disabled'
152
+ : !event?.meetingId
153
+ ? 'waiting-room'
154
+ : isConnected
155
+ ? 'joined'
156
+ : 'loading'
157
+ ) as 'disabled' | 'waiting-room' | 'joined' | 'loading',
158
+ }
159
+ }
@@ -0,0 +1,19 @@
1
+ export {
2
+ TwilioVideoProvider,
3
+ useTwilioVideo,
4
+ type TwilioVideoState,
5
+ type TwilioVideoActions,
6
+ type TwilioVideoContextType,
7
+ type TwilioVideoProviderProps,
8
+ } from './TwilioVideoContext'
9
+
10
+ export {
11
+ useStartTwilioVideoCall,
12
+ useJoinTwilioVideoCall,
13
+ useTwilioMeetingForCalendarEvent,
14
+ } from './hooks'
15
+
16
+ export { TwilioParticipant, type TwilioParticipantProps } from './TwilioParticipant'
17
+ export { TwilioControlBar, type TwilioControlBarProps } from './TwilioControls'
18
+ export { TwilioVideoRoom, type TwilioVideoRoomProps } from './TwilioVideoRoom'
19
+ export { TwilioLocalPreview, type TwilioLocalPreviewProps } from './TwilioLocalPreview'
package/src/index.ts CHANGED
@@ -16,4 +16,5 @@ export * from "./theme"
16
16
  export * from "./Forms/index"
17
17
  export * from "./Community/index"
18
18
  export * from "./CMS/index"
19
- export * from "./Calendar/index"
19
+ export * from "./Calendar/index"
20
+ export * from "./TwilioVideo/index"