import React, { useState } from 'react'; import { Box, VStack, HStack, Text, Button, Radio, RadioGroup, Checkbox, CheckboxGroup, Progress, Badge, useToast, Image, Heading, useColorModeValue, } from '@chakra-ui/react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { CheckIcon } from '@chakra-ui/icons'; import { Poll, PollOption, votePoll, getPollResults, generateSessionToken, } from '../../services/polls'; interface PollCardProps { poll: Poll; hasVoted: boolean; isActive: boolean; canShowResults: boolean; onVoteSuccess?: () => void; } const PollCard: React.FC = ({ poll, hasVoted: initialHasVoted, isActive, canShowResults: initialCanShowResults, onVoteSuccess, }) => { const toast = useToast(); const queryClient = useQueryClient(); const [selectedOptions, setSelectedOptions] = useState([]); const [hasVoted, setHasVoted] = useState(initialHasVoted); const [canShowResults, setCanShowResults] = useState(initialCanShowResults); const [results, setResults] = useState([]); const [showingResults, setShowingResults] = useState(initialCanShowResults); const bgCard = useColorModeValue('white', 'gray.800'); const borderColor = useColorModeValue('gray.200', 'gray.600'); const hoverBg = useColorModeValue('gray.50', 'gray.700'); // Vote mutation const voteMutation = useMutation({ mutationFn: () => { const sessionToken = generateSessionToken(); return votePoll(poll.id, { option_ids: selectedOptions, session_token: sessionToken, }); }, onSuccess: async () => { setHasVoted(true); setCanShowResults(true); setShowingResults(true); // Fetch results try { const resultsData = await getPollResults(poll.id); setResults(resultsData.results); } catch (error) { console.error('Failed to fetch results:', error); } queryClient.invalidateQueries({ queryKey: ['polls'] }); queryClient.invalidateQueries({ queryKey: ['poll', poll.id] }); toast({ title: 'Hlas zaznamenán!', description: 'Děkujeme za vaši účast v anketě.', status: 'success', duration: 3000, }); if (onVoteSuccess) { onVoteSuccess(); } }, onError: (error: any) => { toast({ title: 'Chyba', description: error.response?.data?.error || 'Nepodařilo se zaznamenat váš hlas', status: 'error', duration: 5000, }); }, }); const handleVote = () => { if (selectedOptions.length === 0) { toast({ title: 'Vyberte možnost', description: 'Před hlasováním vyberte alespoň jednu možnost.', status: 'warning', duration: 3000, }); return; } if (poll.allow_multiple && selectedOptions.length > poll.max_choices) { toast({ title: 'Příliš mnoho voleb', description: `Můžete vybrat maximálně ${poll.max_choices} možností.`, status: 'warning', duration: 3000, }); return; } voteMutation.mutate(); }; const handleSingleChoice = (value: string) => { setSelectedOptions([parseInt(value)]); }; const handleMultipleChoice = (values: (string | number)[]) => { const numValues = values.map((v) => (typeof v === 'string' ? parseInt(v) : v)); if (numValues.length <= poll.max_choices) { setSelectedOptions(numValues); } }; const loadResults = async () => { try { const resultsData = await getPollResults(poll.id); setResults(resultsData.results); setShowingResults(true); } catch (error: any) { toast({ title: 'Chyba', description: 'Nepodařilo se načíst výsledky', status: 'error', duration: 3000, }); } }; const calculatePercentage = (voteCount: number) => { if (poll.total_votes === 0) return 0; return (voteCount / poll.total_votes) * 100; }; // Show results if available if (showingResults && canShowResults) { const displayResults = results.length > 0 ? results : poll.options.map(opt => ({ option_id: opt.id, text: opt.text, vote_count: opt.vote_count, percentage: calculatePercentage(opt.vote_count), image_url: opt.image_url, })); return ( {poll.image_url && ( {poll.title} )} {poll.title} {hasVoted && ( Hlasováno )} {poll.description && ( {poll.description} )} Výsledky ({poll.total_votes} hlasů) {displayResults.map((result) => ( {result.text} {result.vote_count} ({result.percentage.toFixed(1)}%) ))} ); } // Show voting form return ( {poll.image_url && ( {poll.title} )} {poll.title} {poll.description && ( {poll.description} )} {!isActive && ( Anketa je momentálně uzavřena )} {isActive && ( <> {poll.allow_multiple ? ( Vyberte až {poll.max_choices} možností {poll.options.map((option) => ( {option.text} {option.description && ( {option.description} )} ))} ) : ( {poll.options.map((option) => ( {option.text} {option.description && ( {option.description} )} {option.player && ( {option.player.image_url && ( {`${option.player.first_name} )} #{option.player.jersey_number} {option.player.first_name}{' '} {option.player.last_name} )} ))} )} )} {canShowResults && !showingResults && ( )} Celkem hlasů: {poll.total_votes} ); }; export default PollCard;