Remove vote on leave/disconnect, require 2+ members, restore vote on sync
All checks were successful
Build & Push Container Image / build (push) Successful in 10s
All checks were successful
Build & Push Container Image / build (push) Successful in 10s
- Add removeVote (only during VOTING state, preserves revealed votes) - Remove user's vote on disconnect, room:leave, and kick - After vote removal, check auto-reveal for remaining members - Send poker:my-vote on sync so card selection is restored - Disable voting cards until at least 2 participants are present Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0b713d3858
commit
bf5f71aa35
3 changed files with 64 additions and 3 deletions
|
|
@ -60,21 +60,32 @@ export default function PokerRoom({ session, issue, user, members, roomId, onSav
|
|||
setError(payload?.error || 'Unexpected poker error');
|
||||
}
|
||||
|
||||
function onMyVote(payload) {
|
||||
if (payload.sessionId !== session.id) return;
|
||||
if (payload.vote !== null && payload.vote !== undefined) {
|
||||
setMyVote(payload.vote);
|
||||
}
|
||||
}
|
||||
|
||||
socket.on('poker:vote-update', onVoteUpdate);
|
||||
socket.on('poker:revealed', onRevealed);
|
||||
socket.on('poker:saved', onSavedPayload);
|
||||
socket.on('poker:error', onError);
|
||||
socket.on('poker:my-vote', onMyVote);
|
||||
|
||||
return () => {
|
||||
socket.off('poker:vote-update', onVoteUpdate);
|
||||
socket.off('poker:revealed', onRevealed);
|
||||
socket.off('poker:saved', onSavedPayload);
|
||||
socket.off('poker:error', onError);
|
||||
socket.off('poker:my-vote', onMyVote);
|
||||
};
|
||||
}, [session.id, socket]);
|
||||
|
||||
const canVote = !revealed && members.length >= 2;
|
||||
|
||||
function handleVote(value) {
|
||||
if (revealed) return;
|
||||
if (!canVote) return;
|
||||
setMyVote(value);
|
||||
socket.emit('poker:vote', {
|
||||
sessionId: session.id,
|
||||
|
|
@ -162,14 +173,18 @@ export default function PokerRoom({ session, issue, user, members, roomId, onSav
|
|||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-7 gap-2">
|
||||
{!canVote && members.length < 2 && (
|
||||
<p className="text-sm text-slate-400 text-center m-0">Waiting for at least 2 participants to start voting...</p>
|
||||
)}
|
||||
<div className={`grid grid-cols-7 gap-2${!canVote ? ' opacity-50 pointer-events-none' : ''}`}>
|
||||
{CARDS.map((card) => {
|
||||
const isSelected = myVote === card.value;
|
||||
return (
|
||||
<button
|
||||
key={card.value}
|
||||
onClick={() => handleVote(card.value)}
|
||||
className="aspect-[2/3] rounded-sm border-2 transition-all flex flex-col items-center justify-center gap-1 hover:scale-105 cursor-pointer bg-transparent"
|
||||
disabled={!canVote}
|
||||
className="aspect-[2/3] rounded-sm border-2 transition-all flex flex-col items-center justify-center gap-1 hover:scale-105 cursor-pointer bg-transparent disabled:cursor-not-allowed"
|
||||
style={{
|
||||
borderColor: isSelected ? card.color : 'var(--card-border, #e2e8f0)',
|
||||
backgroundColor: isSelected ? `${card.color}15` : 'transparent'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue