Skip to content

Commit

Permalink
Merged PR 4332: Match lobby
Browse files Browse the repository at this point in the history
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
  • Loading branch information
TsungaiChipato committed Jun 9, 2023
1 parent 50296ca commit 1fb5d95
Show file tree
Hide file tree
Showing 16 changed files with 189 additions and 71 deletions.
4 changes: 4 additions & 0 deletions frontend/src/design/measurements.ts
Original file line number Diff line number Diff line change
@@ -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",
};
Expand Down
46 changes: 29 additions & 17 deletions frontend/src/molecules/chat/chat.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement, MouseEvent> | React.KeyboardEvent<HTMLInputElement>) => void;
handleKeyEvent: (e: React.KeyboardEvent<HTMLInputElement>) => 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<ChatProps> = ({ messages, messageInput, handleKeyEvent, setMessageInput, handleSendEvent }) => {
export const Chat: FC<ChatProps> = ({ messages, messageInput, channelId, handleKeyEvent, setMessageInput }) => {
const handleSendEvent = (e: React.MouseEvent<HTMLInputElement, MouseEvent> | React.KeyboardEvent<HTMLInputElement>) => {
e.stopPropagation();
if (e.currentTarget.value === "") return;
sendMessage(channelId, e.currentTarget.value);
setMessageInput("");
};

return (
<ChatContainer>
<ChatContainer alignItems="center">
<ChatMessageListWrapper>
{messages.map((groupedMessages, index) => (
<GroupedChatMessages key={index} messages={groupedMessages} />
))}
</ChatMessageListWrapper>
<ChatInput
placeholder={text.general.typeHere}
type="text"
value={messageInput}
onChange={(event) => setMessageInput(event.target.value)}
onClick={(event) => handleSendEvent(event)}
onKeyDownCapture={(event) => handleKeyEvent(event)}
/>
<ChatMessageInput alignItems="center" justifyContent="center">
<ChatInput
placeholder={text.general.typeHere}
type="text"
value={messageInput}
onChange={(event) => setMessageInput(event.target.value)}
onClick={(event) => handleSendEvent(event)}
onKeyDownCapture={(event) => handleKeyEvent(event)}
width={CHAT_INPUT_SIZE}
/>
</ChatMessageInput>
</ChatContainer>
);
};
39 changes: 21 additions & 18 deletions frontend/src/molecules/chat/grouped-chat-meesages.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -13,26 +13,29 @@ interface Props {
* @param {messages} - An array of messages.
*/
export const GroupedChatMessages: FC<Props> = ({ messages }) => {
const isNameShowing = !messages.at(0)?.isLocalUser;
return (
<>
{messages.map((message, index) => (
<MessageWrapper key={index} isGroupedMessage={message.isGroupedMessage} isLocalUser={message.isLocalUser}>
<Message isLocalUser={message.isLocalUser} isGroupedMessage={message.isGroupedMessage} padding={spacing.xs}>
{index === 0 && !message.isLocalUser && (
<BaseRow alignItems="flex-end" gap="inherit">
<BaseIcon
src={
<CircleIconWrapper circleColor={message.color}>
<CircleIconSVG />
</CircleIconWrapper>
}
iconColor={message.color}
/>
<PlayerInfoText fontWeight={fontWeights.bold} fontSize={fontSizes.playerInfo}>
{message.name}
</PlayerInfoText>
</BaseRow>
)}
<Message isLocalUser={message.isLocalUser} isGroupedMessage={message.isGroupedMessage} padding={CHAT_MESSAGE_SIZE}>
<BaseColumn gap={spacing.xxs}>
{isNameShowing && index === messages.length - 1 && (
<BaseRow alignItems="flex-end" gap="inherit">
<BaseIcon
src={
<CircleIconWrapper circleColor={message.color}>
<CircleIconSVG />
</CircleIconWrapper>
}
iconColor={message.color}
/>
<PlayerInfoText fontWeight={fontWeights.bold} fontSize={fontSizes.playerInfo}>
{message.name}
</PlayerInfoText>
</BaseRow>
)}
</BaseColumn>
<GeneralText>{message.content}</GeneralText>
</Message>
</MessageWrapper>
Expand Down
26 changes: 15 additions & 11 deletions frontend/src/molecules/chat/styles.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -32,10 +34,7 @@ interface MessageProps {
}

export const Message = styled(MessageBlock)<MessageProps>`
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} {
Expand All @@ -44,8 +43,13 @@ export const Message = styled(MessageBlock)<MessageProps>`
`;

export const MessageWrapper = styled.section<MessageProps>`
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};
`;
22 changes: 12 additions & 10 deletions frontend/src/molecules/lobby-player/lobby-player.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -27,13 +27,15 @@ export const LobbyPlayer: FC<LobbyPlayerProps> = ({ player, totalPlayers }) => {
if (!player.avatarId) return <ContentLoader isLoading />;

return (
<LobbyPlayerWrapper isWaiting={!player.isReady} alignItems="center" justifyContent="center">
<FloatingPlayer
avatarName={avatars[player.avatarId].name}
height={avatarHeight.md}
width="auto"
maxWidth={getLobbyMaxWidth(maxWidth)}
/>
<LobbyPlayerWrapper justifyContent="space-between">
<LobbyPlayerContainer isWaiting={!player.isReady} alignItems="center" justifyContent="center">
<FloatingPlayer
avatarName={avatars[player.avatarId].name}
height={avatarHeight.md}
width="auto"
maxWidth={getLobbyMaxWidth(maxWidth)}
/>
</LobbyPlayerContainer>
<LobbyStatus playerName={player.username} isWaiting={!player.isConnected} isReady={player.isReady} />
</LobbyPlayerWrapper>
);
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/molecules/lobby-player/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ interface Props {
isWaiting?: boolean;
}

export const LobbyPlayerWrapper = styled(BaseColumn)<Props>`
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)<Props>`
opacity: ${({ isWaiting }) => (isWaiting ? opacity.background : opacity.visible)};
filter: ${({ isWaiting }) => (isWaiting ? "blur(1.2px)" : "blur(0)")};
height: ${containerHeight.fluid};
`;
4 changes: 3 additions & 1 deletion frontend/src/molecules/player-lineup/styles.ts
Original file line number Diff line number Diff line change
@@ -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};
`;
1 change: 1 addition & 0 deletions frontend/src/organisms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
1 change: 1 addition & 0 deletions frontend/src/organisms/lobby/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./lobby";
68 changes: 68 additions & 0 deletions frontend/src/organisms/lobby/lobby.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement, MouseEvent> | React.KeyboardEvent<HTMLInputElement>) => {
e.stopPropagation();
if (e.currentTarget.value === "") return;
sendMessage(channelId, e.currentTarget.value);
setMessageInput("");
};

const handleKeyEvent = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") handleSendEvent(e);
};

return (
<>
<MatchOptionsBar totalDice={totalDice} stageNumber={stageNumber} drawNumber={drawRoundCounter} />
<MatchNavigationBar />
<BoxPattern />
<PlayerLineup players={players} />
<RectanglePattern>
<LobbyWaitingWrapper justifyContent="center" alignItems="center">
{isPlayerReady ? (
<LobbyWaitingContainer justifyContent="center" alignItems="center">
<BodyText>{text.general.waitingForTheOthersToBeReady}</BodyText>
</LobbyWaitingContainer>
) : (
<PrimaryButton primaryText={text.general.imReady} onClick={handleClick} />
)}
</LobbyWaitingWrapper>
</RectanglePattern>
<PlayerLogo
handleKeyEvent={handleKeyEvent}
setMessageInput={setMessageInput}
messageInput={messageInput}
messages={messages}
channelId={channelId}
/>
</>
);
};
14 changes: 14 additions & 0 deletions frontend/src/organisms/lobby/styles.ts
Original file line number Diff line number Diff line change
@@ -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);
`;
12 changes: 6 additions & 6 deletions frontend/src/organisms/player-logo/player-logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLInputElement, MouseEvent> | React.KeyboardEvent<HTMLInputElement>) => void;
channelId?: string;

handleKeyEvent: (e: React.KeyboardEvent<HTMLInputElement>) => 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<Props> = ({ messages, messageInput, handleKeyEvent, setMessageInput, handleSendEvent }) => {
export const PlayerLogo: FC<Props> = ({ messages, messageInput, handleKeyEvent, setMessageInput, channelId }) => {
return (
<PlayerLogoWrapper>
<PlayerLogoContainer>
Expand All @@ -41,7 +41,7 @@ export const PlayerLogo: FC<Props> = ({ messages, messageInput, handleKeyEvent,
isPanelExpanded
messages={messages}
isSingular
handleSendEvent={handleSendEvent}
channelId={channelId}
handleKeyEvent={handleKeyEvent}
setMessageInput={setMessageInput}
messageInput={messageInput}
Expand Down
Loading

0 comments on commit 1fb5d95

Please sign in to comment.