Skip to content

Commit

Permalink
frontend: Implemented the gamepage and GameContext
Browse files Browse the repository at this point in the history
Created gamepage ui rendering at /game and also
Created GameContext.tsx in contexts which stores
state. Further changes will be done after backend
implementation.

fixes: shivansh-bhatnagar18#95
  • Loading branch information
sksmagr23 authored and kuv2707 committed Jun 15, 2024
1 parent 089b5b7 commit 047a7ee
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 7 deletions.
Binary file added frontend/public/cardPool.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/card_faces/back.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/deckMat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/playBackground.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/playerIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import Home from './pages/Home';
import AppLayout from './pages/AppLayout';
import Error from './pages/Error';
import Game from './pages/Game';
import About from './pages/About';
import { AuthProvider } from './contexts/AuthContext';
import Login from './pages/Login';
import SignUp from './pages/SignUp';
import { GameProvider } from './contexts/GameContext';

const router = createBrowserRouter([
{
Expand All @@ -21,7 +21,7 @@ const router = createBrowserRouter([
},
{
path: '/game',
element: <Game />,
element: <GameProvider />,
},
{ path: '/about', element: <About /> },
{ path: '/error', element: <Error /> },
Expand Down
79 changes: 79 additions & 0 deletions frontend/src/contexts/GameContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* eslint-disable */
import React, { createContext, useContext, useState, useEffect } from 'react';
import Game from '../pages/Game';
import { useLocation } from 'react-router-dom';

interface GameState {
players: { id: number; name: string; cards: string[] }[];
cards: string[];
currentTurn: number;
lastThrownCard: string;
}

interface GameContextProps {
gameState: GameState | null;
setGameState: React.Dispatch<React.SetStateAction<GameState | null>>;
}

const defaultGameState: GameState = {
players: [],
cards: [],
currentTurn: 0,
lastThrownCard: '',
};

const GameContext = createContext<GameContextProps>({
gameState: null,
setGameState: () => {},
});

export const GameProvider = () => {
const [gameState, setGameState] = useState<GameState | null>(
defaultGameState
);

const location = useLocation();
const backendUrl = process.env.REACT_APP_BACKEND_URL;

useEffect(() => {
const queryParams = new URLSearchParams(location.search);
const gameType = queryParams.get('type');

fetch(`${backendUrl}/api/game?type=${gameType}`)
.then((response) => response.json())
.then((data) => {
setGameState(data);
});

// polling
const interval = setInterval(() => {
fetch(`${backendUrl}/api/game/state`)
.then((response) => response.json())
.then((data) => {
setGameState(data);
});
}, 5000);

return () => clearInterval(interval);
}, [location.search]);

return (
<GameContext.Provider value={{ gameState, setGameState }}>
{gameState ? (
<Game />
) : (
<div className="bg-gray-800 h-screen text-white text-5xl font-kavoon text-center">
Loading...
</div>
)}
</GameContext.Provider>
);
};

export const useGameContext = () => {
const context = useContext(GameContext);
if (!context) {
throw new Error('useGameContext must be used within a GameProvider');
}
return context;
};
108 changes: 104 additions & 4 deletions frontend/src/pages/Game.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,109 @@
function Game() {
import React from 'react';
import { useGameContext } from '../contexts/GameContext';
import Button from '../library/button';

const Game: React.FC = () => {
const { gameState } = useGameContext();

if (!gameState) {
return (
<div className="bg-gray-800 h-screen text-white text-5xl font-kavoon text-center">
Loading...
</div>
);
}

const playerPositions = [
{ top: '12%', left: '29%', transform: 'translate(-50%, -50%)' },
{ top: '12%', left: '71%', transform: 'translate(-50%, -50%)' },
{ top: '40%', left: '10%', transform: 'translate(-50%, -50%)' },
{ top: '40%', left: '90%', transform: 'translate(-50%, -50%)' },
{ top: '75%', left: '15%', transform: 'translate(-50%, -50%)' },
{ top: '75%', left: '85%', transform: 'translate(-50%, -50%)' },
];

return (
<div>
<div>X's turn</div>
<div className="flex justify-center items-center min-h-screen bg-gray-700">
<div className="relative w-full max-w-6xl h-[85vh] bg-cover bg-center bg-table-bg">
{/* Players */}
{gameState.players.slice(0, 6).map((player, index) => (
<div
key={index}
className="absolute flex flex-col items-center justify-center bg-player-icon-bg"
style={{
...playerPositions[index],
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
width: '70px',
height: '80px',
zIndex: 2,
}}
>
<div className="player-cards text-black mt-[61px]">
{player.cards.length}
</div>
</div>
))}

{/* Center Deck and UNO Button */}
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 flex flex-col items-center justify-center z-10">
<div className="relative flex">
<img
src="/cardPool.png"
alt="Card Pool"
className="w-56 h-36"
/>
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 flex space-x-4 z-20">
<img
src="/card_faces/back.jpeg"
alt="Card 1"
className="w-15 h-20"
/>
<img
src={
gameState.lastThrownCard
? `/card_faces/${gameState.lastThrownCard}.svg`
: '/card_faces/back.jpeg'
}
alt="Last Thrown Card"
className="w-15 h-20"
/>
</div>
</div>
<Button
text="UNO"
className="border-2 active:bg-red-600 mt-4"
backgroundColor="bg-purple-800"
hoverColor="hover:bg-purple-900"
buttonSize="w-18 h-10"
/>
</div>

{/* Player Mat */}
<div className="absolute bottom-20 left-1/2 transform -translate-x-1/2 flex flex-col items-center z-20">
<img
src="/deckMat.png"
alt="Deck Mat"
className="w-[calc(7*2.5rem)] h-20 relative z-10"
/>
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 flex z-30">
{Array.from({ length: 7 }).map((_, index) => (
<img
key={index}
src="/card_faces/g8.svg"
alt={`Card ${index}`}
className="w-12 h-16"
style={{
marginLeft: index === 0 ? 0 : '-1.2rem',
zIndex: 11 + index,
}}
/>
))}
</div>
</div>
</div>
</div>
);
}
};

export default Game;
2 changes: 1 addition & 1 deletion frontend/src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const Home: React.FC = () => {
const CreateGame = () => {
// Logic to create a game
console.log('Create Game');
navigate('/error');
navigate('/game');
};

const JoinGame = () => {
Expand Down
2 changes: 2 additions & 0 deletions frontend/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export default {
extend: {
backgroundImage: {
'uno-bg': "url('/src/assets/bg.jpg')",
'table-bg': "url('/playBackground.png')",
'player-icon-bg': "url('/playerIcon.png')",
},
},
},
Expand Down

0 comments on commit 047a7ee

Please sign in to comment.