This commit is contained in:
2024-09-27 22:24:33 -04:00
parent 7f6116450f
commit bb60182164
58 changed files with 2414 additions and 681 deletions

View 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;