import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
import { useMedia } from 'react-use';
import data from '@emoji-mart/data/sets/14/apple.json';
import Picker from '@emoji-mart/react';
import { HMSException, selectLocalPeer, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
import { EmojiIcon, PauseCircleIcon, SendIcon, VerticalMenuIcon } from '@100mslive/react-icons';
import { Box, config as cssConfig, Flex, IconButton as BaseIconButton, Popover, styled, Text } from '../../..';
import { IconButton } from '../../../IconButton';
import { MoreSettings } from '../MoreSettings/MoreSettings';
import { RaiseHand } from '../RaiseHand';
// @ts-ignore: No implicit any
import { ToastManager } from '../Toast/ToastManager';
import { ChatSelectorContainer } from './ChatSelectorContainer';
import { useRoomLayoutConferencingScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen';
// @ts-ignore: No implicit any
import { useChatDraftMessage } from '../AppData/useChatState';
// @ts-ignore: No implicit any
import { useSetSubscribedChatSelector, useSubscribeChatSelector } from '../AppData/useUISettings';
import { useIsPeerBlacklisted } from '../hooks/useChatBlacklist';
// @ts-ignore: No implicit any
import { useEmojiPickerStyles } from './useEmojiPickerStyles';
import { useDefaultChatSelection, useLandscapeHLSStream, useMobileHLSStream } from '../../common/hooks';
import { CHAT_MESSAGE_LIMIT } from './utils';
import { CHAT_SELECTOR, SESSION_STORE_KEY } from '../../common/constants';
const TextArea = styled('textarea', {
width: '100%',
bg: 'transparent',
color: '$on_primary_high',
resize: 'none',
lineHeight: '1rem',
position: 'relative',
fontFamily: '$sans',
fontSize: '100%',
margin: 0,
padding: 0,
top: '$3',
'&:focus': {
boxShadow: 'none',
outline: 'none',
},
});
function EmojiPicker({ onSelect }: { onSelect: (emoji: any) => void }) {
const [showEmoji, setShowEmoji] = useState(false);
const ref = useEmojiPickerStyles(showEmoji);
return (
);
}
export const ChatFooter = ({ onSend, children }: { onSend: (count: number) => void; children?: ReactNode }) => {
const hmsActions = useHMSActions();
const inputRef = useRef(null);
const [draftMessage, setDraftMessage] = useChatDraftMessage();
const isMobile = useMedia(cssConfig.media.md);
const { elements, screenType } = useRoomLayoutConferencingScreen();
const message_placeholder = elements?.chat?.message_placeholder || 'Send a message';
const localPeer = useHMSStore(selectLocalPeer);
const isOverlayChat = elements?.chat?.is_overlay;
const canDisableChat = !!elements?.chat?.real_time_controls?.can_disable_chat;
const selectedPeer = useSubscribeChatSelector(CHAT_SELECTOR.PEER);
const [selectedRole, setRoleSelector] = useSetSubscribedChatSelector(CHAT_SELECTOR.ROLE);
const defaultSelection = useDefaultChatSelection();
const selection = selectedPeer.name || selectedRole || defaultSelection;
const isLocalPeerBlacklisted = useIsPeerBlacklisted({ local: true });
const isMwebHLSStream = useMobileHLSStream();
const [messageLengthExceeded, setMessageLengthExceeded] = useState(false);
const isLandscapeHLSStream = useLandscapeHLSStream();
useEffect(() => {
if (!selectedPeer.id && !selectedRole && !['Everyone', ''].includes(defaultSelection)) {
setRoleSelector(defaultSelection);
} else {
// @ts-ignore
if (!(isMobile || isLandscapeHLSStream) && !elements?.chat?.disable_autofocus) {
inputRef.current?.focus();
}
}
}, [defaultSelection, selectedPeer, selectedRole, setRoleSelector, isMobile, isLandscapeHLSStream, elements?.chat]);
const resetInputHeight = useCallback(() => {
if (inputRef.current) {
inputRef.current.style.height = `${Math.max(
32,
inputRef.current.value ? Math.min(inputRef.current.scrollHeight, 24 * 4) : 0,
)}px`;
}
}, []);
const updateInputHeight = useCallback(() => {
if (inputRef.current) {
inputRef.current.style.height = `${Math.max(32, Math.min(inputRef.current.scrollHeight, 24 * 4))}px`;
}
}, []);
const sendMessage = useCallback(async () => {
const message = inputRef?.current?.value;
if (!message || !message.trim().length) {
return;
}
try {
if (selectedRole) {
await hmsActions.sendGroupMessage(message, [selectedRole]);
} else if (selectedPeer.id) {
await hmsActions.sendDirectMessage(message, selectedPeer.id);
} else {
await hmsActions.sendBroadcastMessage(message);
}
inputRef.current.value = '';
resetInputHeight();
setTimeout(() => {
onSend(1);
}, 0);
} catch (error) {
const err = error as HMSException;
ToastManager.addToast({
title: err.message.startsWith('Invalid peer') ? `${selectedPeer.name} is not in this room` : err.message,
});
}
}, [selectedRole, selectedPeer, hmsActions, onSend]);
useEffect(() => {
const messageElement = inputRef.current;
if (messageElement) {
messageElement.value = draftMessage;
updateInputHeight();
setMessageLengthExceeded(draftMessage.length > CHAT_MESSAGE_LIMIT);
}
}, [draftMessage]);
useEffect(() => {
const messageElement = inputRef.current;
return () => {
setDraftMessage(messageElement?.value || '');
};
}, [setDraftMessage]);
if (isLocalPeerBlacklisted) {
return null;
}
return (
{canDisableChat && isMobile && isOverlayChat ? (
e.stopPropagation()}>
{
const chatState = {
enabled: false,
updatedBy: {
peerId: localPeer?.id,
userId: localPeer?.customerUserId,
userName: localPeer?.name,
},
updatedAt: Date.now(),
};
hmsActions.sessionStore.set(SESSION_STORE_KEY.CHAT_STATE, chatState);
}}
css={{
backgroundColor: '$surface_default',
display: 'flex',
alignItems: 'center',
gap: '$4',
borderRadius: '$1',
color: '$on_surface_high',
cursor: 'pointer',
'&:hover': { backgroundColor: '$surface_dim' },
}}
>
Pause Chat
) : null}
{selection && (
{children}
{(isMwebHLSStream || isLandscapeHLSStream) && (
<>
>
)}
)}
{messageLengthExceeded && (
Message cannot exceed 2000 characters
)}
);
};