Skip to content

Commit

Permalink
Add dealing card and bet animations
Browse files Browse the repository at this point in the history
  • Loading branch information
mhzrerfani committed Sep 28, 2024
1 parent c475b34 commit 1effb1d
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 254 deletions.
43 changes: 43 additions & 0 deletions apps/web/src/app/games/[id]/components/Pot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useSelector } from "@legendapp/state/react";
import chips from "@src/assets/images/chips/chips-3-stacks.png";
import Image from "next/image";
import { useEffect, useState } from "react";
import { selectPot$ } from "../state/selectors/gameSelectors";

export default function Pot() {
const [started, setStarted] = useState(false);
const pot = useSelector(selectPot$());
const raisedSeats = [2, 3, 6, 8];

useEffect(() => {
setTimeout(() => {
setStarted(true);
}, 4000);
});

return (
<>
<div
className={`text-white items-center bg-black/20 px-4 py-1 mt-2 absolute pot ${
started ? "animate-headShake " : ""
}`}
>
${pot}
</div>
{raisedSeats.map((seat) => {
return (
<Image
key={seat}
className={`absolute duration-700 ${
started ? "pot animate-fading opacity-0" : `seat-${seat} opacity-0`
}`}
width={32}
height={32}
alt="chips"
src={chips}
/>
);
})}
</>
);
}
88 changes: 88 additions & 0 deletions apps/web/src/app/games/[id]/components/PrivateCards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
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 { useEffect, useMemo, useRef, useState } from "react";
import Card from "./Card";
export default function PrivateCards({
playersPrivateCards,
}: {
playersPrivateCards: Record<number /* seat number start from */, number[]>;
}) {
const [startRevealing, setStartRevealing] = useState(false);
const [revealedCards, setRevealedCards] = useState(false);
const [dealedCards, setDealedCards] = useState<number[]>([]);
const dealCardEffect = useAudio(dealCardSound, "effect");

const mounted = useRef(false);

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

useEffect(() => {
if (mounted.current) return;

mounted.current = true;

seats.forEach((seat, index) => {
setTimeout(() => {
dealCardEffect.play();
setDealedCards((prev) => [...prev, seat]);
}, index * 200);
});
}, [seats, dealCardEffect]);

return (
<>
{seats.map((seat, i) => {
return (
<div
className={`flex grow-0 cards shrink-0 w-max duration-700 transition-all cards-${seat} ${
dealedCards.includes(seat) ? "" : "cards-center"
} `}
key={seat}
>
{revealedCards ? (
<>
{playersPrivateCards[seat]?.map(
(cardName, i) =>
CARDS_MAP[cardName] && (
<Card
className={`w-16 h-24 animate-flip-y grow-0 shrink-0 ${
revealedCards ? "" : ""
}`}
key={cardName}
cardName={CARDS_MAP[cardName]}
/>
),
)}
</>
) : (
<div className="relative">
<div
className={`w-14 h-20 rounded-lg animate-deal bg-[url("/images/card-back.png")] bg-no-repeat bg-contain justify-center grow-0 shrink-0 duration-[600ms] transition-all ${
revealedCards ? "" : ""
}`}
style={{
transform: startRevealing ? "rotateY(90deg)" : "",
transformStyle: "preserve-3d",
}}
/>
<div
className={`w-14 h-20 rounded-lg animate-deal absolute bg-[url("/images/card-back.png")] bg-no-repeat bg-contain justify-center grow-0 shrink-0 duration-[600ms] left-0 top-0 transition-all ${
dealedCards.includes(seat) ? "!left-7" : ""
}`}
style={{
transform: startRevealing ? "rotateY(90deg)" : "",
transformStyle: "preserve-3d",
}}
/>
</div>
// <UnrevealedCards startRevealing={startRevealing} />
)}
</div>
);
})}
</>
);
}
21 changes: 21 additions & 0 deletions apps/web/src/app/games/[id]/components/PublicCards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { CARDS_MAP } from "@src/lib/constants/cards";
import Card from "./Card";

export default function PublicCards({ cards }: { cards: number[] }) {
return (
<div className="flex">
{cards.map((cardIndex) => {
const cardName = CARDS_MAP[cardIndex];
return (
cardName && (
<Card
className="xl:w-24 2xl:w-28 animate-deal w-12 sm:w-16"
key={cardName}
cardName={cardName}
/>
)
);
})}
</div>
);
}
88 changes: 17 additions & 71 deletions apps/web/src/app/games/[id]/components/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,76 +1,22 @@
"use client";
import TableBackground from "@src/assets/images/table.png";
import Image from "next/image";
import type { ReactNode } from "react";

import { useWallet } from "@aptos-labs/wallet-adapter-react";
import { GameEventTypes } from "@jeton/ts-sdk";
import FullPageLoading from "@jeton/ui/FullPageLoading";
import { useSelector } from "@legendapp/state/react";
import { useRouter } from "next/navigation";
import { type FC, useEffect, useState } from "react";
import { initGame, setTableId } from "../state/actions/gameActions";
import {
selectGamePlayers$,
selectGameStatus$,
selectIsGameLoading$,
selectShufflingPlayer$,
} from "../state/selectors/gameSelectors";
import { useSubscribeToGameEvent } from "./useSubscribeToGameEvent";

type TableComponentProps = {
id: string;
};

export const TableComponent: FC<TableComponentProps> = ({ id }) => {
const [toffState, setToffState] = useState(false);
const players = useSelector(selectGamePlayers$());
const gameStatus = useSelector(selectGameStatus$());
const shufflingPlayer = useSelector(selectShufflingPlayer$());
const [{ percentage }] = useSubscribeToGameEvent(GameEventTypes.DOWNLOAD_PROGRESS) || [
{ percentage: undefined },
];
const router = useRouter();
const {
connected,
isLoading: isWalletLoading,
signMessage,
signAndSubmitTransaction,
account,
} = useWallet();

useEffect(() => {
if (!isWalletLoading && !connected && toffState) {
router.push("/");
} else if (!isWalletLoading && !connected) {
setTimeout(() => setToffState(true), 100);
}
}, [isWalletLoading, connected, router, toffState]);

useEffect(() => {
if (!isWalletLoading && account) {
initGame(account.address, signMessage, signAndSubmitTransaction);
}
setTableId(id);
}, [id, signMessage, signAndSubmitTransaction, isWalletLoading, account]);
export function Table({ children }: { children: ReactNode }) {
return (
<div className="flex justify-center items-center w-full h-full animate-grow-in">
<div className="h-full-z-40 md:scale-x-100 max-w-[70dvh] md:scale-y-100 md:scale-100 w-full md:max-w-[90dvw] xl:max-w-[90dvw] md:max-h-[80dvh] duration-500 scale-x-150 scale-y-150 sm:scale-y-125 relative md:right-0 flex items-center justify-center">
<Image
draggable={false}
priority
className="object-fill w-full h-full rotate-90 md:rotate-0 md:max-h-[80dvh]"
src={TableBackground}
alt="table"
style={{ imageRendering: "pixelated" }}
/>

const isLoading = useSelector(selectIsGameLoading$()) || isWalletLoading;
if (isLoading)
return (
<div>
{percentage && <p>downloading... {percentage}%</p>}
<FullPageLoading />
{children}
</div>
);

return (
<div>
<p>game state is ${gameStatus}</p>
<p>this is the actual game page</p>
<p>players are: </p>
{players?.map((p) => (
<div key={p.id}>
<p> player id: {p.id}</p>
{p === shufflingPlayer && <span style={{ color: "red" }}>shuffling</span>}
</div>
))}
</div>
);
};
}
9 changes: 9 additions & 0 deletions apps/web/src/app/games/[id]/components/WaitingIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function WaitingIndicator() {
return (
<div className="text-white flex text-xl animate-fadeIn px-2 py-1">
Waiting for players <div className="animate-bounce">.</div>
<div className="animate-bounce delay-300">.</div>
<div className="animate-bounce delay-700">.</div>
</div>
);
}
Loading

0 comments on commit 1effb1d

Please sign in to comment.