Skip to content

Commit

Permalink
Merge pull request #49 from JetonDAO/great-stuff
Browse files Browse the repository at this point in the history
Add great stuff, jeton is responsive now
  • Loading branch information
arssly authored Oct 14, 2024
2 parents e165a28 + ef6ac76 commit 40bb51e
Show file tree
Hide file tree
Showing 16 changed files with 303 additions and 201 deletions.
12 changes: 6 additions & 6 deletions apps/web/src/app/@modal/(.)create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import { JetonContext } from "@src/components/JetonContextProvider";
import useCheckIn from "@src/hooks/useCheckIn";

const INITIAL_FORM_VALUES: FormValues = {
smallBlind: 0,
numberOfRaises: 0,
smallBlind: 1,
numberOfRaises: 2,
minPlayers: 2,
maxPlayers: 10,
minBuyIn: 100,
maxBuyIn: 1000,
maxPlayers: 9,
waitingTimeout: 3600,
chipUnit: ChipUnits.apt,
};
Expand All @@ -35,10 +35,8 @@ const INPUT_FIELDS = [
{ label: "Small Blind", name: "smallBlind" },
{ label: "Number of Raises", name: "numberOfRaises" },
{ label: "Minimum Players", name: "minPlayers" },
{ label: "Maximum Players", name: "maxPlayers" },
{ label: "Minimum Buy-in", name: "minBuyIn" },
{ label: "Maximum Buy-in", name: "maxBuyIn" },
{ label: "Waiting timeOut(seconds)", name: "waitingTimeOut" },
];

export default function GameCreateModal() {
Expand Down Expand Up @@ -68,13 +66,15 @@ export default function GameCreateModal() {
if (!createTable) throw new Error("create Table must exist");
if (!checkIn) throw new Error("Check in you must do");

const TIMEOUT = 300; // 5 minutes

const jeton = await createTable(
formValues.smallBlind,
formValues.numberOfRaises,
formValues.minPlayers,
formValues.minBuyIn,
formValues.maxBuyIn,
formValues.waitingTimeout,
TIMEOUT,
formValues.chipUnit,
checkIn,
account!.address,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/games/[id]/components/GameContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default function GameContainer({ children }: PropsWithChildren) {
<div
className={`flex flex-col relative items-center justify-center py-2 bg-[url("/images/pixel-wooden-pattern.png")] bg-repeat bg-center bg-[length:120px_120px] overflow-hidden h-[100dvh] w-[100dvw] z-50 min-h-screen`}
>
{children}
<div className="h-full max-w-[2000px] mx-auto w-full relative">{children}</div>
</div>
);
}
24 changes: 14 additions & 10 deletions apps/web/src/app/games/[id]/components/GameStatusBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
selectMyCards$,
selectShufflingPlayer$,
} from "../state/selectors/gameSelectors";
import LogsButton from "./LogsSidebar";

export default function GameStatusBox() {
const gameStatus = useSelector(selectGameStatus$());
Expand All @@ -29,15 +30,18 @@ export default function GameStatusBox() {
}

return (
<motion.div
className="absolute top-4 left-4 bg-black bg-opacity-70 text-[10px] max-w-[50vw] sm:text-base text-white p-3 rounded-lg shadow-md"
key={statusMessage}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3 }}
>
<p>{statusMessage}</p>
</motion.div>
<div className="flex gap-1 items-center absolute top-4 left-4 z-[420]">
<LogsButton />
<motion.div
className=" bg-black bg-opacity-70 text-[10px] max-w-[50vw] sm:text-base text-white p-3 rounded-lg shadow-md"
key={statusMessage}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3 }}
>
<p>{statusMessage}</p>
</motion.div>
</div>
);
}
69 changes: 69 additions & 0 deletions apps/web/src/app/games/[id]/components/LogsSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import CloseIcon from "@src/assets/icons/close.svg";
import Image from "next/image";
import { useState } from "react";

export default function LogsButton() {
const [isSidebarOpen, setIsSidebarOpen] = useState(false);

const handleToggleSidebar = () => {
setIsSidebarOpen(!isSidebarOpen);
};

const logs = [
{ description: "Player A shuffled", link: "https://example.com/tx/12345" },
{
description: "Player B placed a bet",
link: "https://example.com/tx/67890",
},
{ description: "Player C folded", link: "" },
{
description: "Player D won the hand",
link: "https://example.com/tx/54321",
},
];

return (
<div className="hidden sm:block">
<button
onClick={handleToggleSidebar}
className="flex flex-col bg-black bg-opacity-70 px-3 py-3 rounded-lg gap-2 justify-between w-14 items-center cursor-pointer z-50"
>
<div className="w-full h-1 bg-white" />
<div className="w-full h-1 bg-white" />
<div className="w-full h-1 bg-white" />
</button>

<div
className={`fixed top-0 left-0 py-4 h-full w-96 bg-black bg-opacity-90 text-white transition-transform duration-300 z-50 ease-in-out ${
isSidebarOpen ? "translate-x-0" : "-translate-x-full"
}`}
>
<div className="flex justify-between items-center px-4">
<h2 className="text-lg font-bold">Game Logs</h2>
<button className="opacity-80 hover:scale-90 duration-300" onClick={handleToggleSidebar}>
<Image width={36} height={36} src={CloseIcon} alt="close icon" />
</button>
</div>
<div className="p-4 divide-y-2 divide-white/20">
{logs.map((log, index) => (
<div key={log.description} className="py-4">
<p className="text-sm">
{index + 1}. {log.description}
</p>
{log.link && (
<a
href={log.link}
target="_blank"
rel="noopener noreferrer"
className="text-blue-400 underline text-xs"
>
Transaction
</a>
)}
</div>
))}
</div>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion apps/web/src/app/games/[id]/components/PlayerActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function PlayerActions() {
};

return (
<div className="fixed bottom-5 gap-5 left-5 right-5 flex justify-center ">
<div className="fixed bottom-5 gap-5 left-5 right-5 flex justify-center max-w-[1000px] mx-auto">
{actions.map((action) => (
<button
key={action}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/games/[id]/components/Pot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function Pot() {
return (
<>
<div
className={`text-white sm:text-lg text-[10px] items-center bg-black/20 px-4 py-1 mt-2 absolute pot ${
className={`text-white sm:text-lg text-[8px] items-center bg-black/20 px-2 sm:px-4 py-1 mt-2 absolute pot ${
started ? "" : ""
}`}
>
Expand Down
20 changes: 13 additions & 7 deletions apps/web/src/app/games/[id]/components/PrivateCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function PrivateCards({
}: {
playersPrivateCards: Record<number /* seat number start from */, number[]> | null;
}) {
const [startRevealing, setStartRevealing] = useState(false);
const [receivedCards, setReceivedCards] = useState(true);
const [revealedCards, setRevealedCards] = useState(false);
const [dealCards, setDealCards] = useState<number[]>([]);
const dealCardEffect = useAudio(dealCardSound, "effect");
Expand All @@ -35,6 +35,12 @@ export default function PrivateCards({
});
}, [seats, dealCardEffect]);

useEffect(() => {
setTimeout(() => {
setRevealedCards(true);
}, 3000);
}, []);

return (
<>
{seats.map((seat, i) => {
Expand All @@ -53,7 +59,7 @@ export default function PrivateCards({
(cardName, i) =>
CARDS_MAP[cardName] && (
<Card
className={`w-16 h-24 animate-flip-y grow-0 shrink-0 ${
className={`sm:w-[72px] w-5 animate-flip-y grow-0 shrink-0 ${
revealedCards ? "" : ""
}`}
key={cardName}
Expand All @@ -65,20 +71,20 @@ export default function PrivateCards({
) : (
<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 ${
className={`sm:w-14 sm:h-20 w-5 h-8 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)" : "",
transform: receivedCards ? "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 ${
dealCards.includes(seat) ? "!left-7" : ""
className={`sm:w-14 sm:h-20 w-5 h-8 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 ${
dealCards.includes(seat) ? "sm:!left-7 !left-2" : ""
}`}
style={{
transform: startRevealing ? "rotateY(90deg)" : "",
transform: receivedCards ? "rotateY(90deg)" : "",
transformStyle: "preserve-3d",
}}
/>
Expand Down
9 changes: 7 additions & 2 deletions apps/web/src/app/games/[id]/components/PublicCards.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { useSelector } from "@legendapp/state/react";
import { CARDS_MAP } from "@src/lib/constants/cards";
import { mockPublicCards } from "@src/lib/constants/mocks";
import { selectPublicCards$ } from "../state/selectors/gameSelectors";
import Card from "./Card";

export default function PublicCards({ cards }: { cards: number[] }) {
export default function PublicCards() {
const cards = useSelector(selectPublicCards$);

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"
className="xl:w-24 2xl:w-[115px] animate-deal w-7 sm:w-16"
key={cardName}
cardName={cardName}
/>
Expand Down
70 changes: 44 additions & 26 deletions apps/web/src/app/games/[id]/components/Seat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,18 @@ export default function Seat({
const shufflingPlayer = useSelector(selectShufflingPlayer$());
const awaitingBetFrom = useSelector(selectAwaitingBetFrom$());
const isPlayerTurn = awaitingBetFrom?.id === player.id;
const myCards = useSelector(selectMyCards$());
// const myCards = useSelector(selectMyCards$());
const myCards = [1, 2];
const dealer = useSelector(selectDealer$());

const gameStatus = useSelector(selectGameStatus$());
const [lastAction, setLastAction] = useState("");
const isWinner = false;

const isMainPlayer = useMemo(() => {
return seatNumber === 1 && myCards && myCards.length > 0;
}, [seatNumber]);

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

Expand All @@ -89,7 +94,7 @@ export default function Seat({

return (
<div
className={`seat-position items-center flex z-30 shrink-0 md:w-28 xl:w-32 w-10 grow-0 flex-col duration-1000 ${
className={`seat-position items-center flex z-30 shrink-0 md:w-28 xl:w-36 w-6 grow-0 duration-1000 ${
shufflingPlayer?.id === player.id
? "seat-dealer scale-110"
: `seat-${seatNumber} ${2 > Math.random() ? "z-[501]" : ""} ${
Expand All @@ -98,21 +103,32 @@ export default function Seat({
}`}
style={{ animationDelay: `${seatNumber * 100 + 100}ms` }}
>
<Image
draggable={false}
src={playerAvatar ?? ""}
alt="avatar"
className={`w-full aspect-square object-contain bg-black/70 h-full animate-grow-in grow-0 sm:w-14 rounded-full shrink-0 border-2 md:border-8 ${
shufflingPlayer?.id === player.id ? "scale-125 animate-bounce delay-1000" : ""
} ${isPlayerTurn ? "ring-8 animate-bounce ring-blue-600 duration-500" : ""} ${
player.status === PlayerStatus.sittingOut || player.status === PlayerStatus.folded
? "scale-95"
: ""
} ${isWinner ? "animate-tada" : ""}`}
style={{
transitionDelay: mounted.current ? "0ms" : `${150 * seatNumber}ms`,
}}
/>
<div
className={`flex flex-col items-center duration-500 ${
isMainPlayer && myCards.length > 0 ? "-translate-x-5" : ""
}`}
>
<Image
draggable={false}
src={playerAvatar ?? ""}
alt="avatar"
className={`aspect-square object-contain bg-black/70 h-full animate-grow-in grow-0 rounded-full shrink-0 border-2 md:border-8 ${
shufflingPlayer?.id === player.id ? "scale-125 animate-bounce delay-1000" : ""
} ${isPlayerTurn ? "ring-8 animate-bounce ring-amber-600 duration-500" : ""} ${
player.status === PlayerStatus.sittingOut || player.status === PlayerStatus.folded
? "scale-95"
: ""
} ${isWinner ? "animate-tada" : ""}`}
style={{
transitionDelay: mounted.current ? "0ms" : `${150 * seatNumber}ms`,
}}
/>
<div className="bg-black/70 shrink-0 flex-col rounded-sm line-clamp-1 relative flex justify-center text-[6px] text-white text-center shadow-2xl md:text-sm px-1 ">
<span>{seatNumber === 1 ? "me" : player.id.slice(2, 8)} </span>{" "}
<span>${player.balance}</span>
</div>
</div>

{isWinner && (
<Image
className={`absolute top-0 -right-14 animate-grow-in ${isWinner ? "animate-tada" : ""}`}
Expand All @@ -122,33 +138,35 @@ export default function Seat({
)}

{(lastAction || player.status === PlayerStatus.folded) && (
<div className="nes-balloon from-left z-50 animate-grow-in origin-bottom-left absolute top-0 -right-20 text-center p-2 sm:p-2">
<div className="nes-balloon hidden sm:block sm:absolute from-left z-50 animate-grow-in origin-bottom-left -top-5 -right-14 text-center p-2 sm:p-2">
<p className="text-[8px] sm:text-sm">
{player.status === PlayerStatus.folded ? "Folded" : lastAction}
</p>
</div>
)}
{dealer?.id === player.id && <DealerBadge />}

{seatNumber === 1 && myCards && myCards.length > 0 && (
<div className="justify-center flex absolute shrink-0 -right-[200%] bottom-0">
{isMainPlayer && (
<div className="justify-center flex sm:absolute shrink-0 -translate-x-4 sm:translate-x-0 sm:bottom-0 -bottom-5 right-[-160%]">
{myCards?.map(
(cardName, i) =>
CARDS_MAP[cardName] && (
<Card
className={
i === 0 ? "animate-dealAndRotate1" : "animate-dealAndRotate2 relative right-14"
}
className={`
w-10 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 className="bg-black/70 shrink-0 flex-col rounded-sm line-clamp-1 relative flex justify-center text-[8px] text-white text-center shadow-2xl md:text-sm px-1 ">
<span>{player.id.slice(2, 8)} </span> <span>${player.balance}</span>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions apps/web/src/app/games/[id]/components/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import type { ReactNode } from "react";
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-[72dvh] duration-500 scale-x-150 scale-y-125 sm:scale-y-125 relative md:right-0 flex items-center justify-center">
<div className="-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-[70dvh] duration-500 scale-x-[1.9] scale-y-[1.75] sm:scale-y-125 relative 2xl:bottom-10 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-[72dvh]"
className="object-fill w-full h-full rotate-90 md:rotate-0 md:max-h-[70dvh]"
src={TableBackground}
alt="table"
style={{ imageRendering: "pixelated" }}
Expand Down
Loading

0 comments on commit 40bb51e

Please sign in to comment.