emoji-mart#Picker JavaScript Examples
The following examples show how to use
emoji-mart#Picker.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.js From cometchat-pro-react-ui-kit with MIT License | 6 votes |
render() {
const exclude = ["search", "recent"];
return(
<div css={pickerStyle()}>
<Picker
title={this.state.title}
emoji="point_up"
native
onClick={this.props.emojiClicked}
showPreview={false}
exclude={exclude}
i18n={{ categories: this.state.categories }}
style={{ bottom: "100px", "zIndex": "2", "width": "100%", height: "230px" }} />
</div>
);
}
Example #2
Source File: MessengerInput.js From social-network with MIT License | 6 votes |
render() {
const { value } = this.state;
const display = this.state.showPicker ? "grid" : "none";
return (
<div className="message-input">
<div
style={{
display,
justifyItems: "end"
}}
>
<Picker native={true} onSelect={this.addEmoji} />
</div>
<div className="wrap">
<form onSubmit={this.handleSubmit}>
<input
onChange={this.handleChange}
value={value}
type="text"
placeholder="Write your message..."
/>
</form>
<label>
<input
type="file"
accept={acceptedFileTypes}
multiple={false}
onChange={this.handleFileSelect}
/>
<i className="fa fa-paperclip" aria-hidden="true"></i>
</label>
<button onClick={this.toggleEmojiPicker}>
<i className="fa fa-smile-o" aria-hidden="true"></i>
</button>
</div>
</div>
);
}
Example #3
Source File: ConversationTexterContact.jsx From Spoke with MIT License | 5 votes |
renderBottomFixedSection() {
const { optOutDialogOpen, skipDialogOpen } = this.state;
const { contact } = this.props.data;
const { messageStatus } = contact;
const message =
optOutDialogOpen || skipDialogOpen ? (
""
) : (
<div className={css(styles.messageField)}>
<GSForm
ref="form"
schema={this.messageSchema}
value={{ messageText: this.state.messageText }}
onSubmit={this.handleMessageFormSubmit}
onChange={
messageStatus === "needsMessage"
? ""
: this.handleMessageFormChange
}
>
<div className={css(styles.messageWrapper)}>
<Form.Field
className={css(styles.textField)}
name="messageText"
label="Your message"
multiLine
fullWidth
rowsMax={6}
autoFocus
ref="msgInput"
onKeyDown={this.onMessageInputKeyDown}
floatingLabelStyle={{ color: theme.colors.EWnavy }}
underlineStyle={{ borderColor: theme.colors.EWnavy }}
hintStyle={{ color: theme.colors.EWnavy }}
/>
<div ref="emojiPicker" className={css(styles.emojiPickerWrapper)}>
{this.state.showEmojiPicker && (
<Picker
style={inlineStyles.picker}
className={css(styles.picker)}
onSelect={this.addEmoji}
color={theme.colors.EWdarkLibertyGreen}
title=""
emoji={"statue_of_liberty"}
/>
)}
<MoodIcon
onClick={this.handleShowEmojiPicker}
className={css(styles.moodIcon)}
color={theme.colors.lightGray}
/>
</div>
</div>
{this.renderCorrectSendButton()}
</GSForm>
</div>
);
return (
<div>
{this.renderSurveySection()}
<div>
{message}
{optOutDialogOpen || skipDialogOpen ? "" : this.renderActionToolbar()}
</div>
{this.renderSkipDialog()}
{this.renderOptOutDialog()}
</div>
);
}
Example #4
Source File: Icons.js From mern-social-media with MIT License | 5 votes |
Icons = ({ setContent, content, theme }) => {
return (
<div
className="nav-item dropdown"
style={{
opacity: "1",
zIndex: "10",
filter: theme ? "invert(1)" : "invert(0)",
}}
>
<span
className="nav-link position-relative px-1"
id="navbarDropdown"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<span>?</span>
</span>
<div className="dropdown-menu" aria-labelledby="navbarDropdown">
<Picker
theme={theme ? "dark" : "light"}
showSkinTones="true"
showPreview="false"
onSelect={(emoji) => setContent(content + emoji.native)}
i18n={{
search: "Search",
clear: "Clear", // Accessible label on "clear" button
notfound: "No Emoji Found",
skintext: "Choose your default skin tone",
categories: {
search: "Search Results",
recent: "Frequently Used",
smileys: "Smileys & Emotion",
people: "People & Body",
nature: "Animals & Nature",
foods: "Food & Drink",
activity: "Activity",
places: "Travel & Places",
objects: "Objects",
symbols: "Symbols",
flags: "Flags",
custom: "Custom",
},
categorieslabel: "Emoji categories", // Accessible title for the list of categories
skintones: {
1: "Default Skin Tone",
2: "Light Skin Tone",
3: "Medium-Light Skin Tone",
4: "Medium Skin Tone",
5: "Medium-Dark Skin Tone",
6: "Dark Skin Tone",
},
}}
/>
</div>
</div>
);
}
Example #5
Source File: PaletteMetaForm.js From flat-ui-colors with MIT License | 5 votes |
render() {
const { newPaletteName, stage } = this.state;
const { hideForm } = this.props;
return (
<div>
<Dialog open={stage === 'emoji'} onClose={hideForm}>
<DialogTitle id='form-dialog-title'>
Choose a Palette Name
</DialogTitle>
<Picker title='Pick a Palette Emoji' onSelect={this.savePalette} />
</Dialog>
<Dialog
open={stage === 'form'}
aria-labelledby='form-dialog-title'
onClose={hideForm}
>
<DialogTitle id='form-dialog-title'>
Choose a Palette Name
</DialogTitle>
<ValidatorForm onSubmit={this.showEmojiPicker}>
<DialogContent>
<DialogContentText>
Please enter a name for your new beautiful palette. Make sure
it's unique!
</DialogContentText>
<TextValidator
label='Palette Name'
value={newPaletteName}
name='newPaletteName'
onChange={this.handleChange}
fullWidth
margin='normal'
validators={['required', 'isPaletteNameUnique']}
errorMessages={['Enter Palette Name', 'Name already used']}
/>
</DialogContent>
<DialogActions>
<Button onClick={hideForm} color='primary'>
Cancel
</Button>
<Button variant='contained' color='primary' type='submit'>
Save Palette
</Button>
</DialogActions>
</ValidatorForm>
</Dialog>
</div>
);
}
Example #6
Source File: PickerButton.jsx From react-sendbird-messenger with GNU General Public License v3.0 | 5 votes |
export function PickerButton({
style,
show = false,
handleEmojiMart = () => {},
}) {
const emojiMartRef = useRef()
const [showEmojiMart, setShowEmojiMart] = useState(false)
useClickOutSide(emojiMartRef, handleClickOutSide)
function handleClickOutSide() {
setShowEmojiMart(false)
}
return (
<Fragment>
<div ref={emojiMartRef}>
{showEmojiMart && (
<Picker
style={style}
title="Pick your emoji…"
emoji="point_up"
size={20}
emojiSize={20}
color={PRIMARY_COLOR}
showPreview={false}
showSkinTones={false}
set="apple"
onSelect={handleEmojiMart}
/>
)}
<Button
style={{ border: 0 }}
type="ghost"
icon={<SmileOutlined />}
size="large"
onClick={() => setShowEmojiMart((prevState) => !prevState)}
/>
</div>
</Fragment>
)
}
Example #7
Source File: index.js From ant-simple-pro with MIT License | 5 votes |
Index = memo(function Index() {
const addEmoji = useCallback((val)=>{
console.log(`输出的结果===>>`, val)
})
const I18nConfig = {
search: '搜索',
clear: '清除', // Accessible label on "clear" button
notfound: '没有找到表情',
skintext: '选择默认肤色',
categories: {
search: '搜索结果',
recent: '经常使用',
smileys: '笑脸与情感',
people: '人与身体',
nature: '动物与自然',
foods: '食物和饮料',
activity: '活动',
places: '旅游与地方',
objects: '对象',
symbols: '符号',
flags: '标志',
custom: '风俗',
},
categorieslabel: '表情符号类别',
skintones: {
1: 'Default Skin Tone',
2: 'Light Skin Tone',
3: 'Medium-Light Skin Tone',
4: 'Medium Skin Tone',
5: 'Medium-Dark Skin Tone',
6: 'Dark Skin Tone',
},
}
return (
<PageLayout>
<Row>
<Col xs={24} sm={24} md={12} lg={12} xl={12}>
<h2 style={{fontSize:'20px',marginBottom:"10px"}} >中文版:</h2>
<Picker onSelect={addEmoji} i18n={ I18nConfig } />
</Col>
<Col xs={24} sm={24} md={12} lg={12} xl={12}>
<h2 style={{fontSize:'20px',marginBottom:"10px"}} >英文版:</h2>
<Picker title='选择' emoji='point_up' />
</Col>
</Row>
</PageLayout>
)
})
Example #8
Source File: EmojiTextArea.js From react-saas-template with MIT License | 4 votes |
function EmojiTextarea(props) {
const {
theme,
classes,
rightContent,
placeholder,
maxCharacters,
emojiSet,
inputClassName,
onChange
} = props;
const [open, setOpen] = useState(false);
const [value, setValue] = useState("");
const [characters, setCharacters] = useState(0);
const onSelectEmoji = useCallback(
emoji => {
let _characters;
let _value = value + emoji.native;
if (maxCharacters) {
_characters = countWithEmojis(_value);
if (_characters > maxCharacters) {
return;
}
}
if (onChange) {
onChange(_value, _characters);
}
setValue(_value);
setCharacters(_characters);
},
[value, setValue, setCharacters, maxCharacters, onChange]
);
const handleTextFieldChange = useCallback(
event => {
const { target } = event;
const { value } = target;
let characters;
if (maxCharacters) {
characters = countWithEmojis(value);
if (characters > maxCharacters) {
return;
}
}
if (onChange) {
onChange(value, characters);
}
setValue(value);
setCharacters(characters);
},
[maxCharacters, onChange, setValue, setCharacters]
);
const toggleOpen = useCallback(() => {
setOpen(!open);
}, [open, setOpen]);
return (
<Fragment>
<Grid spacing={0} container>
<Grid
item
xs={rightContent ? 8 : 12}
sm={rightContent ? 9 : 12}
lg={rightContent ? 10 : 12}
className={classes.relative}
>
<TextField
fullWidth
multiline
variant="outlined"
rows={6}
onInput={handleTextFieldChange}
value={value}
placeholder={placeholder}
InputProps={{
classes: {
notchedOutline: inputClassName ? inputClassName : null
}
}}
/>
<div className={classes.floatButtonWrapper}>
<IconButton onClick={toggleOpen} size="large">
{open ? (
<CloseIcon color="primary" />
) : (
<EmojiEmotionsIcon color="primary" />
)}
</IconButton>
</div>
</Grid>
{rightContent && (
<Grid item xs={4} sm={3} lg={2}>
{rightContent}
</Grid>
)}
</Grid>
{maxCharacters && (
<FormHelperText error={characters >= maxCharacters}>
{`${characters}/${maxCharacters} characters`}
</FormHelperText>
)}
<Collapse in={open}>
<Box mt={1}>
<Picker
set={emojiSet}
color={theme.palette.primary.main}
style={{ width: "100%" }}
onSelect={onSelectEmoji}
emojisToShowFilter={emojisToShowFilter}
/>
</Box>
</Collapse>
</Fragment>
);
}
Example #9
Source File: Fotter.jsx From airdrop with MIT License | 4 votes |
function Fotter({ indicateFull, sendFile }) {
const file = useRef(null);
const [showEmoji, setShowEmoji] = useState(false);
const [emoji, setEmoji] = useState('');
const [indicate, setIndicate] = useState('');
const { id } = useParams();
useEffect(() => {
const da =
(indicateFull.get(id) && indicateFull.get(id).indication) || 'NO_CONTENT';
setIndicate(da);
}, [indicate, indicateFull, id]);
const handleClick = () => {
setShowEmoji(!showEmoji);
};
const addEmoji = (eji) => {
setEmoji({ date: Date.now(), emoji: eji.native });
};
const handleClickFile = () => {
file.current.click();
};
const handleFileChange = (e) => {
if (!e.target.files[0]) return;
const [FileList] = e.target.files;
const shareID = sha1.sync(FileList.name + FileList.size);
// sendInfo(shareID, channelId, FileList);
const url = URL.createObjectURL(FileList);
sendFile(FileList, url, shareID, id);
};
return (
<>
{showEmoji && (
<Picker
native
className="z-10"
style={{
position: 'absolute',
width: 'auto',
maxWidth: '325px',
bottom: 'calc(60px - 20px)',
left: '4px',
}}
title="Pick your emoji…"
emoji="point_up"
theme="auto"
emojiTooltip
onSelect={addEmoji}
/>
)}
<div
style={{
border: '0px',
borderTop: '1px solid rgba(50, 82, 88,0.49)',
minHeight: '60px',
transition: 'all 1s',
}}
className="bg-primary shadow-md sticky px-2 z-50 py-1 lg:px-3 bottom-0 w-full flex flex-row justify-between items-center "
>
<div className="flex flex-row items-center justify-around">
<svg
title="Pick a emoji"
onClick={handleClick}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
className={`m-1 fill-current ${Styles.gray1} ${
showEmoji && 'text-accent'
} ${
!showEmoji && Styles.gray1
}hover:text-accent cursor-pointer rounded-full`}
>
<path
fill="currentCaolor"
d="M9.153 11.603c.795 0 1.439-.879 1.439-1.962s-.644-1.962-1.439-1.962-1.439.879-1.439 1.962.644 1.962 1.439 1.962zm-3.204 1.362c-.026-.307-.131 5.218 6.063 5.551 6.066-.25 6.066-5.551 6.066-5.551-6.078 1.416-12.129 0-12.129 0zm11.363 1.108s-.669 1.959-5.051 1.959c-3.505 0-5.388-1.164-5.607-1.959 0 0 5.912 1.055 10.658 0zM11.804 1.011C5.609 1.011.978 6.033.978 12.228s4.826 10.761 11.021 10.761S23.02 18.423 23.02 12.228c.001-6.195-5.021-11.217-11.216-11.217zM12 21.354c-5.273 0-9.381-3.886-9.381-9.159s3.942-9.548 9.215-9.548 9.548 4.275 9.548 9.548c-.001 5.272-4.109 9.159-9.382 9.159zm3.108-9.751c.795 0 1.439-.879 1.439-1.962s-.644-1.962-1.439-1.962-1.439.879-1.439 1.962.644 1.962 1.439 1.962z"
/>
</svg>
<button type="button" title="Pick a file" onClick={handleClickFile}>
<input type="file" ref={file} onChange={handleFileChange} hidden />
<svg
title="Send files"
className={`${
indicate === 'CONTENT' ? 'hidden' : 'block'
} m-2 fill-current ${
Styles.gray1
} hover:text-accent cursor-pointer`}
width="24"
height="24"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M12 2.00098C6.486 2.00098 2 6.48698 2 12.001C2 17.515 6.486 22.001 12 22.001C17.514 22.001 22 17.515 22 12.001C22 6.48698 17.514 2.00098 12 2.00098ZM17 13.001H13V17.001H11V13.001H7V11.001H11V7.00098H13V11.001H17V13.001Z"
/>
</svg>
</button>
</div>
<Input emoji={emoji} />
</div>
</>
);
}
Example #10
Source File: ChatInput.js From openos with MIT License | 4 votes |
function ChatInput() {
const dispatch = useDispatch();
const electron = window.require("electron");
const { remote } = window.require("electron");
const {
currentChatRoom,
emojiVisible,
emoticonVisible,
currentEmoticon,
chatMessages,
} = useSelector((state) => state.chats);
const [inputValue, setInputValue] = useState("");
const [isAlreadyTyped, setIsAlreadyTyped] = useState(false);
const [isAlreadyRoomSelected, setIsAlreadyRoomSelected] = useState(false);
const inputRef = useRef(null);
const loginUser = remote.getGlobal("USER");
useEffect(() => {
electron.ipcRenderer.on(
"upload-file-progress",
(event, uploadKey, uploadedLength, fileLength) => {
const percentage = Number((uploadedLength / fileLength) * 100);
if (percentage % 20 > 0.89 && percentage % 20 < 0.9) {
// console.log(percentage.toFixed(0));
dispatch(setFileSkeleton(uploadKey, `${percentage.toFixed(0)}%`));
}
// if (((uploadedLength / fileLength) * 100).toFixed(0) % 20 === 0) {
// const status = ((uploadedLength / fileLength) * 100).toFixed(0) + "%";
// }
}
);
return () => {
electron.ipcRenderer.removeAllListeners("upload-file-progress");
dispatch(setEmojiVisible(false));
dispatch(setEmoticonVisible(false));
dispatch(setCurrentEmoticon(``));
};
}, []);
const handleSelectFile = async (e) => {
const files = e.target.files;
for (let i = 0; i < files.length; i++) {
dispatch(
addFileSkeleton(files[i].name, loginUser.userName, loginUser.userId)
);
const resData = await uploadFile(files[i].path, files[i].path);
console.log(`file upload complete: `, resData.data);
const fileInfo = `${files[i].name}|${files[i].size}|SAVE_SERVER|${
remote.getGlobal("SERVER_INFO").FS.pubip
};${remote.getGlobal("SERVER_INFO").FS.port}|${resData.data}|${
files[i].path
}`;
let userNames;
if (!currentChatRoom.chat_entry_names) {
userNames = await getDispUserNames(
currentChatRoom?.chat_entry_ids?.split("|")
);
} else {
userNames = currentChatRoom.chat_entry_names;
}
dispatch(
addChatMessage(
currentChatRoom.chat_entry_ids,
userNames,
fileInfo,
currentEmoticon ? currentEmoticon : `맑은 고딕`,
false,
currentChatRoom.room_key,
loginUser.userName,
loginUser.userId,
EchatType.file.toString()
)
);
await delay(500);
}
};
const onInputValueChange = (e) => {
if (!currentChatRoom) return;
setInputValue(e.currentTarget.value);
};
const handleDrop = async (files) => {
if (!currentChatRoom) return;
for (let i = 0; i < files.length; i++) {
dispatch(
addFileSkeleton(files[i].name, loginUser.userName, loginUser.userId)
);
const resData = await uploadFile(files[i].path, files[i].path);
console.log(`file upload complete: `, resData.data);
const fileInfo = `${files[i].name}|${files[i].size}|SAVE_SERVER|${
remote.getGlobal("SERVER_INFO").FS.pubip
};${remote.getGlobal("SERVER_INFO").FS.port}|${resData.data}|`;
let userNames;
if (!currentChatRoom.chat_entry_names) {
userNames = await getDispUserNames(
currentChatRoom?.chat_entry_ids?.split("|")
);
} else {
userNames = currentChatRoom.chat_entry_names;
}
dispatch(
addChatMessage(
currentChatRoom.chat_entry_ids,
userNames,
fileInfo,
currentEmoticon ? currentEmoticon : `맑은 고딕`,
false,
currentChatRoom.room_key,
loginUser.userName,
loginUser.userId,
EchatType.file.toString()
)
);
await delay(500);
}
};
const handleNewLine = (e) => {
const {
which,
nativeEvent: { shiftKey },
} = e;
if (which === 13 && !shiftKey) {
e.preventDefault();
onSubmit();
}
};
const handleEmojiVisible = () => {
dispatch(setEmojiVisible(false));
};
const handleFocusInput = () => {
inputRef.current.focus();
};
const handleEmoticonPick = () => {
if (!currentChatRoom) return;
dispatch(setEmojiVisible(false));
dispatch(setEmoticonVisible(!emoticonVisible));
};
const handleEmojiPick = () => {
if (!currentChatRoom) return;
dispatch(setEmoticonVisible(false));
dispatch(setEmojiVisible(!emojiVisible));
};
const handleEmojiClick = (emoji, event) => {
if (!currentChatRoom) return;
setInputValue(inputValue + emoji.native);
};
const onSubmit = async (event) => {
if (!currentChatRoom) return;
let userNames;
if (!currentChatRoom.chat_entry_names) {
userNames = await getDispUserNames(
currentChatRoom?.chat_entry_ids?.split("|")
);
} else {
userNames = currentChatRoom.chat_entry_names;
}
if (inputValue.trim().length === 0 && !currentEmoticon) {
setIsAlreadyTyped(true);
setTimeout(() => {
setIsAlreadyTyped(false);
}, 2000);
return;
}
if (!currentChatRoom) {
setIsAlreadyRoomSelected(true);
setTimeout(() => {
setIsAlreadyRoomSelected(false);
}, 2000);
return;
}
setInputValue("");
dispatch(
addChatMessage(
currentChatRoom.chat_entry_ids,
userNames,
inputValue,
currentEmoticon ? currentEmoticon : `맑은 고딕`,
false,
currentChatRoom.room_key,
loginUser.userName,
loginUser.userId,
currentEmoticon
? EchatType.emoticon.toString()
: EchatType.chat.toString()
)
);
dispatch(setEmojiVisible(false));
dispatch(setEmoticonVisible(false));
dispatch(setCurrentEmoticon(``));
};
return (
<>
{isAlreadyTyped && (
<div
style={{
position: "absolute",
left: "0",
bottom: "150px",
width: "100%",
}}
>
<Alert variant="danger">먼저 글자를 입력해주세요.</Alert>
</div>
)}
{isAlreadyRoomSelected && (
<div
style={{
position: "absolute",
left: "0",
bottom: "150px",
width: "100%",
}}
>
<Alert variant="danger">먼저 방을 선택해주세요.</Alert>
</div>
)}
<div>
<Picker
showPreview={false}
showSkinTones={false}
emojiTooltip={true}
onClick={handleEmojiClick}
style={{
display: emojiVisible ? `block` : `none`,
}}
/>
<Hover emojiVisible={emojiVisible} onClick={handleEmojiVisible}>
<CloseButton />
</Hover>
</div>
<EmoticonSelector visible={emoticonVisible ? true : false} />
<div className="chat-input-area">
<DragAndDropSupport handleDrop={handleDrop}>
<div className="chat-input-wrap" onClick={handleFocusInput}>
<textarea
ref={inputRef}
className="chat-input"
value={inputValue}
onChange={onInputValueChange}
placeholder="채팅 내용을 입력해주세요."
onKeyDown={handleNewLine}
></textarea>
<button
onClick={onSubmit}
type="submit"
style={{ width: "78px", height: "48px" }}
className="btn-ghost-m"
>
전송
</button>
</div>
</DragAndDropSupport>
<div className="input-action-wrap">
<div
className="input-action btn-txt"
title="텍스트 (글꼴, 크기, 색상,표)"
></div>
<div
className="input-action btn-emoticon"
title="이모티콘"
onClick={handleEmoticonPick}
></div>
<div
className="input-action btn-emoji"
title="이모지"
onClick={handleEmojiPick}
></div>
<div class="input-action-file-wrapper">
<label for="btn-add-file">
<div className="input-action btn-add-file" title="파일전송"></div>
</label>
{currentChatRoom ? (
<input
type="file"
multiple="multiple"
id="btn-add-file"
class="btn-add-file"
onChange={handleSelectFile}
/>
) : (
<div class="btn-add-file"></div>
)}
</div>
</div>
</div>
</>
);
}
Example #11
Source File: Chat.js From Chathub with MIT License | 4 votes |
function Chat() {
const [input, setInput] = useState("");
const [seed, setSeed] = useState("");
const { roomId } = useParams();
const [roomName, setRoomName] = useState("");
const [messages, setMessages] = useState([]);
const [{ user }] = useStateValue();
const chatBodyRef = useRef(null);
const inputRef = useRef(null);
const [showEmoji, setEMoji] = useState(false);
const [open, setOpen] = useState(false);
const [fileObjects, setFileObjects] = useState([]);
const upload = () => {
if (fileObjects == null) return;
storage
.ref(`/files/${fileObjects}`)
.put(fileObjects)
.on("state_changed", alert("success"), alert);
};
const dialogTitle = () => (
<>
<span>Upload file</span>
<IconButton
style={{ right: "12px", top: "8px", position: "absolute" }}
onClick={() => setOpen(false)}
>
<CloseIcon />
</IconButton>
</>
);
useEffect(() => {
if (roomId) {
db.collection("rooms")
.doc(roomId)
.onSnapshot((snapshot) => setRoomName(snapshot.data().name));
db.collection("rooms")
.doc(roomId)
.collection("messages")
.orderBy("timestamp", "asc")
.onSnapshot((snapshot) =>
setMessages(snapshot.docs.map((doc) => doc.data()))
);
}
}, [roomId]);
useEffect(() => {
setSeed(Math.floor(Math.random() * 5000));
}, [roomId]);
useEffect(() => {
chatBodyRef.current.scrollTop = chatBodyRef.current.scrollHeight;
});
const toggleEMoji = () => {
sEmoji();
};
const sEmoji = (e) => {
setEMoji(!showEmoji);
};
const addEmoji = (e) => {
sEmoji();
let emoji = e.native;
setInput(input + emoji);
};
const sendMessage = (e) => {
e.preventDefault();
db.collection("rooms").doc(roomId).collection("messages").add({
message: input,
name: user.displayName,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
});
setInput("");
};
const copyToClipBoard = (e) => {
e.preventDefault();
inputRef.current.select();
document.execCommand("copy");
};
return (
<div className="chat">
<div className="chat__header">
<Avatar src={`https://avatars.dicebear.com/api/human/${seed}.svg`} />
<div className="chat__headerInfo">
<h3 className="chat-room-name">{roomName}</h3>
<p className="chat-room-last-seen">
Last seen{" "}
{new Date(
messages[messages.length - 1]?.timestamp?.toDate()
).toUTCString()}
</p>
</div>
<div className="chat__headerRight">
<IconButton>
<SearchOutlined />
</IconButton>
<IconButton onClick={() => setOpen(true)}>
<AttachFile />
</IconButton>
<DropzoneDialogBase
dialogTitle={dialogTitle()}
acceptedFiles={[]}
fileObjects={fileObjects}
cancelButtonText={"cancel"}
submitButtonText={"submit"}
maxFileSize={5000000}
open={open}
onAdd={(newFileObjs) => {
console.log("onAdd", newFileObjs);
setFileObjects([].concat(fileObjects, newFileObjs));
}}
onDelete={(deleteFileObj) => {
console.log("onDelete", deleteFileObj);
}}
onClose={() => setOpen(false)}
onSave={() => {
console.log("onSave", fileObjects);
upload();
setOpen(false);
}}
showPreviews={true}
showFileNamesInPreview={true}
/>
<IconButton>
<MoreVert />
</IconButton>
</div>
</div>
<div className="chat__body" ref={chatBodyRef}>
{messages.map((message) => (
<p
className={`chat__message ${
message.name === user.displayName && "chat__receiver"
}`}
>
<span className="chat__name">{message.name}</span>
{message.message}
{/*{fileObjects.length > 0 && (
<div className="chat__name">
{message.name}
{fileObjects.length}
</div>
)}*/}
<span className="chat__timestamp">
{" "}
{new Date(message.timestamp?.toDate()).toUTCString()}
</span>
</p>
))}
</div>
<div className="chat__footer">
{showEmoji ? (
<Picker onSelect={addEmoji} emojiTooltip={true} title="Chathub" />
) : null}
<button
type="button"
style={{ cursor: "pointer", background: "none" }}
className="toggle-emoji"
onClick={toggleEMoji}
>
<InsertEmoticonIcon />
</button>
<form>
<input
ref={inputRef}
value={input}
onChange={(e) => setInput(e.target.value)}
type="text"
placeholder="Type a message"
/>
<button type="submit" onClick={sendMessage}>
{" "}
Send a Message
</button>
</form>
<Tooltip title="Copy">
<AssignmentIcon onClick={copyToClipBoard} />
</Tooltip>
<MicIcon />
</div>
</div>
);
}
Example #12
Source File: TweetEditor.js From twitter-frontend with GNU General Public License v3.0 | 4 votes |
function TweetEditor() {
const { feed, setFeed, tags, setTags } = useContext(FeedContext);
const [preview, setPreview] = useState("");
const [postImage, setPostImage] = useState("");
const [textTweet, setTextTweet] = useState("");
const [toggleEmoji, setToggleEmoji] = useState(false);
const handleUploadImage = (e) => {
if (e.target.files[0]) {
const reader = new FileReader();
reader.onload = (e) => {
setPreview(e.target.result);
};
reader.readAsDataURL(e.target.files[0]);
uploadImage(e.target.files[0]).then((res) => {
setPostImage(res.secure_url);
});
}
};
const handleSubmitPost = () => {
if (!textTweet) {
return toast.error("Please write something");
}
const tag = textTweet
.split(" ")
.filter((caption) => caption.startsWith("#"))
.map((val) => val.slice(1, val.length));
const cleanedCaption = textTweet
.split(" ")
.filter((caption) => !caption.startsWith("#"))
.join(" ");
setTextTweet("");
const newPost = {
caption: cleanedCaption,
files: [postImage],
tags: tag,
};
client(`/posts`, { body: newPost }).then((res) => {
const post = res.data;
post.isLiked = false;
post.isSaved = false;
post.isMine = true;
setFeed([post, ...feed]);
window.scrollTo(0, 0);
setPreview('')
tag.forEach((tg) => {
if (!tags.includes(tg)) {
setTags([tg, ...tags])
}
});
toast.success("Tweet gönderimi başarılı.");
});
};
const addEmoji = e => {
let sym = e.unified.split('-')
let codesArray = []
sym.forEach(el => codesArray.push('0x' + el))
let emoji = String.fromCodePoint(...codesArray)
setTextTweet(textTweet + emoji)
}
return (
<div className="tweet-editor">
<Avatar className="tweet-editor--avatar" size='medium' />
<div className="tweet-editor__body">
{preview && (
<img style={{ width: "100%" }} src={preview} alt="preview" />
)}
<TextareaAutosize
rows="59"
placeholder="What's happening?"
type="text"
onChange={(e) => setTextTweet(e.target.value)}
value={textTweet}
/>
<div className="tweet-editor__body--secondary">
<div className="tweet-editor__body--icons">
<label htmlFor="file-input" style={{ cursor: "pointer" }}>
<Button icon style={{ pointerEvents: "none" }} >
<Media />
</Button>
</label>
<input id="file-input" accept="image/*" type="file" onChange={handleUploadImage} />
<label htmlFor="file-input" style={{ cursor: "pointer" }}>
<Button icon style={{ pointerEvents: "none" }} >
<Gif />
</Button>
</label>
<Button icon>
<Question />
</Button>
<div style={{ position: 'relative' }}>
<Button icon onClick={() => setToggleEmoji(!toggleEmoji)} >
<Emoji />
</Button>
{toggleEmoji && <Picker onSelect={addEmoji} style={{ position: 'absolute', top: '20px', left: '20px' }} />}
</div>
</div>
<ThemeButton primary onClick={handleSubmitPost}>Tweet</ThemeButton>
</div>
</div>
</div>
)
}
Example #13
Source File: SyntaxChat.js From SyntaxMeets with MIT License | 4 votes |
SyntaxChat = (props) => {
const classes = useStyles();
const [emojiPickerState, SetEmojiPicker] = useState(false);
const messagesEndRef = useRef(null);
const [openDrawer, setopenDrawer] = useState(false);
const handleMessageSubmit = () => {
// this if block is called when page is reloaded
// it ensures that user is connected back to same room to incorporate smooth chating
if (localStorage.getItem("flag") && sessionStorage.getItem("isconnected")) {
if (props.message.trim() === "") return;
SetEmojiPicker(false);
// this data extract info from localStorage
let data = {
name: localStorage.getItem("name"),
roomId: localStorage.getItem("roomId"),
message: props.message
};
// this is used to connect back the user
props.socket.emit("chatmessage", data);
props.setMessages(data);
props.setMessage("");
}
// this block is called when the user connects first time
else {
if (props.message.trim() === "") return;
SetEmojiPicker(false);
let data = {
name: props.name,
roomId: props.roomId,
message: props.message
};
props.socket.emit("chatmessage", data);
props.setMessages(data);
props.setMessage("");
}
};
useEffect(() => {
props.socket.on("chatmessage", (data) => {
props.setMessages(data);
});
let timeout;
// recieve the user who is currently typing's data from the backend
props.socket.on("typing", (data) => {
props.whoIsTyping(data.name);
//Remove the timeout(to clear typing message) , if someone has again typed something
clearTimeout(timeout);
timeout = setTimeout(() => {
//Remove the typing message if no one is typing after 500ms
props.whoIsTyping();
}, 500);
});
}, []);
useEffect(()=> {
let lastMessage = props.messages[props.messages.length - 1];
if (props.name && lastMessage) {
if (props.name !== lastMessage.name) {
console.log("NEW MESSAGE");
lastMessage.message.length > 20 ? props.setSnackBar(`${lastMessage.name}: ${lastMessage.message.substring(0,20)}...`, "warning") : props.setSnackBar(`${lastMessage.name}: ${lastMessage.message}`, "warning")
}
}
}, [props.messages]);
const scrollToBottom = () => {
if (messagesEndRef.current) {
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
}
};
function triggerPicker(event) {
event.preventDefault();
SetEmojiPicker(!emojiPickerState);
}
useEffect(scrollToBottom, [props.messages]);
let emojiPicker;
if (emojiPickerState) {
emojiPicker = (
<Picker
title="Pick your emoji…"
emoji="point_up"
onSelect={(emoji) => props.setMessage(props.message + emoji.native)}
// style={{width: "90%", display: "flex"}}
/>
);
}
const toggleDrawer = (open) => (event) => {
if (
event.type === "keydown" &&
(event.key === "Tab" || event.key === "Shift")
) {
return;
}
setopenDrawer(open);
};
return (
<div>
<Button
onClick={toggleDrawer(true)}
variant="contained"
startIcon={<ForumIcon />}
color="primary"
style={{
fontFamily: "poppins",
marginLeft: "15px",
fontWeight: "600",
color: "white"
}}
>
Chat Box
</Button>
<Drawer anchor={"right"} open={openDrawer} onClose={toggleDrawer(false)}>
<CloseSharpIcon
style={{ padding: "5px", fontSize: "3em", cursor: "pointer" }}
onClick={toggleDrawer(false)}
/>
<div
className={classes.list}
style={{ display: "flex", flexDirection: "column" }}
role="presentation"
>
<div
style={{
paddingBottom: "70px",
marginBottom: "70px",
height: "90%"
}}
>
{<ChatMessage messages={props.messages} />}
<div ref={messagesEndRef} />
</div>
<div
style={{
bottom: "0",
position: "fixed",
paddingBottom: "20px",
paddingTop: "10px",
backgroundColor: "#fff"
}}
>
<Grid container justify="center" spacing={3}>
<Grid item xs={12}>
<Divider />
</Grid>
</Grid>
{props.typingUser ? (
<Grid container justify="center">
<Grid item xs={1}></Grid>
<Typography
display="block"
variant="overline"
color="textSecondary"
align="justify"
style={{ marginBottom: "4px" }}
gutterBottom
>
<b>{props.typingUser}</b> is typing...
</Typography>
<Grid item xs={1}></Grid>
</Grid>
) : undefined}
<Grid container spacing={3} alignContent="center">
{/* <Grid item xs={1}></Grid> */}
<Grid item xs={1} alignContent="center">
{/* <Button
variant="contained"
// className={classes.button}
// class="ma4 b ph3 pv2 input-reset ba b--black bg-transparent grow pointer f6 dib"
onClick={triggerPicker}
color="white"
size="small"
></Button> */}
<Grid item xs={1}></Grid>
<InsertEmoticonIcon
onClick={triggerPicker}
color="primary"
// className={classes.list}
style={{
display: "flex",
alignSelf: "center",
marginLeft: "5px",
marginTop: "10px",
cursor: "pointer"
}}
alignContent="center"
></InsertEmoticonIcon>
{/* <Grid item xs={1}></Grid> */}
</Grid>
<Grid item xs={7} alignContent="center">
<TextField
id="outlined-basic"
label="Enter Your Message"
variant="outlined"
fullWidth
size="small"
value={props.message}
onChange={(e) => {
props.socket.emit("typing", {
id: props.socket.id,
name: props.name
});
props.setMessage(e.target.value);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleMessageSubmit();
}
}}
/>
{/* <input
id="name"
class="input-reset ba b--black-20 pa2 mb2 db w-100"
type="text"
aria-describedby="name-desc"
value={message}
onChange={(event) => SetMessage(event.target.value)}
/> */}
</Grid>
<Grid item xs={3} alignContent="center">
<Button
variant="contained"
color="primary"
className={classes.button}
// size="large"
style={{
fontFamily: "poppins",
marginLeft: "auto",
fontWeight: "600",
color: "white"
}}
endIcon={<SendIcon />}
onClick={handleMessageSubmit}
>
Send
</Button>
<Grid item xs={1}></Grid>
</Grid>
</Grid>
<Grid container spacing={3} style={{ paddingTop: "10px" }}>
<Grid item xs={1}></Grid>
{emojiPicker}
<Grid item xs={1}></Grid>
</Grid>
</div>
</div>
</Drawer>
</div>
);
}
Example #14
Source File: EditInput.js From AdaptivApps-fe with MIT License | 4 votes |
EditInput = ({ messageToEdit, setUpdateChat, setEditInput }) => {
const classes = useStyles();
const [toggleEmoji, setToggleEmoji] = useState(false);
const [updateChat] = useMutation(UPDATE_CHAT);
const [message, setMessage] = useState(messageToEdit.message);
const emojiClick = (e) => {
setMessage(message ? message + e.native : e.native);
};
// Speech to text logic
const { listen, listening, stop } = useSpeechRecognition({
onResult: result => {
setMessage(message ? message + result : result);
},
onEnd: () => console.log('Listening has finished')});
const toggleListen = listening ? stop : () => listen();
// Update message via text
const updateMessage = async () => {
await updateChat({
variables: {
id: messageToEdit.id,
message: message
}
})
setEditInput(false);
setUpdateChat(true);
};
return(
<div>
<div className={classes.inputDiv}>
<div className={classes.iconDiv}
aria-label="create speech-to-text message"
onClick={toggleListen}>
<MicNoneIcon className={classes.speechIcon}/>
{listening && "Go ahead, I'm listening"}
</div>
<TextField
className={classes.messageBox}
multiline={true}
rowsMax='4'
value={message}
variant="outlined"
type="text"
name="updateChat"
onChange={(e) => setMessage(e.target.value)}
InputProps={{
endAdornment:
<InputAdornment position="end">
<Tooltip title="Update Message">
<SendIcon
className={classes.sendMessageIcon}
onClick={updateMessage}
aria-label="update message" />
</Tooltip>
</InputAdornment>
}} />
<div className={classes.iconDiv}>
<Tooltip title="Add an emoji!">
<MoodIcon
className={classes.icons}
onClick={() => setToggleEmoji(true)}
aria-label="open emoji picker"/>
</Tooltip>
<Modal
className={classes.modal}
open={toggleEmoji}
onClose={() => setToggleEmoji(false)}>
{toggleEmoji ?
<Picker
onClick={emojiClick}
title='Pick an Emoji!'
emoji='woman_in_manual_wheelchair'
/> : null}
</Modal>
</div>
</div>
</div>
)
}
Example #15
Source File: index.js From whaticket with MIT License | 4 votes |
MessageInput = ({ ticketStatus }) => {
const classes = useStyles();
const { ticketId } = useParams();
const [medias, setMedias] = useState([]);
const [inputMessage, setInputMessage] = useState("");
const [showEmoji, setShowEmoji] = useState(false);
const [loading, setLoading] = useState(false);
const [recording, setRecording] = useState(false);
const [quickAnswers, setQuickAnswer] = useState([]);
const [typeBar, setTypeBar] = useState(false);
const inputRef = useRef();
const [anchorEl, setAnchorEl] = useState(null);
const { setReplyingMessage, replyingMessage } =
useContext(ReplyMessageContext);
const { user } = useContext(AuthContext);
const [signMessage, setSignMessage] = useLocalStorage("signOption", true);
useEffect(() => {
inputRef.current.focus();
}, [replyingMessage]);
useEffect(() => {
inputRef.current.focus();
return () => {
setInputMessage("");
setShowEmoji(false);
setMedias([]);
setReplyingMessage(null);
};
}, [ticketId, setReplyingMessage]);
const handleChangeInput = (e) => {
setInputMessage(e.target.value);
handleLoadQuickAnswer(e.target.value);
};
const handleQuickAnswersClick = (value) => {
setInputMessage(value);
setTypeBar(false);
};
const handleAddEmoji = (e) => {
let emoji = e.native;
setInputMessage((prevState) => prevState + emoji);
};
const handleChangeMedias = (e) => {
if (!e.target.files) {
return;
}
const selectedMedias = Array.from(e.target.files);
setMedias(selectedMedias);
};
const handleInputPaste = (e) => {
if (e.clipboardData.files[0]) {
setMedias([e.clipboardData.files[0]]);
}
};
const handleUploadMedia = async (e) => {
setLoading(true);
e.preventDefault();
const formData = new FormData();
formData.append("fromMe", true);
medias.forEach((media) => {
formData.append("medias", media);
formData.append("body", media.name);
});
try {
await api.post(`/messages/${ticketId}`, formData);
} catch (err) {
toastError(err);
}
setLoading(false);
setMedias([]);
};
const handleSendMessage = async () => {
if (inputMessage.trim() === "") return;
setLoading(true);
const message = {
read: 1,
fromMe: true,
mediaUrl: "",
body: signMessage
? `*${user?.name}:*\n${inputMessage.trim()}`
: inputMessage.trim(),
quotedMsg: replyingMessage,
};
try {
await api.post(`/messages/${ticketId}`, message);
} catch (err) {
toastError(err);
}
setInputMessage("");
setShowEmoji(false);
setLoading(false);
setReplyingMessage(null);
};
const handleStartRecording = async () => {
setLoading(true);
try {
await navigator.mediaDevices.getUserMedia({ audio: true });
await Mp3Recorder.start();
setRecording(true);
setLoading(false);
} catch (err) {
toastError(err);
setLoading(false);
}
};
const handleLoadQuickAnswer = async (value) => {
if (value && value.indexOf("/") === 0) {
try {
const { data } = await api.get("/quickAnswers/", {
params: { searchParam: inputMessage.substring(1) },
});
setQuickAnswer(data.quickAnswers);
if (data.quickAnswers.length > 0) {
setTypeBar(true);
} else {
setTypeBar(false);
}
} catch (err) {
setTypeBar(false);
}
} else {
setTypeBar(false);
}
};
const handleUploadAudio = async () => {
setLoading(true);
try {
const [, blob] = await Mp3Recorder.stop().getMp3();
if (blob.size < 10000) {
setLoading(false);
setRecording(false);
return;
}
const formData = new FormData();
const filename = `${new Date().getTime()}.mp3`;
formData.append("medias", blob, filename);
formData.append("body", filename);
formData.append("fromMe", true);
await api.post(`/messages/${ticketId}`, formData);
} catch (err) {
toastError(err);
}
setRecording(false);
setLoading(false);
};
const handleCancelAudio = async () => {
try {
await Mp3Recorder.stop().getMp3();
setRecording(false);
} catch (err) {
toastError(err);
}
};
const handleOpenMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuItemClick = (event) => {
setAnchorEl(null);
};
const renderReplyingMessage = (message) => {
return (
<div className={classes.replyginMsgWrapper}>
<div className={classes.replyginMsgContainer}>
<span
className={clsx(classes.replyginContactMsgSideColor, {
[classes.replyginSelfMsgSideColor]: !message.fromMe,
})}
></span>
<div className={classes.replyginMsgBody}>
{!message.fromMe && (
<span className={classes.messageContactName}>
{message.contact?.name}
</span>
)}
{message.body}
</div>
</div>
<IconButton
aria-label="showRecorder"
component="span"
disabled={loading || ticketStatus !== "open"}
onClick={() => setReplyingMessage(null)}
>
<ClearIcon className={classes.sendMessageIcons} />
</IconButton>
</div>
);
};
if (medias.length > 0)
return (
<Paper elevation={0} square className={classes.viewMediaInputWrapper}>
<IconButton
aria-label="cancel-upload"
component="span"
onClick={(e) => setMedias([])}
>
<CancelIcon className={classes.sendMessageIcons} />
</IconButton>
{loading ? (
<div>
<CircularProgress className={classes.circleLoading} />
</div>
) : (
<span>
{medias[0]?.name}
{/* <img src={media.preview} alt=""></img> */}
</span>
)}
<IconButton
aria-label="send-upload"
component="span"
onClick={handleUploadMedia}
disabled={loading}
>
<SendIcon className={classes.sendMessageIcons} />
</IconButton>
</Paper>
);
else {
return (
<Paper square elevation={0} className={classes.mainWrapper}>
{replyingMessage && renderReplyingMessage(replyingMessage)}
<div className={classes.newMessageBox}>
<Hidden only={["sm", "xs"]}>
<IconButton
aria-label="emojiPicker"
component="span"
disabled={loading || recording || ticketStatus !== "open"}
onClick={(e) => setShowEmoji((prevState) => !prevState)}
>
<MoodIcon className={classes.sendMessageIcons} />
</IconButton>
{showEmoji ? (
<div className={classes.emojiBox}>
<ClickAwayListener onClickAway={(e) => setShowEmoji(false)}>
<Picker
perLine={16}
showPreview={false}
showSkinTones={false}
onSelect={handleAddEmoji}
/>
</ClickAwayListener>
</div>
) : null}
<input
multiple
type="file"
id="upload-button"
disabled={loading || recording || ticketStatus !== "open"}
className={classes.uploadInput}
onChange={handleChangeMedias}
/>
<label htmlFor="upload-button">
<IconButton
aria-label="upload"
component="span"
disabled={loading || recording || ticketStatus !== "open"}
>
<AttachFileIcon className={classes.sendMessageIcons} />
</IconButton>
</label>
<FormControlLabel
style={{ marginRight: 7, color: "gray" }}
label={i18n.t("messagesInput.signMessage")}
labelPlacement="start"
control={
<Switch
size="small"
checked={signMessage}
onChange={(e) => {
setSignMessage(e.target.checked);
}}
name="showAllTickets"
color="primary"
/>
}
/>
</Hidden>
<Hidden only={["md", "lg", "xl"]}>
<IconButton
aria-controls="simple-menu"
aria-haspopup="true"
onClick={handleOpenMenuClick}
>
<MoreVert></MoreVert>
</IconButton>
<Menu
id="simple-menu"
keepMounted
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleMenuItemClick}
>
<MenuItem onClick={handleMenuItemClick}>
<IconButton
aria-label="emojiPicker"
component="span"
disabled={loading || recording || ticketStatus !== "open"}
onClick={(e) => setShowEmoji((prevState) => !prevState)}
>
<MoodIcon className={classes.sendMessageIcons} />
</IconButton>
</MenuItem>
<MenuItem onClick={handleMenuItemClick}>
<input
multiple
type="file"
id="upload-button"
disabled={loading || recording || ticketStatus !== "open"}
className={classes.uploadInput}
onChange={handleChangeMedias}
/>
<label htmlFor="upload-button">
<IconButton
aria-label="upload"
component="span"
disabled={loading || recording || ticketStatus !== "open"}
>
<AttachFileIcon className={classes.sendMessageIcons} />
</IconButton>
</label>
</MenuItem>
<MenuItem onClick={handleMenuItemClick}>
<FormControlLabel
style={{ marginRight: 7, color: "gray" }}
label={i18n.t("messagesInput.signMessage")}
labelPlacement="start"
control={
<Switch
size="small"
checked={signMessage}
onChange={(e) => {
setSignMessage(e.target.checked);
}}
name="showAllTickets"
color="primary"
/>
}
/>
</MenuItem>
</Menu>
</Hidden>
<div className={classes.messageInputWrapper}>
<InputBase
inputRef={(input) => {
input && input.focus();
input && (inputRef.current = input);
}}
className={classes.messageInput}
placeholder={
ticketStatus === "open"
? i18n.t("messagesInput.placeholderOpen")
: i18n.t("messagesInput.placeholderClosed")
}
multiline
maxRows={5}
value={inputMessage}
onChange={handleChangeInput}
disabled={recording || loading || ticketStatus !== "open"}
onPaste={(e) => {
ticketStatus === "open" && handleInputPaste(e);
}}
onKeyPress={(e) => {
if (loading || e.shiftKey) return;
else if (e.key === "Enter") {
handleSendMessage();
}
}}
/>
{typeBar ? (
<ul className={classes.messageQuickAnswersWrapper}>
{quickAnswers.map((value, index) => {
return (
<li
className={classes.messageQuickAnswersWrapperItem}
key={index}
>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a onClick={() => handleQuickAnswersClick(value.message)}>
{`${value.shortcut} - ${value.message}`}
</a>
</li>
);
})}
</ul>
) : (
<div></div>
)}
</div>
{inputMessage ? (
<IconButton
aria-label="sendMessage"
component="span"
onClick={handleSendMessage}
disabled={loading}
>
<SendIcon className={classes.sendMessageIcons} />
</IconButton>
) : recording ? (
<div className={classes.recorderWrapper}>
<IconButton
aria-label="cancelRecording"
component="span"
fontSize="large"
disabled={loading}
onClick={handleCancelAudio}
>
<HighlightOffIcon className={classes.cancelAudioIcon} />
</IconButton>
{loading ? (
<div>
<CircularProgress className={classes.audioLoading} />
</div>
) : (
<RecordingTimer />
)}
<IconButton
aria-label="sendRecordedAudio"
component="span"
onClick={handleUploadAudio}
disabled={loading}
>
<CheckCircleOutlineIcon className={classes.sendAudioIcon} />
</IconButton>
</div>
) : (
<IconButton
aria-label="showRecorder"
component="span"
disabled={loading || ticketStatus !== "open"}
onClick={handleStartRecording}
>
<MicIcon className={classes.sendMessageIcons} />
</IconButton>
)}
</div>
</Paper>
);
}
}
Example #16
Source File: AddMessage.js From juggernaut-desktop with MIT License | 4 votes |
AddMessage = props => {
const { balance, sendMessage } = props;
const [state, setState] = useState({
message: '',
disabled: true,
error: null,
saving: false
});
const [menuOpen, setMenuOpen] = useState(false);
const [emojiMenuOpen, setEmojiMenuOpen] = useState(false);
const handleSendMessage = async messageParams => {
setState({ ...state, saving: true });
await sendMessage(messageParams);
setState({ ...state, saving: false, message: '' });
};
const sendPaymentRequest = async () => {
setMenuOpen(false);
// eslint-disable-next-line no-constant-condition
while (true) {
const paymentRequestResponse = await queue.promptForm({
title: 'Request Payment',
body:
'Send a payment request by specifying how many sats you want them to pay and an optional memo.',
inputs: [
{
name: 'amount',
label: 'Amount',
required: true,
type: 'number'
},
{
name: 'memo',
label: 'Memo (Optional)'
}
],
acceptLabel: 'Send',
cancelLabel: 'Cancel'
});
if (!paymentRequestResponse) {
// user canceled dialog prompt
break;
}
const { amount, memo } = paymentRequestResponse;
const satAmount = parseInt(amount, 10);
if (isNaN(satAmount) || !amount.match(/^[0-9]+$/) || satAmount <= 0) {
queue.alert({
title: 'Invalid Payment Request',
body: 'Amount must be an integer greater than zero'
});
} else {
handleSendMessage({
message: `${satAmount * 1000},${memo}`,
amount: balance,
contentType: 'paymentrequest',
requestIdentifier: ''
});
break;
}
}
};
const attachPayment = async () => {
setMenuOpen(false);
// eslint-disable-next-line no-constant-condition
while (true) {
const paymentAmountResponse = await queue.promptForm({
title: 'Send Money',
body: 'How many sats would you like to send?',
inputs: [
{
name: 'amount',
label: 'Amount',
required: true,
type: 'number'
},
{
name: 'memo',
label: 'Memo (Optional)'
}
],
acceptLabel: 'Send',
cancelLabel: 'Cancel'
});
if (!paymentAmountResponse) {
// user canceled dialog prompt
break;
}
const { amount, memo } = paymentAmountResponse;
const satAmount = parseInt(amount, 10);
if (isNaN(satAmount) || !amount.match(/^[0-9]+$/) || satAmount <= 0) {
queue.alert({
title: 'Invalid Send Amount',
body: `Amount must be an integer greater or equal to zero`
});
} else {
handleSendMessage({
message: `${memo}`,
amount: satAmount * 1000,
contentType: 'payment',
requestIdentifier: ''
});
break;
}
}
};
const saveMessage = async () => {
if (state.message.length === 0) {
return;
}
handleSendMessage({
message: state.message,
contentType: 'text',
requestIdentifier: '',
amount: balance
});
};
return (
<div className="addMessageWrapper">
<MenuSurfaceAnchor
onMouseLeave={() => {
setMenuOpen(false);
}}
>
<Menu
anchorCorner="bottomLeft"
open={menuOpen}
focusOnOpen={false}
style={{ width: '225px', borderRadius: '10px' }}
>
<MenuItem onClick={sendPaymentRequest}>
<ListItemGraphic icon={<PaymentRequestIcon />} />
Payment Request
</MenuItem>
<MenuItem onClick={attachPayment}>
<ListItemGraphic icon={<PaymentIcon />} />
Payment
</MenuItem>
</Menu>
<IconButton
icon="add"
onMouseEnter={() => {
setMenuOpen(true);
}}
/>
</MenuSurfaceAnchor>
<input
className="add-message"
ref={input => input && input.focus()}
disabled={state.saving}
onChange={e => {
setState({
...state,
message: e.target.value
});
}}
onKeyPress={e => {
if (e.which === 13) {
saveMessage();
}
}}
value={state.message}
type="text"
name="message"
placeholder="Write a message..."
/>
<MenuSurfaceAnchor
onMouseLeave={() => {
setEmojiMenuOpen(false);
}}
>
<MenuSurface
anchorCorner="bottomLeft"
open={emojiMenuOpen}
style={{ borderRadius: '10px' }}
>
<Picker
useButton={false}
showPreview
showSkinTones
native
title=""
skinEmoji="hand"
set="twitter"
onSelect={emoji => {
setState({ ...state, message: state.message + emoji.native });
}}
/>
</MenuSurface>
<IconButton
icon="insert_emoticon"
onMouseEnter={() => {
setEmojiMenuOpen(true);
}}
/>
</MenuSurfaceAnchor>
{state.saving && <IconButton disabled icon={<CircularProgress />} />}
{!state.saving && (
<IconButton
icon="flash_on"
disabled={state.message.length === 0}
onClick={saveMessage}
className="sendButton"
/>
)}
</div>
);
}
Example #17
Source File: EditAction.js From Website with MIT License | 4 votes |
EditAction = ({ initial, close, guild, message, update, join }) => {
const [action, setAction] = useState(initial);
const [open, setOpen] = useState(false);
useEffect(() => {
(async () => {
const displayRoles = initial?.role?.map?.(role => guild.roles.find(r => r.id === role));
setAction({
...initial,
role: displayRoles?.map?.(role => ({
label: <RoleItem {...role}>{role?.name}</RoleItem>,
value: TransformObjectToSelectValue(role),
})),
});
})();
}, [initial, guild]);
const submit = () => {
const roleIDs = action.role.map(role => JSON.parse(role.value.split("=")[1]).id);
console.log(roleIDs);
const actionObj = {
role: roleIDs,
type: action.type,
DMuser: !!action.DMuser,
};
if (update) {
update(actionObj, action.emoji);
} else {
firebase.db
.collection("reactions")
.doc(guild.id)
.update({ [`${message}.actions.${action.emoji}`]: actionObj });
}
return close?.();
};
return (
<ActionBody style={{ zIndex: 1000 }}>
<ActionHead>
<div>
{action.emoji ? (
<span style={{ marginRight: ".5rem", textTransform: "capitalize" }}>
<Twemoji options={{ className: "twemoji" }}>
{action.emoji?.replace("catch-all", "All").replace("-", " ")}
</Twemoji>
</span>
) : (
<Picker
theme="dark"
style={{ position: "absolute", top: ".75rem", zIndex: 100 }}
set="twitter"
title="Pick your emoji…"
emoji="point_up"
onSelect={emoji => setAction({ ...action, emoji: emoji.native })}
/>
)}
</div>
<div>
{/* Roles:{" "} */}
<div style={{ marginLeft: ".5rem", width: "100%" }}>
<StyledSelect
isMulti
closeMenuOnSelect={false}
onChange={e => {
setAction(prev => ({ ...prev, role: e }));
}}
placeholder="Select Reaction Roles"
value={action.role || ""}
options={guild?.roles
?.filter(role => role.name !== "@everyone" && !role.managed)
?.sort((a, b) => b.rawPosition - a.rawPosition)
?.map(role => ({
value: `${role.name}=${JSON.stringify(role)}`,
label: <RoleItem {...role}>{role.name}</RoleItem>,
}))}
/>
</div>
</div>
<div>
<ActionButton onClick={() => setOpen(prev => !prev)}>
<KeyboardArrowDownIcon />
</ActionButton>
{!join && action.role && action.type && action.emoji && (
<ActionButton onClick={submit}>
<CheckIcon />
</ActionButton>
)}
<ActionButton onClick={() => close?.()}>
<CloseIcon />
</ActionButton>
</div>
</ActionHead>
<ActionFooter open={open}>
<span>
<FormControlLabel
control={
<FancySwitch
color="primary"
checked={action.emoji === "catch-all"}
onChange={e => {
if (e.target.checked) {
setAction(prev => ({ ...prev, emoji: "catch-all" }));
} else {
setAction(prev => ({ ...prev, emoji: null }));
}
}}
name={"catch-all"}
/>
}
label={"ALL"}
/>
</span>
<div style={{ marginLeft: ".5rem", width: "50%" }}>
<StyledSelect
onChange={e => {
setAction(prev => ({ ...prev, type: e.value }));
}}
placeholder="Select Action Type"
value={
action?.type
? {
value: action?.type,
label: REACTION_ROLE_ACTION_TYPES[action?.type],
}
: ""
}
options={Object.entries(REACTION_ROLE_ACTION_TYPES || {})?.map(
([key, value]) => ({
value: key,
label: value,
})
)}
/>
</div>
<div style={{ paddingLeft: ".75rem" }}>
<FormControlLabel
control={
<FancySwitch
color="primary"
checked={!!action.DMuser}
onChange={e => {
setAction(prev => ({ ...prev, DMuser: e.target.checked }));
}}
name={"dm_user"}
/>
}
label={"DM"}
/>
</div>
</ActionFooter>
</ActionBody>
);
}
Example #18
Source File: CreateAction.js From Website with MIT License | 4 votes |
CreateAction = ({ guild, onSubmit, close }) => {
const [action, setAction] = useState({
type: "TOGGLE",
});
console.log(action);
const { update } = useContext(RoleContext);
const [open, setOpen] = useState(false);
const submit = () => {
const roleIDs = action.role.map(role => JSON.parse(role.value.split("=")[1]).id);
console.log(roleIDs);
const actionObj = {
role: roleIDs,
type: action.type,
DMuser: !!action.DMuser,
};
if (onSubmit) {
onSubmit(action.emoji, actionObj);
} else {
update(`manager.actions[${action.emoji}]`, actionObj);
}
return close?.();
};
return (
<ActionBody style={{ zIndex: 1000 }}>
<ActionHead>
<div>
{action.emoji ? (
<span style={{ marginRight: ".5rem", textTransform: "capitalize" }}>
<Twemoji options={{ className: "twemoji" }}>
{action.emoji?.replace("catch-all", "All").replace("-", " ")}
</Twemoji>
</span>
) : (
<Picker
theme="dark"
style={{ position: "absolute", top: ".75rem", zIndex: 100 }}
set="twitter"
title="Pick your emoji…"
emoji="point_up"
onSelect={emoji =>
setAction(prev => ({ ...action, emoji: emoji.native }))
}
/>
)}
</div>
<div>
{/* Roles:{" "} */}
<div style={{ marginLeft: ".5rem", width: "100%" }}>
<StyledSelect
isMulti
closeMenuOnSelect={false}
onChange={e => {
setAction(prev => ({ ...prev, role: e }));
}}
placeholder="Select Reaction Roles"
value={action.role || ""}
options={guild?.roles
?.filter(role => role.name !== "@everyone" && !role.managed)
?.sort((a, b) => b.rawPosition - a.rawPosition)
?.map(role => ({
value: `${role.name}=${JSON.stringify(role)}`,
label: <RoleItem {...role}>{role.name}</RoleItem>,
}))}
/>
</div>
</div>
<div>
<ActionButton onClick={() => setOpen(prev => !prev)}>
<KeyboardArrowDownIcon />
</ActionButton>
{action.role && action.type && action.emoji && (
<ActionButton onClick={submit}>
<CheckIcon />
</ActionButton>
)}
<ActionButton onClick={() => close?.()}>
<CloseIcon />
</ActionButton>
</div>
</ActionHead>
<ActionFooter open={open}>
<span>
<FormControlLabel
control={
<FancySwitch
color="primary"
checked={action.emoji === "catch-all"}
onChange={e => {
if (e.target.checked) {
setAction(prev => ({ ...prev, emoji: "catch-all" }));
} else {
setAction(prev => ({ ...prev, emoji: null }));
}
}}
name={"catch-all"}
/>
}
label={"ALL"}
/>
</span>
<div style={{ marginLeft: ".5rem", width: "50%" }}>
<StyledSelect
onChange={e => {
setAction(prev => ({ ...prev, type: e.value }));
}}
placeholder="Select Action Type"
value={
action?.type
? {
value: action?.type,
label: `Action Type: ${REACTION_ROLE_ACTION_TYPES[action?.type]}`,
}
: ""
}
options={Object.entries(REACTION_ROLE_ACTION_TYPES || {})?.map(
([key, value]) => ({
value: key,
label: value,
})
)}
/>
</div>
<div style={{ paddingLeft: ".75rem" }}>
<FormControlLabel
control={
<FancySwitch
color="primary"
checked={!!action.DMuser}
onChange={e => {
setAction(prev => ({ ...prev, DMuser: e.target.checked }));
}}
name={"dm_user"}
/>
}
label={"DM"}
/>
</div>
</ActionFooter>
</ActionBody>
);
}
Example #19
Source File: App.js From React-Messenger-App with MIT License | 4 votes |
function App() {
const [loading, setLoading] = useState(false);
const [input, setInput] = useState("");
const [messages, setMessages] = useState([]);
const [username, setUsername] = useLocalStorage("username", "");
const [uid, setUid] = useLocalStorage("uid", "");
const [openWelcomeDialogBox, setOpenWelcomeDialogBox] = useState(false);
const [dark, setDark] = useLocalStorage("dark", false);
const messagesEndRef = useRef(null);
const inputElement = useRef(null);
const [click, setClick] = useState(false);
const [showEmojis, setshowEmojis] = useState(false);
const [showKeyboard, setshowKeybord] = useState(false);
const { finalTranscript, resetTranscript } = useSpeechRecognition();
const [showAlert, setShowAlert] = useState(false);
const [messageCount, setMessageCount] = useState(50);
const [scrollTop, setScrollTop] = useState(false);
const [layout, setLayout] = useState("default");
const keyboard = useRef();
const [progress, setProgress] = useState(0);
const [value, setValue] = useState("");
const [status, setStatus] = useState(false);
useEffect(() => {
if (!username || !uid) setOpenWelcomeDialogBox(true);
}, []);
useEffect(() => {
localStorage.setItem("messages", messages);
}, [messages]);
useEffect(() => {
setLoading(true);
console.log("setting true", loading);
db.collection("messages")
.orderBy("timestamp", "desc")
.limit(messageCount)
.onSnapshot((snapshot) => {
setMessages(snapshot.docs.map((doc) => doc.data()).reverse());
setLoading(false);
});
setScrollTop(true);
}, [messageCount]);
useEffect(() => {
if (scrollTop) return setScrollTop(false);
scrollToBottom();
}, [messages]);
const handleClick = () => setClick(!click);
const handlelogout = () => {
setClick(!click);
localStorage.removeItem("RMA-username");
setUsername("");
};
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "auto" });
};
const newMessage = (event) => {
if (input.trim() !== "") {
db.collection("messages").add({
username: username,
uid: uid,
message: input,
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
new Audio(Messagesentaudio).play();
}
setInput("");
};
const handleKeypress = (event) => {
console.log("yes");
//it triggers by pressing the enter key
if (event.key === "Enter") {
console.log("13");
newMessage();
}
};
const theme = (event) => {
if (dark === false) {
document.body.classList.add("dark-bg");
setDark(true);
} else {
document.body.classList.remove("dark-bg");
setDark(false);
}
};
const addEmoji = (e) => {
let emoji = e.native;
let cursorPositionStart = inputElement.current.selectionStart;
let newinput =
input.slice(0, cursorPositionStart) +
emoji +
input.slice(cursorPositionStart);
setInput(newinput);
inputElement.current.focus();
};
const emojiToggle = (e) => {
console.log("in emojiToggle");
if (showEmojis === true) {
setshowEmojis(false);
console.log("picker not visible");
} else {
setshowEmojis(true);
console.log("picker visible");
}
};
const keyboardToggle = (e) => {
console.log("in keyboardToggle");
if (showKeyboard === true) {
setshowKeybord(false);
console.log("picker not visible");
} else {
setshowKeybord(true);
console.log("picker visible");
}
};
const loadOlderMessages = () => {
setMessageCount((prev) => prev + 50);
setProgress(100);
};
useEffect(() => {
if (finalTranscript !== "") {
setShowAlert(false);
setInput(finalTranscript);
resetTranscript();
}
});
const Speechtoinput = (e) => {
setShowAlert(true);
SpeechRecognition.startListening();
};
const handleShift = () => {
const newLayoutName = layout === "default" ? "shift" : "default";
setLayout(newLayoutName);
};
const onKeyPress = (button) => {
console.log("Button pressed", button);
//If you want to handle the shift and caps lock buttons
if (button === "{shift}" || button === "{lock}") handleShift();
};
const onChange = (input) => {
setInput(input);
console.log("Input changed", input);
};
const onChangeInput = (event) => {
const input = event.target.value;
setInput(input);
keyboard.current.setInput(input);
};
return (
<Router>
{/*================ NavBar. Common across all routes ======================*/}
<nav className={`${dark ? "nav_dark" : "navbar"}`}>
<div className="nav-container">
<a href="/landing">
<img
className="Logo"
aspect-ratio="1/1"
height="auto"
width="50px"
src={logo}
alt="messenger-logo"
/>
</a>
<h1 style={{ fontSize: "25px" }} className={`messenger`}>
Messenger
</h1>
<a href="/" className="nav-logo"></a>
<ul
className={click ? "nav-menu active" : "nav-menu"}
id={dark ? "nav-menu_dark" : "nav-menu_light"}
>
<li className="nav-item">
<Link
to="/"
activeClassName="active"
className="nav-links"
onClick={handleClick}
>
Home
</Link>
</li>
<li className="nav-item">
<Link
to="/features"
activeClassName="active"
className="nav-links"
onClick={handleClick}
>
Features
</Link>
</li>
<li className="nav-item">
<Link
to="/about"
activeClassName="active"
className="nav-links"
onClick={handleClick}
>
About Us
</Link>
</li>
{username && (
<li className="nav-item">
<Link
to="/landing"
activeClassName="active"
className="nav-links"
onClick={handlelogout}
>
Logout
</Link>
</li>
)}
{!username && (
<>
<li className="nav-item">
<Link
to="/login"
activeClassName="active"
className="nav-links"
onClick={handleClick}
>
Login
</Link>
</li>
<li className="nav-item">
<Link
to="/signup"
activeClassName="active"
className="nav-links"
onClick={handleClick}
>
Signup
</Link>
</li>
</>
)}
<li className="nav-item toggle-nav" style={{ border: "none" }}>
<Button
title="toggle Dark Mode"
className="dark "
onClick={theme}
>
<Brightness4Icon
className="darkthemeicon"
style={{ border: "none", fontSize: "25px" }}
/>
</Button>
</li>
</ul>
<div
className={`nav-icon ${dark ? "nav-icon_dark" : "nav-icon_light"}`}
onClick={handleClick}
>
<i>
<MenuIcon style={{ fontSize: "30px", marginTop: "3px" }} />
</i>
</div>
</div>
</nav>
{/*========================== End of NavBar ============================*/}
<Switch>
<Suspense
fallback={
<div
style={{
display: "flex",
justifyContent: "center",
marginTop: "50px"
}}
>
Loading...
</div>
}
>
{/*========================== about us ============================*/}
<Route exact path="/about">
<About apptheme5={dark} />
<Faq apptheme4={dark} />
<ContactUs apptheme={dark} />
<Footer apptheme2={dark} />
</Route>
{/*========================== landing page ============================*/}
<Route exact path="/landing">
<Landing apptheme={dark} />
<Footer apptheme2={dark} />
</Route>
{/* ============================Login page ============================ */}
<Route exact path="/login">
<Login apptheme={dark} />
<Footer apptheme2={dark} />
</Route>
<Route exact path="/signup">
<Signup apptheme={dark} />
<Footer apptheme2={dark} />
</Route>
<Route exact path="/forget">
<Forget apptheme={dark} />
<Footer apptheme2={dark} />
</Route>
<Route exact path="/reset">
<Reset apptheme={dark} />
<Footer apptheme2={dark} />
</Route>
{/* ============================features page ============================ */}
<Route exact path="/features">
<Features apptheme3={dark} />
<Footer apptheme2={dark} />
</Route>
{/*========================== home page ============================*/}
<Route exact path="/">
<div className="App">
{loading ? (
<CircularProgress className="loading" />
) : (
<>
<div className="scroll">
<LoadingBar
color=" red"
progress={progress}
onLoaderFinished={() => setProgress(0)}
/>
<br />
<br />
<br />
<button
className={`${
dark ? "loadOlderMessages_dark" : "loadOlderMessages"
}`}
onClick={loadOlderMessages}
>
Load Older Messages
</button>
<br />
<br />
{messages.map((message) => (
<Messages
messages={message}
username={username}
uid={uid}
dark={dark}
key={genKey()}
/>
))}
<div />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
</div>
<div ref={messagesEndRef} />
<Mention trigger="@" />
<div className="div__footer">
<footer className={`${dark ? "footer_dark" : ""}`}>
<div className="content__footer">
<div
className={` ${
dark ? "sendNewMessagedark" : "sendNewMessage"
}`}
>
<button
className={`addfiles ${dark ? "darkButton" : ""}`}
>
<i className="fa fa-plus"></i>
</button>
<button className="EmojiToggle">
<InsertEmoticonIcon onClick={emojiToggle} />
</button>
{showEmojis && (
<span
className={`${
dark ? "EmojiPicker_dark" : "EmojiPicker"
}`}
>
<Picker onSelect={addEmoji} />
</span>
)}
<button className="KeyboardToggle">
<i
className="fa fa-keyboard-o"
onClick={keyboardToggle}
></i>
</button>
{showKeyboard && (
<span
className={`${
dark ? "KeyboardPicker_dark" : "KeyboardPicker"
}`}
>
{/* <input
onChange={onChangeInput}
/> */}
<Keyboard
keyboardRef={(r) => (keyboard.current = r)}
layoutName={layout}
onChange={onChange}
onKeyPress={onKeyPress}
/>
</span>
)}
<input
type="text"
onChange={(e) => {
setValue(e.target.value);
setStatus(false);
}}
/>
<CopyToClipboard
text={value}
onCopy={() => setStatus(true)}
>
<button className="copy">
{" "}
<i className="fa fa-copy"></i>
</button>
</CopyToClipboard>
{status && (
<p className="copied_status"> Copied!!!</p>
)}
<input
ref={inputElement}
className={`input ${
dark ? "dark_input" : "light_input"
}`}
type="text"
placeholder="Type a message"
onChange={(event) => setInput(event.target.value)}
onKeyPress={handleKeypress}
value={input}
/>
<div className="speak">
<button onClick={Speechtoinput}>
<i className="fa fa-microphone"></i>
</button>
{showAlert && (
<span className="Speaknow_alert">Speak now</span>
)}
</div>
<Geolocation > </Geolocation>
<button
className={`btnsend ${
dark ? "darkButtonSend" : ""
}`}
id="sendMsgBtn"
type="submit"
variant="contained"
crossOrigin="anonymous"
onClick={newMessage}
>
<i className="fa fa-paper-plane"></i>
</button>
</div>
</div>
</footer>
<div
className={dark ? "scrolltobottomdark" : "scrolltobottom"}
>
<Button title="scroll to bottom" onClick={scrollToBottom}>
<KeyboardArrowDownIcon
className={dark ? "scrollicondark" : "scrollicon"}
style={{ width: "20px", height: "40px" }}
/>
</Button>
</div>
<WelcomeDialogBox
className={dark ? "wlcm_dark" : "wlcm_light"}
open={openWelcomeDialogBox}
close={() => setOpenWelcomeDialogBox(false)}
setUsername={setUsername}
setUid={setUid}
/>
</div>
</>
)}
</div>
</Route>
</Suspense>
</Switch>
</Router>
);
}
Example #20
Source File: Input.js From AdaptivApps-fe with MIT License | 4 votes |
Input = ({ chatRoom, user }) => {
const classes = useStyles();
const [toggleEmoji, setToggleEmoji] = useState(false);
const [sendChat] = useMutation(SEND_CHAT);
const [message, setMessage] = useState('');
const emojiClick = (e) => {
setMessage(message ? message + e.native : e.native);
};
// Speech to text logic
const { listen, listening, stop } = useSpeechRecognition({
onResult: result => {
setMessage(message ? message + result : result);
},
onEnd: () => console.log('Listening has finished')});
const toggleListen = listening ? stop : () => listen();
// Remove current user from participants array
const recipient = chatRoom.participants.filter(participant => {
return participant.email !== user.email
});
// Create message via text or speech message
const newMessage = async () => {
await sendChat({
variables: {
id: chatRoom.id,
email: user.email,
message: message,
recipient: recipient[0].email
}
})
setMessage('');
};
return(
<div>
<div className={classes.inputDiv}>
<div className={classes.iconDiv}
aria-label="create speech-to-text message"
onClick={toggleListen}>
<MicNoneIcon className={classes.speechIcon}/>
{listening && "Go ahead, I'm listening"}
</div>
<TextField
className={classes.messageBox}
multiline={true}
rowsMax='4'
value={message}
variant="outlined"
type="text"
name="newChat"
placeholder="Type a message..."
onChange={(e) => setMessage(e.target.value)}
InputProps={{
endAdornment: <InputAdornment position="end">
<Tooltip title="Send Message">
<SendIcon
className={classes.sendMessageIcon}
onClick={newMessage}
aria-label="send message"
/>
</Tooltip>
</InputAdornment>
}}
/>
<div className={classes.iconDiv}>
<Tooltip title="Add an emoji!">
<MoodIcon
className={classes.icons}
onClick={() => setToggleEmoji(true)}
aria-label="open emoji picker"/>
</Tooltip>
<Modal
className={classes.modal}
open={toggleEmoji}
onClose={() => setToggleEmoji(false)}>
{toggleEmoji ?
<Picker
onClick={emojiClick}
title='Pick an Emoji!'
emoji='woman_in_manual_wheelchair'
/> : null}
</Modal>
</div>
</div>
</div>
)
}