Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
JessicaMulein committed Nov 7, 2024
1 parent 8c27ca1 commit 725e43f
Show file tree
Hide file tree
Showing 12 changed files with 1,137 additions and 471 deletions.
82 changes: 78 additions & 4 deletions src/components/GameInterface.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, SyntheticEvent, useEffect, useRef, useState } from 'react';
import React, { FC, MouseEvent, SyntheticEvent, useEffect, useRef, useState } from 'react';
import {
Box,
Button,
Expand All @@ -21,15 +21,24 @@ import { useGameContext } from '@/components/GameContext';
import SupplyCounts from '@/components/SupplyCounts';
import GameClock from '@/components/GameClock';
import { CurrentStep } from '@/game/enumerations/current-step';
import { addLogEntry } from '@/game/dominion-lib-log';
import {
addLogEntry,
applyGroupedAction,
applyGroupedActionSubAction,
prepareGroupedActionTriggers,
} from '@/game/dominion-lib-log';
import { NO_PLAYER } from '@/game/constants';
import { GameLogAction } from '@/game/enumerations/game-log-action';
import { IGame } from '@/game/interfaces/game';
import { deepClone } from '@/game/utils';
import TurnAdjustmentsSummary from '@/components/TurnAdjustments';
import FloatingCounter from '@/components/FloatingCounter';
import { RecipesList } from '@/components/RecipeList';
import ForwardRefBox from './ForwardRefBox';
import ForwardRefBox from '@/components/ForwardRefBox';
import { RecipeKey, Recipes, RecipeSections } from '@/components/Recipes';
import { IGroupedAction } from '@/game/interfaces/grouped-action';
import { RecipeSummaryPopover } from '@/components/RecipeSummaryPopover';
import { useAlert } from '@/components/AlertContext';

interface GameInterfaceProps {
nextTurn: () => void;
Expand Down Expand Up @@ -71,6 +80,10 @@ const GameInterface: FC<GameInterfaceProps> = ({ nextTurn, endGame, undoLastActi
const [viewportWidth, setViewportWidth] = useState(window.innerWidth);
const [tabValue, setTabValue] = useState(0);
const viewBoxRef = useRef<HTMLDivElement>(null);
const [hoverRecipe, setHoverRecipe] = useState<IGroupedAction | null>(null);
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
const anchorRef = useRef<HTMLElement | null>(null);
const { showAlert } = useAlert();

useEffect(() => {
setCanUndo(canUndoAction(gameState, gameState.log.length - 1));
Expand All @@ -95,6 +108,55 @@ const GameInterface: FC<GameInterfaceProps> = ({ nextTurn, endGame, undoLastActi
endGame();
};

const handleRecipeHover = (
section: RecipeSections,
recipeKey: RecipeKey,
event: MouseEvent<HTMLElement>
) => {
const recipeSection = Recipes[section];
const groupedAction = recipeSection.recipes[recipeKey] as IGroupedAction;
setHoverRecipe(groupedAction);
anchorRef.current = event.currentTarget;
setAnchorEl(event.currentTarget);
};

const handleRecipeLeave = () => {
setHoverRecipe(null);
setAnchorEl(null);
};

const handleRecipeClick = (
event: React.MouseEvent<HTMLDivElement>,
section: RecipeSections,
recipeKey: RecipeKey
) => {
event.preventDefault();
const recipeSection = Recipes[section];
const groupedAction = recipeSection.recipes[recipeKey] as IGroupedAction;

if (!groupedAction) {
return;
}

try {
const newGame = applyGroupedAction(
gameState,
groupedAction,
new Date(),
applyGroupedActionSubAction,
prepareGroupedActionTriggers,
recipeKey
);
setGameState(newGame);
} catch (error) {
if (error instanceof Error) {
showAlert(`${groupedAction.name} Failed`, error.message);
} else {
showAlert(`${groupedAction.name} Failed`, 'Unknown error');
}
}
};

const lastAction =
gameState.log.length > 0 ? gameState.log[gameState.log.length - 1].action : null;
const lastActionIsPause = lastAction === GameLogAction.PAUSE;
Expand Down Expand Up @@ -168,7 +230,14 @@ const GameInterface: FC<GameInterfaceProps> = ({ nextTurn, endGame, undoLastActi
)}
{tabValue === 1 && <TurnAdjustmentsSummary />}
{tabValue === 2 && <SupplyCounts />}
{tabValue === 3 && <RecipesList viewBoxRef={viewBoxRef} />}
{tabValue === 3 && (
<RecipesList
viewBoxRef={viewBoxRef}
onHover={handleRecipeHover}
onLeave={handleRecipeLeave}
onClick={handleRecipeClick}
/>
)}
</ForwardRefBox>
</Container>
<FabContainer>
Expand Down Expand Up @@ -212,6 +281,11 @@ const GameInterface: FC<GameInterfaceProps> = ({ nextTurn, endGame, undoLastActi
</Button>
</DialogActions>
</Dialog>
<RecipeSummaryPopover
open={!!hoverRecipe}
anchorEl={anchorRef.current}
recipe={hoverRecipe}
/>
</>
);
};
Expand Down
30 changes: 20 additions & 10 deletions src/components/GameLogEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,18 @@ const GameLogEntry: FC<GameLogEntryProps> = ({ logIndex, entry, onOpenTurnAdjust
'data-action-id': entry.linkedActionId ?? entry.id,
};

const groupedAction =
entry.action === GameLogAction.GROUPED_ACTION && entry.actionKey
? (() => {
for (const section of Object.values(Recipes)) {
if (section.recipes[entry.actionKey]) {
return section.recipes[entry.actionKey];
}
}
return null;
})()
: null;

return (
<>
<Box
Expand Down Expand Up @@ -189,16 +201,14 @@ const GameLogEntry: FC<GameLogEntryProps> = ({ logIndex, entry, onOpenTurnAdjust
{relevantPlayer !== undefined && !isNotTriggeredByPlayer && (
<ColoredPlayerName player={relevantPlayer} marginDirection="right" />
)}
{entry.action === GameLogAction.GROUPED_ACTION &&
entry.actionKey &&
Recipes[entry.actionKey] && (
<Box
component="span"
sx={{ fontSize: '16px', display: 'inline-flex', alignItems: 'center', mr: 1 }}
>
{Recipes[entry.actionKey].icon ?? <FontAwesomeIcon icon={faPlay} />}
</Box>
)}
{groupedAction && (
<Box
component="span"
sx={{ fontSize: '16px', display: 'inline-flex', alignItems: 'center', mr: 1 }}
>
{groupedAction.icon ?? <FontAwesomeIcon icon={faPlay} />}
</Box>
)}
<Typography variant="body2" component="span">
{actionText}
</Typography>
Expand Down
84 changes: 41 additions & 43 deletions src/components/RecipeCard.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,62 @@
import React, { FC } from 'react';
import {
applyGroupedAction,
applyGroupedActionSubAction,
prepareGroupedActionTriggers,
} from '@/game/dominion-lib-log';
import React, { FC, MouseEvent } from 'react';
import { IGroupedAction } from '@/game/interfaces/grouped-action';
import { RecipeKey, Recipes } from '@/components/Recipes';
import { RecipeKey, RecipeSections } from '@/components/Recipes';
import { Box, Link, Typography } from '@mui/material';
import { useGameContext } from '@/components/GameContext';
import { useAlert } from '@/components/AlertContext';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlay } from '@fortawesome/pro-solid-svg-icons';

interface RecipeCardProps {
section: RecipeSections;
recipeKey: RecipeKey;
recipe: IGroupedAction;
onHover: (section: RecipeSections, recipeKey: RecipeKey, event: MouseEvent<HTMLElement>) => void;
onLeave: () => void;
onClick: (
event: MouseEvent<HTMLDivElement>,
section: RecipeSections,
recipeKey: RecipeKey
) => void;
}

export const RecipeCard: FC<RecipeCardProps> = ({ recipeKey, recipe }) => {
const { gameState, setGameState } = useGameContext();
const { showAlert } = useAlert();
const handleRecipe = (event: React.MouseEvent<HTMLAnchorElement>, recipeName: string) => {
event.preventDefault();
const groupedAction = Recipes[recipeName];
if (!groupedAction) {
return;
}
try {
const newGame = applyGroupedAction(
gameState,
groupedAction,
new Date(),
applyGroupedActionSubAction,
prepareGroupedActionTriggers,
recipeKey
);
setGameState(newGame);
} catch (error) {
if (error instanceof Error) {
showAlert(`${groupedAction.name} Failed`, error.message);
} else {
showAlert(`${groupedAction.name} Failed`, 'Unknown error');
}
}
};

export const RecipeCard: FC<RecipeCardProps> = ({
section,
recipeKey,
recipe,
onHover,
onLeave,
onClick,
}) => {
return (
<Box key={recipeKey} display="flex" alignItems="center" height="28px">
<Box key={recipeKey} display="flex" alignItems="center" height="28px" width="100%">
<Link
href="#"
onClick={(event) => handleRecipe(event, recipeKey)}
sx={{ display: 'flex', alignItems: 'center' }}
component="div"
onMouseEnter={(event: MouseEvent<HTMLDivElement>) => onHover(section, recipeKey, event)}
onMouseLeave={onLeave}
onClick={(event: MouseEvent<HTMLDivElement>) => onClick(event, section, recipeKey)}
sx={{ display: 'flex', alignItems: 'center', width: '100%', cursor: 'pointer' }}
>
<Box
component="span"
sx={{ fontSize: '26px', display: 'flex', alignItems: 'center', width: '30px' }}
sx={{
fontSize: '26px',
display: 'flex',
alignItems: 'center',
width: '30px',
flexShrink: 0,
}}
>
{recipe.icon ?? <FontAwesomeIcon icon={faPlay} />}
</Box>
<Typography className="recipe-name" sx={{ ml: 1 }}>
<Typography
className="recipe-name"
sx={{
ml: 1,
flexGrow: 1,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
>
{recipe.name}
</Typography>
</Link>
Expand Down
Loading

0 comments on commit 725e43f

Please sign in to comment.