import React, { useState, useEffect, useContext, useRef, useCallback, useMemo } from "react"; import Paper from '@material-ui/core/Paper'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemText from '@material-ui/core/ListItemText'; import Moment from 'react-moment'; import TextField from '@material-ui/core/TextField'; import 'moment-timezone'; import "./Chat.css"; import { PlayerColor } from './PlayerColor.js'; import { Resource } from './Resource.js'; import { Dice } from './Dice.js'; import { GlobalContext } from "./GlobalContext.js"; const Chat = () => { const [lastTop, setLastTop] = useState(0); const [autoScroll, setAutoScroll] = useState(true); const [latest, setLatest] = useState(''); const [scrollTime, setScrollTime] = useState(0); const [chat, setChat] = useState([]); const [startTime, setStartTime] = useState(0); const { ws, name } = useContext(GlobalContext); const fields = useMemo(() => [ 'chat', 'startTime' ], []); const onWsMessage = (event) => { const data = JSON.parse(event.data); switch (data.type) { case 'game-update': console.log(`chat - game update`); if (data.update.chat && data.update.chat.length !== chat.length) { console.log(`chat - game update - ${data.update.chat.length} lines`); setChat(data.update.chat); } if (data.update.startTime && data.update.startTime !== startTime) { setStartTime(data.update.startTime); } break; default: break; } }; const refWsMessage = useRef(onWsMessage); useEffect(() => { refWsMessage.current = onWsMessage; }); useEffect(() => { if (!ws) { return; } const cbMessage = e => refWsMessage.current(e); ws.addEventListener('message', cbMessage); return () => { ws.removeEventListener('message', cbMessage); } }, [ws, refWsMessage]); useEffect(() => { if (!ws) { return; } ws.send(JSON.stringify({ type: 'get', fields })); }, [ws, fields]); const chatKeyPress = useCallback((event) => { if (event.key === "Enter") { if (!autoScroll) { setAutoScroll(true); } ws.send(JSON.stringify({ type: 'chat', message: event.target.value })); event.target.value = ""; } }, [ws, setAutoScroll, autoScroll]); const chatScroll = (event) => { const chatList = event.target, fromBottom = Math.round(Math.abs((chatList.scrollHeight - chatList.offsetHeight) - chatList.scrollTop)); /* If scroll is within 20 pixels of the bottom, turn on auto-scroll */ const shouldAutoscroll = (fromBottom < 20); if (shouldAutoscroll !== autoScroll) { setAutoScroll(shouldAutoscroll); } /* If the list should not auto scroll, then cache the current * top of the list and record when we did this so we honor * the auto-scroll for at least 500ms */ if (!shouldAutoscroll) { const target = Math.round(chatList.scrollTop); if (target !== lastTop) { setLastTop(target); setScrollTime(Date.now()); } } }; useEffect(() => { const chatList = document.getElementById("ChatList"), currentTop = Math.round(chatList.scrollTop); if (autoScroll) { /* Auto-scroll to the bottom of the chat window */ const target = Math.round(chatList.scrollHeight - chatList.offsetHeight); if (currentTop !== target) { chatList.scrollTop = target; } return; } /* Maintain current position in scrolled view if the user hasn't * been scrolling in the past 0.5s */ if ((Date.now() - scrollTime) > 500 && currentTop !== lastTop) { chatList.scrollTop = lastTop; } }); const messages = chat.map((item, index) => { let message; /* Do not perform extra parsing on player-generated * messages */ if (item.normalChat) { message =