1 Commits

Author SHA1 Message Date
Mikayla Dobson
2c549e7020 backtrack to rework ui 2022-09-20 12:24:19 -05:00
34 changed files with 1298 additions and 1772 deletions

View File

@@ -1,65 +1,47 @@
import { v4 } from 'uuid';
import { CardProps } from '../../util/propTypes';
import { CardData, PlayerCards, ResourceCost } from '../../util/types';
import { ResourceCost } from '../../util/types';
import { useCurrentPlayer } from '../../hooks/useCurrentPlayer';
import { buyCardActions } from '../Player/ActionMethods';
import { hasMaxReserved, reserveCard } from '../Player/ActionMethods/reserveCardActions';
const { buyCard, tooExpensive } = buyCardActions;
export default function Card({ data, state, setState, reserved = false, collapsed = false }: CardProps) {
export default function Card({ data, state, setState }: CardProps) {
const currentPlayer = useCurrentPlayer(state);
if (!data || !currentPlayer) return <div className="card"></div>;
const purchaseDisabled = (): boolean => {
// TO DO: check whether a card belongs to the current player,
// if card is tagged as reserved
return tooExpensive(data, state);
}
if (!data) return <div className="card"></div>;
return (
<div className='card' key={v4()}>
{ /*
{ collapsed ? <div className={`img-placeholder-${data.gemValue}`}></div> : <img src={data.image} loading="lazy" /> }
*/ }
<div className={reserved ? `foreground-${data.gemValue}` : 'foreground'}>
<section className="card-top-section">
<p>{data.gemValue.toUpperCase()}</p>
<div className="total-card-cost">
{
Object.keys(data.resourceCost).map((key: keyof ResourceCost | string) => {
// @ts-ignore
return (data.resourceCost[key as keyof ResourceCost] > 0) && (
<p key={v4()} className={`card-cost-${key}`}>
{data.resourceCost[key as keyof ResourceCost]}
</p>
)
})
}
</div>
{ (data.points && data.points > 0) ? <p>{data.points} {data.points === 1 ? 'point' : 'points'}</p> : null }
</section>
{
(state.actions.buyCard.active || state.actions.reserveCard.active) && (
<section className="card-action-section">
{ state.actions.buyCard.active &&
<button
onClick={() => buyCard(state, setState, data)}
disabled={purchaseDisabled()}>
Buy This Card
</button>
}
{ !reserved && state.actions.reserveCard.active &&
<button
onClick={() => reserveCard(state, setState, data)}
disabled={hasMaxReserved(currentPlayer)}>
Reserve This Card
</button>
}
</section>
<div className="card" key={v4()}>
<p>Counts as: {data.gemValue}</p>
<p>Point value: {data.points || 0}</p>
<p>Cost:</p>
<div className="total-card-cost">
{
Object.keys(data.resourceCost).map((key: keyof ResourceCost | string) => {
// @ts-ignore
return (data.resourceCost[key as keyof ResourceCost] > 0) && (
<p key={v4()} className={`card-cost-${key}`}>
{data.resourceCost[key as keyof ResourceCost]}
</p>
)
}
})
}
</div>
{ state.actions.buyCard.active &&
<button
onClick={() => buyCard(state, setState, data)}
disabled={tooExpensive(data, state)}>
Buy This Card
</button>
}
{ state.actions.reserveCard.active &&
<button
onClick={() => reserveCard(state, setState, data)}
disabled={hasMaxReserved(currentPlayer)}>
Reserve This Card
</button>
}
</div>
)
}

View File

@@ -1,77 +1,33 @@
@import "../../sass/helper/mixins";
@import "../../sass/helper/variables";
@import "../../sass/helper/placeholders";
.card-row {
display: flex;
flex-flow: column nowrap;
margin: 1rem 0;
width: 75vw;
.card-row-top-bar {
display: flex;
align-items: center;
justify-content: center;
> * {
margin: 8px 16px;
}
}
margin: 2rem;
width: 80vw;
.card-row-cards-visible {
display: flex;
flex-flow: row wrap;
justify-content: right;
flex-flow: row nowrap;
width: 100%;
.card {
width: 18%;
border: 2px solid black;
img {
width: 100%;
height: 100%;
object-fit: cover;
z-index: 1;
}
.foreground {
// position: relative;
// top: -100%;
display: flex;
flex-direction: column;
align-items: center;
z-index: 6;
> * {
margin: 1rem;
padding: 6px;
border-radius: 12px;
background-color: rgb(39, 36, 36);
}
.total-card-cost {
display: flex;
flex-flow: row wrap;
justify-content: center;
@include map-gem-values(".card-cost");
}
}
}
justify-content: space-around;
}
.card-count {
background-color: black;
color: white;
width: 25%;
.card {
width: 25%;
border: 2px solid black;
> * {
margin: 1rem;
}
.cc-tier {
&-1 {
background-color: rgb(3, 30, 3);
}
&-2 {
background-color: rgb(80, 80, 7);
}
&-3 {
background-color: rgb(9, 9, 77);
.total-card-cost {
display: flex;
justify-content: center;
@include map-gem-values(".card-cost");
p {
@extend %chip-design;
}
}
}
@@ -79,11 +35,12 @@
.tier-1 {
background-color: rgb(23, 73, 23);
background-color: rgb(9, 67, 9);
}
.tier-2 {
background-color: rgb(174, 174, 32);
color: black;
}
.tier-3 {

View File

@@ -1,13 +1,11 @@
import { useEffect, useState } from 'react';
import { v4 } from 'uuid';
import cardTierToKey from '../../util/mechanics/cardTierToKey';
import { CardRowProps } from '../../util/propTypes';
import { CardData } from "../../util/types"
import Card from "../Card/Card"
import { v4 } from 'uuid';
import cardTierToKey from '../../util/cardTierToKey';
import "./CardRow.scss";
export default function CardRow({tier, state, setState, liftCollapsed}: CardRowProps) {
const [collapsed, setCollapsed] = useState(true);
export default function CardRow({tier, state, setState}: CardRowProps) {
const typedTier = cardTierToKey(tier);
let cards: Array<CardData>
@@ -26,22 +24,15 @@ export default function CardRow({tier, state, setState, liftCollapsed}: CardRowP
break;
}
useEffect(() => {
liftCollapsed(collapsed, tier);
}, [collapsed])
return (
<div className={`card-row tier-${tier} ${collapsed && 'collapsed'}`}>
<div className="card-row-top-bar">
<p>Tier: {tier}</p>
<button onClick={() => setCollapsed(!collapsed)}>{collapsed ? "Show" : "Hide"}</button>
</div>
<div className={`card-row-cards-visible ${collapsed && 'hidden'}`}>
<div className={`card-count cc-tier-${tier}`}>
<div className={`card-row tier-${tier}`}>
<p>Tier: {tier}</p>
<div className="card-row-cards-visible">
<div className="card card-count">
<p>Remaining: {state.gameboard.deck[typedTier].length}</p>
</div>
{ cards && cards.map((cardData: CardData) => {
return <Card key={v4()} data={cardData} state={state} setState={setState} collapsed={collapsed} />
return <Card key={v4()} data={cardData} state={state} setState={setState} />
})}
</div>
</div>

View File

@@ -1,47 +0,0 @@
.gameboard {
display: flex;
flex-flow: column nowrap;
align-items: flex-start;
justify-content: center;
background-color: rgb(57, 57, 65);
width: 90vw;
padding: 0 18px 12px;
#round-marker {
padding-left: 8px;
}
.gameboard-columns {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: flex-start;
width: 100%;
section {
display: flex;
flex-flow: column nowrap;
}
.gameboard-left {
align-items: flex-start;
width: 50%;
}
.gameboard-right {
justify-content: flex-end;
width: 50%;
}
.gameboard-left-expanded {
align-items: flex-start;
width: 90%;
}
.gameboard-right-compact {
justify-content: flex-end;
width: 10%;
}
}
}

View File

@@ -1,58 +1,50 @@
// types, data, utils
import { useCallback, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import initializeBoard, { setCardRows } from '../../util/setup/initializeBoard';
import { AppState, PlayerData, ResourceCost, UIState } from '../../util/types';
import { defaultUIState } from '../../util/setup/defaultUIState';
import initializeBoard, { setCardRows } from '../../util/initializeBoard';
import { AppState, PlayerData, ResourceCost } from '../../util/types';
import { getChipsActions } from '../Player/ActionMethods';
import { StateProps } from '../../util/propTypes';
import './Gameboard.scss';
// components
import Nobles from '../Nobles/Nobles';
import AvailableChips from '../Resources/AvailableChips';
import AllPlayers from '../Player/AllPlayers';
import CardRow from '../Card/CardRow';
import SelectionView from '../Resources/SelectionView';
import { useCurrentPlayer } from '../../hooks/useCurrentPlayer';
import usePreviousPlayer from '../../hooks/usePreviousPlayer';
import { shouldRightSideCollapse } from '../../util/mechanics/shouldRightSideCollapse';
import { setStateUpdateSelection } from '../../hooks/stateSetters';
const { validateChips } = getChipsActions;
export default function Gameboard({ state, setState }: StateProps) {
const [view, setView] = useState(<p>Loading...</p>);
const [endgame, setEndgame] = useState<PlayerData>();
const [UICollapse, setUICollapse] = useState<UIState>(defaultUIState);
// callbacks for lifting state
const liftSelection = useCallback((value: keyof ResourceCost) => {
if (!state.actions.getChips.active) return;
setState((prev: AppState) => setStateUpdateSelection(prev, value));
}, [state]);
setState((prev: AppState) => {
let newSelection = prev.actions.getChips.selection;
newSelection?.push(value);
const liftCollapsed = useCallback((collapsed: boolean, tier = 5) => {
setUICollapse((prev: UIState) => {
switch (tier) {
case 1:
return {
...prev,
tierOneCollapsed: collapsed
}
case 2:
return {
...prev,
tierTwoCollapsed: collapsed
}
case 3:
return {
...prev,
tierThreeCollapsed: collapsed
}
default:
return {
...prev,
noblesCollapsed: collapsed
let newState = {
...prev,
actions: {
...state.actions,
getChips: {
active: true,
selection: newSelection,
valid: false
}
}
}
});
}, [UICollapse, setUICollapse])
const result = validateChips(newState);
newState.actions.getChips.valid = result;
return newState;
})
}, [state]);
// util functions, setup on mount
useEffect(() => initializeBoard(state, setState), [])
@@ -71,12 +63,12 @@ export default function Gameboard({ state, setState }: StateProps) {
useEffect(() => {
if (endgame) {
let winner: PlayerData;
const winnerData = state.players;
const currentPlayer = useCurrentPlayer(state);
if (!currentPlayer) return;
if (currentPlayer.id <= endgame.id) {
winner = winnerData.sort((x,y) => x.points + y.points)[0];
const winnerData = state.players;
winner = winnerData.sort((x,y) => x.points - y.points)[0];
console.log(winner.name + ' wins!');
}
}
@@ -93,25 +85,19 @@ export default function Gameboard({ state, setState }: StateProps) {
);
} else {
setView(
<div className="gameboard">
<h2 id="round-marker">Round: {state.round}</h2>
<div className="gameboard-columns">
<section className={shouldRightSideCollapse(UICollapse) ? "gameboard-left-expanded" : "gameboard-left"}>
<Nobles state={state} setState={setState} liftCollapsed={liftCollapsed} />
<CardRow tier={3} state={state} setState={setState} liftCollapsed={liftCollapsed} />
<CardRow tier={2} state={state} setState={setState} liftCollapsed={liftCollapsed} />
<CardRow tier={1} state={state} setState={setState} liftCollapsed={liftCollapsed} />
</section>
<section className={shouldRightSideCollapse(UICollapse) ? "gameboard-right-compact" : "gameboard-right"}>
<AllPlayers
state={state} setState={setState} liftSelection={liftSelection}
UICollapse={UICollapse} setUICollapse={setUICollapse} liftCollapsed={liftCollapsed} />
</section>
</div>
<div className="gameboard-rows">
<strong>Round: {state.round}</strong>
<Nobles state={state} setState={setState} />
<CardRow tier={3} state={state} setState={setState} />
<CardRow tier={2} state={state} setState={setState} />
<CardRow tier={1} state={state} setState={setState} />
<SelectionView state={state} setState={setState} />
<AvailableChips state={state} setState={setState} liftSelection={liftSelection} />
<AllPlayers state={state} setState={setState} />
</div>
)
}
}, [state, UICollapse]);
}, [state]);
return view
}

View File

@@ -1,5 +1,5 @@
import { expect, it, describe, vi } from 'vitest';
import initializeBoard from '../../util/setup/initializeBoard';
import initializeBoard from '../../util/initializeBoard';
import { initialState } from '../../hooks/stateSetters';
import { AppState, setStateType } from '../../util/types';

View File

@@ -1,44 +1,18 @@
@import "../../sass/helper/mixins";
.nobles-panel {
display: flex;
flex-flow: column nowrap;
background-color: rgb(212, 196, 152);
background-color: rgb(240, 236, 225);
padding: 1.5rem;
color: black;
padding: 1rem 0;
width: 45vw;
.nobles-topbar {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: baseline;
> * {
margin: 0 1rem;
}
}
.all-nobles {
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
.noble-card {
display: inline-flex;
flex-flow: column nowrap;
align-items: center;
height: 100%;
min-width: 25%;
border-right: 1px solid black;
&:last-child {
border-right: none;
}
.mapped-noble-costs {
display: flex;
@include map-gem-values(".noble-cost");
}
}
}
}
.all-nobles {
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
}
.noble-card {
display: inline-flex;
flex-flow: column nowrap;
}

View File

@@ -1,16 +1,9 @@
import { v4 } from "uuid";
import { NobleData, ResourceCost } from "../../util/types";
import { NobleProps } from "../../util/propTypes";
import { StateProps } from "../../util/propTypes";
import "../Nobles/Nobles.scss"
import { useEffect, useState } from "react";
export default function Nobles({ state, liftCollapsed }: NobleProps) {
const [collapsed, setCollapsed] = useState(true);
useEffect(() => {
liftCollapsed(collapsed);
}, [collapsed]);
export default function Nobles({ state }: StateProps) {
if (!state.gameboard.nobles.length) {
return (
<div className="nobles-panel">
@@ -19,31 +12,23 @@ export default function Nobles({ state, liftCollapsed }: NobleProps) {
</div>
)
}
return (
<div className={`nobles-panel ${collapsed && 'collapsed'}`}>
<div className="nobles-topbar">
<strong className="nobles-header">Nobles</strong>
<button onClick={() => setCollapsed(!collapsed)}>{collapsed ? "Show" : "Hide"}</button>
</div>
<div className={collapsed ? "hidden" : "all-nobles"}>
<div className="nobles-panel">
<strong>NOBLES</strong>
<div className="all-nobles">
{
state && state.gameboard.nobles.map((noble: NobleData) => {
return (
<div className="noble-card" key={v4()}>
<p>Points: {noble.points}</p>
<p>Cost:</p>
<div className="mapped-noble-costs">
{
Object.keys(noble.resourceCost).map((each) => {
// @ts-ignore
return (noble.resourceCost[each as keyof ResourceCost] > 0) && (
<p key={v4()} className={`noble-cost-${each}`}>
{noble.resourceCost[each as keyof ResourceCost]}
</p>
)
return (noble.resourceCost[each as keyof ResourceCost] > 0) && <p key={v4()}>{each}: {noble.resourceCost[each as keyof ResourceCost]}</p>
})
}
</div>
</div>
)
})

View File

@@ -1,4 +1,4 @@
import getTotalBuyingPower from "../../util/mechanics/getTotalBuyingPower";
import getTotalBuyingPower from "../../util/getTotalBuyingPower";
import { NobleData, PlayerData, ResourceCost } from "../../util/types";
export const canPickUpNoble = (player: PlayerData, noble: NobleData) => {

View File

@@ -1,7 +1,7 @@
import { turnOrderUtil } from "../../../util/mechanics/TurnOrderUtil";
import getTotalBuyingPower from "../../../util/mechanics/getTotalBuyingPower";
import { turnOrderUtil } from "../../../util/turnOrderUtil";
import getTotalBuyingPower from "../../../util/getTotalBuyingPower";
import { AppState, CardData, PlayerCards, ResourceCost, setStateType } from "../../../util/types";
import cardTierToKey from "../../../util/mechanics/cardTierToKey";
import cardTierToKey from "../../../util/cardTierToKey";
import { canPickUpNoble } from "../../Nobles/canPickUpNoble";
import { initialActions, setStateGetNoble } from "../../../hooks/stateSetters";
import { useCurrentPlayer } from "../../../hooks/useCurrentPlayer";

View File

@@ -1,7 +1,7 @@
import { AppState, PlayerData, setStateType } from '../../../util/types';
import { useCurrentPlayer } from '../../../hooks/useCurrentPlayer';
// @ts-ignore
import { turnOrderUtil } from '../../../util/mechanics/TurnOrderUtil';
import { turnOrderUtil } from '../../../util/turnOrderUtil';
import { initialActions } from "../../../hooks/stateSetters";
export const hasMaxChips = (player: PlayerData | null): boolean => {

View File

@@ -1,6 +1,6 @@
import cardTierToKey from "../../../util/mechanics/cardTierToKey";
import cardTierToKey from "../../../util/cardTierToKey";
import { initialActions } from "../../../hooks/stateSetters";
import { turnOrderUtil } from "../../../util/mechanics/TurnOrderUtil";
import { turnOrderUtil } from "../../../util/turnOrderUtil";
import { AppState, CardData, FullDeck, PlayerData, setStateType } from "../../../util/types";
import { useCurrentPlayer } from "../../../hooks/useCurrentPlayer";

View File

@@ -1,108 +1,27 @@
@import '../../sass/helper/mixins';
@import '../../sass/helper/variables';
@import '../../sass/helper/placeholders';
// local placeholder
%all-players-base {
display: flex;
flex-flow: column nowrap;
justify-content: space-around;
align-items: center;
background-color: rgb(188, 176, 146);
color: black;
.player-ui {
.subheader {
font-weight: bold;
}
background-color:rgb(172, 149, 94);
margin: 1rem 0;
padding: 0 2rem;
}
.card {
width: 100%;
img {
display: none;
}
@each $gem in $gemlist {
@include map-gem-values('.foreground');
.foreground-#{$gem} {
display: flex;
flex-direction: column;
align-items: center;
padding: 8px;
p {
display: inline;
padding: 8px;
}
.total-card-cost {
display: flex;
flex-flow: row wrap;
justify-content: center;
@include map-gem-values(".card-cost");
}
}
}
}
}
.all-players {
@extend %all-players-base;
.selection-view {
.current-selections {
display: flex;
align-items: center;
justify-content: center;
@include map-gem-values(".selection-value");
p {
margin: 1rem;
padding: 1rem;
border-radius: 50%;
}
}
}
display: flex;
background-color: rgb(237, 213, 156);
color: black;
.player-ui {
p {
margin: 1rem;
}
.subheader {
font-weight: bold;
}
background-color:rgb(172, 149, 94);
margin: 1rem 0;
padding: 0 2rem;
.turn-and-action-based {
display: flex;
flex-flow: row nowrap;
}
.resources {
.player-chips-enum {
display: flex;
justify-content: center;
@include map-gem-values(".player-chip");
}
}
.reserved-card-view {
background-color: rgb(232, 224, 200);
.reserved-card-cost {
display: flex;
flex-flow: row wrap;
justify-content: center;
@include map-gem-values(".reserve-cost");
p {
@extend %chip-design;
}
}
}
}
}
.all-players-mini {
@extend %all-players-base;
}

View File

@@ -1,76 +1,15 @@
// framework
import { useEffect, useMemo, useState } from "react";
import { v4 } from "uuid";
// util
import { shouldRightSideCollapse } from "../../util/mechanics/shouldRightSideCollapse";
import { AllPlayersProps } from "../../util/propTypes";
import { useCurrentPlayer } from "../../hooks/useCurrentPlayer";
import { defaultUIState } from "../../util/setup/defaultUIState";
import { UIState } from "../../util/types";
// components
import AvailableChips from "../Resources/AvailableChips";
import SelectionView from "../Resources/SelectionView";
import Player from "./Player";
import { PlayerData } from "../../util/types";
import { StateProps } from "../../util/propTypes";
import "./AllPlayers.scss"
export default function AllPlayers({ state, setState, liftSelection, UICollapse, setUICollapse, liftCollapsed }: AllPlayersProps) {
const [playerView, setPlayerView] = useState<JSX.Element>();
const [collapseClass, setCollapseClass] = useState("all-players");
const collapseAll = () => {
liftCollapsed(true);
liftCollapsed(true, 3);
liftCollapsed(true, 2);
liftCollapsed(true, 1);
// let value = UICollapse[each as keyof UIState];
// if (each === "playerUICollapsed") {
// continue;
// } else if (each === "noblesCollapsed") {
// console.log(each);
// liftCollapsed(value);
// } else {
// console.log(each, value);
// switch (each) {
// case "tierThreeCollapsed":
// liftCollapsed(value, 3);
// break;
// case "tierTwoCollapsed":
// liftCollapsed(value, 2);
// break;
// case "tierOneCollapsed":
// liftCollapsed(value, 1);
// break;
// default: break;
// }
// }
}
const allowCollapseAll = useMemo(() => {
for (let each of Object.keys(UICollapse)) {
if (each === "playerUICollapsed") continue;
if (!UICollapse[each as keyof UIState]) return true;
}
return false;
}, [UICollapse]);
useEffect(() => {
const currentPlayer = useCurrentPlayer(state);
if (!currentPlayer) return;
setPlayerView(<Player key={v4()} player={currentPlayer} state={state} setState={setState} />);
}, [state]);
useEffect(() => {
setCollapseClass( shouldRightSideCollapse(UICollapse) ? "all-players-mini" : "all-players" );
}, [UICollapse]);
export default function AllPlayers({ state, setState }: StateProps) {
const playerPool = state.players?.map((player: PlayerData) => <Player key={v4()} player={player} state={state} setState={setState} />);
return (
<div className={collapseClass}>
{ allowCollapseAll && <button onClick={collapseAll}>Collapse All</button> }
<SelectionView state={state} setState={setState} UICollapse={UICollapse} />
<AvailableChips state={state} setState={setState} liftSelection={liftSelection} />
{ playerView }
<div className="all-players">
{ playerPool }
</div>
)
}

View File

@@ -1,10 +1,10 @@
import { useEffect, useState } from "react";
import { v4 } from "uuid";
import { setStateAwaitAction, setStateBuyCard, setStateGetChips, setStateReserveCard } from "../../hooks/stateSetters";
import { useEffect, useState } from "react";
import { PlayerProps } from "../../util/propTypes";
import { CardData, PlayerData } from "../../util/types"
import { hasMaxReserved } from "./ActionMethods/reserveCardActions";
import { hasMaxChips } from "./ActionMethods/getChipsActions";
import { CardData, PlayerData } from "../../util/types"
import { PlayerProps } from "../../util/propTypes";
import { v4 } from "uuid";
import Card from "../Card/Card";
export default function Player({ player, state, setState }: PlayerProps) {
@@ -27,10 +27,14 @@ export default function Player({ player, state, setState }: PlayerProps) {
)
dynamic && setReservedView(
<div className="reserved-card-view">
<>
<p>Reserved cards:</p>
{ dynamic.reservedCards?.map((data: CardData) => <Card key={v4()} data={data} state={state} setState={setState} reserved={true} />) }
</div>
{
dynamic.reservedCards?.map((data: CardData) => {
return <Card key={v4()} data={data} state={state} setState={setState} />
})
}
</>
)
}, [dynamic, setState])
@@ -54,9 +58,13 @@ export default function Player({ player, state, setState }: PlayerProps) {
return (
<div className="player-ui" key={v4()}>
<p className="subheader">Name: {player.name} {player.starter && "(round starter)"}</p>
<p>Score: {dynamic && dynamic.points}</p>
{/* Dynamic data from state */}
<section className="turn-and-action-based">
<p>Score: {dynamic && dynamic.points}</p>
<p>{dynamic?.turnActive ? "It's your turn!" : "..."}</p>
{/* Player actions */}
<button
disabled={(dynamic && hasMaxChips(dynamic)) || (!dynamic?.turnActive)}
onClick={() => handleClick(0)}>
@@ -74,9 +82,12 @@ export default function Player({ player, state, setState }: PlayerProps) {
onClick={() => handleClick(2)}>
Reserve Card
</button>
</section>
<section className="resources">
<p className="subheader">{dynamic?.name}'s Resources</p>
<div className="player-chips">
<p>Chips:</p>
<div className="player-chips-enum">

View File

@@ -1,22 +1,14 @@
@import "../../sass/helper/mixins";
@import "../../sass/helper/variables";
.available-chips {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
flex-flow: row nowrap;
background-color: rgb(236, 238, 186);
color: black;
margin: 1rem;
p {
margin: 1rem;
}
@include map-gem-values(".chips");
@each $gem in $gemlist {
.chips-#{$gem} {
border-radius: 50%;
}
}
}

View File

@@ -19,7 +19,7 @@ export default function AvailableChips({ state, liftSelection }: ResourceProps)
disabled={state.gameboard.tradingResources[typedKey] <= 0}
onClick={() => liftSelection(typedKey)}
>
{state.gameboard.tradingResources[typedKey]}
{key}: {state.gameboard.tradingResources[typedKey]}
</button>
)
})

View File

@@ -0,0 +1,16 @@
@import "../../sass/helper/mixins";
.selection-view {
.current-selections {
display: flex;
align-items: center;
justify-content: center;
@include map-gem-values(".selection-value");
p {
margin: 1rem;
padding: 0.5rem;
border-radius: 25%;
}
}
}

View File

@@ -1,10 +1,10 @@
import { useEffect, useState } from "react";
import { SelectionProps } from "../../util/propTypes";
import { StateProps } from "../../util/propTypes";
import { useCurrentPlayer } from "../../hooks/useCurrentPlayer";
import { GetChipsHTML, ReserveCardHTML } from "./ViewHTML";
import { shouldRightSideCollapse } from "../../util/mechanics/shouldRightSideCollapse";
import './SelectionView.scss';
export default function SelectionView({ state, setState, UICollapse }: SelectionProps) {
export default function SelectionView({ state, setState }: StateProps) {
const [currentPlayer, setCurrentPlayer] = useState(useCurrentPlayer(state));
const actionTypes = [
state.actions.getChips,
@@ -15,20 +15,19 @@ export default function SelectionView({ state, setState, UICollapse }: Selection
const [view, setView] = useState(<></>);
useEffect(() => {
setCurrentPlayer(useCurrentPlayer(state));
setView(() => {
switch (true) {
case (actionTypes[0].active):
return <GetChipsHTML state={state} setState={setState} UICollapse={UICollapse} />
return <GetChipsHTML state={state} setState={setState} />
case (actionTypes[1].active):
return (
<div className={shouldRightSideCollapse(UICollapse) ? "selection-view-mini" : "selection-view"}>
<div className="selection-view">
<h2>{currentPlayer?.name} has elected to purchase a card!</h2>
<strong>Choose a card above to purchase.</strong>
</div>
)
case (actionTypes[2].active):
return <ReserveCardHTML state={state} setState={setState} UICollapse={UICollapse} />;
return <ReserveCardHTML state={state} setState={setState} />;
default:
return (
<div className="selection-view">
@@ -37,7 +36,9 @@ export default function SelectionView({ state, setState, UICollapse }: Selection
);
}
})
}, [state, setState])
setCurrentPlayer(useCurrentPlayer(state));
}, [state, state.actions, setState])
return view
}

View File

@@ -2,22 +2,16 @@ import { useEffect, useState } from "react";
import { v4 } from "uuid";
import { setStateGetChips, setStateReserveCard, setStateReservePlusGold } from "../../hooks/stateSetters";
import { useCurrentPlayer } from "../../hooks/useCurrentPlayer";
import { shouldRightSideCollapse } from "../../util/mechanics/shouldRightSideCollapse";
import { SelectionProps } from "../../util/propTypes";
import { StateProps } from "../../util/propTypes";
import { ResourceCost } from "../../util/types";
import { getChipsActions } from "../Player/ActionMethods";
import { hasMaxChips } from "../Player/ActionMethods/getChipsActions";
const { getChips } = getChipsActions;
export const GetChipsHTML = ({ state, setState, UICollapse }: SelectionProps) => {
export const GetChipsHTML = ({ state, setState }: StateProps) => {
const [prompt, setPrompt] = useState("");
const [style, setStyle] = useState("");
const currentPlayer = useCurrentPlayer(state);
useEffect(() => {
setStyle(shouldRightSideCollapse(UICollapse) ? "selection-view-mini" : "selection-view");
}, [UICollapse]);
useEffect(() => {
if (!state.actions.getChips.active) setPrompt("");
if (state.actions.getChips.selection?.length === 0) {
@@ -28,13 +22,13 @@ export const GetChipsHTML = ({ state, setState, UICollapse }: SelectionProps) =>
}, [state])
return (
<div className={style}>
<div className="selection-view">
<h2>{currentPlayer?.name} has elected to collect resources!</h2>
<strong>{prompt}</strong>
<div className="current-selections">
{
state.actions.getChips.active &&
state.actions.getChips.selection?.map((each: keyof ResourceCost) => <p className={`selection-value-${each}`} key={v4()}>{each[0].toUpperCase()}</p>)
state.actions.getChips.selection?.map((each: keyof ResourceCost) => <p className={`selection-value-${each}`} key={v4()}>{each}</p>)
}
</div>
{
@@ -47,15 +41,10 @@ export const GetChipsHTML = ({ state, setState, UICollapse }: SelectionProps) =>
)
}
export const ReserveCardHTML = ({ state, setState, UICollapse }: SelectionProps) => {
export const ReserveCardHTML = ({ state, setState }: StateProps) => {
const [takeGold, setTakeGold] = useState(false);
const [style, setStyle] = useState("");
const currentPlayer = useCurrentPlayer(state);
useEffect(() => {
setStyle(shouldRightSideCollapse(UICollapse) ? "selection-view-mini" : "selection-view");
}, [UICollapse]);
useEffect(() => {
switch (takeGold) {
case true:
@@ -70,7 +59,7 @@ export const ReserveCardHTML = ({ state, setState, UICollapse }: SelectionProps)
}, [takeGold]);
return (
<div className={style}>
<div className="selection-view">
<h2>{currentPlayer?.name} has elected to reserve a card!</h2>
<strong>Please make your selection above.</strong>
{ !hasMaxChips(currentPlayer) && (

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
import { AppState, CardData, NobleData, PlayerData, ResourceCost, UIState } from "../util/types";
import { AppState, CardData, NobleData, PlayerData, ResourceCost } from "../util/types";
import CardDeck from '../data/cards.json';
import { validateChips } from "../components/Player/ActionMethods/getChipsActions";
export const initialActions = {
buyCard: { active: false },
@@ -52,27 +51,6 @@ export const setStateGetChips = (prev: AppState) => {
}
}
export const setStateUpdateSelection = (prev: AppState, value: keyof ResourceCost) => {
let newSelection = prev.actions.getChips.selection;
newSelection?.push(value);
let newState = {
...prev,
actions: {
...prev.actions,
getChips: {
active: true,
selection: newSelection,
valid: false
}
}
}
const result = validateChips(newState);
newState.actions.getChips.valid = result;
return newState;
}
export const setStateBuyCard = (prev: AppState) => {
return {
...prev,

View File

@@ -1,17 +1,15 @@
@import './helper/placeholders';
#root {
.hidden {
display: none;
}
.collapsed {
width: 20vw;
align-items: flex-end;
display: none
}
display: flex;
align-items: center;
justify-content: center;
width: 99vw;
margin: 0 0.5vw;
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}

View File

@@ -1,5 +1,3 @@
@import "./placeholders";
@mixin map-gem-values($parentClass) {
#{$parentClass} {
&-emerald {
@@ -26,16 +24,6 @@
background-color: gold;
color: black;
}
}
p {
@extend %chip-design;
}
}
@mixin get-random-image($targetList) {
$idx: random(6);
$nth: nth($targetList, $idx);
background-image: url($nth);
}
}

View File

@@ -1 +0,0 @@
$gemlist: 'ruby', 'sapphire', 'onyx', 'emerald', 'diamond', 'gold';

View File

@@ -1,4 +1,4 @@
import { AppState, PlayerData } from "../types";
import { AppState, PlayerData } from "./types";
export const turnOrderUtil = (prev: AppState, dynamic: PlayerData) => {
let roundIncrement = false;

View File

@@ -1,4 +1,4 @@
import { FullDeck } from "../types"
import { FullDeck } from "./types"
export default function cardTierToKey(tier: number): keyof FullDeck {
switch (tier) {

View File

@@ -1,4 +1,4 @@
import { PlayerData, ResourceCost } from "../types";
import { PlayerData, ResourceCost } from "./types";
export default function getTotalBuyingPower(currentPlayer: PlayerData) {
let totalBuyingPower = {

View File

@@ -1,5 +1,5 @@
import { AppState, FullDeck, NobleData, ResourceCost, setStateType } from "../types";
import NobleStore from '../../data/nobles.json';
import { AppState, FullDeck, NobleData, ResourceCost, setStateType } from "./types";
import NobleStore from '../data/nobles.json';
const shuffleDeck = (state: AppState, setState: setStateType) => {
if (!state.gameboard.deck) return;

View File

@@ -1,12 +0,0 @@
import { UIState } from "../types";
export const shouldRightSideCollapse = (UICollapse: UIState) => {
for (let slice of Object.keys(UICollapse)) {
if (slice === "playerUICollapsed") continue;
if (!UICollapse[slice as keyof UIState]) {
return true;
}
}
return false;
}

View File

@@ -1,5 +1,4 @@
import { Dispatch, SetStateAction } from "react";
import { AppState, CardData, PlayerData, ResourceCost, setStateType, UIState } from "./types";
import { AppState, CardData, PlayerData, ResourceCost, SetActionType, setStateType } from "./types";
export interface StateProps {
state: AppState,
@@ -8,17 +7,14 @@ export interface StateProps {
export interface CardProps extends StateProps {
data: CardData
reserved?: boolean
collapsed?: boolean
}
export interface CardRowProps extends StateProps {
tier: number
liftCollapsed: (collapsed: boolean, tier: number) => void
}
export interface NobleProps extends StateProps {
liftCollapsed: (collapsed: boolean) => void
export interface AllPlayersProps extends StateProps {
setActionState: (value: SetActionType, player?: PlayerData) => void
}
export interface PlayerProps extends StateProps {
@@ -29,12 +25,3 @@ export interface ResourceProps extends StateProps {
liftSelection: (value: keyof ResourceCost) => void
}
export interface AllPlayersProps extends ResourceProps {
UICollapse: UIState,
setUICollapse: Dispatch<SetStateAction<UIState>>
liftCollapsed: (collapsed: boolean, tier?: number) => void
}
export interface SelectionProps extends StateProps {
UICollapse: UIState
}

View File

@@ -1,9 +0,0 @@
import { UIState } from "../types";
export const defaultUIState: UIState = {
noblesCollapsed: true,
tierThreeCollapsed: true,
tierTwoCollapsed: true,
tierOneCollapsed: true,
playerUICollapsed: false
}

View File

@@ -88,7 +88,6 @@ export interface CardData {
tier: number
points?: number
resourceCost: ResourceCost
image: string
}
export interface ResourceCost {
@@ -105,11 +104,3 @@ export interface NobleData {
points: number,
resourceCost: ResourceCost
}
export interface UIState {
noblesCollapsed: boolean
tierThreeCollapsed: boolean
tierTwoCollapsed: boolean
tierOneCollapsed: boolean
playerUICollapsed: boolean
}

View File

@@ -1,9 +1,9 @@
import { describe, expect, test } from "vitest"
import cardTierToKey from "./mechanics/cardTierToKey";
import cardTierToKey from "./cardTierToKey";
import { mockPlayerOne, mockState } from "./testUtils";
import { turnOrderUtil } from "./mechanics/TurnOrderUtil";
import { turnOrderUtil } from "./turnOrderUtil";
import { useCurrentPlayer } from "../hooks/useCurrentPlayer";
import getTotalBuyingPower from "./mechanics/getTotalBuyingPower";
import getTotalBuyingPower from "./getTotalBuyingPower";
describe('app utilities', () => {
test('useCurrentPlayer', () => {