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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
    )
}