@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.
- package/lib/cjs/Forms/inputs.d.ts +1 -1
- package/lib/cjs/TwilioVideo/TwilioControls.d.ts +8 -0
- package/lib/cjs/TwilioVideo/TwilioControls.d.ts.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioControls.js +57 -0
- package/lib/cjs/TwilioVideo/TwilioControls.js.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioLocalPreview.d.ts +6 -0
- package/lib/cjs/TwilioVideo/TwilioLocalPreview.d.ts.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioLocalPreview.js +173 -0
- package/lib/cjs/TwilioVideo/TwilioLocalPreview.js.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioParticipant.d.ts +11 -0
- package/lib/cjs/TwilioVideo/TwilioParticipant.d.ts.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioParticipant.js +98 -0
- package/lib/cjs/TwilioVideo/TwilioParticipant.js.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioVideoContext.d.ts +28 -0
- package/lib/cjs/TwilioVideo/TwilioVideoContext.d.ts.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioVideoContext.js +222 -0
- package/lib/cjs/TwilioVideo/TwilioVideoContext.js.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioVideoRoom.d.ts +10 -0
- package/lib/cjs/TwilioVideo/TwilioVideoRoom.d.ts.map +1 -0
- package/lib/cjs/TwilioVideo/TwilioVideoRoom.js +49 -0
- package/lib/cjs/TwilioVideo/TwilioVideoRoom.js.map +1 -0
- package/lib/cjs/TwilioVideo/hooks.d.ts +44 -0
- package/lib/cjs/TwilioVideo/hooks.d.ts.map +1 -0
- package/lib/cjs/TwilioVideo/hooks.js +232 -0
- package/lib/cjs/TwilioVideo/hooks.js.map +1 -0
- package/lib/cjs/TwilioVideo/index.d.ts +7 -0
- package/lib/cjs/TwilioVideo/index.d.ts.map +1 -0
- package/lib/cjs/TwilioVideo/index.js +19 -0
- package/lib/cjs/TwilioVideo/index.js.map +1 -0
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/Forms/inputs.d.ts +1 -1
- package/lib/esm/TwilioVideo/TwilioControls.d.ts +8 -0
- package/lib/esm/TwilioVideo/TwilioControls.d.ts.map +1 -0
- package/lib/esm/TwilioVideo/TwilioControls.js +53 -0
- package/lib/esm/TwilioVideo/TwilioControls.js.map +1 -0
- package/lib/esm/TwilioVideo/TwilioLocalPreview.d.ts +6 -0
- package/lib/esm/TwilioVideo/TwilioLocalPreview.d.ts.map +1 -0
- package/lib/esm/TwilioVideo/TwilioLocalPreview.js +166 -0
- package/lib/esm/TwilioVideo/TwilioLocalPreview.js.map +1 -0
- package/lib/esm/TwilioVideo/TwilioParticipant.d.ts +11 -0
- package/lib/esm/TwilioVideo/TwilioParticipant.d.ts.map +1 -0
- package/lib/esm/TwilioVideo/TwilioParticipant.js +94 -0
- package/lib/esm/TwilioVideo/TwilioParticipant.js.map +1 -0
- package/lib/esm/TwilioVideo/TwilioVideoContext.d.ts +28 -0
- package/lib/esm/TwilioVideo/TwilioVideoContext.d.ts.map +1 -0
- package/lib/esm/TwilioVideo/TwilioVideoContext.js +214 -0
- package/lib/esm/TwilioVideo/TwilioVideoContext.js.map +1 -0
- package/lib/esm/TwilioVideo/TwilioVideoRoom.d.ts +10 -0
- package/lib/esm/TwilioVideo/TwilioVideoRoom.d.ts.map +1 -0
- package/lib/esm/TwilioVideo/TwilioVideoRoom.js +45 -0
- package/lib/esm/TwilioVideo/TwilioVideoRoom.js.map +1 -0
- package/lib/esm/TwilioVideo/hooks.d.ts +44 -0
- package/lib/esm/TwilioVideo/hooks.d.ts.map +1 -0
- package/lib/esm/TwilioVideo/hooks.js +226 -0
- package/lib/esm/TwilioVideo/hooks.js.map +1 -0
- package/lib/esm/TwilioVideo/index.d.ts +7 -0
- package/lib/esm/TwilioVideo/index.d.ts.map +1 -0
- package/lib/esm/TwilioVideo/index.js +7 -0
- package/lib/esm/TwilioVideo/index.js.map +1 -0
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.d.ts.map +1 -1
- package/lib/esm/index.js +1 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -11
- package/src/TwilioVideo/TwilioControls.tsx +110 -0
- package/src/TwilioVideo/TwilioLocalPreview.tsx +151 -0
- package/src/TwilioVideo/TwilioParticipant.tsx +136 -0
- package/src/TwilioVideo/TwilioVideoContext.tsx +198 -0
- package/src/TwilioVideo/TwilioVideoRoom.tsx +98 -0
- package/src/TwilioVideo/hooks.ts +159 -0
- package/src/TwilioVideo/index.ts +19 -0
- 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