import { RainbowContext } from '../../store'; import React, { useEffect, useState } from 'react'; import { Alert, SectionList, SectionListData, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { Strings } from '../../resources/localization/Strings' import { IContact } from '../../store/contacts/types'; import { eventEmitter, EventType } from '../../services/EventEmitter'; import { giveOwnerShip, hangupParticipant, promoteBubbleParticipant, demoteBubbleParticipant, removeContactFromBubble } from '../../store/bubbles/bubblesSlice'; import { IBubble, IBubbleParticipant } from '../../store/bubbles/types'; import { ContactCardView } from '../contacts/ContactCardView'; import { checkIfAllUserAreMutedResult, muteAllParticipants, unMuteAllParticipants } from '../../store/conference/conferenceSlice'; import { Logger } from '../../utils/Log'; import { IConference, IConferenceParticipants } from '../../store/conference/types'; import { DropDownMenu } from '../common/DropDownMenu'; import Icon from 'react-native-vector-icons/FontAwesome5'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; const logger = new Logger('BubbleParticipantsList'); interface IProps { bubble: IBubble; conferenceCall?: IConference; } export const BubbleParticipants: React.FunctionComponent = ({ bubble, conferenceCall, }) => { const [conferenceAttendees, setConferenceAttendees] = useState(conferenceCall?.attendees ?? []); const { bubbleOwner, isMyUserOwner, isMyUserModerator, hasActiveConference, participants } = bubble; const dispatch = useAppDispatch(); const areAllConfUsersMuted = useAppSelector((state) => state.conference.areAllConfUsersMuted); useEffect(() => { const areAllConfUserMutedEvent = eventEmitter.addListener(EventType.AreAllConfUserMuted, (areAllConfUserMuted: boolean) => { logger.info(`AreAllConfUserMuted: ${areAllConfUserMuted}`); dispatch(checkIfAllUserAreMutedResult(areAllConfUserMuted)); }); const conferenceAttendeesUpdatesEvent = eventEmitter.addListener(EventType.ConferenceAttendeesUpdates, (attendees: IConferenceParticipants[]) => { logger.info(`get conference participants with count ${attendees?.length}`); setConferenceAttendees(attendees); }); //TODO: handle it as participant update // TODO: handle the failure case const removeContactFromBubbleResultEvent = eventEmitter.addListener(EventType.RemoveContactFromBubbleResult, (eventData: { members: IContact[], organizers: IContact[] }) => { logger.info(`addListener for ${EventType.RemoveContactFromBubbleResult} : ${eventData}`) // setBubbleMembersResult(eventData.members); // setOrganizers(eventData.organizers); }); const promoteBubbleOwnerResultEvent = eventEmitter.addListener(EventType.PromoteBubbleOwnerResult, (eventData: string) => { logger.info(`addListener for ${EventType.PromoteBubbleOwnerResult} : ${eventData}`); if (eventData === 'failure') { Alert.alert('Failure', 'Failed with promote the user to bubble owner'); } }); const hangUpParticipantFailedEvent = eventEmitter.addListener(EventType.HangUpParticipantFailed, (eventData: string) => { logger.info(`addListener for ${EventType.HangUpParticipantFailed} : ${eventData}`) Alert.alert('Failure', eventData) }); return () => { areAllConfUserMutedEvent.remove(); conferenceAttendeesUpdatesEvent.remove(); removeContactFromBubbleResultEvent.remove(); promoteBubbleOwnerResultEvent.remove(); hangUpParticipantFailedEvent.remove(); } }, [bubble, conferenceCall, areAllConfUsersMuted]); const onHangupParticipant = (bubbleId: string, participantJid: string) => { dispatch(hangupParticipant({bubbleId, contactJid: participantJid})) } enum BubbleParticipantOption { RemoveContact = 'Remove Contact', GiveOwnerShip = 'Give OwnerShip', HangupParticipant = 'Hang-Up participant', PromoteContact = 'Promote Contact', DemoteContact = 'Demote Contact' } const renderDropDown = (contact: IContact) => { const contactParticipant = contact as IBubbleParticipant; const { isMyUser } = contactParticipant; const contactJid = contactParticipant.jId; const ownerJId = bubbleOwner.jId; const options: BubbleParticipantOption[] = []; const isThisContactBubbleOwner = contactJid === ownerJId; const isUserOrganizer = contactParticipant.isModerator; const isMyUserAttendees = conferenceCall?.hasMyUserJoinedConferenceCall; const isParticipantConferenceIsOwner = conferenceCall?.isOwner; const canRemoveParticipant = isMyUserModerator && !isMyUser && !isThisContactBubbleOwner && !isMyUserAttendees; const canHangUpParticipant = isMyUserAttendees && isMyUserModerator && !isParticipantConferenceIsOwner && !isMyUser; const canGiveOwnerShipToParticipant = isMyUserOwner && isUserOrganizer && !isThisContactBubbleOwner && !isMyUser && !hasActiveConference; const canPromoteMember = !isMyUser && !isThisContactBubbleOwner && !isUserOrganizer && isMyUserModerator; const canDemoteOrganizer = !isMyUser && !isThisContactBubbleOwner && isUserOrganizer && isMyUserModerator; const handleOnParticipantMenuClicked = (item: string) => { switch (item) { case BubbleParticipantOption.RemoveContact: dispatch(removeContactFromBubble({bubbleId: bubble.id, contactJid})) break; case BubbleParticipantOption.GiveOwnerShip: dispatch(giveOwnerShip({bubbleId: bubble.id, contactJid})) break; case BubbleParticipantOption.HangupParticipant: onHangupParticipant(bubble.id, contactJid); break; case BubbleParticipantOption.PromoteContact: dispatch(promoteBubbleParticipant({bubbleId: bubble.id, contactJid})) break; case BubbleParticipantOption.DemoteContact: dispatch(demoteBubbleParticipant({bubbleId: bubble.id, contactJid})) break; } } if (canRemoveParticipant) { options.push(BubbleParticipantOption.RemoveContact); } if (canGiveOwnerShipToParticipant) { options.push(BubbleParticipantOption.GiveOwnerShip); } if (canHangUpParticipant) { options.push(BubbleParticipantOption.HangupParticipant); } if (canPromoteMember) { options.push(BubbleParticipantOption.PromoteContact); } if (canDemoteOrganizer) { options.push(BubbleParticipantOption.DemoteContact); } if (options.length > 0) { return } if (isThisContactBubbleOwner) { return } else { return null } }; const renderItem = ({ item }: { item?: IContact }) => { if (item) { return ( ); } return null; }; const renderSectionHeader = ({ section, }: { section: SectionListData; }) => { if (section.data.length > 0) { return {section.title}; } return null; }; const muteUnmuteParticipants = (bubbleId: string) => () => { if (areAllConfUsersMuted) dispatch(unMuteAllParticipants(bubbleId)); else dispatch(muteAllParticipants(bubbleId)); } const getSections = () => { const bubbleParticipants = participants; if (conferenceCall && conferenceCall?.hasMyUserJoinedConferenceCall) { const nonAttendees = bubbleParticipants.filter((participant: IBubbleParticipant) => !conferenceAttendees.some((attendee: IConferenceParticipants) => participant.jId === attendee.jId)); return [ { title: `${Strings.Attendees} (${conferenceAttendees.length})`, data: conferenceAttendees as IContact[] }, { title: `${Strings.NonAttendees} (${nonAttendees.length})`, data: nonAttendees as IContact[] } ] } else { const organizers = bubbleParticipants.filter((participant: IBubbleParticipant) => participant.isModerator); const members = bubbleParticipants.filter((participant: IBubbleParticipant) => !participant.isModerator); return [ { title: Strings.Organizer, data: organizers as IContact[] }, { title: Strings.Members, data: members as IContact[] } ] } } const renderSectionList = () => { return ( ) } return ( {renderSectionList()} {(conferenceCall?.hasMyUserJoinedConferenceCall && isMyUserModerator) && ( {areAllConfUsersMuted ? : } ) } ); } const styles = StyleSheet.create({ container: { flex: 1, paddingTop: 10, }, sectionHeader: { paddingTop: 5, paddingBottom: 5, paddingLeft: 10, paddingRight: 10, fontSize: 15, fontWeight: 'bold', color: '#0086CF', backgroundColor: '#eeeded', }, ownerIcon: { color: '#0086CF', fontSize: 20 }, muteAllButtonContainer: { position: 'absolute', bottom: 10, width: '100%' }, muteAllButtonView: { backgroundColor: '#02a2ff', alignItems: 'center' }, micIcon: { color: 'white' }, menuIcon: { color: '#0086CF', fontSize: 30 } });