Skip to content

Commit

Permalink
Merge pull request #55 from JetonDAO/late-stuff
Browse files Browse the repository at this point in the history
add winning and betting animations
  • Loading branch information
arssly authored Oct 15, 2024
2 parents fd4de03 + c568c27 commit 16d3814
Show file tree
Hide file tree
Showing 13 changed files with 281 additions and 180 deletions.
9 changes: 5 additions & 4 deletions apps/web/src/app/games/[id]/components/DownloadModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,24 @@ import { selectIsGameLoading$, selectProgressPercentage$ } from "../state/select
export default function DownloadModal() {
const { isLoading: isWalletLoading } = useWallet();
const percentage = useSelector(selectProgressPercentage$());

const isLoading = useSelector(selectIsGameLoading$()) || isWalletLoading;

if (isLoading)
return (
<Modal closeButton={false} className="w-96 h-52 animate-grow-in">
<div className="flex flex-col items-center gap-1 text-white text-center">
<div className="flex text-nowrap text-sm flex-col items-center gap-1 text-white text-center">
{percentage ? (
<>
Downloading assets
<progress
className="nes-progress is-success duration-300 transition-all"
className="nes-progress is-success duration-300 transition-all h-6"
value={percentage}
max={100}
/>
{`%${percentage}`}
</>
) : (
"Starting download assets..."
"Starting downloading assets..."
)}
</div>
</Modal>
Expand Down
31 changes: 27 additions & 4 deletions apps/web/src/app/games/[id]/components/PlayerActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@ import { useWallet } from "@aptos-labs/wallet-adapter-react";
import { PlacingBettingActions } from "@jeton/ts-sdk";
import { useSelector } from "@legendapp/state/react";
import { JetonContext } from "@src/components/JetonContextProvider";
import { CARDS_MAP } from "@src/lib/constants/cards";
import { mockMyCards } from "@src/lib/constants/mocks";
import { finalAddress } from "@src/utils/inAppWallet";
import { useContext, useEffect, useMemo, useState } from "react";
import {
selectAvailableActions$,
selectAwaitingBetFrom$,
selectGamePlayers$,
selectMyCards$,
} from "../state/selectors/gameSelectors";
import Card from "./Card";

export default function PlayerActions() {
const availableActions = useSelector(selectAvailableActions$());
const awaitingBetFrom = useSelector(selectAwaitingBetFrom$());
const { game } = useContext(JetonContext);
const players = useSelector(selectGamePlayers$());
const myCards = useSelector(selectMyCards$());

const [queuedAction, setQueuedAction] = useState<PlacingBettingActions | null>(null);
const [isActionQueued, setIsActionQueued] = useState(false);
const { account } = useWallet();
Expand All @@ -37,8 +43,7 @@ export default function PlayerActions() {
if (isPlayerTurn && queuedAction) {
console.log(`Player turn, executing queued action: ${queuedAction}`);
handlePlayerAction(queuedAction);
setQueuedAction(null);
setIsActionQueued(false);
clearQueue();
}
}, [isPlayerTurn, queuedAction]);

Expand All @@ -64,7 +69,6 @@ export default function PlayerActions() {
console.log(`Action taken: ${action}`);
if (!game) throw new Error("Must exist by now");
game.placeBet(action);
clearQueue();
};

return (
Expand All @@ -74,7 +78,7 @@ export default function PlayerActions() {
actions.map((action) => (
<button
key={action}
className={`capitalize focus:outline-[#b87d5b] nes-btn is-warning disabled:hover:cursor-not-allowed w-full py-2 sm:py-4 text-[10px] sm:text-lg text-white hover:brightness-90 ${
className={`capitalize focus:outline-[#b87d5b] z-20 relative nes-btn is-warning disabled:hover:cursor-not-allowed w-full py-2 sm:py-4 text-[10px] sm:text-base text-white flex hover:brightness-90 ${
isActionQueued && queuedAction === action ? "cursor-pointer" : ""
}`}
onClick={() => handlePlayerAction(action)}
Expand All @@ -85,6 +89,25 @@ export default function PlayerActions() {
{`${action} ${isActionQueued && queuedAction === action ? "(Queued)" : ""}`}
</button>
))}
<div className="justify-center flex absolute shrink-0 -translate-x-4 sm:translate-x-0 -top-20 -right-5 sm:-top-28 sm:right-44 z-10">
{myCards?.map(
(cardName, i) =>
CARDS_MAP[cardName] && (
<Card
className={`
w-20 sm:w-32 z-50 relative
${
i === 0
? "animate-dealAndRotate1"
: "animate-dealAndRotate2 right-4 sm:right-14"
}
`}
key={cardName}
cardName={CARDS_MAP[cardName]}
/>
),
)}
</div>
</div>
);
}
108 changes: 92 additions & 16 deletions apps/web/src/app/games/[id]/components/Pot.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,78 @@
import { useSelector } from "@legendapp/state/react";
import chips from "@src/assets/images/chips/chips-3-stacks.png";
import Image from "next/image";
import React, { useEffect, useState } from "react";
import { selectPot$ } from "../state/selectors/gameSelectors";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { selectGameStatus$, selectPot$ } from "../state/selectors/gameSelectors";

export default function Pot() {
import { BettingActions, GameStatus } from "@jeton/ts-sdk";
import { mockPlayers } from "@src/lib/constants/mocks";
import type { UIPlayer } from "../state/state";

export default function Pot({ players }: { players: (UIPlayer | null)[] }) {
const [started, setStarted] = useState(false);
const [winning, setWinning] = useState(false);
const [betting, setBetting] = useState(false);
const pot = useSelector(selectPot$());
const raisedSeats = [2, 3, 6, 8];
const gameStatus = useSelector(selectGameStatus$());
const raisedSeats = mockPlayers.reduce<number[]>((acc, curr, i) => {
if (
curr.roundAction?.action === BettingActions.CALL ||
curr.roundAction?.action === BettingActions.RAISE
) {
acc.push(i + 1);
}
return acc;
}, []);

const winnerSeats = mockPlayers?.reduce<number[]>((acc, curr, i) => {
if (curr.winAmount && curr.winAmount > 0) {
acc.push(i + 1);
}
return acc;
}, []);

useEffect(() => {
if (winnerSeats && winnerSeats?.length > 0) {
setWinning(true);
setTimeout(() => {
setStarted(true);
}, 2000);
} else {
setWinning(false);
}
}, [winnerSeats]);

useEffect(() => {
console.log(raisedSeats, winnerSeats);
}, [winnerSeats, raisedSeats]);

const raise = useCallback(() => {
setBetting(true);

setTimeout(() => {
setStarted(true);

setTimeout(() => {
setBetting(false);
setStarted(false);
});
}, 500);
}, []);

useEffect(() => {
if (
gameStatus === GameStatus.DrawRiver ||
gameStatus === GameStatus.DrawFlop ||
gameStatus === GameStatus.DrawTurn
) {
if (raisedSeats.length > 0) {
raise();
} else {
setWinning(false);
setStarted(false);
}
}
}, [gameStatus, raise, raisedSeats.length]);

return (
<>
Expand All @@ -18,18 +83,29 @@ export default function Pot() {
>
${pot}
</div>
{raisedSeats.map((seat) => (
<Image
key={seat}
className={`absolute duration-1000 ${
started ? "pot animate-fading opacity-0" : `seat-${seat} opacity-0`
}`}
width={32}
height={32}
alt="chips"
src={chips}
/>
))}
{betting &&
raisedSeats.map((seat) => (
<Image
key={seat}
className={`absolute duration-1000 w-8 h-8 sm:w-14 sm:h-14 ${
started ? "pot animate-fading opacity-0" : `seat-${seat} opacity-0`
}`}
alt="chips"
src={chips}
/>
))}

{winning &&
winnerSeats.map((seat) => (
<Image
key={seat}
className={`absolute duration-[2s] w-8 h-8 sm:w-14 sm:h-14 ${
started ? `seat-${seat} animate-fading opacity-0` : "pot opacity-0"
}`}
alt="chips"
src={chips}
/>
))}
</>
);
}
10 changes: 6 additions & 4 deletions apps/web/src/app/games/[id]/components/PrivateCards.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import dealCardSound from "@src/assets/audio/effects/card-place.mp3";
import { useAudio } from "@src/hooks/useAudio";
import { CARDS_MAP } from "@src/lib/constants/cards";
import { mockPrivateCards } from "@src/lib/constants/mocks";
import React, { useEffect, useMemo, useRef, useState } from "react";
import Card from "./Card";

Expand All @@ -14,11 +15,12 @@ export default function PrivateCards({
const [dealCards, setDealCards] = useState<number[]>([]);
const dealCardEffect = useAudio(dealCardSound, "effect");

const cards = playersPrivateCards;
const mounted = useRef(false);

const seats = useMemo(() => {
return playersPrivateCards ? Object.keys(playersPrivateCards).map((seat) => Number(seat)) : [];
}, [playersPrivateCards]);
return cards ? Object.keys(cards).map((seat) => Number(seat)) : [];
}, [cards]);

useEffect(() => {
if (mounted.current || seats.length === 0) return;
Expand Down Expand Up @@ -53,9 +55,9 @@ export default function PrivateCards({
} `}
key={seat}
>
{revealedCards && playersPrivateCards ? (
{revealedCards && cards ? (
<>
{playersPrivateCards[seat]?.map(
{cards[seat]?.map(
(cardName, i) =>
CARDS_MAP[cardName] && (
<Card
Expand Down
Loading

0 comments on commit 16d3814

Please sign in to comment.