s22-poll/src/hooks/useVoteLogic.ts
2025-08-13 17:44:40 -05:00

145 lines
4.0 KiB
TypeScript

import { useState, useEffect, useRef } from "react";
import { mapOptions } from "../constants";
import { shuffleArray } from "../utils";
import { voteService } from "../services/api";
export function useVoteLogic() {
const [cards, setCards] = useState(() => shuffleArray(mapOptions));
const [selectedCard, setSelectedCard] = useState<number | null>(null);
const [showConfirmation, setShowConfirmation] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false);
const [voteTimestamp, setVoteTimestamp] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [pollEnded, setPollEnded] = useState(false);
const dragItem = useRef<number | null>(null);
const dragOverItem = useRef<number | null>(null);
useEffect(() => {
checkVoteStatus();
}, []);
const checkVoteStatus = async () => {
try {
const data = await voteService.checkVoteStatus();
setPollEnded(data.isPollEnded);
if (data.hasVoted && data.vote) {
setVoteTimestamp(data.timestamp || null);
setCards(data.vote);
setIsSubmitted(true);
}
} catch (error) {
console.error("Failed to check vote status:", error);
} finally {
setLoading(false);
}
};
const handleDragStart = (index: number) => {
if (isSubmitted || pollEnded) return;
dragItem.current = index;
};
const handleDragEnter = (index: number) => {
if (isSubmitted || pollEnded) return;
dragOverItem.current = index;
};
const handleDragEnd = () => {
if (isSubmitted || pollEnded) return;
const from = dragItem.current;
const to = dragOverItem.current;
if (from === null || to === null || from === to) return;
const updatedCards = [...cards];
const [removed] = updatedCards.splice(from, 1);
updatedCards.splice(to, 0, removed);
setCards(updatedCards);
dragItem.current = null;
dragOverItem.current = null;
};
const handleCardTap = (index: number) => {
if (isSubmitted || pollEnded) return;
if (selectedCard === null) {
setSelectedCard(index);
} else if (selectedCard === index) {
setSelectedCard(null);
} else {
const updatedCards = [...cards];
const [removed] = updatedCards.splice(selectedCard, 1);
updatedCards.splice(index, 0, removed);
setCards(updatedCards);
setSelectedCard(null);
}
};
const handleSubmit = () => {
setShowConfirmation(true);
};
const handleConfirmSubmit = async () => {
try {
await voteService.submitVote(cards);
setIsSubmitted(true);
setShowConfirmation(false);
setSelectedCard(null);
setVoteTimestamp(new Date().toISOString());
} catch (error) {
if (error instanceof Error) {
alert(`Error submitting vote: ${error.message}`);
} else {
alert("Failed to submit vote. Please try again.");
}
}
};
const handleCancelSubmit = () => {
setShowConfirmation(false);
};
const handleTouchStart = (index: number) => {
dragItem.current = index;
};
const handleTouchMove = (e: React.TouchEvent) => {
e.preventDefault();
const touch = e.touches[0];
const elementBelow = document.elementFromPoint(
touch.clientX,
touch.clientY
);
const cardElement = elementBelow?.closest(
"[data-card-index]"
) as HTMLElement;
if (cardElement) {
const index = parseInt(cardElement.dataset.cardIndex || "0");
dragOverItem.current = index;
}
};
const handleTouchEnd = () => {
handleDragEnd();
};
return {
cards,
selectedCard,
showConfirmation,
isSubmitted,
voteTimestamp,
loading,
pollEnded,
handleDragStart,
handleDragEnter,
handleDragEnd,
handleCardTap,
handleSubmit,
handleConfirmSubmit,
handleCancelSubmit,
handleTouchStart,
handleTouchMove,
handleTouchEnd,
};
}