Skip to content

Commit

Permalink
Frontend: Dislay The Player Whose Turn It Is Currently
Browse files Browse the repository at this point in the history
1. Brightened player icons for active turn indication.

2. Displayed current player's name on game board.

Fixes: #157
  • Loading branch information
asmit27rai committed Jun 26, 2024
1 parent ab4243f commit 34001dc
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 59 deletions.
1 change: 1 addition & 0 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion frontend/src/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,13 @@ export function AuthProvider({ children }: { children: ReactElement }) {
}
);
if (!response.ok) {
toast.open({ message: 'Invalid credentials', color: 'error' });
toast.open({
message: {
heading: 'Error',
content: 'Invalid credentials',
},
color: 'error',
});
return;
}
const data = await response.json();
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/contexts/GameContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ export const GameProvider = () => {
}
} catch (e) {
toast.open({
message: (e as Error).message,
message: {
heading: 'Error',
content: (e as Error).message,
},
color: 'error',
});
navigate('/');
Expand Down
10 changes: 6 additions & 4 deletions frontend/src/library/chatbox/Chatbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ const Chatbox: React.FC = () => {
case ChatEventTypes.SEND_MESSAGE:
if (!isVisible) {
toast.open({
message:
event.data.playerName +
': ' +
event.data.content,
message: {
heading: event.data.playerName,
content: event.data.content,
},
position: 'top-center',
color: 'info',
});
}
event.data.reactions = []; // should be done server-side
Expand Down
75 changes: 42 additions & 33 deletions frontend/src/library/toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ function useTimeout(callback: () => void, duration: number) {
}, [duration]);
}

type Message = {
heading: string;
content: string;
};

type ToastProperties = {
message: string;
message: Message;
close: () => void;
duration: number;
position: string;
Expand Down Expand Up @@ -64,13 +69,18 @@ export function Toast({

return (
<div className={`toast ${position}-animation ${color}`}>
<p>
<i className={iconClass} style={{ marginRight: '8px' }}></i>
{message}
</p>
<button className="close-button" onClick={close}>
<i className="fa-regular fa-circle-xmark"></i>
</button>
<div className="toast-content">
<div className="toast-icon">
<i className={`${iconClass} large-icon`}></i>
</div>
<div className="toast-message">
<b>{message.heading}</b>
<p>{message.content}</p>
</div>
<button className="close-button small-close" onClick={close}>
<i className="fa-regular fa-circle-xmark"></i>
</button>
</div>
</div>
);
}
Expand All @@ -80,7 +90,7 @@ type ToastProviderProperties = {
};

type ToastType = {
message: string;
message: Message;
id: number;
duration: number;
position: string;
Expand All @@ -89,18 +99,18 @@ type ToastType = {

export function ToastProvider({ children }: ToastProviderProperties) {
const [toasts, setToasts] = useState<ToastType[]>([]);
const [position, setPosition] = useState('top-center');
const [position, setPosition] = useState('top-left');

type Options = {
message?: string;
message?: Message;
duration?: number;
position?: string;
color?: 'info' | 'warning' | 'error' | 'success';
};

const openToast = useCallback(
({
message = '',
message = { heading: '', content: '' },
duration = 5000,
position = 'top-center',
color = 'info',
Expand All @@ -119,14 +129,8 @@ export function ToastProvider({ children }: ToastProviderProperties) {
);

const closeToast = useCallback((id: number) => {
setTimeout(() => {
setToasts((prevToasts) =>
prevToasts.filter((toast) => toast.id !== id)
);
}, 300);

setToasts((toasts) => {
return toasts.map((toast) => {
setToasts((prevToasts) =>
prevToasts.map((toast) => {
if (toast.id === id) {
if (toast.position === 'top-left')
toast.position = 'fade-out-left';
Expand All @@ -136,8 +140,14 @@ export function ToastProvider({ children }: ToastProviderProperties) {
toast.position = 'fade-out-center';
}
return toast;
});
});
})
);

setTimeout(() => {
setToasts((prevToasts) =>
prevToasts.filter((toast) => toast.id !== id)
);
}, 300);
}, []);

const contextValue = useMemo(
Expand All @@ -152,17 +162,16 @@ export function ToastProvider({ children }: ToastProviderProperties) {
<ToastContext.Provider value={contextValue}>
{children}
<div className={`toasts ${position}`}>
{toasts &&
toasts.map((toast) => (
<Toast
key={toast.id}
message={toast.message}
close={() => closeToast(toast.id)}
duration={toast.duration}
position={toast.position}
color={toast.color}
/>
))}
{toasts.map((toast) => (
<Toast
key={toast.id}
message={toast.message}
close={() => closeToast(toast.id)}
duration={toast.duration}
position={toast.position}
color={toast.color}
/>
))}
</div>
</ToastContext.Provider>
);
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/library/toast/toast-context.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { createContext, useContext } from 'react';

type Message = {
heading: string;
content: string;
};

type Options = {
message?: string;
message?: Message;
duration?: number;
position?: string;
color?: 'info' | 'warning' | 'error' | 'success';
Expand Down
72 changes: 56 additions & 16 deletions frontend/src/library/toast/toast.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,46 @@
display: flex;
font-family: Kavoon;
font-size: small;
align-items: center;
}

.toast-content {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}

.toast-icon {
font-size: 32px;
margin-right: 15px;
}

.toast-message {
flex-grow: 1;
}

.toast-message b {
font-size: 18px;
margin-bottom: 5px;
}

.toast-message p {
font-size: 14px;
margin: 0;
}

.close-button {
padding: 3px;
background: none;
cursor: pointer;
border: transparent;
color: black;
font-size: 18px;
}

.small-close {
font-size: 16px;
}

.top-right {
Expand All @@ -28,6 +68,7 @@
top: 10px;
left: 10px;
}

.top-center {
position: fixed;
top: 10px;
Expand Down Expand Up @@ -59,10 +100,11 @@
80% {
transform: translateX(5%);
}
80% {
100% {
transform: translateX(0);
}
}

@keyframes slideinCenter {
0% {
transform: translateY(-100%);
Expand All @@ -73,7 +115,7 @@
80% {
transform: translateY(-5%);
}
80% {
100% {
transform: translateY(0);
}
}
Expand All @@ -88,7 +130,7 @@
80% {
transform: translateX(-5%);
}
80% {
100% {
transform: translateX(0);
}
}
Expand Down Expand Up @@ -125,6 +167,7 @@
transform: translateX(-200%);
}
}

@keyframes fade-out-right {
0% {
transform: translateX(0%);
Expand Down Expand Up @@ -172,24 +215,12 @@
color: #fff;
background-color: #d9534f;
}

.warning {
color: #000;
background-color: #f0ad4e;
}

.close-button {
position: absolute;
right: 0px;
top: 0px;
margin-top: 4px;
padding: 0px 5px;
background: none;
cursor: pointer;
border: transparent;
color: black;
font-size: 23px;
}

@media (max-width: 640px) {
.toast {
flex-direction: column;
Expand Down Expand Up @@ -217,3 +248,12 @@
right: 0.5rem;
}
}

.toast p {
margin: 0;
}

.toast p strong {
font-size: larger;
display: block;
}
15 changes: 14 additions & 1 deletion frontend/src/pages/Game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ function Game() {
{ top: '75%', left: '15%', transform: 'translate(-50%, -50%)' },
{ top: '75%', left: '85%', transform: 'translate(-50%, -50%)' },
];

const cardStyles = {
filter: 'brightness(1)',
};

if (!gameState) {
return (
<div className="bg-gray-800 h-screen text-white text-5xl font-kavoon text-center">
Expand All @@ -190,18 +195,26 @@ function Game() {
return (
<div className="flex justify-center items-center min-h-screen bg-table-bg bg-cover">
<div className="relative w-full max-w-6xl h-[75vh]">
<div className="absolute top-4 left-1/2 transform -translate-x-1/2 text-yellow-400 text-xl font-bold">
{gameState.players[gameState.currentPlayerIndex].name}'s
Turn
</div>
{/* 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"
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,
...(index === gameState.currentPlayerIndex && {
...cardStyles,
filter: 'brightness(1.5)',
}),
}}
>
<div className="player-cards text-black mt-[61px]">
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ function JoinGameModalContent() {
navigate('/game?type=join&code=' + gameCode);
} else {
open({
message: 'Please Enter The Game Code',
message: {
heading: 'Warning',
content: 'Please Enter The Game Code',
},
duration: 3000,
position: 'top-center',
color: 'warning',
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/pages/SignUp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ const SignUp: React.FC = () => {
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (password !== confirmPass) {
toast.open({ message: 'Passwords do not match', color: 'error' });
toast.open({
message: {
heading: 'Error',
content: 'Passwords do not match',
},
color: 'error',
});
return;
}
await auth.authenticate(username, password, true);
Expand Down

0 comments on commit 34001dc

Please sign in to comment.