mySQL
This commit is contained in:
203
src/components/VotingTable/index.jsx
Normal file
203
src/components/VotingTable/index.jsx
Normal file
@@ -0,0 +1,203 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import VotingBoard from '../VotingBoard';
|
||||
import BoardCard from '../BoardCard';
|
||||
import Results from '../Results';
|
||||
import styles from './VotingTable.module.css';
|
||||
import titleCardSrc from '../../assets/images/titlecard.png';
|
||||
import { ReactComponent as ExitIcon } from '../../assets/images/exit.svg';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import ProfileMenuButton from '../ProfileMenuButton';
|
||||
import api from '../../services/api';
|
||||
|
||||
const VotingTable = ({ userId }) => {
|
||||
const [users, setUsers] = useState([]);
|
||||
const [votes, setVotes] = useState({});
|
||||
const [, setVotedUsers] = useState(0);
|
||||
const [isFinal, setIsFinal] = useState(false);
|
||||
const { sessionId } = useParams();
|
||||
const [currentUID, setCurrentUID] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const maxUsers = 32;
|
||||
const username =
|
||||
users.find((user) => user.uid === currentUID)?.username || '';
|
||||
|
||||
const goToLobby = useCallback(() => {
|
||||
navigate(`/lobby/${sessionId}`);
|
||||
}, [sessionId, navigate]);
|
||||
|
||||
async function handleLogout() {
|
||||
await handleDropUser(currentUID);
|
||||
}
|
||||
|
||||
async function handleInvite() {
|
||||
try {
|
||||
navigator.clipboard.writeText(window.location.href);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy invite link: ', err);
|
||||
}
|
||||
}
|
||||
|
||||
const handleDropUser = async (userId) => {
|
||||
try {
|
||||
// Remove user vote and user from session via API calls
|
||||
await api.delete(`/api/session/${sessionId}/votes/${userId}`);
|
||||
await api.delete(`/api/session/${sessionId}/users/${userId}`);
|
||||
|
||||
// Fetch updated session data after user removal
|
||||
const sessionResponse = await api.get(`/api/session/${sessionId}`);
|
||||
const sessionData = sessionResponse.data;
|
||||
|
||||
if (!sessionData) return;
|
||||
|
||||
// Update state with the new session data
|
||||
const userList = Object.entries(sessionData.users || {}).map(
|
||||
([uid, userInfo]) => ({
|
||||
uid,
|
||||
username: userInfo.username,
|
||||
})
|
||||
);
|
||||
|
||||
setUsers(userList);
|
||||
setVotes(sessionData.votes || {});
|
||||
|
||||
// Redirect the dropped user to the lobby
|
||||
await api.post(`/api/users/${userId}`, {
|
||||
currentSessionId: `lobby/${sessionId}`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error removing user:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFinalizeVoting = async () => {
|
||||
try {
|
||||
// Finalize voting by setting the isFinal flag in the session via API call
|
||||
await api.post(`/api/session/${sessionId}/finalize`, {
|
||||
isFinal: true,
|
||||
});
|
||||
setIsFinal(true);
|
||||
} catch (error) {
|
||||
console.error('Error finalizing voting:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetVoting = async () => {
|
||||
try {
|
||||
// Reset the session's votes and isFinal flag via API call
|
||||
await api.post(`/api/session/${sessionId}/reset`, {
|
||||
votes: {},
|
||||
isFinal: false,
|
||||
});
|
||||
setVotes({});
|
||||
setVotedUsers(0);
|
||||
setIsFinal(false);
|
||||
} catch (error) {
|
||||
console.error('Error resetting voting:', error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSessionData = async () => {
|
||||
try {
|
||||
// Fetch session data from the API
|
||||
const sessionResponse = await api.get(`/api/session/${sessionId}`);
|
||||
const sessionData = sessionResponse.data;
|
||||
|
||||
if (!sessionData) {
|
||||
// Initialize the session if it doesn't exist
|
||||
await api.post(`/api/session/${sessionId}`, {
|
||||
votes: {},
|
||||
maxUsers: maxUsers,
|
||||
isFinal: false,
|
||||
users: {},
|
||||
});
|
||||
} else {
|
||||
// Load the existing session data
|
||||
const userList = Object.entries(sessionData.users || {}).map(
|
||||
([uid, userInfo]) => ({
|
||||
uid,
|
||||
username: userInfo.username,
|
||||
})
|
||||
);
|
||||
setUsers(userList);
|
||||
setVotes(sessionData.votes || {});
|
||||
setIsFinal(sessionData.isFinal || false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching session data:', error);
|
||||
goToLobby(); // Redirect to lobby if the session doesn't exist
|
||||
}
|
||||
};
|
||||
|
||||
fetchSessionData();
|
||||
|
||||
// Polling or WebSocket could be used to listen for real-time updates
|
||||
const intervalId = setInterval(fetchSessionData, 5000); // Poll every 5 seconds
|
||||
return () => clearInterval(intervalId); // Clean up the interval
|
||||
}, [sessionId, maxUsers, navigate, setCurrentUID, goToLobby]);
|
||||
|
||||
const allVoted = Object.values(votes).every((v) => v >= 0);
|
||||
|
||||
return (
|
||||
<div className={styles.votingTable}>
|
||||
<ProfileMenuButton
|
||||
username={username}
|
||||
onLogout={handleLogout}
|
||||
onInvite={handleInvite}
|
||||
/>
|
||||
<img className={styles.titleCard} src={titleCardSrc} alt="title-card" />
|
||||
<div className={styles.tableCards}>
|
||||
{users.map(({ uid, username }) => (
|
||||
<div key={uid} className={styles.userCardWrapper}>
|
||||
<BoardCard
|
||||
username={username}
|
||||
vote={votes[uid]}
|
||||
isRevealed={isFinal && votes[uid] !== -1}
|
||||
isDimmed={votes[uid] === -1}
|
||||
isHighlighted={currentUID === uid}
|
||||
/>
|
||||
{
|
||||
<ExitIcon
|
||||
className={styles.dropButton}
|
||||
onClick={
|
||||
uid === currentUID ? handleLogout : () => handleDropUser(uid)
|
||||
}
|
||||
title="Drop User"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className={styles.form}>
|
||||
{allVoted && !isFinal && (
|
||||
<div
|
||||
className={`${styles.reveal} ${styles.button}`}
|
||||
onClick={handleFinalizeVoting}
|
||||
>
|
||||
Reveal Votes
|
||||
</div>
|
||||
)}
|
||||
{isFinal && (
|
||||
<div
|
||||
className={`${styles.restart} ${styles.button}`}
|
||||
onClick={handleResetVoting}
|
||||
>
|
||||
Restart Voting
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!isFinal ? (
|
||||
<VotingBoard
|
||||
sessionId={sessionId}
|
||||
userId={userId}
|
||||
maxUsers={maxUsers}
|
||||
/>
|
||||
) : (
|
||||
<Results votes={votes} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VotingTable;
|
||||
Reference in New Issue
Block a user