react-device-detect#isSafari JavaScript Examples

The following examples show how to use react-device-detect#isSafari. 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: InfiniteScroller.js    From website with MIT License 6 votes vote down vote up
componentDidUpdate() {
    if (this.props.isReverse && this.loadMore) {
      const parentElement = this.getParentElement(this.scrollComponent);
      // after loading more, safari's scrollTop need not to be adjusted as it is not
      // affected (since it is a negative value w.r.t the bottom instead of the top)
      if (!isSafari) {
        parentElement.scrollTop = parentElement.scrollHeight - this.beforeScrollHeight + this.beforeScrollTop;
      }
      this.loadMore = false;
    }
    this.attachScrollListener();
  }
Example #2
Source File: CardLog.jsx    From ashteki with GNU Affero General Public License v3.0 5 votes vote down vote up
CardLog = ({ cards, onMouseOut, onMouseOver }) => {
    const [show, setShow] = useState(true);

    if (!cards) {
        return null;
    }

    const renderSimpleCard = (card) => {
        if (!show) return '';

        if (card.type === 'die') {
            return (
                <div className='x-large cardlog-die mb-2'>
                    <DieIcon key={'cld-' + card.uuid} die={card} />
                </div>
            )
        }

        if (!card.id) return '';

        return (
            <div
                className='target-card vertical mb-2'
                onMouseOut={() => onMouseOut && onMouseOut(card)}
                onMouseOver={() => onMouseOver && onMouseOver(card)}
            >
                <CardImage card={card} />
            </div>
        );
    };

    const renderLastCard = (card) => {
        if (card.type === 'die') {
            return (
                <div className='x-large cardlog-die mb-2'>
                    <DieIcon key={'cld-' + card.uuid} die={card} />
                </div>
            )
        }

        if (!card.id) return '';

        return (
            <div
                className='last-card vertical mb-2'
                onMouseOut={() => onMouseOut && onMouseOut(card)}
                onMouseOver={() => onMouseOver && onMouseOver(card)}
            >
                <CardImage card={card} />
            </div>
        );
    };

    let logLength = cards.length - 1;
    if (isSafari) {
        logLength = Math.min(3, logLength);
    }

    const cardPics =
        cards.length > 1 ? cards.slice(0, logLength).map((c) => renderSimpleCard(c)) : null;
    const firstCard = cards.length ? renderLastCard(cards[logLength]) : null;
    // const size = card.type === 'decklist' ? 'x-large' : 'normal';
    const arrow = show ? '︿' : '﹀';
    return (
        <div className='cardlog-wrapper'>
            {firstCard}
            <div className='card-log bg-dark'>
                {cardPics}
                <div className='card-log-arrow' onClick={() => setShow(!show)}>
                    {arrow}
                </div>
            </div>
        </div>
    );
}
Example #3
Source File: InfiniteScroller.js    From website with MIT License 5 votes vote down vote up
scrollListener() {
    const el = this.scrollComponent;
    const scrollEl = window;
    const parentNode = this.getParentElement(el);

    let offset;
    if (this.props.useWindow) {
      const doc = document.documentElement || document.body.parentNode || document.body;
      const scrollTop = scrollEl.pageYOffset !== undefined ? scrollEl.pageYOffset : doc.scrollTop;
      if (this.props.isReverse) {
        offset = scrollTop;
      } else {
        offset = this.calculateOffset(el, scrollTop);
      }
    } else if (this.props.isReverse) {
      if (isSafari) {
        // known issue with safari:
        // scrollTop will be starting from 0 (instead of scrollHeight) even when `flex-direction: column-reverse`,
        // hence the scroll top will be a negative value when scrolling from the div, need to handle separately
        // reference: https://bugzilla.mozilla.org/show_bug.cgi?id=1042151#c36
        offset = parentNode.scrollHeight + parentNode.scrollTop - parentNode.clientHeight;
      } else {
        offset = parentNode.scrollTop;
      }
    } else {
      offset = el.scrollHeight - parentNode.scrollTop - parentNode.clientHeight;
    }

    // Here we make sure the element is visible as well as checking the offset
    if (offset < Number(this.props.threshold) && el && el.offsetParent !== null) {
      this.detachScrollListener();
      this.beforeScrollHeight = parentNode.scrollHeight;
      this.beforeScrollTop = parentNode.scrollTop;
      // Call loadMore after detachScrollListener to allow for non-async loadMore functions
      // added check for this.props.hasMore to prevent loading more when it does not have more
      if (typeof this.props.loadMore === 'function' && this.props.hasMore) {
        this.props.loadMore((this.pageLoaded += 1));
        this.loadMore = true;
      }
    }
  }
Example #4
Source File: index.js    From website with MIT License 4 votes vote down vote up
ChatDialogMessages = ({ postType, inputRowHeight, isShowPostDetails }) => {
  const { state } = useContext(ChatContext);
  const loggedInUser = getUser(state);
  const isNewChat = getIsNewChat(state);
  const selectedChatId = getSelectedChatId(state);
  const navBarHeight = useNavbarHeight();

  const [chatMessageDocs, setChatMessageDocs] = useState([]);
  // only consider loading more when it's not a new chat, since it's impossible to have a new chat
  // to have messages initially
  const [shouldSeeMore, setShouldSeeMore] = useState(!isNewChat);
  const [isLoadingMore, setIsLoadingMore] = useState(false); // to prevent multiple loads at the same time
  const [isShowScrollerButton, setIsShowScrollerButton] = useState(false);
  const [unreadCount, setUnreadCount] = useState(0);
  const { isTablet } = useMediaQuery();
  const bottomOfScrollerRef = useRef(null);
  const scrollerRef = useRef(null);
  const { height: viewportHeight } = useWindowDimensions();

  useEffect(() => {
    // reset values every time selectedChatId changes
    setChatMessageDocs([]);
    setShouldSeeMore(!isNewChat);
    setIsShowScrollerButton(false);

    let unsubscribeFunction;
    const { userId } = loggedInUser.user;
    // when selected a chat, subscribe to the corresponding chat messages
    if (selectedChatId !== null || !isNewChat) {
      api.chats
        .subscribeToChatMessages(selectedChatId, userId, updateChatMessages)
        .then((fn) => (unsubscribeFunction = fn))
        .then(() => {
          api.chats.activateUserChatPresence(selectedChatId, userId);
        });
      disableFurtherLoadsIfMessagesLessThanOneBatch();
    }

    return () => {
      if (unsubscribeFunction) {
        api.chats.unsubscribeFromChatMessages(selectedChatId, userId, unsubscribeFunction).then(() => {
          api.chats.deactivateUserChatPresence(selectedChatId, userId);
          setChatMessageDocs([]);
        });
      }
    };
  }, [selectedChatId]);

  const scrollToBottomIfSentByLoggedInUser = (chatMessage) => {
    if (chatMessage.sender.id === loggedInUser.user.userId) {
      bottomOfScrollerRef.current.scrollIntoView();
    }
  };

  const incrementUnreadCountIfSentByOppositeUser = (chatMessage) => {
    if (chatMessage.sender.id !== loggedInUser.user.userId) {
      const bottomScrollTop = isSafari ? 0 : scrollerRef.current.scrollHeight - scrollerRef.current.clientHeight;
      if (scrollerRef.current.scrollTop < bottomScrollTop) {
        setUnreadCount((unreadCount) => unreadCount + 1);
      }
    }
  };

  /**
   * Callback function that is called when:
   * i) fetching the initial batch of chat messages
   * ii) when new chat messages are received
   */
  const updateChatMessages = (chatMessageDoc) => {
    let isNewlySentMessage = false;
    setChatMessageDocs((prevChatMessageDocs) => {
      const newChatMessage = chatMessageDoc.data();
      const lastChatMessageDoc = prevChatMessageDocs[prevChatMessageDocs.length - 1];
      const firstChatMessageDoc = prevChatMessageDocs[0];

      // insert chat message doc to the front if no messages or the message is an older message
      if (
        !firstChatMessageDoc ||
        firstChatMessageDoc.data().dateTime.toMillis() >= newChatMessage.dateTime.toMillis()
      ) {
        return [chatMessageDoc, ...prevChatMessageDocs];
      }

      if (lastChatMessageDoc.data().dateTime.toMillis() <= newChatMessage.dateTime.toMillis()) {
        // insert chat message doc to the back if it is a newly sent message
        isNewlySentMessage = true;
        return [...prevChatMessageDocs, chatMessageDoc];
      } else {
        // insert chat message doc to the correct position if not newly sent message
        // note: this occurs when there are concurrency issues when sending and receiving messages
        for (let i = prevChatMessageDocs.length - 1; i >= 0; i--) {
          const currMessage = prevChatMessageDocs[i].data();
          if (newChatMessage.dateTime.toMillis() > currMessage.dateTime.toMillis()) {
            return [...prevChatMessageDocs.slice(0, i + 1), chatMessageDoc, ...prevChatMessageDocs.slice(i + 1)];
          }
        }
      }
    });
    if (isNewlySentMessage) {
      scrollToBottomIfSentByLoggedInUser(chatMessageDoc.data());
      incrementUnreadCountIfSentByOppositeUser(chatMessageDoc.data());
    }
  };

  /**
   * A hacky way to determine if we should load more after the first batch,
   * since the subscription method does not tell whether the first load of chat
   * messages are less than one CHAT_MESSAGES_BATCH_SIZE
   */
  const disableFurtherLoadsIfMessagesLessThanOneBatch = () => {
    api.chats.getChatMessages(selectedChatId).then((rawNewChatMessages) => {
      if (rawNewChatMessages.docs.length < CHAT_MESSAGES_BATCH_SIZE) {
        // loaded all chat messages
        setShouldSeeMore(false);
      }
    });
  };

  const handleOnSeeMore = () => {
    if (chatMessageDocs.length === 0) {
      return; // assuming that you can see more after loading the initial batch
    }
    setIsLoadingMore(true);
    api.chats.getChatMessages(selectedChatId, chatMessageDocs[0]).then((rawNewChatMessages) => {
      // need to reverse the new chat message docs since the order of the array is latest -> oldest, but in our
      // array the order is oldest -> latest
      const newChatMessageDocs = rawNewChatMessages.docs.reverse();
      setChatMessageDocs([...newChatMessageDocs, ...chatMessageDocs]);
      if (newChatMessageDocs.length < CHAT_MESSAGES_BATCH_SIZE) {
        // loaded all chat messages
        setShouldSeeMore(false);
      }
      setIsLoadingMore(false);
    });
  };

  /**
   * Handler to show the scroller button if scroll position is not at the bottom
   */
  const scrollHandler = () => {
    // note:
    // safari and chrome browsers' bottom has scrollTop of 0, negative values when scroll up
    // other browsers' bottom has scrollTop of scrollHeight - clientHeight
    const bottomScrollTop = isSafari ? 0 : scrollerRef.current.scrollHeight - scrollerRef.current.clientHeight;
    const currScrollTop = scrollerRef.current.scrollTop;
    if (currScrollTop < bottomScrollTop && currScrollTop !== 0) {
      setIsShowScrollerButton(true);
    } else {
      setIsShowScrollerButton(false);
      setUnreadCount(0);
    }
  };

  // get all heights of components within the chatDialog, only inputRowHeight is passed in as
  // the height is not constant
  const { chatDialogBackButton, chatDialogSeePostRow, chatDialogUserRow, chatDialogMessagesPadding } = isTablet
    ? desktopHeights
    : mobileHeights;

  let sumOfOtherComponentHeights = chatDialogBackButton + chatDialogMessagesPadding + inputRowHeight;

  if (isShowPostDetails) {
    // only add the heights of see post row and user row if it is going to be shown
    sumOfOtherComponentHeights += chatDialogSeePostRow + chatDialogUserRow;
  }

  const offsetHeight = navBarHeight + sumOfOtherComponentHeights;

  // display tips before first message is being sent for a wish
  if (isNewChat && !selectedChatId && postType === wishes) {
    return (
      <CardSection>
        <MessageContainer offsetHeight={offsetHeight} viewportHeight={viewportHeight}>
          <NewChatTipsForWish postType={postType} />
        </MessageContainer>
      </CardSection>
    );
  }

  return (
    <CardSection>
      <MessageContainer
        offsetHeight={offsetHeight}
        viewportHeight={viewportHeight}
        onScroll={scrollHandler}
        ref={scrollerRef}
      >
        <InfiniteScroll
          loadMore={handleOnSeeMore}
          hasMore={shouldSeeMore && !isLoadingMore}
          isReverse
          initialLoad={false}
          useWindow={false}
          loader={<Loading type="pageLoader" key={0} />}
        >
          <Stack direction="column">
            {chatMessageDocs &&
              chatMessageDocs.map((messageDoc) => {
                const message = messageDoc.data();
                const { sender, content, dateTime } = message;
                // right side is logged in user's messages, left side is opposite user's
                return sender.id === loggedInUser.user.userId ? (
                  <RightMessageSection
                    key={`${messageDoc.id}`}
                    message={message}
                    loggedInUser={loggedInUser}
                    selectedChatId={selectedChatId}
                    offsetHeight={offsetHeight}
                  />
                ) : (
                  <LeftMessageSection
                    key={`${messageDoc.id}`}
                    message={message}
                    loggedInUser={loggedInUser}
                    selectedChatId={selectedChatId}
                    offsetHeight={offsetHeight}
                  />
                );
              })}
          </Stack>
          <div ref={bottomOfScrollerRef} />
        </InfiniteScroll>
      </MessageContainer>
      {isShowScrollerButton && (
        <ScrollToBottomContainer>
          <ScrollerButtonContainer>
            <Button
              circled
              transparent
              iconLeft={<ChevronDown />}
              asComponent={ScrollToBottomButton}
              onClick={() => bottomOfScrollerRef.current.scrollIntoView({ behavior: 'smooth' })}
            ></Button>
          </ScrollerButtonContainer>
          {unreadCount > 0 && (
            <NotificationBadgeWrapper>
              <NotificationBadge type="info">{unreadCount}</NotificationBadge>
            </NotificationBadgeWrapper>
          )}
        </ScrollToBottomContainer>
      )}
    </CardSection>
  );
}
Example #5
Source File: WyreTopUpBalanceDropdown.jsx    From v3-ui with MIT License 4 votes vote down vote up
export function WyreTopUpBalanceDropdown(props) {
  const { t } = useTranslation()

  const { label, className, hoverTextColor, textColor, tickerUpcased } = props

  const onValueSet = (currency) => {
    handleOpenWyre(currency)
  }

  const applePay = (
    <>
      {isSafari && (
        <>
          , <img src={ApplePay} className='inline-block relative h-6 w-12' style={{ top: 0 }} />
        </>
      )}
    </>
  )

  const currencies = {
    [tickerUpcased]: {
      label: (
        <span className='text-xs'>
          {t('buyTickerDebitCreditCard', {
            ticker: tickerUpcased
          })}
          {applePay}
        </span>
      )
    },
    ETH: {
      label: (
        <span className='text-xs'>
          {t('buyEthDebitCreditCard')}
          {applePay}
        </span>
      )
    }
  }

  const handleOpenWyre = async (currency) => {
    const { usersAddress } = props

    const params = {
      path: `/v3/orders/reserve`,
      dest: `ethereum:${usersAddress}`,
      destCurrency: currency.toUpperCase()
    }

    let response

    try {
      response = await axiosInstance.post(`${WYRE_LAMBDA_PATH}`, params)

      // dropdownRef.handleClose()

      const url = response?.data?.url

      if (url) {
        window.open(url)
      } else {
        console.warn(response.error)
      }
    } catch (e) {
      poolToast.error(`Wyre - purchase error, please try again or message support`)
      console.error(e)
    }
  }

  const formatValue = (key) => {
    const currency = currencies[key]

    return <>{currency.label}</>
  }

  return (
    <>
      <span className='relative z-50'>
        <DropdownList
          id='topup-dropdown'
          label={label}
          className={className}
          textColor={textColor}
          hoverTextColor={hoverTextColor}
          formatValue={formatValue}
          onValueSet={onValueSet}
          current={null}
          values={currencies}
        />
      </span>
    </>
  )
}