diff --git a/src/@components/@common/BestPiickleCard/LastBestPiickleCard/index.tsx b/src/@components/@common/BestPiickleCard/LastBestPiickleCard/index.tsx new file mode 100644 index 00000000..ce0f31e1 --- /dev/null +++ b/src/@components/@common/BestPiickleCard/LastBestPiickleCard/index.tsx @@ -0,0 +1,20 @@ +import * as St from "./style"; + +interface LastCardProps { + handleClickCard: () => void; +} + +export default function LastBestPiickleCard(props: LastCardProps) { + const { handleClickCard } = props; + + return ( + + + 나머지 주제들도 +
+ 보고 싶다면? +
+ 나머지 보기 +
+ ); +} diff --git a/src/@components/@common/BestPiickleCard/LastBestPiickleCard/style.ts b/src/@components/@common/BestPiickleCard/LastBestPiickleCard/style.ts new file mode 100644 index 00000000..ebfefcac --- /dev/null +++ b/src/@components/@common/BestPiickleCard/LastBestPiickleCard/style.ts @@ -0,0 +1,53 @@ +import styled from "styled-components"; + +export const LastCard = styled.div` + position: relative; + + display: flex; + flex-direction: column; + + width: 18rem; + height: 10.6rem; + + border-radius: 0.4rem; + + padding: 2.1rem 1.2rem 0.8rem; + background: ${({ theme }) => theme.newColors.white}; + + cursor: default; +`; + +export const LastCardWButtonWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + + margin-top: 1.2rem; + align-self: flex-end; + + width: 6.9rem; + height: 2.5rem; + + border-radius: 2.9rem; + background: ${({ theme }) => theme.newColors.green}; + + color: ${({ theme }) => theme.newColors.white}; + ${({ theme }) => theme.newFonts.btn2} + + cursor: pointer; +`; + +export const LastCardContent = styled.p` + margin-top: 0.4rem; + + text-align: left; + + white-space: normal; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + + ${({ theme }) => theme.newFonts.btn1} + color: ${({ theme }) => theme.newColors.gray900}; +`; diff --git a/src/@components/@common/BestPiickleCard/index.tsx b/src/@components/@common/BestPiickleCard/index.tsx index 7a36e9bf..825f6ef0 100644 --- a/src/@components/@common/BestPiickleCard/index.tsx +++ b/src/@components/@common/BestPiickleCard/index.tsx @@ -1,6 +1,7 @@ import { LocationType } from "../../../types/cardCollection"; import { GTM_CLASS_NAME } from "../../../util/const/gtm"; -import useNavigateCardCollection, { NavigateCardCollectionBestType } from "../hooks/useNavigateCardCollection"; +import useNavigateCardCollection, { NavigateRecentCollectionType } from "../hooks/useNavigateCardCollection"; +import LastBestPiickleCard from "./LastBestPiickleCard"; import * as St from "./style"; interface BestPiickleCardProps { @@ -12,24 +13,25 @@ interface BestPiickleCardProps { idx: number; canNavigate: boolean; isLast?: boolean; + locationType: LocationType; } export default function BestPiickleCard(props: BestPiickleCardProps) { - const { bestPiickle, idx, canNavigate, isLast } = props; + const { bestPiickle, idx, canNavigate, isLast, locationType } = props; const { content, tags } = bestPiickle; const GTM_IDX_KEY = `mainBestPiickle${idx + 1}`; - const navigateCardCollection = useNavigateCardCollection(LocationType.BEST) as NavigateCardCollectionBestType; + const navigateCardCollection = useNavigateCardCollection(locationType) as NavigateRecentCollectionType; - const onClickCard = () => { + const handleClickCard = () => { if (!canNavigate) return; navigateCardCollection(idx); }; return ( - - {isLast ? ( - + + {!isLast ? ( + {tags.map((tag: string, i: number) => { return {tag.slice(1)}; @@ -39,14 +41,7 @@ export default function BestPiickleCard(props: BestPiickleCardProps) { 카드 보기 ) : ( - - - 나머지 주제들도 -
- 보고 싶다면? -
- 나머지 보기 -
+ )}
); diff --git a/src/@components/@common/BestPiickleCard/style.ts b/src/@components/@common/BestPiickleCard/style.ts index 82683011..20ed8e21 100644 --- a/src/@components/@common/BestPiickleCard/style.ts +++ b/src/@components/@common/BestPiickleCard/style.ts @@ -47,25 +47,3 @@ export const PickButtonWrapper = styled.div` text-align: right; `; - -export const LastCard = styled(BestPiickleCard)` - display: flex; - flex-direction: column; - - padding-top: 2.1rem; - background: ${({ theme }) => theme.newColors.white}; -`; - -export const LastCardButton = styled.button` - margin-top: 1.2rem; - align-self: flex-end; - - width: 6.9rem; - height: 2.5rem; - - border-radius: 2.9rem; - background: ${({ theme }) => theme.newColors.green}; - - color: ${({ theme }) => theme.newColors.white}; - ${({ theme }) => theme.newFonts.btn2} -`; diff --git a/src/@components/@common/hooks/useNavigateCardCollection.ts b/src/@components/@common/hooks/useNavigateCardCollection.ts index a3d753f2..cadf0754 100644 --- a/src/@components/@common/hooks/useNavigateCardCollection.ts +++ b/src/@components/@common/hooks/useNavigateCardCollection.ts @@ -12,6 +12,9 @@ export type NavigateCardCollectionBookMarkType = (sliderIdx?: number) => void; export type NavigateCardCollectionCategoryType = (categoryId: string, sliderIdx?: number) => void; export type NavigateCardCollectionFilterType = (filterTypes: string[], sliderIdx?: number) => void; export type NavigateCardCollectionMedleyType = (medleyId: string, sliderIdx?: number) => void; +export type NavigateRecentCollectionType = (sliderIdx?: number) => void; +export type NavigateFemaleCollectionType = (sliderIdx?: number) => void; +export type NavigateMaleCollectionType = (sliderIdx?: number) => void; export default function useNavigateCardCollection(locationType: LocationType) { const navigate = useNavigate(); @@ -57,6 +60,22 @@ export default function useNavigateCardCollection(locationType: LocationType) { navigate(`${routePaths.CardCollection}?type=${LocationType.MEDLEY}&medleyId=${medleyId}`); setSliderIdx(sliderIdx); }; + + case LocationType.RECENT: + return (sliderIdx = 0) => { + navigate(`${routePaths.CardCollection}?type=${LocationType.RECENT}`); + setSliderIdx(sliderIdx); + }; + case LocationType.FEMALE: + return (sliderIdx = 0) => { + navigate(`${routePaths.CardCollection}?type=${LocationType.FEMALE}`); + setSliderIdx(sliderIdx); + }; + case LocationType.MALE: + return (sliderIdx = 0) => { + navigate(`${routePaths.CardCollection}?type=${LocationType.MALE}`); + setSliderIdx(sliderIdx); + }; } } diff --git a/src/@components/BestPiicklePage/BestPiickleRank/RankItem/index.tsx b/src/@components/BestPiicklePage/BestPiickleRank/RankItem/index.tsx index de8ad5da..df42d36b 100644 --- a/src/@components/BestPiicklePage/BestPiickleRank/RankItem/index.tsx +++ b/src/@components/BestPiicklePage/BestPiickleRank/RankItem/index.tsx @@ -1,40 +1,35 @@ -import { useState } from "react"; - import IcBookmarkCheck_16_20 from "../../../../asset/icon/IcBookmarkCheck_16_20"; -import { cardCollectionApi } from "../../../../core/api/cardCollection"; import { LocationType } from "../../../../types/cardCollection"; import useNavigateCardCollection, { NavigateCardCollectionBookMarkType, } from "../../../@common/hooks/useNavigateCardCollection"; +import useCardBookmark from "../../../CardCollectionPage/hooks/useCardBookmark"; import * as St from "./style"; interface RankItemProps { + openLoginModalHandler: () => void; cardId: string; content: string; rank: number; + isBookmark: boolean; } export default function RankItem(props: RankItemProps) { - const { cardId, content, rank } = props; + const { cardId, content, rank, isBookmark, openLoginModalHandler } = props; const navigateRankCollection = useNavigateCardCollection(LocationType.BEST) as NavigateCardCollectionBookMarkType; - const [isBookmarked, setIsBookmarked] = useState(true); - const toggleBookmark = () => { - setIsBookmarked((prev) => !prev); - //cardCollectionApi.addNDeleteBookmark(cardId); - }; + const { isBookmarked, handleClickBookmark } = useCardBookmark(isBookmark, openLoginModalHandler); return ( - {rank} - {content} + {rank + 1} + navigateRankCollection(rank)}>{content} - + handleClickBookmark(cardId)}> - navigateRankCollection(rank)} /> ); } diff --git a/src/@components/BestPiicklePage/BestPiickleRank/RankItem/style.ts b/src/@components/BestPiicklePage/BestPiickleRank/RankItem/style.ts index 9b140acb..05450098 100644 --- a/src/@components/BestPiicklePage/BestPiickleRank/RankItem/style.ts +++ b/src/@components/BestPiicklePage/BestPiickleRank/RankItem/style.ts @@ -14,15 +14,6 @@ export const RankItemContainer = styled.article` height: 4.8rem; `; -export const RankItemLink = styled.button` - position: absolute; - top: 0; - bottom: 0; - left: 0; - - width: 80%; -`; - export const RankItemContent = styled.span` display: flex; flex-direction: row; @@ -43,8 +34,10 @@ export const RankItemText = styled.p` overflow: hidden; white-space: nowrap; text-overflow: ellipsis; - + width: 26.4rem; + + cursor: pointer; `; export const BookmarkWrapper = styled.div` diff --git a/src/@components/BestPiicklePage/BestPiickleRank/index.tsx b/src/@components/BestPiicklePage/BestPiickleRank/index.tsx index cecaf9a0..36128224 100644 --- a/src/@components/BestPiicklePage/BestPiickleRank/index.tsx +++ b/src/@components/BestPiicklePage/BestPiickleRank/index.tsx @@ -1,5 +1,12 @@ +import { LocationType } from "../../../types/cardCollection"; import { HeadingTitle } from "../../../util/main/headingTitles"; import HeadingTitleContainer from "../../@common/HeadingTitleContainer"; +import useModal from "../../@common/hooks/useModal"; +import useNavigateCardCollection, { + NavigateCardCollectionBookMarkType, +} from "../../@common/hooks/useNavigateCardCollection"; +import LoginModal from "../../@common/LoginModal"; +import { useBestPiickle } from "../../MainPage/hooks/useBestPiickle"; import RankItem from "./RankItem"; import * as St from "./style"; @@ -9,21 +16,30 @@ const rankTitles: HeadingTitle = { }; export default function BestPiickleRank() { + const { bestPiickle } = useBestPiickle(); + const { isModalOpen: isLoginModalOpen, toggleModal: toggleLoginModal } = useModal(); + const navigateRankCollection = useNavigateCardCollection(LocationType.BEST) as NavigateCardCollectionBookMarkType; return ( - {/* todo : rankitem id 수정*/} - - - - - - - - + {bestPiickle && + [...bestPiickle.data] + .slice(0, 8) + .map(({ _id, content, isBookmark }, idx) => ( + + ))} - 이어서 베스트 피클 카드 보기 + navigateRankCollection(8)}>이어서 베스트 피클 카드 보기 + + {isLoginModalOpen && } ); } diff --git a/src/@components/BestPiicklePage/BestPiickleRecommend/RecommendItem/index.tsx b/src/@components/BestPiicklePage/BestPiickleRecommend/RecommendItem/index.tsx index ec9854bf..98f07dbc 100644 --- a/src/@components/BestPiicklePage/BestPiickleRecommend/RecommendItem/index.tsx +++ b/src/@components/BestPiicklePage/BestPiickleRecommend/RecommendItem/index.tsx @@ -1,34 +1,34 @@ import BestPiickleCard from "../../../@common/BestPiickleCard"; import useDraggingContainer from "../../../@common/hooks/useDraggingContainer"; -import { useBestPiickle } from "../../../MainPage/hooks/useBestPiickle"; +import { recommendListType } from ".."; import * as St from "./style"; interface RecommendProps { - recommendType: string; + recommendList: recommendListType; } export default function RecommendItem(props: RecommendProps) { - const { recommendType } = props; - const { bestPiickle } = useBestPiickle(); + const { recommendList } = props; const { scrollableContainerProps, isDragging } = useDraggingContainer(); + return ( - {recommendType} + {recommendList.subtitle} - {bestPiickle && ( + {recommendList.cards && ( - {bestPiickle && - bestPiickle.data.slice(0, 4).map((bestPiickle, idx) => { - return ( - - ); - })} + {recommendList.cards.slice(0, 4).map((cards, idx) => { + return ( + + ); + })} )} diff --git a/src/@components/BestPiicklePage/BestPiickleRecommend/hooks/useCardsByGender.ts b/src/@components/BestPiicklePage/BestPiickleRecommend/hooks/useCardsByGender.ts new file mode 100644 index 00000000..3d11add8 --- /dev/null +++ b/src/@components/BestPiicklePage/BestPiickleRecommend/hooks/useCardsByGender.ts @@ -0,0 +1,20 @@ +import useSWR from "swr"; + +import { realReq } from "../../../../core/api/common/axios"; +import { PATH } from "../../../../core/api/common/constants"; +import { CardList } from "../../../../types/cardCollection"; +import { PiickleSWRResponse } from "../../../../types/remote/swr"; + +export function useCardsByGender(gender: "남" | "여") { + const { data } = useSWR>( + `${PATH.CARDS_}${PATH.CARDS_GENDER}/${gender}`, + realReq.GET_SWR, + { + suspense: true, + }, + ); + + return { + genderBookmarkedCards: data?.data.data, + }; +} diff --git a/src/@components/BestPiicklePage/BestPiickleRecommend/hooks/useRecentlyBookmarked.ts b/src/@components/BestPiicklePage/BestPiickleRecommend/hooks/useRecentlyBookmarked.ts new file mode 100644 index 00000000..a62101a4 --- /dev/null +++ b/src/@components/BestPiicklePage/BestPiickleRecommend/hooks/useRecentlyBookmarked.ts @@ -0,0 +1,16 @@ +import useSWR from "swr"; + +import { realReq } from "../../../../core/api/common/axios"; +import { PATH } from "../../../../core/api/common/constants"; +import { RecentCardList } from "../../../../types/cardCollection"; +import { PiickleSWRResponse } from "../../../../types/remote/swr"; + +export function useRecentlyBookmarked() { + const { data } = useSWR>(`${PATH.CARDS_}${PATH.CARDS_RECENT}`, realReq.GET_SWR, { + suspense: true, + }); + + return { + recentlyBookmarkedCards: data?.data.data.cardResponseDtos, + }; +} diff --git a/src/@components/BestPiicklePage/BestPiickleRecommend/index.tsx b/src/@components/BestPiicklePage/BestPiickleRecommend/index.tsx index fc446455..fee8b028 100644 --- a/src/@components/BestPiicklePage/BestPiickleRecommend/index.tsx +++ b/src/@components/BestPiicklePage/BestPiickleRecommend/index.tsx @@ -1,5 +1,8 @@ +import { CardList, LocationType } from "../../../types/cardCollection"; import { HeadingTitle } from "../../../util/main/headingTitles"; import HeadingTitleContainer from "../../@common/HeadingTitleContainer"; +import { useCardsByGender } from "./hooks/useCardsByGender"; +import { useRecentlyBookmarked } from "./hooks/useRecentlyBookmarked"; import RecommendItem from "./RecommendItem"; import * as St from "./style"; @@ -8,17 +11,41 @@ const recommendTitles: HeadingTitle = { content: "", }; +export type recommendListType = { + subtitle: string; + cards?: CardList[]; + locationType: LocationType; +}; + export default function BestPiickleRecommend() { + const { recentlyBookmarkedCards } = useRecentlyBookmarked(); + const { genderBookmarkedCards: femaleBookmarkedCards } = useCardsByGender("여"); + const { genderBookmarkedCards: maleBookmarkedCards } = useCardsByGender("남"); + + const recommendLists: recommendListType[] = [ + { + subtitle: "💖 유저들이 가장 최근에 북마크한 대화주제", + cards: recentlyBookmarkedCards, + locationType: LocationType.RECENT, + }, + { + subtitle: "👩 여성이 북마크한 대화주제들", + cards: femaleBookmarkedCards, + locationType: LocationType.FEMALE, + }, + { + subtitle: "👱‍♂️ 남성이 북마크한 대화주제를 확인해보세요", + cards: maleBookmarkedCards, + locationType: LocationType.MALE, + }, + ]; + return ( - {[ - "💖 유저들이 가장 최근에 북마크한 대화주제", - "👩 여성이 북마크한 대화주제들", - "👱‍♂️ 남성이 북마크한 대화주제를 확인해보세요", - ].map((recommendType, idx) => ( - + {recommendLists.map((recommendList, idx) => ( + ))} ); diff --git a/src/@components/BestPiicklePage/index.tsx b/src/@components/BestPiicklePage/index.tsx index eef6b368..c763c210 100644 --- a/src/@components/BestPiicklePage/index.tsx +++ b/src/@components/BestPiicklePage/index.tsx @@ -4,7 +4,7 @@ import Header from "../@common/Header"; import SuspenseBoundary from "../@common/SuspenseBoundary"; import BestPiickleRank from "./BestPiickleRank"; import BestPiickleRecommend from "./BestPiickleRecommend"; -import St from "./style"; +import * as St from "./style"; export default function BestPiicklePage() { return ( diff --git a/src/@components/BestPiicklePage/style.ts b/src/@components/BestPiicklePage/style.ts index f6668530..8a70aaf9 100644 --- a/src/@components/BestPiicklePage/style.ts +++ b/src/@components/BestPiicklePage/style.ts @@ -1,11 +1,6 @@ import styled from "styled-components"; -const Root = styled.main` +export const Root = styled.main` display: flex; flex-direction: column; `; - -const St = { - Root, -}; -export default St; diff --git a/src/@components/CardCollectionPage/hooks/useCardLists.ts b/src/@components/CardCollectionPage/hooks/useCardLists.ts index d795e73a..3fac554e 100644 --- a/src/@components/CardCollectionPage/hooks/useCardLists.ts +++ b/src/@components/CardCollectionPage/hooks/useCardLists.ts @@ -11,6 +11,7 @@ import useCardListsFilter from "./useCardListsFilter"; interface ExtendedCardList extends Array { cardList?: CardList[]; // with category id cards?: CardList[]; // with medly id + cardResponseDtos?: CardList[]; } export function useCardLists() { @@ -43,6 +44,8 @@ function getReturnCardLists( return data?.data.data.cardList; case LocationType.MEDLEY: return data?.data.data.cards; + case LocationType.RECENT: + return data?.data.data.cardResponseDtos; default: return data?.data.data; } @@ -88,6 +91,13 @@ function getSWRFetchingKeyByLocation(cardsTypeLocation: CardsTypeLocation) { case LocationType.FILTER: { return `${PATH.CATEGORIES_}${PATH.CATEGORIES_CARDS}?${cardsTypeLocation.filterTypes}`; } + case LocationType.RECENT: + return `${PATH.CARDS_}${PATH.CARDS_RECENT}`; + case LocationType.FEMALE: + return `${PATH.CARDS_}${PATH.CARDS_GENDER}/여`; + case LocationType.MALE: + return `${PATH.CARDS_}${PATH.CARDS_GENDER}/남`; + case LocationType.ALL: default: { const searchParams = qs.stringify( diff --git a/src/@components/MainPage/BestPiickle/index.tsx b/src/@components/MainPage/BestPiickle/index.tsx index 17578115..84f61824 100644 --- a/src/@components/MainPage/BestPiickle/index.tsx +++ b/src/@components/MainPage/BestPiickle/index.tsx @@ -1,4 +1,5 @@ import { routePaths } from "../../../core/routes/path"; +import { LocationType } from "../../../types/cardCollection"; import { headingTitles } from "../../../util/main/headingTitles"; import BestPiickleCard from "../../@common/BestPiickleCard"; import HeadingTitleContainer from "../../@common/HeadingTitleContainer"; @@ -28,7 +29,7 @@ export default function BestPiickle() { bestPiickle={bestPiickle} idx={idx} canNavigate={!isDragging} - isLast={idx !== 5} + locationType={LocationType.BEST} /> ); })} diff --git a/src/core/api/common/constants.ts b/src/core/api/common/constants.ts index bda52959..43566117 100644 --- a/src/core/api/common/constants.ts +++ b/src/core/api/common/constants.ts @@ -10,6 +10,8 @@ export const PATH = { BALLOTS: "/ballots", CARDS_: "/cards", CARDS_BEST: "/best", + CARDS_RECENT: "/recentlyBookmarkedCard", + CARDS_GENDER: "/cardByBookmarkedGender", NOTICES: "/notices", MEDLEY: "/medley", }; diff --git a/src/types/cardCollection.ts b/src/types/cardCollection.ts index a1e1db75..b4127f89 100644 --- a/src/types/cardCollection.ts +++ b/src/types/cardCollection.ts @@ -5,6 +5,9 @@ export const enum LocationType { CATEGORY = "category", FILTER = "filter", MEDLEY = "medley", + RECENT = "recent", + FEMALE = "female", + MALE = "male", } interface AllTypeLocation { @@ -33,13 +36,28 @@ interface MedleyTypeLocation { medleyId: string; } +interface RecentTypeLocation { + type: LocationType.RECENT; +} + +interface FemaleTypeLocation { + type: LocationType.FEMALE; +} + +interface MaleTypeLocation { + type: LocationType.MALE; +} + export type CardsTypeLocation = | AllTypeLocation | BestTypeLocation | BookmarkTypeLocation | CategoryTypeLocation | FilterTypeLocation - | MedleyTypeLocation; + | MedleyTypeLocation + | RecentTypeLocation + | FemaleTypeLocation + | MaleTypeLocation; export interface CardList { _id: string; @@ -48,3 +66,8 @@ export interface CardList { isBookmark: boolean; filter: string[]; } + +export interface RecentCardList { + recentlyDate: string; + cardResponseDtos: CardList[]; +}