1- import { Box , Chip , Icon , IconButton , Icons , Text , Tooltip , TooltipProvider } from 'folds' ;
2- import { useState } from 'react' ;
1+ import { Box , Chip , Icon , IconButton , Icons , Spinner , Text , Tooltip , TooltipProvider } from 'folds' ;
2+ import { useCallback } from 'react' ;
3+ import { useSetAtom } from 'jotai' ;
34import { StatusDivider } from './components' ;
45import { CallEmbed , useCallControlState } from '../../plugins/call' ;
6+ import { AsyncStatus , useAsyncCallback } from '../../hooks/useAsyncCallback' ;
7+ import { callEmbedAtom } from '../../state/callEmbed' ;
58
69type MicrophoneButtonProps = {
710 enabled : boolean ;
811 onToggle : ( ) => Promise < unknown > ;
12+ disabled ?: boolean ;
913} ;
10- function MicrophoneButton ( { enabled, onToggle } : MicrophoneButtonProps ) {
14+ function MicrophoneButton ( { enabled, onToggle, disabled } : MicrophoneButtonProps ) {
1115 return (
1216 < TooltipProvider
1317 position = "Top"
@@ -26,6 +30,7 @@ function MicrophoneButton({ enabled, onToggle }: MicrophoneButtonProps) {
2630 size = "300"
2731 onClick = { ( ) => onToggle ( ) }
2832 outlined
33+ disabled = { disabled }
2934 >
3035 < Icon size = "100" src = { enabled ? Icons . Mic : Icons . MicMute } filled = { ! enabled } />
3136 </ IconButton >
@@ -37,8 +42,9 @@ function MicrophoneButton({ enabled, onToggle }: MicrophoneButtonProps) {
3742type SoundButtonProps = {
3843 enabled : boolean ;
3944 onToggle : ( ) => void ;
45+ disabled ?: boolean ;
4046} ;
41- function SoundButton ( { enabled, onToggle } : SoundButtonProps ) {
47+ function SoundButton ( { enabled, onToggle, disabled } : SoundButtonProps ) {
4248 return (
4349 < TooltipProvider
4450 position = "Top"
@@ -57,6 +63,7 @@ function SoundButton({ enabled, onToggle }: SoundButtonProps) {
5763 size = "300"
5864 onClick = { ( ) => onToggle ( ) }
5965 outlined
66+ disabled = { disabled }
6067 >
6168 < Icon
6269 size = "100"
@@ -72,8 +79,9 @@ function SoundButton({ enabled, onToggle }: SoundButtonProps) {
7279type VideoButtonProps = {
7380 enabled : boolean ;
7481 onToggle : ( ) => Promise < unknown > ;
82+ disabled ?: boolean ;
7583} ;
76- function VideoButton ( { enabled, onToggle } : VideoButtonProps ) {
84+ function VideoButton ( { enabled, onToggle, disabled } : VideoButtonProps ) {
7785 return (
7886 < TooltipProvider
7987 position = "Top"
@@ -92,6 +100,7 @@ function VideoButton({ enabled, onToggle }: VideoButtonProps) {
92100 size = "300"
93101 onClick = { ( ) => onToggle ( ) }
94102 outlined
103+ disabled = { disabled }
95104 >
96105 < Icon
97106 size = "100"
@@ -104,9 +113,12 @@ function VideoButton({ enabled, onToggle }: VideoButtonProps) {
104113 ) ;
105114}
106115
107- function ScreenShareButton ( ) {
108- const [ enabled , setEnabled ] = useState ( false ) ;
109-
116+ type ScreenShareButtonProps = {
117+ enabled : boolean ;
118+ onToggle : ( ) => void ;
119+ disabled ?: boolean ;
120+ } ;
121+ function ScreenShareButton ( { enabled, onToggle, disabled } : ScreenShareButtonProps ) {
110122 return (
111123 < TooltipProvider
112124 position = "Top"
@@ -123,8 +135,9 @@ function ScreenShareButton() {
123135 fill = "Soft"
124136 radii = "300"
125137 size = "300"
126- onClick = { ( ) => setEnabled ( ! enabled ) }
138+ onClick = { onToggle }
127139 outlined
140+ disabled = { disabled }
128141 >
129142 < Icon size = "100" src = { Icons . ScreenShare } filled = { enabled } />
130143 </ IconButton >
@@ -133,32 +146,80 @@ function ScreenShareButton() {
133146 ) ;
134147}
135148
136- export function CallControl ( { callEmbed } : { callEmbed : CallEmbed } ) {
137- const { microphone, video, sound } = useCallControlState ( callEmbed . control ) ;
149+ export function CallControl ( {
150+ callEmbed,
151+ compact,
152+ callJoined,
153+ } : {
154+ callEmbed : CallEmbed ;
155+ compact : boolean ;
156+ callJoined : boolean ;
157+ } ) {
158+ const { microphone, video, sound, screenshare } = useCallControlState ( callEmbed . control ) ;
159+ const setCallEmbed = useSetAtom ( callEmbedAtom ) ;
160+
161+ const [ hangupState , hangup ] = useAsyncCallback (
162+ useCallback ( ( ) => callEmbed . hangup ( ) , [ callEmbed ] )
163+ ) ;
164+ const exiting =
165+ hangupState . status === AsyncStatus . Loading || hangupState . status === AsyncStatus . Success ;
166+
167+ const handleHangup = ( ) => {
168+ if ( ! callJoined ) {
169+ setCallEmbed ( undefined ) ;
170+ return ;
171+ }
172+ hangup ( ) ;
173+ } ;
138174
139175 return (
140176 < Box shrink = "No" alignItems = "Center" gap = "300" >
141177 < Box alignItems = "Inherit" gap = "200" >
142178 < MicrophoneButton
143179 enabled = { microphone }
144180 onToggle = { ( ) => callEmbed . control . toggleMicrophone ( ) }
181+ disabled = { ! callJoined }
182+ />
183+ < SoundButton
184+ enabled = { sound }
185+ onToggle = { ( ) => callEmbed . control . toggleSound ( ) }
186+ disabled = { ! callJoined }
145187 />
146- < SoundButton enabled = { sound } onToggle = { ( ) => callEmbed . control . toggleSound ( ) } />
147- < VideoButton enabled = { video } onToggle = { ( ) => callEmbed . control . toggleVideo ( ) } />
148- { false && < ScreenShareButton /> }
188+ { ! compact && < StatusDivider /> }
189+ < VideoButton
190+ enabled = { video }
191+ onToggle = { ( ) => callEmbed . control . toggleVideo ( ) }
192+ disabled = { ! callJoined }
193+ />
194+ { ! compact && (
195+ < ScreenShareButton
196+ enabled = { screenshare }
197+ onToggle = { ( ) => callEmbed . control . toggleScreenshare ( ) }
198+ disabled = { ! callJoined }
199+ />
200+ ) }
149201 </ Box >
150202 < StatusDivider />
151203 < Chip
152204 variant = "Critical"
153- radii = "300 "
205+ radii = "Pill "
154206 fill = "Soft"
155- before = { < Icon size = "50" src = { Icons . PhoneDown } filled /> }
207+ before = {
208+ exiting ? (
209+ < Spinner variant = "Critical" fill = "Soft" size = "50" />
210+ ) : (
211+ < Icon size = "50" src = { Icons . PhoneDown } filled />
212+ )
213+ }
214+ disabled = { exiting }
156215 outlined
157- onClick = { ( ) => callEmbed . hangup ( ) }
216+ onClick = { handleHangup }
158217 >
159- < Text as = "span" size = "L400" >
160- End
161- </ Text >
218+ { ! compact && (
219+ < Text as = "span" size = "L400" >
220+ End
221+ </ Text >
222+ ) }
162223 </ Chip >
163224 </ Box >
164225 ) ;
0 commit comments