Skip to content

Commit

Permalink
[FE] 코드 리팩토링, ui 작업 및 사운드 효과 추가 (#76)
Browse files Browse the repository at this point in the history
* refactor: 룰렛 음악 효과 변경

* refactor: 주식 로고 배경 삭제

* refactor: 상수 변수명 스네이크 스크리밍 케이스로 변경

* refactor: 바뀐 상수명 적용

* refactor: 주식 구매 모달 랜더링 방법 변경

- 주식 칸에 도착했을 때 랜더링

* refactor: 게임 보드 및 토큰 ui 변경

* refactor: 사운드 음소거 여부 로컬스토리지 연동

* feat: 주사위, 룰렛 사운드 이펙트 추가

* refactor: 주식 현황판 모달 토글 버튼 위치 변경

* refactor: 주식 전체 현황판 로고 추가

* refactor: 프로젝트 테스트 후 리팩토링

* refactor: 게임 시작 버튼 방장만 보이게 수정

* refactor: order 옵셔널 추가
  • Loading branch information
aaaz425 authored Nov 3, 2023
1 parent c244bc0 commit 329b1f1
Show file tree
Hide file tree
Showing 22 changed files with 120 additions and 92 deletions.
Binary file modified fe/public/sound/roulette.mp3
Binary file not shown.
Binary file modified fe/src/assets/images/gs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fe/src/assets/images/hermes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fe/src/assets/images/nongshim.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fe/src/assets/images/starkindustry.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 12 additions & 8 deletions fe/src/components/GameBoard/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { cellImageMap } from '@assets/images';
import { PlayerStatusType } from '@store/reducer/type';
import { addCommasToNumber } from '@utils/index';
import { styled } from 'styled-components';
import { PRISON_CELL } from './constants';

type CellType = {
theme?: string;
Expand All @@ -26,11 +27,13 @@ export default function Cell({
selectTargetLocation,
}: Cellprops) {
const isSelected = targetLocation === cell.location;
const isPrison = cell.location === PRISON_CELL;

return (
<Container
$status={playerStatus}
$isSelected={isSelected}
$isPrison={isPrison}
onClick={() => {
if (playerStatus !== 'teleport') return;
if (cell.location === 18) {
Expand Down Expand Up @@ -58,29 +61,29 @@ export default function Cell({
const Container = styled.div<{
$status: PlayerStatusType;
$isSelected: boolean;
$isPrison: boolean;
}>`
width: 6rem;
height: 6rem;
display: flex;
flex-direction: column;
border-width: 1px;
border-style: solid;
border-color: ${({ theme }) => theme.color.accentText};
border: ${({ theme }) => `1px solid ${theme.color.neutralBackgroundBold}`};
background-color: ${({ theme, $isSelected }) =>
$isSelected ? theme.color.accentTertiary : theme.color.accentPrimary};
$isSelected ? theme.color.accentTertiary : theme.color.accentText};
box-shadow: ${({ $isPrison }) =>
$isPrison ? 'none' : '10px 5px 5px rgba(0, 0, 0, 1)'};
`;

const Header = styled.div`
min-height: 2rem;
display: flex;
justify-content: center;
align-items: center;
background-color: ${({ theme: { color } }) => color.accentText};
`;

const Logo = styled.img`
width: 1.5rem;
height: 1.5rem;
width: 2rem;
height: 2rem;
`;

const CellImg = styled.img`
Expand All @@ -89,7 +92,7 @@ const CellImg = styled.img`
`;

const Name = styled.div`
color: ${({ theme: { color } }) => color.accentPrimary};
color: ${({ theme: { color } }) => color.neutralText};
`;

const Content = styled.div`
Expand All @@ -98,4 +101,5 @@ const Content = styled.div`
flex-direction: column;
justify-content: space-evenly;
align-items: center;
color: ${({ theme: { color } }) => color.neutralText};
`;
12 changes: 11 additions & 1 deletion fe/src/components/GameBoard/Dice.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import useMoveToken from '@hooks/useMoveToken';
import useSound from '@hooks/useSound';
import { useGameInfoValue, usePlayers, useSetGameInfo } from '@store/reducer';
import { useEffect, useRef, useState } from 'react';
import ReactDice, { ReactDiceRef } from 'react-dice-complete';
Expand All @@ -11,6 +12,10 @@ export default function Dice() {
const gameInfo = useGameInfoValue();
const moveToken = useMoveToken();
const setGameInfo = useSetGameInfo();
const [isRolling, setIsRolling] = useState(false);
const { sound: DiceRollSound } = useSound({
src: '/sound/roll.mp3',
});

useEffect(() => {
if (gameInfo.dice[0] === 0 || gameInfo.dice[1] === 0) return;
Expand All @@ -19,14 +24,18 @@ export default function Dice() {

const rollDice = (dice1: number, dice2: number) => {
reactDice.current?.rollAll([dice1, dice2]);
setIsRolling(true);
};

const rollDone = async () => {
if (gameInfo.dice[0] === 0 || gameInfo.dice[1] === 0) return;

const totalDiceValue = gameInfo.dice[0] + gameInfo.dice[1];
setDiceValue(totalDiceValue);
const targetPlayer = players.find(
(player) => player.playerId === gameInfo.currentPlayerId
);
setIsRolling(false);

if (!targetPlayer) return;
if (!targetPlayer.gameboard.hasEscaped) return;
Expand All @@ -47,12 +56,13 @@ export default function Dice() {
numDice={2}
ref={reactDice}
rollDone={rollDone}
rollTime={0.5}
rollTime={1}
faceColor="#fff"
dotColor="#000"
disableIndividual={true}
/>
<DiceValue>{diceValue}</DiceValue>
{isRolling && DiceRollSound}
</>
);
}
Expand Down
6 changes: 5 additions & 1 deletion fe/src/components/GameBoard/GameBoard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import useGetSocketUrl from '@hooks/useGetSocketUrl';
import { usePlayerIdValue } from '@store/index';
import {
playerAtomsAtom,
useGameInfoValue,
Expand All @@ -23,6 +24,7 @@ export default function GameBoard() {
const [playerAtoms] = useAtom(playerAtomsAtom);
const socketUrl = useGetSocketUrl();
const { gameId } = useParams();
const playerId = usePlayerIdValue();
const { sendJsonMessage } = useWebSocket(socketUrl, {
share: true,
});
Expand All @@ -34,6 +36,8 @@ export default function GameBoard() {
(player) => player.playerId === gameInfo.currentPlayerId
);
const currentPlayerStatus = currentPlayer?.gameboard.status ?? 'event';
const isCaptain =
players.find((player) => player.playerId === playerId)?.order === 1;

const handleStart = () => {
const message = {
Expand Down Expand Up @@ -73,7 +77,7 @@ export default function GameBoard() {
})}
</Line>
))}
{!gameInfo.isPlaying && isEveryoneReady && (
{!gameInfo.isPlaying && isEveryoneReady && isCaptain && (
<Button onClick={handleStart}>게임 시작</Button>
)}
{gameInfo.isPlaying && (
Expand Down
13 changes: 7 additions & 6 deletions fe/src/components/GameBoard/PlayerToken.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Icon } from '@components/icon/Icon';
import { ANT_LIST } from '@pages/constants';
import { PlayerType } from '@store/reducer/type';
import { PrimitiveAtom, useAtom } from 'jotai';
import { useEffect, useRef } from 'react';
import { styled } from 'styled-components';
import { DefaultTheme } from 'styled-components/dist/types';

type PlayerTokenWithAtomProps = {
playerAtom: PrimitiveAtom<PlayerType>;
Expand All @@ -11,6 +12,7 @@ type PlayerTokenWithAtomProps = {
export default function PlayerToken({ playerAtom }: PlayerTokenWithAtomProps) {
const tokenRef = useRef<HTMLDivElement>(null);
const [player, setPlayer] = useAtom(playerAtom);
const antName = ANT_LIST.find((ant) => ant.order === player?.order)!.antName;

useEffect(() => {
setPlayer((prev) => {
Expand All @@ -28,22 +30,21 @@ export default function PlayerToken({ playerAtom }: PlayerTokenWithAtomProps) {

return (
<Token ref={tokenRef} $order={player.order}>
{player.order}
<Icon name={antName} size="2.5rem" />
</Token>
);
}

const Token = styled.div<{ $order: number }>`
width: 2rem;
height: 2rem;
width: 2.5rem;
height: 2.5rem;
position: absolute;
bottom: ${({ $order }) => ($order === 1 || $order === 2 ? 3 : 0.5)}rem;
left: ${({ $order }) => ($order === 2 || $order === 3 ? 3 : 0.5)}rem;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
background-color: ${({ theme, $order }) =>
theme.color[`player${$order}` as keyof DefaultTheme['color']]};
background-color: ${({ theme }) => theme.color.accentTertiary};
transition: transform 0.2s;
`;
23 changes: 10 additions & 13 deletions fe/src/components/GameBoard/Roulette.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import EventModal from '@components/Modal/EventModal/EventModal';
import useGetSocketUrl from '@hooks/useGetSocketUrl';
import useSound from '@hooks/useSound';
import { usePlayerIdValue } from '@store/index';
import { useGameInfo, useResetEventRound } from '@store/reducer';
import { delay } from '@utils/index';
Expand All @@ -12,7 +13,7 @@ import { styled } from 'styled-components';
export default function Roulette() {
const [mustSpin, setMustSpin] = useState(false);
const [prizeNumber, setPrizeNumber] = useState(0);
const [stockSellTime, setStockSellTime] = useState(30);
const [stockSellTime, setStockSellTime] = useState(20);
const [isEventModalOpen, setIsEventModalOpen] = useState(false);

const { gameId } = useParams();
Expand All @@ -24,6 +25,11 @@ export default function Roulette() {
share: true,
});

const [isRolling, setIsRolling] = useState(false);
const { sound: RouletteRollingSound } = useSound({
src: '/sound/roulette.mp3',
});

const startSpin = useCallback(() => {
const eventListData = gameInfo.eventList.map((event) => event.title);
if (eventListData.length === 0) return;
Expand All @@ -34,6 +40,7 @@ export default function Roulette() {
events: eventListData,
};
sendJsonMessage(message);
setIsRolling(true);
}, [
gameId,
playerId,
Expand Down Expand Up @@ -76,6 +83,7 @@ export default function Roulette() {

const handleSpinDone = async () => {
setIsEventModalOpen(true);
setIsRolling(false);
await delay(5000);
resetGameInfo();
setMustSpin(false);
Expand All @@ -99,9 +107,9 @@ export default function Roulette() {
/>
<Wrapper>
<Timer>남은 매도시간: {stockSellTime}</Timer>
<Button onClick={startSpin}>룰렛 테스트 버튼</Button>
</Wrapper>
{isEventModalOpen && <EventModal />}
{isRolling && RouletteRollingSound}
</>
);
}
Expand All @@ -115,14 +123,3 @@ const Wrapper = styled.div`
const Timer = styled.div`
font-size: ${({ theme }) => theme.fontSize.sMedium};
`;

const Button = styled.button`
width: 150px;
margin-right: 10px;
margin-bottom: 10px;
align-self: flex-end;
border: 1px solid ${({ theme }) => theme.color.accentText};
border-radius: ${({ theme }) => theme.radius.small};
color: ${({ theme }) => theme.color.neutralTextStrong};
background-color: ${({ theme }) => theme.color.neutralBackground};
`;
1 change: 1 addition & 0 deletions fe/src/components/GameBoard/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const CELL = {
};

export const CORNER_CELLS = [0, 6, 12, 18];
export const PRISON_CELL = 6;

export const directions = {
top: { x: 0, y: -CELL.HEIGHT },
Expand Down
41 changes: 16 additions & 25 deletions fe/src/components/Header/GameHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import StatusBoardModal from '@components/Modal/StatusBoardModal/StatusBoardModal';
import StockBuyModal from '@components/Modal/StockBuyModal/StockBuyModal';
import { Icon } from '@components/icon/Icon';
import useSound from '@hooks/useSound';
import { ROUTE_PATH } from '@router/constants';
Expand All @@ -10,7 +9,6 @@ import { styled } from 'styled-components';
export default function GameHeader() {
const navigate = useNavigate();
const [isStatusBoardModalOpen, setIsStatusBoardModalOpen] = useState(false);
const [isStockBuyModalOpen, setIsStockBuyModalOpen] = useState(false);

const {
isSoundPlaying,
Expand All @@ -28,16 +26,17 @@ export default function GameHeader() {
setIsStatusBoardModalOpen((prev) => !prev);
};

const toggleStockBuyModal = () => {
setIsStockBuyModalOpen((prev) => !prev);
};

return (
<>
<Header>
<Logo>Gaemi Marble</Logo>
<Temp>
<IconContainer onClick={toggleStockBuyModal}>칸도착</IconContainer>
<IconContainer
className="status-board"
onClick={toggleStatusBoardModal}
>
<Icon name="statusBoard" size="3rem" color="neutralText" />
</IconContainer>
<Navigation>
<IconContainer>
<Icon
name={isSoundPlaying ? 'soundPlaying' : 'soundMute'}
Expand All @@ -46,14 +45,6 @@ export default function GameHeader() {
onClick={togglePlayingSound}
/>
</IconContainer>
<IconContainer>
<Icon
name="statusBoard"
size="3rem"
color="neutralText"
onClick={toggleStatusBoardModal}
/>
</IconContainer>
<IconContainer>
<Icon
name="exit"
Expand All @@ -62,23 +53,17 @@ export default function GameHeader() {
onClick={handleExit}
/>
</IconContainer>
</Temp>
</Navigation>
</Header>
{isStatusBoardModalOpen && (
<StatusBoardModal handleClose={toggleStatusBoardModal} />
)}
{isStockBuyModalOpen && (
<StockBuyModal handleClose={toggleStockBuyModal} />
)}
{GameBgm}
</>
);
}

const Header = styled.div`
#sound {
display: none;
}
width: 100%;
display: flex;
top: 0.5rem;
Expand All @@ -92,8 +77,7 @@ const Logo = styled.h1`
color: ${({ theme: { color } }) => color.accentText};
`;

// Todo: have to delete!!!
const Temp = styled.div`
const Navigation = styled.div`
display: flex;
gap: 1rem;
`;
Expand All @@ -116,4 +100,11 @@ const IconContainer = styled.div`
fill: ${({ theme: { color } }) => color.accentText};
}
}
&.status-board {
width: 4rem;
height: 4rem;
justify-content: center;
margin-right: 75px;
}
`;
Loading

0 comments on commit 329b1f1

Please sign in to comment.