This commit is contained in:
Tomáš Dvořák
2025-10-16 13:32:05 +02:00
commit 12cba639b9
663 changed files with 168914 additions and 0 deletions
@@ -0,0 +1,118 @@
import React from 'react';
import {
Box,
VStack,
Heading,
Spinner,
Text,
useColorModeValue,
} from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { getPolls, getPoll } from '../../services/polls';
import PollCard from './PollCard';
interface EmbeddedPollProps {
articleId?: number;
eventId?: number;
videoUrl?: string;
title?: string;
showTitle?: boolean;
}
/**
* EmbeddedPoll component - displays polls related to specific content
* Use in article pages, event pages, or video pages
*/
const EmbeddedPoll: React.FC<EmbeddedPollProps> = ({
articleId,
eventId,
videoUrl,
title = 'Hlasování',
showTitle = true,
}) => {
const bgSection = useColorModeValue('gray.50', 'gray.900');
// Build query params based on what's provided
const queryParams: any = {};
if (articleId) queryParams.article_id = articleId;
if (eventId) queryParams.event_id = eventId;
if (videoUrl) queryParams.video_url = videoUrl;
// Fetch polls related to this content
const { data: polls, isLoading } = useQuery({
queryKey: ['embedded-polls', queryParams],
queryFn: () => getPolls(queryParams),
enabled: !!(articleId || eventId || videoUrl), // Only fetch if at least one param is provided
staleTime: 2 * 60 * 1000,
});
// Get full poll data for each
const pollsToDisplay = polls?.slice(0, 3) || []; // Max 3 polls per content
const { data: pollsData, isLoading: isLoadingPolls } = useQuery({
queryKey: ['embedded-polls-details', pollsToDisplay.map((p) => p.id)],
queryFn: async () => {
const promises = pollsToDisplay.map((poll) => getPoll(poll.id));
return await Promise.all(promises);
},
enabled: pollsToDisplay.length > 0,
});
// Don't render anything if no content identifier provided
if (!articleId && !eventId && !videoUrl) {
return null;
}
// Don't render if loading initially
if (isLoading) {
return (
<Box py={4}>
<VStack spacing={2}>
<Spinner size="sm" />
<Text fontSize="sm" color="gray.500">
Načítání hlasování...
</Text>
</VStack>
</Box>
);
}
// Don't render if no polls found
if (!polls || polls.length === 0 || !pollsData || pollsData.length === 0) {
return null;
}
return (
<Box bg={bgSection} py={8} px={4} borderRadius="xl" my={8}>
<VStack spacing={6} maxW="3xl" mx="auto">
{showTitle && (
<Heading size="md" textAlign="center">
{title}
</Heading>
)}
<VStack spacing={4} w="full">
{isLoadingPolls ? (
<VStack py={8}>
<Spinner />
<Text>Načítání...</Text>
</VStack>
) : (
pollsData.map((pollResponse) => (
<Box key={pollResponse.poll.id} w="full">
<PollCard
poll={pollResponse.poll}
hasVoted={pollResponse.has_voted}
isActive={pollResponse.is_active}
canShowResults={pollResponse.can_show_results}
/>
</Box>
))
)}
</VStack>
</VStack>
</Box>
);
};
export default EmbeddedPoll;