Skip to content

Commit

Permalink
Merge pull request #81 from TeamPiickle/feat/#61-card_view
Browse files Browse the repository at this point in the history
Feat/#61 card view
  • Loading branch information
joohaem committed Jul 19, 2022
2 parents e955db0 + ca00a77 commit f807913
Show file tree
Hide file tree
Showing 21 changed files with 144 additions and 103 deletions.
6 changes: 4 additions & 2 deletions src/components/CardCollection/Card/LastCard/style.ts
Expand Up @@ -8,12 +8,14 @@ export const St = {

ContentTitle: styled(StCard.ContentWrapper)`
margin-top: 8.6rem;
${({ theme }) => theme.fonts.body5};
`,

Content: styled.p`
margin: 1.2rem 0 0 2.4rem;
${({ theme }) => theme.fonts.h2};
${({ theme }) => theme.fonts.body6};
color: ${({ theme }) => theme.colors.bg};
`,

Expand All @@ -37,7 +39,7 @@ export const St = {
justify-content: center;
align-items: center;
${({ theme }) => theme.fonts.caption2};
${({ theme }) => theme.fonts.btn1};
color: ${({ theme }) => theme.colors.gray600};
border-bottom: 0.08rem solid ${({ theme }) => theme.colors.gray600};
Expand Down
12 changes: 6 additions & 6 deletions src/components/CardCollection/Card/index.tsx
@@ -1,18 +1,18 @@
import { useState } from "react";

import { real } from "../../../core/api/cardCollection";
import { CardIdList } from "../../../types/cardCollection";
import { CardList } from "../../../types/cardCollection";
import CustomFullHeart from "../CustomFullHeart";
import TagsSlider from "../TagsSlider";
import { St } from "./style";

interface LoginCheckProps {
cardIdList: CardIdList;
cardList: CardList;
openLoginModalHandler: () => void;
}

export default function Card(props: LoginCheckProps) {
const { cardIdList, openLoginModalHandler } = props;
const { cardList, openLoginModalHandler } = props;
const LOGIN_STATE = localStorage.getItem("piickle-token") ? true : false;

const [isBookmarked, setIsBookmarked] = useState(false);
Expand All @@ -32,10 +32,10 @@ export default function Card(props: LoginCheckProps) {
return (
<St.Card>
<St.TagsWrapper>
<TagsSlider tags={cardIdList.tags} />
<TagsSlider tags={cardList.tags} />
</St.TagsWrapper>
<St.ContentWrapper>{cardIdList.content}</St.ContentWrapper>
<St.HeartWrapper onClick={() => handleClickHeart(cardIdList._id)}>
<St.ContentWrapper>{cardList.content}</St.ContentWrapper>
<St.HeartWrapper onClick={() => handleClickHeart(cardList._id)}>
<St.IcEmptyHeart />
{isBookmarked && <CustomFullHeart />}
</St.HeartWrapper>
Expand Down
69 changes: 26 additions & 43 deletions src/components/CardCollection/CardSlider/index.tsx
Expand Up @@ -4,67 +4,51 @@ import "slick-carousel/slick/slick-theme.css";
import { useEffect, useRef, useState } from "react";
import { useLocation } from "react-router-dom";
import Slider from "react-slick";
import { useRecoilState } from "recoil";

import { real } from "../../../core/api/cardCollection";
import { sliderSettings } from "../../../core/cardCollection/slider";
import { CardIdList, CardsTypeLocation } from "../../../types/cardCollection";
import { sliderIdxState } from "../../../core/atom/slider";
import { CardList, CardsTypeLocation } from "../../../types/cardCollection";
import fetchCardCollection from "../../../util/fetchCardCollection";
import Card from "../Card";
import LastCard from "../Card/LastCard";
import { St } from "./style";

interface CardSliderProps {
openFilterModalHandler: () => void;
openLoginModalHandler: () => void;
cardsTypeLoaction: CardsTypeLocation;
}

// 1. 카테고리 :: /categories/:categoryId :: { type: "category", categoryId: "62cbb7d8a8c54f168a6ddfe1"}
// 2. 베스트 카드 :: /cards/best :: { type: "best", index: 1 }
// 2. 베스트 카드 :: /cards/best :: { type: "best" }
// 3. all 전체 카드 :: /categories/cards :: { type: "all" }
// 4. 필터 :: /categories/cards?search={type} :: { type: "filter", filters: ["남자", "상관없음"] }
export default function CardSlider(props: CardSliderProps) {
const { openFilterModalHandler, openLoginModalHandler } = props;

const location = useLocation();
const CARD_TYPE_LOCATION = location.state as CardsTypeLocation;
const { openFilterModalHandler, openLoginModalHandler, cardsTypeLoaction } = props;

const [sliderIdx, setSliderIdx] = useRecoilState(sliderIdxState);
const sliderRef = useRef<Slider | null>(null);
const [cardLists, setCardLists] = useState<CardIdList[]>([]);
const [cardLists, setCardLists] = useState<CardList[]>([]);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
switch (CARD_TYPE_LOCATION.type) {
case "category":
(async () => {
const { data } = await real.fetchCardsWithCategory(CARD_TYPE_LOCATION.categoryId);
setCardLists(data.cardList);
})();
break;

case "best":
(async () => {
const { data } = await real.fetchCardsWithBest();
setCardLists(data.cardList);
})();
break;

case "all":
(async () => {
const { data } = await real.fetchCardsWithFilter([]);
setCardLists(data.cardList);
})();
break;

case "filter":
(async () => {
const { data } = await real.fetchCardsWithFilter(CARD_TYPE_LOCATION.filters);
setCardLists(data.cardList);
})();
break;
default:
throw new Error("잘못된 접근입니다.");
}
fetchCardCollection(cardsTypeLoaction, (data: { cardList: CardList[] }) => {
setCardLists(data.cardList);
});
setIsLoading(false);
}, [CARD_TYPE_LOCATION]);
}, [cardsTypeLoaction]);

const sliderSettings = {
className: "center",
centerMode: true,
arrows: false,
dots: false,
infinite: false,
variableWidth: true,
slidesToScroll: 1,
initialSlide: sliderIdx,
afterChange: (idx: number) => setSliderIdx(idx),
};

return (
<St.Wrapper>
Expand All @@ -73,12 +57,11 @@ export default function CardSlider(props: CardSliderProps) {
) : (
<Slider {...sliderSettings} ref={sliderRef}>
{cardLists.map((cardList) => (
<Card key={cardList._id} openLoginModalHandler={openLoginModalHandler} cardIdList={cardList} />
<Card key={cardList._id} openLoginModalHandler={openLoginModalHandler} cardList={cardList} />
))}
<LastCard />
</Slider>
)}
{/* 마지막 index에서는 필터버튼 없애주기 */}
<St.IcFilterBtn onClick={openFilterModalHandler} />
</St.Wrapper>
);
Expand Down
5 changes: 3 additions & 2 deletions src/components/CardCollection/CardSlider/style.ts
Expand Up @@ -9,7 +9,7 @@ export const St = {
& .slick-slide {
width: 30rem;
height: calc(100vh - 14.8rem);
max-height: 52.3rem;
max-height: 49.5em;
}
& .slick-slide > div {
Expand All @@ -30,7 +30,8 @@ export const St = {
}
& .slick-track {
height: calc(100vh - 10.5rem);
/* height: calc(100vh - 10.5rem); */
height: 52rem;
display: flex;
align-items: center;
Expand Down
24 changes: 14 additions & 10 deletions src/components/CardCollection/FilterModal/index.tsx
@@ -1,25 +1,29 @@
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useSetRecoilState } from "recoil";
import { useRecoilState, useSetRecoilState } from "recoil";

import { real } from "../../../core/api/cardCollection";
import { sliderIdxState } from "../../../core/atom/sliderIdx";
import { filterTags, intimacyTags } from "../../../core/cardCollection/filter";
import { filterTagsState, sliderIdxState } from "../../../core/atom/slider";
import { filterTagsInfo, intimacyTags } from "../../../core/cardCollection/filter";
import Modal from "../../common/Modal";
import IntimacySlider from "./IntimacySlider";
import { St } from "./style";

interface FilterModalProps {
closeHandler: () => void;
typeLocation: "filter" | string;
}

export default function FilterModal(props: FilterModalProps) {
const { closeHandler } = props;
const { closeHandler, typeLocation } = props;

const [filterTags, setFilterTags] = useRecoilState(filterTagsState);
const setSliderIdx = useSetRecoilState(sliderIdxState);
const navigation = useNavigate();
const [checkedTags, setCheckedTags] = useState<Set<string>>(new Set()); // 체크한 태그들을 저장할 state
const [intimacyValues, setIntimacyValues] = useState<number[]>([0]); // 친밀도 value
const [checkedTags, setCheckedTags] = useState<Set<string>>(
typeLocation === "filter" ? new Set(filterTags.tags) : new Set(),
); // 체크한 태그들을 저장할 state
const [intimacyValues, setIntimacyValues] = useState<number[]>(typeLocation === "filter" ? filterTags.intimacy : [0]); // 친밀도 value

// 태그를 눌렀을 때 함수
const toggleTag = (_tag: string) => {
Expand All @@ -32,7 +36,7 @@ export default function FilterModal(props: FilterModalProps) {
const submitFilter = () => {
const _checkedTagsArr = [...checkedTags];
_checkedTagsArr.push(intimacyTags[intimacyValues[0]]);
console.log(_checkedTagsArr);
setFilterTags({ tags: _checkedTagsArr, intimacy: [intimacyValues[0]] });

real.fetchCardsWithFilter(_checkedTagsArr);
navigation("/card-collection", { state: { type: "filter", filters: ["남자", "상관없음"] } });
Expand All @@ -44,11 +48,11 @@ export default function FilterModal(props: FilterModalProps) {
return (
<Modal closeHandler={closeHandler}>
<St.ModalContentsWrapper>
{filterTags.map((filterTag, idx) => (
{filterTagsInfo.map((filterTagInfo, idx) => (
<React.Fragment key={`filter-${idx}`}>
<St.FilterTitle>{filterTag.type}</St.FilterTitle>
<St.FilterTitle>{filterTagInfo.type}</St.FilterTitle>
<St.FilterTagsWrapper>
{filterTag.tags.map((tag, index) => (
{filterTagInfo.tags.map((tag, index) => (
<St.FilterTag key={index} isactive={checkedTags.has(tag)} onClick={() => toggleTag(tag)}>
{tag}
</St.FilterTag>
Expand Down
13 changes: 11 additions & 2 deletions src/components/CardCollection/index.tsx
@@ -1,12 +1,17 @@
import { useState } from "react";
import { useLocation } from "react-router-dom";

import { CardsTypeLocation } from "../../types/cardCollection";
import Header from "../common/Header";
import CardSlider from "./CardSlider";
import FilterModal from "./FilterModal";
import LoginModal from "./LoginModal";
import { St } from "./style";

export default function CardCollection() {
const location = useLocation();
const cardsTypeLoaction = location.state as CardsTypeLocation;

const [isOpened, setIsOpened] = useState<boolean>(false);
const [isLoginOpened, setLoginOpened] = useState<boolean>(false);

Expand Down Expand Up @@ -37,10 +42,14 @@ export default function CardCollection() {
return (
<St.MainPage>
<Header />
<CardSlider openFilterModalHandler={clickHandleFilterModal} openLoginModalHandler={clickHandleLoginModal} />
<CardSlider
openFilterModalHandler={clickHandleFilterModal}
openLoginModalHandler={clickHandleLoginModal}
cardsTypeLoaction={cardsTypeLoaction}
/>

{isLoginOpened && <LoginModal closeHandler={closeLoginModal} />}
{isOpened && <FilterModal closeHandler={closeModal} />}
{isOpened && <FilterModal typeLocation={cardsTypeLoaction.type} closeHandler={closeModal} />}
</St.MainPage>
);
}
2 changes: 1 addition & 1 deletion src/components/CardCollection/style.ts
Expand Up @@ -7,7 +7,7 @@ export const St = {
min-height: -webkit-fill-available;
min-height: fill-available;
padding: 6.4rem 0 5.1rem;
padding: 8rem 0 5.1rem;
background: ${({ theme }) => theme.colors.card};
`,
Expand Down
2 changes: 1 addition & 1 deletion src/components/Category/CategoryContents/index.tsx
Expand Up @@ -2,7 +2,7 @@ import { useNavigate } from "react-router-dom";
import { useSetRecoilState } from "recoil";

import { useCategoryLists } from "../../../core/api/main";
import { sliderIdxState } from "../../../core/atom/sliderIdx";
import { sliderIdxState } from "../../../core/atom/slider";
import { gridValue } from "../../../core/category/categoryList";
import { St } from "./style";

Expand Down
2 changes: 1 addition & 1 deletion src/components/Category/index.tsx
Expand Up @@ -2,7 +2,7 @@ import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useSetRecoilState } from "recoil";

import { sliderIdxState } from "../../core/atom/sliderIdx";
import { sliderIdxState } from "../../core/atom/slider";
import { categoryTitles } from "../../core/category/categoryList";
import Header from "../common/Header";
import HeadingTitleContainer from "../common/HeadingTitleContainer";
Expand Down
2 changes: 1 addition & 1 deletion src/components/Main/BestPiickle/BestPiickleCard/index.tsx
@@ -1,7 +1,7 @@
import { useNavigate } from "react-router-dom";
import { useSetRecoilState } from "recoil";

import { sliderIdxState } from "../../../../core/atom/sliderIdx";
import { sliderIdxState } from "../../../../core/atom/slider";
import { St } from "./style";

interface BestPiickleCardProps {
Expand Down
10 changes: 1 addition & 9 deletions src/components/Main/BestPiickle/index.tsx
@@ -1,22 +1,14 @@
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";

import { useEffect, useState } from "react";
import Slider from "react-slick";

import { useBestPiickle } from "../../../core/api/main";
import { headingTitles } from "../../../core/main/headingTitles";
import { Card } from "../../../types/main";
import HeadingTitleContainer from "../../common/HeadingTitleContainer";
import BestPiickleCard from "./BestPiickleCard";
import { St } from "./style";

type bestPiickleType = {
_id: string;
category: string[];
content: string;
};

const sliderSettings = {
arrows: false,
dots: false,
Expand All @@ -34,7 +26,7 @@ export default function BestPiickle() {
<St.SliderWrapper>
<Slider {...sliderSettings}>
{bestPiickle &&
bestPiickle.data.map((bestPiickle: bestPiickleType) => {
bestPiickle.data.cardList.map((bestPiickle) => {
return <BestPiickleCard key={bestPiickle._id} bestPiickle={bestPiickle} />;
})}
</Slider>
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/MenuBar/index.tsx
Expand Up @@ -3,7 +3,7 @@ import { useSetRecoilState } from "recoil";

import { IcCloseBtn, IcMenuBarImg } from "../../../asset/icon";
import { activeState } from "../../../core/atom/menuBar";
import { sliderIdxState } from "../../../core/atom/sliderIdx";
import { sliderIdxState } from "../../../core/atom/slider";
import { St, StContentsContainer } from "./style";

const MenuBarDummy = {
Expand Down
13 changes: 12 additions & 1 deletion src/core/api/main.ts
@@ -1,5 +1,6 @@
import useSWR from "swr";

import { PiickleSWRResponse } from "../../types/swr";
import { realReq } from "./common/axios";
import { PATH } from "./common/constants";

Expand All @@ -14,8 +15,18 @@ export function useCategoryLists() {
};
}

type BestPiickleCard = {
_id: string;
category: string[];
content: string;
};

type BestPiickle = {
cardList: BestPiickleCard[];
};

export function useBestPiickle() {
const { data, error } = useSWR(`${PATH.CARDS}/best`, realReq.GET_SWR);
const { data, error } = useSWR<PiickleSWRResponse<BestPiickle>>(`${PATH.CARDS}/best`, realReq.GET_SWR);

return {
bestPiickle: data?.data,
Expand Down

0 comments on commit f807913

Please sign in to comment.