From 86fbe807845e4c1eb74fc2dc750f87921e7c1dc3 Mon Sep 17 00:00:00 2001 From: Antoine Jaussoin Date: Thu, 20 Jan 2022 15:28:39 +0000 Subject: [PATCH] Improve chat (#337) --- frontend/src/hooks/useFormatDate.ts | 37 +++++++++---------- frontend/src/translations/ar.ts | 1 + frontend/src/translations/de.ts | 1 + frontend/src/translations/en.ts | 3 ++ frontend/src/translations/es.ts | 1 + frontend/src/translations/fr.ts | 1 + frontend/src/translations/hu.ts | 1 + frontend/src/translations/it.ts | 1 + frontend/src/translations/ja.ts | 1 + frontend/src/translations/nl.ts | 1 + frontend/src/translations/pl.ts | 1 + frontend/src/translations/pt-br.ts | 1 + frontend/src/translations/ru.ts | 1 + frontend/src/translations/types.ts | 3 ++ frontend/src/translations/zh-cn.ts | 1 + frontend/src/translations/zh-tw.ts | 1 + frontend/src/views/Game.tsx | 4 +- frontend/src/views/account/AccountPage.tsx | 2 +- .../game/{Participants.tsx => GameFooter.tsx} | 19 +++++++--- frontend/src/views/game/chat/Chat.tsx | 7 +++- frontend/src/views/game/chat/Message.tsx | 6 ++- .../src/views/game/summary/SummaryMode.tsx | 4 +- frontend/src/views/home/TrialPrompt.tsx | 2 +- .../views/home/game-item/PreviousGameItem.tsx | 2 +- 24 files changed, 68 insertions(+), 34 deletions(-) rename frontend/src/views/game/{Participants.tsx => GameFooter.tsx} (84%) diff --git a/frontend/src/hooks/useFormatDate.ts b/frontend/src/hooks/useFormatDate.ts index 2b63a1492..7b593af58 100644 --- a/frontend/src/hooks/useFormatDate.ts +++ b/frontend/src/hooks/useFormatDate.ts @@ -1,36 +1,33 @@ -import { formatDistanceToNow as formatDistanceToNowBase } from 'date-fns'; +import { + formatDistanceToNow as formatDistanceToNowBase, + Locale, +} from 'date-fns'; +import englishLocale from 'date-fns/locale/en-GB'; import { useEffect, useState } from 'react'; import { useLanguage } from '../translations'; -type FormatFunction = (date: Date | number, addSuffix?: boolean) => string; +export default function useFormatDate() { + const locale = useDateLocale(); -function formatEnglish(date: Date | number, addSuffix = false) { - return formatDistanceToNowBase(date, { - addSuffix, - }); + return function formatLocale(date: Date | number, addSuffix = false) { + return formatDistanceToNowBase(date, { + locale: locale, + addSuffix, + }); + }; } -export default function useFormatDate() { +export function useDateLocale() { const language = useLanguage(); - const [formatDistanceToNow, setFormat] = useState( - () => formatEnglish - ); + const [locale, setLocale] = useState(() => englishLocale); useEffect(() => { async function load() { const locale = await language.dateLocale(); - setFormat( - () => - (function formatLocale(date: Date | number, addSuffix = false) { - return formatDistanceToNowBase(date, { - locale: locale.default, - addSuffix, - }); - }) - ); + setLocale(locale.default); } load(); }, [language]); - return { formatDistanceToNow }; + return locale; } diff --git a/frontend/src/translations/ar.ts b/frontend/src/translations/ar.ts index f1ddb3e26..70bb8b32e 100644 --- a/frontend/src/translations/ar.ts +++ b/frontend/src/translations/ar.ts @@ -396,4 +396,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/de.ts b/frontend/src/translations/de.ts index 2128201fd..9fac1540a 100644 --- a/frontend/src/translations/de.ts +++ b/frontend/src/translations/de.ts @@ -403,4 +403,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/en.ts b/frontend/src/translations/en.ts index 712b27664..4de58ad3f 100644 --- a/frontend/src/translations/en.ts +++ b/frontend/src/translations/en.ts @@ -475,4 +475,7 @@ export default { trialEndedSentence: 'Subscribe today to regain access to the Pro features.', subscribeNow: 'Subscribe now!', }, + Chat: { + writeAMessage: 'Write a message here...', + }, } as Translation; diff --git a/frontend/src/translations/es.ts b/frontend/src/translations/es.ts index 756b4388c..94eb07d02 100644 --- a/frontend/src/translations/es.ts +++ b/frontend/src/translations/es.ts @@ -399,4 +399,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/fr.ts b/frontend/src/translations/fr.ts index 60fa9bc7c..8aa5dac97 100644 --- a/frontend/src/translations/fr.ts +++ b/frontend/src/translations/fr.ts @@ -473,4 +473,5 @@ export default { trialEndedSentence: `Abonnez-vous aujourd'hui pour continuer à bénéficier des avantages de la version Pro.`, subscribeNow: `Je m'abonne`, }, + Chat: { writeAMessage: 'Écrivez un message ici...' }, } as Translation; diff --git a/frontend/src/translations/hu.ts b/frontend/src/translations/hu.ts index b3f8e1af3..17f28b292 100644 --- a/frontend/src/translations/hu.ts +++ b/frontend/src/translations/hu.ts @@ -399,4 +399,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/it.ts b/frontend/src/translations/it.ts index 4f06fcb20..bebe26331 100644 --- a/frontend/src/translations/it.ts +++ b/frontend/src/translations/it.ts @@ -409,4 +409,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/ja.ts b/frontend/src/translations/ja.ts index 5b77dcb76..4d3c42da0 100644 --- a/frontend/src/translations/ja.ts +++ b/frontend/src/translations/ja.ts @@ -397,4 +397,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/nl.ts b/frontend/src/translations/nl.ts index 17fd7303f..01d4332a8 100644 --- a/frontend/src/translations/nl.ts +++ b/frontend/src/translations/nl.ts @@ -409,4 +409,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/pl.ts b/frontend/src/translations/pl.ts index 0af0bb9c0..1dc3487bc 100644 --- a/frontend/src/translations/pl.ts +++ b/frontend/src/translations/pl.ts @@ -399,4 +399,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/pt-br.ts b/frontend/src/translations/pt-br.ts index d20c2c758..388f1e6f6 100644 --- a/frontend/src/translations/pt-br.ts +++ b/frontend/src/translations/pt-br.ts @@ -399,4 +399,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/ru.ts b/frontend/src/translations/ru.ts index 5ea6da84a..645b8faef 100644 --- a/frontend/src/translations/ru.ts +++ b/frontend/src/translations/ru.ts @@ -397,4 +397,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/types.ts b/frontend/src/translations/types.ts index dc9c6a3a9..b6adc2426 100644 --- a/frontend/src/translations/types.ts +++ b/frontend/src/translations/types.ts @@ -399,4 +399,7 @@ export interface Translation { trialEndedSentence?: string; subscribeNow?: string; }; + Chat: { + writeAMessage?: string; + }; } diff --git a/frontend/src/translations/zh-cn.ts b/frontend/src/translations/zh-cn.ts index 22d30e242..b80e09be4 100644 --- a/frontend/src/translations/zh-cn.ts +++ b/frontend/src/translations/zh-cn.ts @@ -397,4 +397,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/translations/zh-tw.ts b/frontend/src/translations/zh-tw.ts index 860c8d400..d3be83a31 100644 --- a/frontend/src/translations/zh-tw.ts +++ b/frontend/src/translations/zh-tw.ts @@ -397,4 +397,5 @@ export default { trialEndedSentence: undefined, subscribeNow: undefined, }, + Chat: { writeAMessage: undefined }, } as Translation; diff --git a/frontend/src/views/Game.tsx b/frontend/src/views/Game.tsx index 2574eb625..7eaa98a7d 100644 --- a/frontend/src/views/Game.tsx +++ b/frontend/src/views/Game.tsx @@ -24,7 +24,7 @@ import NoContent from '../components/NoContent'; import useCrypto from '../crypto/useCrypto'; import Unauthorized from './game/Unauthorized'; import SearchBar from './game/SearchBar'; -import Participants from './game/Participants'; +import GameFooter from './game/GameFooter'; import AckWarning from './game/AckWarning'; import useUnauthorised from './game/useUnauthorised'; import useSession from './game/useSession'; @@ -184,7 +184,7 @@ function GamePage() { /> ) : null} - void; messages: Message[]; onMessage: (content: string) => void; }; -function Participants({ onReady, onMessage, messages }: ParticipantsProps) { +function GameFooter({ onReady, onMessage, messages }: GameFooterProps) { const { participants } = useParticipants(); const { session } = useSession(); const user = useUser(); @@ -33,10 +33,17 @@ function Participants({ onReady, onMessage, messages }: ParticipantsProps) { const isUserReady = !!user && !!session && session.ready.includes(user.id); const fullScreen = useMediaQuery('(min-width:600px)'); const [chatOpen, openChat, closeChat] = useModal(); + const [readCount, setReadCount] = useState(0); const handleReady = useCallback(() => { trackEvent('game/session/user-ready'); onReady(); }, [onReady]); + useEffect(() => { + if (chatOpen) { + setReadCount(messages.length); + } + }, [chatOpen, messages.length]); + const unreadCount = messages.length - readCount; return ( - + + + ) : null} {chatOpen ? ( @@ -110,4 +119,4 @@ const Container = styled.div` } `; -export default Participants; +export default GameFooter; diff --git a/frontend/src/views/game/chat/Chat.tsx b/frontend/src/views/game/chat/Chat.tsx index ead19fd0e..e67db180b 100644 --- a/frontend/src/views/game/chat/Chat.tsx +++ b/frontend/src/views/game/chat/Chat.tsx @@ -5,6 +5,7 @@ import Input from './Input'; import ChatMessage from './Message'; import { useMemo } from 'react'; import { sortBy } from 'lodash'; +import useTranslations from 'translations'; type ChatProps = { messages: Message[]; @@ -12,6 +13,7 @@ type ChatProps = { }; export default function Chat({ messages, onMessage }: ChatProps) { + const { Chat: translations } = useTranslations(); const sortedMessages = useMemo(() => { return sortBy(messages, (m) => m.created); }, [messages]); @@ -24,7 +26,10 @@ export default function Chat({ messages, onMessage }: ChatProps) { ))} - + ); } diff --git a/frontend/src/views/game/chat/Message.tsx b/frontend/src/views/game/chat/Message.tsx index 52b6d30e6..cfb938483 100644 --- a/frontend/src/views/game/chat/Message.tsx +++ b/frontend/src/views/game/chat/Message.tsx @@ -2,12 +2,14 @@ import { Message } from 'common'; import styled from '@emotion/styled'; import { colors } from '@mui/material'; import { formatRelative } from 'date-fns'; +import { useDateLocale } from 'hooks/useFormatDate'; type ChatMessageProps = { message: Message; }; export default function ChatMessage({ message }: ChatMessageProps) { + const locale = useDateLocale(); return ( @@ -18,7 +20,9 @@ export default function ChatMessage({ message }: ChatMessageProps) {
{message.user.name} - +
{message.content}
diff --git a/frontend/src/views/game/summary/SummaryMode.tsx b/frontend/src/views/game/summary/SummaryMode.tsx index 8e35ddae2..157fd7193 100644 --- a/frontend/src/views/game/summary/SummaryMode.tsx +++ b/frontend/src/views/game/summary/SummaryMode.tsx @@ -240,9 +240,9 @@ const SummaryMode = ({ columns, search }: SummaryModeProps) => { const SpeedDialContainer = styled.div` position: fixed; - bottom: 20px; + bottom: 85px; right: 20px; - z-index: 4; + z-index: 3; `; export default SummaryMode; diff --git a/frontend/src/views/home/TrialPrompt.tsx b/frontend/src/views/home/TrialPrompt.tsx index 422487200..c22410a9d 100644 --- a/frontend/src/views/home/TrialPrompt.tsx +++ b/frontend/src/views/home/TrialPrompt.tsx @@ -12,7 +12,7 @@ import ProButton from '../../components/ProButton'; export default function TrialPrompt() { const user = useUser(); const isInTrial = useIsTrial(); - const { formatDistanceToNow } = useFormatDate(); + const formatDistanceToNow = useFormatDate(); const { TrialPrompt: translations } = useTranslations(); const { quota } = useQuota(); const quotaLeft = !!quota ? quota.quota - quota.posts : null; diff --git a/frontend/src/views/home/game-item/PreviousGameItem.tsx b/frontend/src/views/home/game-item/PreviousGameItem.tsx index 16ebbf087..2b6e977ca 100644 --- a/frontend/src/views/home/game-item/PreviousGameItem.tsx +++ b/frontend/src/views/home/game-item/PreviousGameItem.tsx @@ -41,7 +41,7 @@ const PreviousGameItem = ({ DeleteSession, } = useTranslations(); const [encryptionKey] = useEncryptionKey(session.id); - const { formatDistanceToNow } = useFormatDate(); + const formatDistanceToNow = useFormatDate(); const [hover, hoverRef] = useOnHover(); const handleClick = useCallback(() => { onClick(session, encryptionKey);