mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 18:52:56 +00:00
de day #74
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
Spinner,
|
||||
Text,
|
||||
useColorModeValue,
|
||||
SimpleGrid,
|
||||
} from '@chakra-ui/react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getPolls, getPoll } from '../../services/polls';
|
||||
@@ -17,6 +18,7 @@ interface EmbeddedPollProps {
|
||||
videoUrl?: string;
|
||||
title?: string;
|
||||
showTitle?: boolean;
|
||||
maxPolls?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,6 +31,7 @@ const EmbeddedPoll: React.FC<EmbeddedPollProps> = ({
|
||||
videoUrl,
|
||||
title = 'Hlasování',
|
||||
showTitle = true,
|
||||
maxPolls,
|
||||
}) => {
|
||||
const bgSection = useColorModeValue('gray.50', 'gray.900');
|
||||
|
||||
@@ -46,16 +49,31 @@ const EmbeddedPoll: React.FC<EmbeddedPollProps> = ({
|
||||
staleTime: 2 * 60 * 1000,
|
||||
});
|
||||
|
||||
// Get full poll data for each
|
||||
const pollsToDisplay = polls?.slice(0, 3) || []; // Max 3 polls per content
|
||||
// Get full poll data for each (all linked polls)
|
||||
const pollsToDisplay = polls || [];
|
||||
|
||||
const preSortedLimited = React.useMemo(() => {
|
||||
const sorted = [...pollsToDisplay].sort((a, b) => {
|
||||
const aRating = a.type === 'rating' ? 1 : 0;
|
||||
const bRating = b.type === 'rating' ? 1 : 0;
|
||||
if (aRating !== bRating) return bRating - aRating;
|
||||
const aFeat = a.featured ? 1 : 0;
|
||||
const bFeat = b.featured ? 1 : 0;
|
||||
if (aFeat !== bFeat) return bFeat - aFeat;
|
||||
const aDate = new Date(a.created_at).getTime();
|
||||
const bDate = new Date(b.created_at).getTime();
|
||||
return bDate - aDate;
|
||||
});
|
||||
return typeof maxPolls === 'number' ? sorted.slice(0, maxPolls) : sorted;
|
||||
}, [pollsToDisplay, maxPolls]);
|
||||
|
||||
const { data: pollsData, isLoading: isLoadingPolls } = useQuery({
|
||||
queryKey: ['embedded-polls-details', pollsToDisplay.map((p) => p.id)],
|
||||
queryKey: ['embedded-polls-details', preSortedLimited.map((p) => p.id)],
|
||||
queryFn: async () => {
|
||||
const promises = pollsToDisplay.map((poll) => getPoll(poll.id));
|
||||
const promises = preSortedLimited.map((poll) => getPoll(poll.id));
|
||||
return await Promise.all(promises);
|
||||
},
|
||||
enabled: pollsToDisplay.length > 0,
|
||||
enabled: preSortedLimited.length > 0,
|
||||
});
|
||||
|
||||
// Don't render anything if no content identifier provided
|
||||
@@ -84,35 +102,83 @@ const EmbeddedPoll: React.FC<EmbeddedPollProps> = ({
|
||||
|
||||
return (
|
||||
<Box bg={bgSection} py={8} px={4} borderRadius="xl" my={8}>
|
||||
<VStack spacing={6} maxW="3xl" mx="auto">
|
||||
<VStack spacing={6} maxW="6xl" 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>
|
||||
{isLoadingPolls ? (
|
||||
<VStack py={8}>
|
||||
<Spinner />
|
||||
<Text>Načítání...</Text>
|
||||
</VStack>
|
||||
) : (
|
||||
(() => {
|
||||
// Sort: rating first, then featured, then newest
|
||||
const sorted = [...(pollsData || [])].sort((a, b) => {
|
||||
const aRating = a.poll.type === 'rating' ? 1 : 0;
|
||||
const bRating = b.poll.type === 'rating' ? 1 : 0;
|
||||
if (aRating !== bRating) return bRating - aRating;
|
||||
const aFeat = a.poll.featured ? 1 : 0;
|
||||
const bFeat = b.poll.featured ? 1 : 0;
|
||||
if (aFeat !== bFeat) return bFeat - aFeat;
|
||||
const aDate = new Date(a.poll.created_at).getTime();
|
||||
const bDate = new Date(b.poll.created_at).getTime();
|
||||
return bDate - aDate;
|
||||
});
|
||||
const limited = typeof maxPolls === 'number' ? sorted.slice(0, maxPolls) : sorted;
|
||||
const count = limited.length;
|
||||
if (count === 1) {
|
||||
const pollResponse = limited[0];
|
||||
return (
|
||||
<Box w="full">
|
||||
<PollCard
|
||||
poll={pollResponse.poll}
|
||||
hasVoted={pollResponse.has_voted}
|
||||
isActive={pollResponse.is_active}
|
||||
canShowResults={pollResponse.can_show_results}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
if (count === 2) {
|
||||
return (
|
||||
<SimpleGrid w="full" columns={{ base: 1, md: 2 }} spacing={4}>
|
||||
{limited.map((pollResponse) => (
|
||||
<Box key={pollResponse.poll.id}>
|
||||
<PollCard
|
||||
poll={pollResponse.poll}
|
||||
hasVoted={pollResponse.has_voted}
|
||||
isActive={pollResponse.is_active}
|
||||
canShowResults={pollResponse.can_show_results}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SimpleGrid w="full" columns={{ base: 1, sm: 2, lg: 3 }} spacing={4}>
|
||||
{limited.map((pollResponse) => (
|
||||
<Box key={pollResponse.poll.id}>
|
||||
<PollCard
|
||||
poll={pollResponse.poll}
|
||||
hasVoted={pollResponse.has_voted}
|
||||
isActive={pollResponse.is_active}
|
||||
canShowResults={pollResponse.can_show_results}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
);
|
||||
})()
|
||||
)}
|
||||
</VStack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmbeddedPoll;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user