Skip to content

Commit

Permalink
feat: 전체 시청 횟수 top10, 전체 좋아요 수 top10 추천 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
gogumalatte committed Nov 27, 2024
1 parent 37029ed commit fb2b6a9
Showing 1 changed file with 164 additions and 119 deletions.
283 changes: 164 additions & 119 deletions src/Main/components/RecommendedContents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ interface Content {
listedIn: string;
description: string;
posterPath?: string;
watchCount?: number;
likeCount?: number;
}

interface CategoryContent {
Expand All @@ -26,6 +28,12 @@ interface CategoryContent {
}

function RecommendedContents(): JSX.Element {
const [watchTop, setWatchTop] = useState<
{ content: Content; watchCount: number }[]
>([]);
const [likeTop, setLikeTop] = useState<
{ content: Content; likeCount: number }[]
>([]);
const [categories, setCategories] = useState<CategoryContent[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [selectedContent, setSelectedContent] = useState<Content | null>(null);
Expand All @@ -44,28 +52,37 @@ function RecommendedContents(): JSX.Element {
};

useEffect(() => {
const fetchRecommendedContents = async () => {
const fetchAllContents = async () => {
setIsLoading(true);
try {
const response = await api.get("/api/recommend/10");
// 많이 시청한 콘텐츠 TOP 10 가져오기
const watchResponse = await api.get("/api/watch/top");
setWatchTop(watchResponse.data || []);

// 좋아요한 콘텐츠 TOP 10 가져오기
const likeResponse = await api.get("/api/like/top");
setLikeTop(likeResponse.data || []);

// 추천 콘텐츠 가져오기
const recommendResponse = await api.get("/api/recommend/10");
const fetchedCategories = Object.keys(categoryLabels).map(
(category) => ({
category,
contents:
response.data[category]?.map(
recommendResponse.data[category]?.map(
(item: { content: Content }) => item.content
) || [],
})
);
setCategories(fetchedCategories);
} catch (error) {
console.error("추천 콘텐츠를 가져오는 중 오류 발생:", error);
console.error("콘텐츠를 가져오는 중 오류 발생:", error);
} finally {
setIsLoading(false);
}
};

fetchRecommendedContents();
fetchAllContents();
}, []);

const handleCardClick = (content: Content) => {
Expand All @@ -78,6 +95,126 @@ function RecommendedContents(): JSX.Element {
setIsModalOpen(false);
};

const renderContentGrid = (
items: { content: Content; count?: number }[],
label: string,
countLabel?: string
) => (
<Box marginBottom="2rem">
<Text
fontSize={{ base: "lg", md: "lg", lg: "xl" }}
fontWeight="bold"
color="teal.500"
marginBottom="1rem"
>
{label}
</Text>
{items.length > 0 ? (
<Flex
overflowX="auto"
paddingBottom="1rem"
alignItems="center"
height="300px"
css={{
"&::-webkit-scrollbar": {
height: "10px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: "#319795",
borderRadius: "4px",
},
"&::-webkit-scrollbar-track": {
backgroundColor: "#e2e8f0",
},
}}
>
<Grid
templateColumns={`repeat(${items.length}, 200px)`}
gap="1rem"
paddingX="1rem"
>
{items.map(({ content, count }) => (
<Box
key={content.id}
padding="1rem"
border="1px solid #e2e8f0"
borderRadius="8px"
boxShadow="sm"
bg="white"
textAlign="center"
cursor="pointer"
width="200px"
transition="transform 0.2s, box-shadow 0.2s"
_hover={{
transform: "scale(1.05)",
boxShadow: "lg",
borderColor: "teal.500",
}}
onClick={() => handleCardClick(content)}
>
{content.posterPath ? (
<Image
src={content.posterPath}
alt={`${content.title} 포스터`}
boxSize="150px"
objectFit="contain"
mx="auto"
marginBottom="0.5rem"
borderRadius="md"
/>
) : (
<Box
boxSize="150px"
display="flex"
flexDirection="column"
justifyContent="center"
alignItems="center"
bg="gray.100"
borderRadius="md"
marginBottom="0.5rem"
mx="auto"
>
<Text fontSize="sm" color="gray.500" textAlign="center">
포스터가 없습니다.
</Text>
</Box>
)}
<Text
fontSize="md"
fontWeight="bold"
color="teal.600"
overflow="hidden"
whiteSpace="nowrap"
textOverflow="ellipsis"
marginBottom="0.5rem"
>
{content.title}
</Text>
{countLabel && (
<Text fontSize="sm" color="gray.500">
{`${countLabel}: ${count}`}
</Text>
)}
</Box>
))}
</Grid>
</Flex>
) : (
<Text fontSize="md" color="gray.500" textAlign="center">
충분한 데이터가 쌓이지 않았습니다.
</Text>
)}
</Box>
);

const renderCategoryGrids = () =>
categories.map(({ category, contents }) =>
renderContentGrid(
contents.map((content) => ({ content })),
categoryLabels[category] || category
)
);

if (isLoading) {
return (
<Box
Expand All @@ -93,120 +230,28 @@ function RecommendedContents(): JSX.Element {

return (
<Box padding="2rem">
{categories.map(({ category, contents }) => (
<Box key={category} marginBottom="2rem">
{/* 카테고리 제목 */}
<Text
fontSize={{ base: "lg", md: "lg", lg: "xl" }}
fontWeight="bold"
color="teal.500"
marginBottom="1rem"
>
{categoryLabels[category]}
</Text>
{contents.length > 0 ? (
<Flex
overflowX="auto"
paddingBottom="1rem"
alignItems="center"
height={"300px"}
css={{
"&::-webkit-scrollbar": {
height: "10px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: "#319795",
borderRadius: "4px",
},
"&::-webkit-scrollbar-track": {
backgroundColor: "#e2e8f0",
},
}}
>
<Box paddingX="1rem" /* 그리드 앞뒤 공간 추가 */ width="100%">
<Grid
templateColumns={`repeat(${contents.length}, 200px)`}
gap="1rem"
>
{contents.map((content) => (
<Box
key={content.id}
padding="1rem"
border="1px solid #e2e8f0"
borderRadius="8px"
boxShadow="sm"
bg="white"
textAlign="center"
cursor="pointer"
width="200px"
transition="transform 0.2s, box-shadow 0.2s"
_hover={{
transform: "scale(1.05)",
boxShadow: "lg",
borderColor: "teal.500",
}}
onClick={() => handleCardClick(content)}
>
{content.posterPath ? (
<Image
src={content.posterPath}
alt={`${content.title} 포스터`}
boxSize="150px"
objectFit="contain"
mx="auto"
marginBottom="0.5rem"
borderRadius="md"
/>
) : (
<Box
boxSize="150px"
display="flex"
flexDirection="column"
justifyContent="center"
alignItems="center"
bg="gray.100"
borderRadius="md"
marginBottom="0.5rem"
mx="auto"
>
<Text
fontSize="sm"
color="gray.500"
textAlign="center"
>
해당 콘텐츠는
</Text>
<Text
fontSize="sm"
color="gray.500"
textAlign="center"
>
포스터가 없습니다.
</Text>
</Box>
)}
<Text
fontSize="md"
fontWeight="bold"
color="teal.600"
overflow="hidden"
whiteSpace="nowrap"
textOverflow="ellipsis"
>
{content.title}
</Text>
</Box>
))}
</Grid>
</Box>
</Flex>
) : (
<Text fontSize="md" color="gray.500" textAlign="center">
충분한 데이터가 쌓이지 않았습니다.
</Text>
)}
</Box>
))}
{/* 많이 시청한 콘텐츠 TOP 10 */}
{renderContentGrid(
watchTop.map((item) => ({
content: item.content,
count: item.watchCount,
})),
"🔥 서비스 이용자들이 많이 시청한 콘텐츠 TOP 10",
"시청 횟수"
)}

{/* 좋아요한 콘텐츠 TOP 10 */}
{renderContentGrid(
likeTop.map((item) => ({
content: item.content,
count: item.likeCount,
})),
"❤️ 서비스 이용자들이 좋아한 콘텐츠 TOP 10",
"좋아요 수"
)}

{/* 기존 추천 콘텐츠 */}
{renderCategoryGrids()}

{/* DetailModal */}
{selectedContent && (
Expand Down

0 comments on commit fb2b6a9

Please sign in to comment.