Skip to content

Commit

Permalink
feat: 추천 콘텐츠 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
gogumalatte committed Nov 19, 2024
1 parent 744a8f5 commit c6e7e28
Show file tree
Hide file tree
Showing 3 changed files with 400 additions and 25 deletions.
150 changes: 150 additions & 0 deletions src/Main/components/DetailModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
ModalFooter,
Button,
Text,
Box,
Flex,
useBreakpointValue,
} from "@chakra-ui/react";
import api from "../../api/interceptor";

interface DetailModalProps {
isOpen: boolean;
onClose: () => void;
content: {
id: number;
showId: string;
type: string;
title: string;
director: string;
cast: string;
country: string;
dateAdded: string;
releaseYear: string;
rating: string;
duration: string;
listedIn: string;
description: string;
} | null;
}

const DetailModal = ({ isOpen, onClose, content }: DetailModalProps) => {
if (!content) return null;

const handleLikeDislike = async (isLike: boolean) => {
try {
await api.post(`/api/like/${content.id}/${isLike}`);
console.log(isLike ? "좋아요 요청 성공" : "싫어요 요청 성공");
} catch (error) {
console.error("좋아요/싫어요 요청 중 오류 발생:", error);
}
};

const handleWatchAndNavigate = async () => {
try {
// 시청 기록 저장 API 호출
await api.post(`/api/watch/${content.id}`);
console.log("시청 기록 저장 요청 성공");
} catch (error) {
console.error("시청 기록 저장 요청 중 오류 발생:", error);
} finally {
// 넷플릭스로 이동
window.open(
"https://www.netflix.com/kr/",
"_blank",
"noopener,noreferrer"
);
}
};

// 반응형 스타일 설정
const textFontSize = useBreakpointValue({ base: "sm", md: "md" });
const headerFontSize = useBreakpointValue({ base: "lg", md: "xl" });
const buttonSize = useBreakpointValue({ base: "sm", md: "md" });
const modalWidth = useBreakpointValue({ base: "90%", md: "500px" });

return (
<Modal isOpen={isOpen} onClose={onClose} isCentered>
<ModalOverlay />
<ModalContent width={modalWidth}>
<ModalHeader fontSize={headerFontSize}>{content.title}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Box>
<Text fontSize={textFontSize}>
<strong>Type:</strong> {content.type}
</Text>
<Text fontSize={textFontSize}>
<strong>Director:</strong> {content.director}
</Text>
<Text fontSize={textFontSize}>
<strong>Cast:</strong> {content.cast}
</Text>
<Text fontSize={textFontSize}>
<strong>Country:</strong> {content.country}
</Text>
<Text fontSize={textFontSize}>
<strong>Date Added:</strong> {content.dateAdded}
</Text>
<Text fontSize={textFontSize}>
<strong>Release Year:</strong> {content.releaseYear}
</Text>
<Text fontSize={textFontSize}>
<strong>Rating:</strong> {content.rating}
</Text>
<Text fontSize={textFontSize}>
<strong>Duration:</strong> {content.duration}
</Text>
<Text fontSize={textFontSize}>
<strong>Genres:</strong> {content.listedIn}
</Text>
<Text fontSize={textFontSize}>
<strong>Description:</strong> {content.description}
</Text>
</Box>
</ModalBody>
<ModalFooter justifyContent="space-between">
{/* 좋아요/싫어요 버튼 */}
<Flex gap="1rem">
<Button
colorScheme="teal"
size={buttonSize}
fontSize={textFontSize}
onClick={() => handleLikeDislike(true)}
>
좋아요
</Button>
<Button
colorScheme="red"
size={buttonSize}
fontSize={textFontSize}
onClick={() => handleLikeDislike(false)}
ml={-3}
>
싫어요
</Button>
</Flex>
{/* 넷플릭스로 이동 버튼 */}
<Button
colorScheme="gray"
size={buttonSize}
fontSize={textFontSize}
onClick={handleWatchAndNavigate}
ml={3}
width={{ base: "100%", md: "auto" }}
>
넷플릭스로 이동
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
};

export default DetailModal;
92 changes: 68 additions & 24 deletions src/Main/components/RandomContents.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
import { useEffect, useState } from "react";
import { Box, Grid, Text, Spinner, useBreakpointValue } from "@chakra-ui/react";
import {
Box,
Grid,
Text,
Spinner,
useBreakpointValue,
useDisclosure,
} from "@chakra-ui/react";
import api from "../../api/interceptor";
import DetailModal from "./DetailModal";

interface Content {
id: number;
showId: string;
type: string;
title: string;
director: string;
cast: string;
country: string;
dateAdded: string;
releaseYear: string;
rating: string;
duration: string;
listedIn: string;
description: string;
}

function RandomContents(): JSX.Element {
const [randomContents, setRandomContents] = useState<Content[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [selectedContent, setSelectedContent] = useState<Content | null>(null);
const { isOpen, onOpen, onClose } = useDisclosure();

useEffect(() => {
const fetchRandomContents = async () => {
Expand All @@ -29,6 +51,11 @@ function RandomContents(): JSX.Element {
fetchRandomContents();
}, []);

const handleCardClick = (content: Content) => {
setSelectedContent(content);
onOpen();
};

const cardColumns = useBreakpointValue({ base: "1fr", md: "repeat(5, 1fr)" });

return (
Expand All @@ -43,33 +70,50 @@ function RandomContents(): JSX.Element {
<Spinner size="lg" color="teal.500" />
</Box>
) : (
<Grid templateColumns={cardColumns} gap="1rem">
{randomContents.map((content, index) => (
<Box
key={index}
padding="1rem"
border="1px solid #e2e8f0"
borderRadius="8px"
boxShadow="sm"
bg="white"
textAlign="center"
overflow="hidden"
whiteSpace="nowrap"
textOverflow="ellipsis"
>
<Text
fontSize="md"
fontWeight="bold"
color="teal.600"
<>
<Grid templateColumns={cardColumns} gap="1rem">
{randomContents.map((content) => (
<Box
key={content.id}
padding="1rem"
border="1px solid #e2e8f0"
borderRadius="8px"
boxShadow="sm"
bg="white"
height="100px"
alignContent={"center"}
textAlign="center"
overflow="hidden"
whiteSpace="nowrap"
textOverflow="ellipsis"
cursor="pointer"
transition="transform 0.2s, box-shadow 0.2s"
_hover={{
transform: "scale(1.05)",
boxShadow: "lg",
borderColor: "teal.500",
}}
onClick={() => handleCardClick(content)}
>
{content.title}
</Text>
</Box>
))}
</Grid>
<Text
fontSize="md"
fontWeight="bold"
color="teal.600"
overflow="hidden"
whiteSpace="nowrap"
textOverflow="ellipsis"
>
{content.title}
</Text>
</Box>
))}
</Grid>
<DetailModal
isOpen={isOpen}
onClose={onClose}
content={selectedContent}
/>
</>
)}
</Box>
);
Expand Down
Loading

0 comments on commit c6e7e28

Please sign in to comment.