From 1fb5d9590be17a7b1f0df20aa9d30bd83ba40b4d Mon Sep 17 00:00:00 2001 From: tsungai Date: Fri, 9 Jun 2023 13:27:03 +0000 Subject: [PATCH] Merged PR 4332: Match lobby QA Create a match as usual and go to the lobby, the lobby should behave as usual. - Check that the chat works accordingly - Check that the new navigation bar works accordingly - Check that u can enter a match --- frontend/src/design/measurements.ts | 4 ++ frontend/src/molecules/chat/chat.tsx | 46 ++++++++----- .../molecules/chat/grouped-chat-meesages.tsx | 39 ++++++----- frontend/src/molecules/chat/styles.ts | 26 ++++--- .../molecules/lobby-player/lobby-player.tsx | 22 +++--- frontend/src/molecules/lobby-player/styles.ts | 7 +- .../src/molecules/player-lineup/styles.ts | 4 +- frontend/src/organisms/index.ts | 1 + frontend/src/organisms/lobby/index.ts | 1 + frontend/src/organisms/lobby/lobby.tsx | 68 +++++++++++++++++++ frontend/src/organisms/lobby/styles.ts | 14 ++++ .../src/organisms/player-logo/player-logo.tsx | 12 ++-- .../src/organisms/player-menu/player-menu.tsx | 8 ++- frontend/src/pages/match/match.tsx | 2 +- frontend/src/pages/test/test.tsx | 2 +- frontend/src/views/match/match.tsx | 4 +- 16 files changed, 189 insertions(+), 71 deletions(-) create mode 100644 frontend/src/organisms/lobby/index.ts create mode 100644 frontend/src/organisms/lobby/lobby.tsx create mode 100644 frontend/src/organisms/lobby/styles.ts diff --git a/frontend/src/design/measurements.ts b/frontend/src/design/measurements.ts index 1430b6d2..8a31668a 100644 --- a/frontend/src/design/measurements.ts +++ b/frontend/src/design/measurements.ts @@ -1,10 +1,14 @@ export const SIDEBAR_HEIGHT = 89; export const DESKTOP_BREAKPOINT = 959; export const TOOLTIP_SIZE = "7vw"; +export const CHAT_MESSAGE_SIZE = "clamp(0.5rem, 0.21vw + 0.38rem, 0.88rem)"; +export const CHAT_INPUT_SIZE = "94.4%"; + export const MATCH_FORM_MARGIN = "0.18rem"; export const MATCH_FORM_SIZE = "0.03rem"; export const POWER_UP_FORM_SIZE = "clamp(400px, 34.72vw + 66.67px, 1400px)"; export const MIN_TOOLTIP_WIDTH = "32vw"; + export const measurements = { localAvatarHeight: "7vh", }; diff --git a/frontend/src/molecules/chat/chat.tsx b/frontend/src/molecules/chat/chat.tsx index f7a82a80..40a8b5d8 100644 --- a/frontend/src/molecules/chat/chat.tsx +++ b/frontend/src/molecules/chat/chat.tsx @@ -1,42 +1,54 @@ import { FC } from "react"; import { text } from "../../assets"; import { ChatInput } from "../../atoms"; +import { CHAT_INPUT_SIZE } from "../../design"; +import { sendMessage } from "../../service"; import { ChatMessageContent } from "../../types"; import { GroupedChatMessages } from "./grouped-chat-meesages"; -import { ChatContainer, ChatMessageListWrapper } from "./styles"; +import { ChatContainer, ChatMessageInput, ChatMessageListWrapper } from "./styles"; interface ChatProps { messages: ChatMessageContent[][]; messageInput?: string; + channelId?: string; - handleSendEvent: (e: React.MouseEvent | React.KeyboardEvent) => void; handleKeyEvent: (e: React.KeyboardEvent) => void; setMessageInput: (value: string) => void; } /** - * @param {messages} - An array of arrays of messages. Use the parseMessages function to get this. - * @param {messageInput} - The current value of the message input. - * @param {handleSendEvent} - A function to handle the send message event. - * @param {handleKeyEvent} - A function to handle the enter key event that will trigger the send event. - * @param {setMessageInput} - A function to set/update the messageInput prop value. + * @param {ChatMessageContent[][]} messages - An array of arrays of messages. Use the parseMessages function to get this. + * @param {string} messageInput - The current value of the message input. + * @param {string} channelId - The channel id for the match chat + * @param {Function} handleKeyEvent - A function to handle the enter key event that will trigger the send event. + * @param {Function} setMessageInput - A function to set/update the messageInput prop value. */ -export const Chat: FC = ({ messages, messageInput, handleKeyEvent, setMessageInput, handleSendEvent }) => { +export const Chat: FC = ({ messages, messageInput, channelId, handleKeyEvent, setMessageInput }) => { + const handleSendEvent = (e: React.MouseEvent | React.KeyboardEvent) => { + e.stopPropagation(); + if (e.currentTarget.value === "") return; + sendMessage(channelId, e.currentTarget.value); + setMessageInput(""); + }; + return ( - + {messages.map((groupedMessages, index) => ( ))} - setMessageInput(event.target.value)} - onClick={(event) => handleSendEvent(event)} - onKeyDownCapture={(event) => handleKeyEvent(event)} - /> + + setMessageInput(event.target.value)} + onClick={(event) => handleSendEvent(event)} + onKeyDownCapture={(event) => handleKeyEvent(event)} + width={CHAT_INPUT_SIZE} + /> + ); }; diff --git a/frontend/src/molecules/chat/grouped-chat-meesages.tsx b/frontend/src/molecules/chat/grouped-chat-meesages.tsx index 0eb8bc1d..92e83956 100644 --- a/frontend/src/molecules/chat/grouped-chat-meesages.tsx +++ b/frontend/src/molecules/chat/grouped-chat-meesages.tsx @@ -1,7 +1,7 @@ import { FC } from "react"; import { CircleIconSVG } from "../../assets"; -import { BaseIcon, BaseRow, GeneralText, PlayerInfoText } from "../../atoms"; -import { fontSizes, fontWeights, spacing } from "../../design"; +import { BaseColumn, BaseIcon, BaseRow, GeneralText, PlayerInfoText } from "../../atoms"; +import { fontSizes, fontWeights, CHAT_MESSAGE_SIZE, spacing } from "../../design"; import { ChatMessageContent } from "../../types"; import { CircleIconWrapper, Message, MessageWrapper } from "./styles"; @@ -13,26 +13,29 @@ interface Props { * @param {messages} - An array of messages. */ export const GroupedChatMessages: FC = ({ messages }) => { + const isNameShowing = !messages.at(0)?.isLocalUser; return ( <> {messages.map((message, index) => ( - - {index === 0 && !message.isLocalUser && ( - - - - - } - iconColor={message.color} - /> - - {message.name} - - - )} + + + {isNameShowing && index === messages.length - 1 && ( + + + + + } + iconColor={message.color} + /> + + {message.name} + + + )} + {message.content} diff --git a/frontend/src/molecules/chat/styles.ts b/frontend/src/molecules/chat/styles.ts index 16b7cf74..fe1de992 100644 --- a/frontend/src/molecules/chat/styles.ts +++ b/frontend/src/molecules/chat/styles.ts @@ -1,16 +1,18 @@ import styled from "@emotion/styled"; -import { BaseColumn, BaseIconWrapper, GeneralText, MessageBlock } from "../../atoms"; -import { color } from "../../design"; +import { BaseColumn, BaseIconWrapper, BaseRow, GeneralText, MessageBlock } from "../../atoms"; +import { CHAT_MESSAGE_SIZE, color, containerWidth, spacing } from "../../design"; export const ChatContainer = styled(BaseColumn)` - width: 100%; + width: ${containerWidth.fluid}; height: inherit; `; export const ChatMessageListWrapper = styled(BaseColumn)` height: inherit; - width: 100%; + width: ${containerWidth.fluid}; overflow: scroll; + flex-direction: column-reverse; + margin-bottom: ${spacing.s}; `; interface Props { @@ -32,10 +34,7 @@ interface MessageProps { } export const Message = styled(MessageBlock)` - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 6px; + box-shadow: none; background: ${({ isLocalUser }): string => (isLocalUser ? color.grey : color.cloudWhite)}; max-width: 23.5vw; ${GeneralText} { @@ -44,8 +43,13 @@ export const Message = styled(MessageBlock)` `; export const MessageWrapper = styled.section` - padding-left: 13px; - padding-right: 13px; - padding-top: ${({ isGroupedMessage }): string => (isGroupedMessage ? "2px" : "16px")}; + padding-left: ${spacing.s}; + padding-right: ${spacing.s}; + padding-top: ${({ isGroupedMessage }): string => (isGroupedMessage ? spacing.xxs : spacing.s)}; align-self: ${({ isLocalUser }): string => (isLocalUser ? "flex-end" : "flex-start")}; `; + +export const ChatMessageInput = styled(BaseRow)` + margin-bottom: ${CHAT_MESSAGE_SIZE}; + width: ${containerWidth.fluid}; +`; diff --git a/frontend/src/molecules/lobby-player/lobby-player.tsx b/frontend/src/molecules/lobby-player/lobby-player.tsx index f0e58761..26f98065 100644 --- a/frontend/src/molecules/lobby-player/lobby-player.tsx +++ b/frontend/src/molecules/lobby-player/lobby-player.tsx @@ -1,13 +1,13 @@ import { FC } from "react"; + import { avatars } from "../../assets"; import { ContentLoader } from "../../components"; -import { avatarHeight, LOBBY_MAX_HEIGHT } from "../../design/avatar"; - +import { avatarHeight, LOBBY_MAX_HEIGHT } from "../../design"; import { PlayerPublic } from "../../types"; import { getLobbyMaxWidth } from "../../util"; import { FloatingPlayer } from "../floating-player"; import { LobbyStatus } from "../lobby-status"; -import { LobbyPlayerWrapper } from "./styles"; +import { LobbyPlayerContainer, LobbyPlayerWrapper } from "./styles"; interface LobbyPlayerProps { player: PlayerPublic; @@ -27,13 +27,15 @@ export const LobbyPlayer: FC = ({ player, totalPlayers }) => { if (!player.avatarId) return ; return ( - - + + + + ); diff --git a/frontend/src/molecules/lobby-player/styles.ts b/frontend/src/molecules/lobby-player/styles.ts index 20cef5ae..8e3d374f 100644 --- a/frontend/src/molecules/lobby-player/styles.ts +++ b/frontend/src/molecules/lobby-player/styles.ts @@ -6,14 +6,17 @@ interface Props { isWaiting?: boolean; } -export const LobbyPlayerWrapper = styled(BaseColumn)` +export const LobbyPlayerWrapper = styled(BaseColumn)` flex: 1; border-right: 1px solid ${color.mediumGrey}; :nth-last-of-type(1) { border-right: none; } + height: ${containerHeight.fluid}; +`; + +export const LobbyPlayerContainer = styled(BaseColumn)` opacity: ${({ isWaiting }) => (isWaiting ? opacity.background : opacity.visible)}; filter: ${({ isWaiting }) => (isWaiting ? "blur(1.2px)" : "blur(0)")}; - height: ${containerHeight.fluid}; `; diff --git a/frontend/src/molecules/player-lineup/styles.ts b/frontend/src/molecules/player-lineup/styles.ts index 1f1f5239..12a66ffc 100644 --- a/frontend/src/molecules/player-lineup/styles.ts +++ b/frontend/src/molecules/player-lineup/styles.ts @@ -1,9 +1,11 @@ import styled from "@emotion/styled"; import { BaseRow } from "../../atoms"; -import { color, containerWidth, lobbySizes } from "../../design"; +import { color, containerWidth, lobbySizes, zIndex } from "../../design"; export const PlayerLineupWrapper = styled(BaseRow)` height: ${lobbySizes.md}; width: ${containerWidth.fluid}; border-top: 1px solid ${color.mediumGrey}; + position: relative; + z-index: -${zIndex.background}; `; diff --git a/frontend/src/organisms/index.ts b/frontend/src/organisms/index.ts index 2f3cef21..a12da900 100644 --- a/frontend/src/organisms/index.ts +++ b/frontend/src/organisms/index.ts @@ -12,4 +12,5 @@ export * from "./get-power-ups"; export * from "./authentication-form"; export * from "./feedback-section"; export * from "./text-logo"; +export * from "./lobby"; export * from "./match-creation-forms"; diff --git a/frontend/src/organisms/lobby/index.ts b/frontend/src/organisms/lobby/index.ts new file mode 100644 index 00000000..7964fb87 --- /dev/null +++ b/frontend/src/organisms/lobby/index.ts @@ -0,0 +1 @@ +export * from "./lobby"; diff --git a/frontend/src/organisms/lobby/lobby.tsx b/frontend/src/organisms/lobby/lobby.tsx new file mode 100644 index 00000000..55712d3a --- /dev/null +++ b/frontend/src/organisms/lobby/lobby.tsx @@ -0,0 +1,68 @@ +import { FC, MouseEvent, useState } from "react"; + +import { text } from "../../assets"; +import { BodyText, BoxPattern, RectanglePattern } from "../../atoms"; +import { PrimaryButton } from "../../molecules"; +import { PlayerLineup } from "../../molecules/player-lineup"; +import { sendMessage, useChat, useMatch, useOrderedPlayers, useTotalDiceInMatch } from "../../service"; +import { useStore } from "../../store"; +import { MatchNavigationBar, MatchOptionsBar } from "../navigation-bar"; +import { PlayerLogo } from "../player-logo"; +import { LobbyWaitingContainer, LobbyWaitingWrapper } from "./styles"; + +export const Lobby: FC = () => { + const { broadcastPlayerReady } = useMatch(); + const setPlayerReady = useStore((state) => state.setPlayerReady); + const isPlayerReady = useStore((state) => state.isPlayerReady); + const totalDice = useTotalDiceInMatch(); + const stageNumber = useStore((state) => state.stageNumber); + const drawRoundCounter = useStore((state) => state.drawRoundCounter); + const channelId = useStore((state) => state.channelId); + const [messageInput, setMessageInput] = useState(""); + const messages = useChat(); + + const players = useOrderedPlayers(); + + const handleClick = async () => { + await broadcastPlayerReady(); + setPlayerReady(true); + }; + + const handleSendEvent = (e: React.MouseEvent | React.KeyboardEvent) => { + e.stopPropagation(); + if (e.currentTarget.value === "") return; + sendMessage(channelId, e.currentTarget.value); + setMessageInput(""); + }; + + const handleKeyEvent = (e: React.KeyboardEvent) => { + if (e.key === "Enter") handleSendEvent(e); + }; + + return ( + <> + + + + + + + {isPlayerReady ? ( + + {text.general.waitingForTheOthersToBeReady} + + ) : ( + + )} + + + + + ); +}; diff --git a/frontend/src/organisms/lobby/styles.ts b/frontend/src/organisms/lobby/styles.ts new file mode 100644 index 00000000..8b9a9a0a --- /dev/null +++ b/frontend/src/organisms/lobby/styles.ts @@ -0,0 +1,14 @@ +import styled from "@emotion/styled"; +import { BaseRow } from "../../atoms"; +import { color, containerWidth, patternSizes, spacing } from "../../design"; + +export const LobbyWaitingWrapper = styled(BaseRow)` + width: ${containerWidth.fluid}; + height: ${patternSizes.md}; +`; + +export const LobbyWaitingContainer = styled(BaseRow)` + padding: 0px ${spacing.lg}; + background: ${color.lightGrey}; + height: calc(100% - 2px); +`; diff --git a/frontend/src/organisms/player-logo/player-logo.tsx b/frontend/src/organisms/player-logo/player-logo.tsx index e7b8d70d..fe8e6573 100644 --- a/frontend/src/organisms/player-logo/player-logo.tsx +++ b/frontend/src/organisms/player-logo/player-logo.tsx @@ -6,25 +6,25 @@ import { ChatMessageContent } from "../../types"; import { PlayerMenu } from "../player-menu"; import { PlayerLogoContainer, PlayerLogoWrapper } from "./styles"; -// TODO: enable chat handlesend event interface Props { messages: ChatMessageContent[][]; messageInput: string; - handleSendEvent: (e: React.MouseEvent | React.KeyboardEvent) => void; + channelId?: string; + handleKeyEvent: (e: React.KeyboardEvent) => void; setMessageInput: (value: string) => void; } /** - * This the component that is displayed in the botoom of the lobby. It includes the boloney logo and the chat. + * This the component that is displayed in the bottom of the lobby. It includes the boloney logo and the chat. * @param {messages} - An array of arrays of messages. Use the parseMessages function to get this. * @param {messageInput} - The current value of the message input. - * @param {handleSendEvent} - A function to handle the send message event. + * @param {string} channelId - The channel id for the match chat * @param {handleKeyEvent} - A function to handle the enter key event that will trigger the send event. * @param {setMessageInput} - A function to set/update the messageInput prop value. */ -export const PlayerLogo: FC = ({ messages, messageInput, handleKeyEvent, setMessageInput, handleSendEvent }) => { +export const PlayerLogo: FC = ({ messages, messageInput, handleKeyEvent, setMessageInput, channelId }) => { return ( @@ -41,7 +41,7 @@ export const PlayerLogo: FC = ({ messages, messageInput, handleKeyEvent, isPanelExpanded messages={messages} isSingular - handleSendEvent={handleSendEvent} + channelId={channelId} handleKeyEvent={handleKeyEvent} setMessageInput={setMessageInput} messageInput={messageInput} diff --git a/frontend/src/organisms/player-menu/player-menu.tsx b/frontend/src/organisms/player-menu/player-menu.tsx index 11b10a2a..15a383d9 100644 --- a/frontend/src/organisms/player-menu/player-menu.tsx +++ b/frontend/src/organisms/player-menu/player-menu.tsx @@ -15,8 +15,9 @@ interface Props { localPlayer?: PlayerPublic; messages: ChatMessageContent[][]; messageInput: string; + channelId?: string; + setMessageInput: (value: string) => void; - handleSendEvent: (e: React.MouseEvent | React.KeyboardEvent) => void; handleKeyEvent: (e: React.KeyboardEvent) => void; setIsChatOpen?: () => void; @@ -29,6 +30,7 @@ interface Props { * @param {boolean} isHistoryOpen - A boolean to define if the history is open. * @param {string} isPanelExpanded - A boolean to define if the panel has been expanded. * @param {boolean} isSingular - A boolean to define if the panel is singular. + * @param {string} channelId - The channel id for the match chat * @param {ChatMessageContent[][]} messages - An array of grouped messages. * @param {string} chatChannelId - The id of the chat channel provided by nakama. * @param {Function} setIsChatOpen - A function whose use is to set if the chat is open or not. @@ -46,8 +48,8 @@ export const PlayerMenu: FC = ({ localPlayer, messages, messageInput, + channelId, setMessageInput, - handleSendEvent, handleKeyEvent, setIsChatOpen, setIsHistoryOpen, @@ -75,7 +77,7 @@ export const PlayerMenu: FC = ({ diff --git a/frontend/src/pages/match/match.tsx b/frontend/src/pages/match/match.tsx index 5e68729e..6ede1d35 100644 --- a/frontend/src/pages/match/match.tsx +++ b/frontend/src/pages/match/match.tsx @@ -9,7 +9,6 @@ import { GetPowerUps, PlayerTurns, RollDice, - Lobby, ErrorView, Loading, FadeTransition, @@ -40,6 +39,7 @@ import { errorPayloadBackendSchema, } from "../../types"; import { parseMatchData, parseMatchIdParam } from "../../util"; +import { Lobby } from "../../organisms"; export const MatchRoute = () => { const { matchId } = useParams(); diff --git a/frontend/src/pages/test/test.tsx b/frontend/src/pages/test/test.tsx index ae71e27e..256e0bf1 100644 --- a/frontend/src/pages/test/test.tsx +++ b/frontend/src/pages/test/test.tsx @@ -563,7 +563,7 @@ export const Test: FC = () => { messageInput={messageInput} setMessageInput={setMessageInput} messages={parseMessages(fakeMessages)} - handleSendEvent={() => console.log("")} + channelId="" /> {/* diff --git a/frontend/src/views/match/match.tsx b/frontend/src/views/match/match.tsx index d60e1fc9..90ba8475 100644 --- a/frontend/src/views/match/match.tsx +++ b/frontend/src/views/match/match.tsx @@ -2,7 +2,7 @@ import { FC, ReactNode } from "react"; import { MatchContentWrapper } from "../../atoms"; import { FadeTransition, Loading } from "../../components"; import { usePlaySound } from "../../hooks"; -import { ErrorView, GetPowerUps, MatchLayout } from "../../organisms"; +import { ErrorView, GetPowerUps, Lobby, MatchLayout } from "../../organisms"; import { useChatHistory, useDeleteNotification, useIsInMatch, useJoinMatch, useLocalPlayer, useNotificationListener } from "../../service"; import { useStore } from "../../store"; import { MatchStage } from "../../types"; @@ -37,6 +37,8 @@ export const Match: FC = ({ matchId }) => { } }; + if (matchStage === "lobbyStage") return ; + return (