From eef814fd1a8449a0a59817240e7216dab0d93556 Mon Sep 17 00:00:00 2001 From: Daewony Date: Mon, 4 Mar 2024 22:47:26 +0900 Subject: [PATCH 01/31] =?UTF-8?q?:memo:=20Docs:=20API=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=20=ED=97=A4=EB=8D=94=EC=97=90=20withCredentials=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Login.jsx | 39 ++++++++++++++++++++++++++++----------- src/pages/Search.jsx | 12 +++++++----- src/services/login.js | 2 +- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index d7a3817..e08419b 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -17,8 +17,8 @@ import { LoginContext } from '../contexts/LoginContextProvider'; export default function Login() { const {setUserId, setUserPwd } = useContext(LoginContext); - const [id, setId] = useState(''); - const [pwd, setPwd] = useState(''); + const [id, setId] = useState('sim'); + const [pwd, setPwd] = useState('1234'); const router = useNavigate(); const [notAllow, setNotAllow] = useState(true); @@ -39,13 +39,13 @@ export default function Login() { if (name === 'password') { setPwd(value); - const regex = - /^(?=.*[a-zA-z])(?=.*[0-9])(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+])(?!.*[^a-zA-z0-9$`~!@$!%*#^?&\\(\\)\-_=+]).{8,20}$/; - if (regex.test(value)) { + // const regex = + // /^(?=.*[a-zA-z])(?=.*[0-9])(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+])(?!.*[^a-zA-z0-9$`~!@$!%*#^?&\\(\\)\-_=+]).{8,20}$/; + // if (regex.test(value)) { setPwdValid(true); - } else { - setPwdValid(false); - } + // } else { + // setPwdValid(false); + // } } }; @@ -119,8 +119,8 @@ export default function Login() { const postLogin = async () => { console.log('아이디:', id, '비번:', pwd); - setUserId(id); - setUserPwd(pwd); + setUserId(id); // 전역에 id 저장 + setUserPwd(pwd); // 전역에 password 저장 if (id.length > 0 && pwd.length > 0) { localStorage.setItem('id', id); localStorage.setItem('password', pwd); @@ -128,6 +128,7 @@ export default function Login() { .post( 'https://port-0-backend-book-pharmacy-umnqdut2blqqhv7sd.sel5.cloudtype.app/login', loginData, + {withCredentials:true} ) .then((res) => { let token = res.headers.authorization; @@ -137,7 +138,8 @@ export default function Login() { // 받아온 token을 암호화 하는 방식에 대해 고민 필요함. - window.location.replace('/main'); + // window.location.replace('/main'); + getCategory(); }) .catch((err) => { console.log(err); @@ -145,6 +147,21 @@ export default function Login() { } }; + const getCategory = async () => { + axios + .get( + 'https://port-0-backend-book-pharmacy-umnqdut2blqqhv7sd.sel5.cloudtype.app/api/category/big', + { withCredentials: true } + ) + .then((res) => { + console.log(res); + }) + .catch((error) => { + console.log(error); + }) + } + + useEffect(() => { if (idValid && pwdValid) { setNotAllow(false); diff --git a/src/pages/Search.jsx b/src/pages/Search.jsx index d1ed74d..50e0d0e 100644 --- a/src/pages/Search.jsx +++ b/src/pages/Search.jsx @@ -83,9 +83,11 @@ const Search = () => { axios .get( 'https://port-0-backend-book-pharmacy-umnqdut2blqqhv7sd.sel5.cloudtype.app/api/category/big', - { - headers: { Authorization: accessToken }, - }, + {withCredentials:true} + // { + // headers: { Authorization: accessToken }, + // }, + ) .then((res) => { // 정상처리 @@ -225,8 +227,8 @@ const Search = () => { }) .catch(() => { console.log('전부 만료!'); - alert('로그인 페이지로 이동합니다.'); - window.location.replace('/login'); + // alert('로그인 페이지로 이동합니다.'); + // window.location.replace('/login'); }); }); }; diff --git a/src/services/login.js b/src/services/login.js index 1c46c06..830f7ed 100644 --- a/src/services/login.js +++ b/src/services/login.js @@ -4,7 +4,7 @@ export const login = async (username, password) => { const result = await axios.post( "https://port-0-backend-book-pharmacy-umnqdut2blqqhv7sd.sel5.cloudtype.app/login", { username, password }, // 키와 값이 같아서 생략함 - { withCredentials: true } + { withCredentials: true } // 쿠키를 브라우저에 자동 저장 및 보내기 ); console.log("result", result); return result; From 480f48aa44ad58d246c7fd80718d45d7e048c2ac Mon Sep 17 00:00:00 2001 From: Daewony Date: Thu, 7 Mar 2024 15:35:55 +0900 Subject: [PATCH 02/31] =?UTF-8?q?Style:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EC=99=80=EC=9D=B4=EC=96=B4=ED=94=84?= =?UTF-8?q?=EB=A0=88=EC=9E=84=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=98=95?= =?UTF-8?q?=ED=83=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + package.json | 2 +- src/App.js | 2 + src/assets/closeIconRound.svg | 1 + "src/assets/icons8-\353\263\204-30 (1).png" | Bin 0 -> 657 bytes ...cons8-\353\271\210\353\263\204-30 (2).png" | Bin 0 -> 853 bytes ...\203\200-\353\260\230-\353\271\210-30.png" | Bin 0 -> 794 bytes src/pages/SearchResult.jsx | 1049 +++++++++++++++++ yarn.lock | 9 +- 9 files changed, 1064 insertions(+), 2 deletions(-) create mode 100644 src/assets/closeIconRound.svg create mode 100644 "src/assets/icons8-\353\263\204-30 (1).png" create mode 100644 "src/assets/icons8-\353\271\210\353\263\204-30 (2).png" create mode 100644 "src/assets/icons8-\354\212\244\355\203\200-\353\260\230-\353\271\210-30.png" create mode 100644 src/pages/SearchResult.jsx diff --git a/.gitignore b/.gitignore index 4d29575..c6e6dda 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ # production /build +localhost-key.pem +localhost.pem + # misc .DS_Store .env.local diff --git a/package.json b/package.json index 09184de..8373162 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "web-vitals": "^2.1.0" }, "scripts": { - "start": "react-scripts start", + "start": "cross-env HTTPS=true SSL_CRT_FILE=localhost.pem SSL_KEY_FILE=localhost-key.pem react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" diff --git a/src/App.js b/src/App.js index 13f630c..8dc277e 100644 --- a/src/App.js +++ b/src/App.js @@ -30,6 +30,7 @@ import PasswordFind from './pages/PasswordFind'; import PasswordFindResult from './pages/PasswordFindResult'; import IdFind from './pages/IdFind'; import LoginContextProvider, { LoginContext } from './contexts/LoginContextProvider'; +import SearchResult from './pages/SearchResult'; function App() { // 브라우저 새로고침 스크롤 이벤트 @@ -51,6 +52,7 @@ function App() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/src/assets/closeIconRound.svg b/src/assets/closeIconRound.svg new file mode 100644 index 0000000..1615930 --- /dev/null +++ b/src/assets/closeIconRound.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git "a/src/assets/icons8-\353\263\204-30 (1).png" "b/src/assets/icons8-\353\263\204-30 (1).png" new file mode 100644 index 0000000000000000000000000000000000000000..62fcd11cfc0bb30a42096676c2a7f4f9fe5fde37 GIT binary patch literal 657 zcmV;C0&e|@P){D54@-D1vxcXrYxhivNHIfT;iEra=F`=>lpgMnnM84M&(QibNo?l&ZVn!$$n7mV6nseysG zxDvXkI^H%dmpnyExF5yNyki7Nu&kV|3*TAT(=we-U zo}%Lh`F-k2k*D)P_2ja9zBxX=(;z=j4=RygncTg4ky*RNpbVvOypN$)>up=*hU793 zf8PL=KMl!^L@l;3`uKypN}kcS^jxfe?BzZ{o^>dqS&j8vtq|BfI_w?P&O<1BoxukA zn(I;ffxYSs29goy!Xg=7$57yzb$~xKHQY%^^N=(YNq$6dCW#9%|w-4=!OTOS$S zz4XBW;(G?=M+?<=5`zH+S0>|0UF4g;Ej+V_b;n-iCxb-LY-y?wP`)k!ep6*Sw_66q zaSsr~vc5-|8zkD=F?fKYvrC>m)FIw!toE-#dD@5%Z^7E_uF!vWrBd0}YAXE&QQ&u^Bz$@a00000NkvXXu0mjfM{qT{ literal 0 HcmV?d00001 diff --git "a/src/assets/icons8-\353\271\210\353\263\204-30 (2).png" "b/src/assets/icons8-\353\271\210\353\263\204-30 (2).png" new file mode 100644 index 0000000000000000000000000000000000000000..757c13db66a3966fbbea4f27dec277e4a3bf0878 GIT binary patch literal 853 zcmV-b1FHOqP)vA8={GorqSj1+5=y zJCj$fA}FGp2yPU0Q9&2F(q-LfeKW6V)Hjo~BBh{$xTyF+iwZ)m_(wD{FR8Yv*1V+2 zz$N$HH|LytU+#P&kpeC1buG0KDYpS>5?QpYqK%YX0xUml*t~4QzRGT0>`7Wyyqrg z#C{8~JTafpypEfi>2&CP$CaukmNiYDzaCj??B)Xd4ziv_(l6%sH>|xgAM?%JcBwHA z<1)?+_b_a53fA<9LGlw=27u%Rus%Z49wbd5>!E*b96UW7_>lG(CWDm$0de_nk&J}olNW}L=t8iAH8wZRMQNUZ?UXGofg#=GZ?xA5LXViuCz1lE2a zfAxr$(C*K+G#GrMVc}A&0m(8Xd5SFE7LH@3!*f9T0X*4Kw5X>WfaE=}UfkODaPt2F zEPyQEtN_Gf=?Mje9?KEqu-|aIb)_0v-vY_iFc;2z4HIBpsg4w4jd5Loq#uD~TfP`% z-EJ7eMhdlt&aO&}JI75e%ohWEYms3rdBds%RL86W;RhDOSGZ}jRI?J_|FM*00000NkvXXu0mjf6>yDY literal 0 HcmV?d00001 diff --git "a/src/assets/icons8-\354\212\244\355\203\200-\353\260\230-\353\271\210-30.png" "b/src/assets/icons8-\354\212\244\355\203\200-\353\260\230-\353\271\210-30.png" new file mode 100644 index 0000000000000000000000000000000000000000..4a2380223803c4a01fff09434e4513ef278ad01c GIT binary patch literal 794 zcmV+#1LgdQP)m$WXrTqGK zC%3f28CaXlcw3U}?L?A&;7XHqE|PQt$(1m40=QU$U=2xU(Cw}?SqzJ1F)g++#*;&q zcasBFdWDk*(hEr1kE~CC}vxdSmS!@ zB7>3iWO;$tF(kd(;dzTp6p-{{pueQut#<|&hy3%l^T=Qzy;}zS410C^qqPIiotD;?g}-K zM)|8^bwySNmLJ90+gLFeTsa-64{0(|#^D$w%|P;LeD+pi)-*Ol;{d~E4S0%qUb&b5 Y0EM++sXw8@C;$Ke07*qoM6N<$g2_H@XaE2J literal 0 HcmV?d00001 diff --git a/src/pages/SearchResult.jsx b/src/pages/SearchResult.jsx new file mode 100644 index 0000000..da81cc2 --- /dev/null +++ b/src/pages/SearchResult.jsx @@ -0,0 +1,1049 @@ +import React from "react"; +import { useParams } from "react-router-dom"; +import Header from "../components/Header"; +import styled from "styled-components"; +import closeIcon from "../assets/closeIconRound.svg"; +import starIcon from "../assets/icons8-별-30 (1).png"; +import bookImg1 from "../assets/category-book-총류.jpg"; + +const SearchResult = () => { + const { title } = useParams(); + console.log(title); + let searchResultsCount = 1234; + searchResultsCount = searchResultsCount.toLocaleString(); + let searchResultsKeywordCount = 123; + let bookTitle = "해리포터와 저주받은 아이"; + let bookAuthor = "J.K. 롤링· 문학수첩"; + + + // 키워드만큼 옵션을 추가하도록 구현 + // 별점 컴포넌트 구현 + // 버튼마다 게시판 / 카드 형식으로 보여주도록 구현 + // 검색에 엔터 누르면 이동되도록 라우팅 설정하기 + // api 연결 + + // 이 페이지 만의 컴포넌트 이렇게 받게 하자 + + + + return ( + <> +
+
+ {/* 검색창 컴포넌트 만들어야함 */} + + + + + + + + + +
+

+ "{title}" 에 대한 + + {" "} + {searchResultsCount} 개의 검색 결과 + +

+
+ + + + +
+ {/* 헤더 영역 */} +
+ + 전체{" "} + + {searchResultsKeywordCount}건 + + +
+ + + + +
+
+ + {/* 키워드 영역 */} +
+
    + + {/*
    저주
    */} + 저주 + +
    +
+
+ + {/* 콘텐츠 영역 */} +
+ {/*
    +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • + +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
  • + 책 표지 이미지 +
    +
    +

    + {bookTitle} +

    +

    + {bookAuthor} +

    +
    +
    +
      + 영미소설 + 판타지소설 + 해리포터 + 마법주문 + 저주 +
    +
    +

    + 평균 ★5.0 (12) +

    +
    + + + + + +
    +
    +
  • +
*/} + +
  • + +

    {bookTitle}

    +

    {bookAuthor}

    + {/* 별 컴포넌트 */} +
  • + + + +
    +
    +
    +
    +
    + + ); +}; + +export default SearchResult; + +const Main = styled.main` + padding: 48px 52px 0px 52px; + max-width: 1440px; + margin: 0 auto; +`; + +const SearchInputWrap = styled.div` + width: 100%; + height: 60px; + box-shadow: 0px 2px 4px #00000033; + padding: 10px 0px 10px 1rem; + border-radius: 5px; + border: 1px solid #b0b0b0; + display: flex; + align-items: center; + font-size: 20px; + margin-bottom: 40px; +`; + +const SelectMenu = styled.select` + width: 140px; + font-size: 20px; + border: none; + /* padding-left: 10px; */ + text-align: center; +`; + +const SearchInput = styled.input` + border: none; + border-left: 1px solid #c0c0c0; + margin-left: 1rem; + padding-left: 1rem; + font-size: 20px; + width: 100%; + &:focus { + outline: none; + } +`; + +const ContentsWrap = styled.div` + display: flex; +`; + +const ContentTitle = styled.h2` + font-size: 20px; + font-weight: bold; +`; + +const SearchKeyword = styled.li` + display: flex; + align-items: center; + justify-content: space-between; + height: 29px; + line-height: 27px; + padding: 0px 0px 0px 12px; + background-color: #c8edf2; + border-radius: 15px; + margin-right: 10px; +`; + +const BookKeyword = styled.li` + display: flex; + align-items: center; + justify-content: space-between; + height: 29px; + padding: 0px 12px; + background-color: #c8edf2; + border-radius: 15px; + margin-right: 10px; +`; + +const CardUIWrap = styled.ul` + padding: 36px 20px; + display: grid; + grid-template-columns: repeat(5,1fr); + grid-gap: 10px; + +`; diff --git a/yarn.lock b/yarn.lock index ec936e7..d073109 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3772,7 +3772,14 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + +cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== From 20229558e5b364c7b0b91d1d31dabe108dc22c96 Mon Sep 17 00:00:00 2001 From: Daewony Date: Thu, 7 Mar 2024 15:41:38 +0900 Subject: [PATCH 03/31] =?UTF-8?q?Fix:=20merge=20=EC=B6=A9=EB=8F=8C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Search.jsx | 51 +++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/src/pages/Search.jsx b/src/pages/Search.jsx index 2acc7d1..ed7e78c 100644 --- a/src/pages/Search.jsx +++ b/src/pages/Search.jsx @@ -44,22 +44,21 @@ const Search = () => { { color: '#D6CABC', image: bookImg10 }, ]; -<<<<<<< HEAD - const getToken = async () => { - axios - .post(baseURL + '/login', loginData) - .then((res) => { - let token = res.headers.authorization; - accessToken = 'Bearer' + token.split(' ')[1]; - refreshToken = 'Bearer' + token.split(' ')[2]; - localStorage.setItem('accessToken', accessToken); // 액세스 토큰 저장 - localStorage.setItem('refreshToken', refreshToken); // 리프레시 토큰 저장 - }) - .then(async () => { - console.log('access:', accessToken); - console.log('refresh:', refreshToken); - }); - }; + // const getToken = async () => { + // axios + // .post(baseURL + '/login', loginData) + // .then((res) => { + // let token = res.headers.authorization; + // accessToken = 'Bearer' + token.split(' ')[1]; + // refreshToken = 'Bearer' + token.split(' ')[2]; + // localStorage.setItem('accessToken', accessToken); // 액세스 토큰 저장 + // localStorage.setItem('refreshToken', refreshToken); // 리프레시 토큰 저장 + // }) + // .then(async () => { + // console.log('access:', accessToken); + // console.log('refresh:', refreshToken); + // }); + // }; // const setCategory = async (res) => { // const fetchedCategories = res.data; @@ -90,8 +89,8 @@ const Search = () => { .then((res) => { // 정상처리 console.log('============ 1 ============='); - console.log('access:', accessToken); - console.log('refresh:', refreshToken); + // console.log('access:', accessToken); + // console.log('refresh:', refreshToken); setCategories(res.data); // res.data가 아래와 같다고 생각하고 로직을 짰습니다. postman의 응답으로 코드 작성 // { @@ -229,22 +228,6 @@ const Search = () => { // window.location.replace('/login'); }); }); -======= - const setCategory = async (res) => { - const fetchedCategories = res.data; - const transformedCategories = Object.keys(fetchedCategories).map( - (key, index) => { - const { color, image } = categoriesInfo[index % categoriesInfo.length]; // 객체에서 색상과 이미지를 가져옴 - return { - title: key, - subtitle: fetchedCategories[key].join(', '), - image: image, - color: color, - }; - }, - ); - setCategories(transformedCategories); ->>>>>>> 9d6c16c0f7943d58514fa86a5ed251d70f5a64d2 }; // 카테고리 대분류, 중분류 GET 요청 및 요청 데이터 사용하기 쉽게 처리 From e6348b2ab7b1a65749407115a05590235cd52504 Mon Sep 17 00:00:00 2001 From: Youngbae1126 Date: Thu, 7 Mar 2024 23:27:28 +0900 Subject: [PATCH 04/31] =?UTF-8?q?:sparkles:=20Feat:=20=EB=8C=80=EB=B6=84?= =?UTF-8?q?=EB=A5=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=B1=85=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=B0=94?= =?UTF-8?q?=EC=9D=B8=EB=94=A9=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BookCard.js | 6 +- src/components/BookListSlide.js | 18 +- src/pages/BookList.jsx | 298 ++++++++++++++-------------- src/styles/BookCard.module.css | 5 + src/styles/BookList.css | 11 + src/styles/BookListSlide.module.css | 4 +- 6 files changed, 183 insertions(+), 159 deletions(-) diff --git a/src/components/BookCard.js b/src/components/BookCard.js index 54e7bf5..7034343 100644 --- a/src/components/BookCard.js +++ b/src/components/BookCard.js @@ -1,11 +1,13 @@ // Styles import styles from '../styles/BookCard.module.css'; -const BookCard = ({ title, author }) => { +const BookCard = ({ title, author, img }) => { return ( <>
    -
    +
    + 썸네일 +
    {title}
    {author}
    diff --git a/src/components/BookListSlide.js b/src/components/BookListSlide.js index cc11def..9df24c7 100644 --- a/src/components/BookListSlide.js +++ b/src/components/BookListSlide.js @@ -8,20 +8,18 @@ import BookCard from './BookCard'; // STYLES import styles from '../styles/BookListSlide.module.css'; -const BookListSlide = ({ bigCategory, midCategoryTitle, author }) => { +const BookListSlide = ({ + bigCategory, + midCategoryTitle, + title, + author, + imageUrl, +}) => { return ( <>
    - <div className={styles['slide']}> - <BookCard title={'책 제목'} author={author} /> - <BookCard title={'책 제목'} author={author} /> - <BookCard title={'책 제목'} author={'저자'} /> - <BookCard title={'책 제목'} author={'저자'} /> - <BookCard title={'책 제목'} author={'저자'} /> - <BookCard title={'책 제목'} author={'저자'} /> - <BookCard title={'책 제목'} author={'저자'} /> - <BookCard title={'책 제목'} author={'저자'} /> + <BookCard title={title} author={author} img={imageUrl} /> </div> </div> </> diff --git a/src/pages/BookList.jsx b/src/pages/BookList.jsx index 93f91b5..269ce72 100644 --- a/src/pages/BookList.jsx +++ b/src/pages/BookList.jsx @@ -2,6 +2,9 @@ import React, { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; import axios from 'axios'; +// SERVICE +import api from '../services/api'; + // COMPONENTS import Header from '../components/Header'; import Title from '../components/ArrowTitle'; @@ -19,149 +22,47 @@ const BookList = () => { // 중분류 const [midCategory, setMidCategory] = useState([]); + const [resMidBookList, setResMidBookList] = useState([]); + + // 중분류에 따른 책 리스트 + const [midCategoryList0, setMidCategoryList0] = useState([]); + const [midCategoryList1, setMidCategoryList1] = useState([]); + const [midCategoryList2, setMidCategoryList2] = useState([]); + const [midCategoryList3, setMidCategoryList3] = useState([]); + const [midCategoryList4, setMidCategoryList4] = useState([]); + const [midCategoryList5, setMidCategoryList5] = useState([]); + const [midCategoryList6, setMidCategoryList6] = useState([]); + const [midCategoryList7, setMidCategoryList7] = useState([]); + const [midCategoryList8, setMidCategoryList8] = useState([]); - const categories = [ - { - 총류: [ - '도서학·서지학', - '문헌정보학', - '백과사전', - '강연집·수필집·연설문집', - '일반연속간행물', - '일반학회·단체·협회·기관', - '신문·언론·저널리즘', - '일반전집·총서', - '향토자료', - ], - 철학: [ - '형이상학', - '인식론·인과론·인간학', - '철학의 체계', - '경학', - '동양철학·7사상', - '서양철학', - '논리학', - '심리학', - '윤리학·도덕철학', - ], - 종교: [ - '비교종교', - '불교', - '기독교', - '도교', - '천도교', - '신도', - '힌두교·브라만교', - '이슬람교(회교)', - '기타 제종교', - ], - 사회과학: [ - '통계학', - '경제학', - '사회학·사회문제', - '정치학', - '행정학', - '법학', - '교육학', - '풍속·예절·민속학', - '국방·군사학', - ], - 자연과학: [ - '수학', - '물리학', - '화학', - '천문학', - '지학', - '광물학', - '생명과학', - '식물학', - '동물학', - ], - 기술과학: [ - '의학', - '농업·농학', - '공학·공업일반·토목공학·환경', - '건축공학', - '기계공학', - '전기공학·전자공학', - '화학공학', - '제조업', - '생활과학', - ], - 예술: [ - '건축물', - '조각·조형예술', - '공예·장식미술', - '서예', - '회화·도화', - '사진예술', - '음악', - '공연예술·매체예술', - '오락·스포츠', - ], - 언어: [ - '한국어', - '중국어', - '일본어·기타아시아제어', - '영어', - '독일어', - '프랑스어', - '스페인어·포르투갈어', - '이탈리아어', - '기타제어', - ], - 문학: [ - // smallCategory 페이지 api 테스트 위해서 한국문학 -> 한국소설로 바꿈 - '한국소설', - '중국문학', - '일본문학·기타아시아문학', - '영미문학', - '독일문학', - '프랑스문학', - '스페인·포르투갈문학', - '이탈리아문학', - '기타제문학', - ], - 역사: [ - '아시아', - '유럽', - '아프리카', - '북아프리카', - '남아메리카', - '오세아니아', - '양극지방', - '지리', - '전기', - ], - }, - ]; + const bookList = []; // 초기에 랜더링될 때 한 번만 실행 useEffect(() => { // 대분류 지정 setBigCategory(title); - // { - // smallCategory.map((e) => { - // console.log(e); - // }); - // } - // setCategory(category[title]); - // console.log(smallCategory); - // 중분류 가져오기 + api.get('/api/category/big').then((res) => { + // console.log(res.data[title]); + setMidCategory(res.data[title]); + }); - // categories.map((res) => { - // console.log('대분류:', title); - // setMidCategory(res[title]); - // }); - axios - .get( - 'https://port-0-backend-book-pharmacy-umnqdut2blqqhv7sd.sel5.cloudtype.app/api/category/big', - ) - .then((res) => { - console.log(res.data[title]); - setMidCategory(res.data[title]); + api.get(`/api/book/list/big?name=${title}`).then((res) => { + res.data.map((list, idx) => { + // console.log(list); + // console.log(idx); + // bookList.concat(list); + // resMidBookList.length === 0 + // ? setResMidBookList(list) + // : setResMidBookList[idx](list); + setResMidBookList(res.data); }); + setMidCategoryList0(res.data[0].bookList); + setMidCategoryList1(res.data[1].bookList); + setMidCategoryList2(res.data[2].bookList); + setMidCategoryList3(res.data[3].bookList); + setMidCategoryList4(res.data[4].bookList); + }); }, []); return ( @@ -171,23 +72,130 @@ const BookList = () => { <Header /> <div className="bookList_title">{bigCategory}</div> <Title + key={bigCategory} bigCategory={bigCategory} title={`${bigCategory} 전체보기`} type={'shadow'} /> + + {resMidBookList.map((list, idx) => { + // console.log(list.categoryName); + return ( + <div className="bookList_wrapper" key={idx}> + <div className="bookList_title_wrapper"> + <Title + key={list[idx]} + bigCategory={bigCategory} + title={list.categoryName} + /> + </div> + <div className="bookList_slide_wrapper"> + {list.bookList.map((item) => { + // console.log(item); + return ( + <BookListSlide + key={item.isbn} + title={item.title} + author={item.author} + bigCategory={bigCategory} + imageUrl={item.imageUrl} + /> + ); + })} + </div> + </div> + ); + })} + + {/* <div className="bookList_wrapper"> + <div className="bookList_title_wrapper"> + <Title + key={midCategory[0]} + bigCategory={bigCategory} + title={midCategory[0]} + /> + </div> + <div className="bookList_slide_wrapper"> + {midCategoryList0.map((item) => { + // console.log(resMidBookList); + return ( + <BookListSlide + key={item.isbn} + title={item.title} + author={item.author} + bigCategory={bigCategory} + imageUrl={item.imageUrl} + /> + ); + })} + </div> + </div> + <div className="bookList_wrapper"> + <div className="bookList_title_wrapper"> + <Title + key={midCategory[1]} + bigCategory={bigCategory} + title={midCategory[1]} + /> + </div> + <div className="bookList_slide_wrapper"> + {midCategoryList1.map((item) => { + return ( + <BookListSlide + key={item.isbn} + title={item.title} + author={item.author} + bigCategory={bigCategory} + imageUrl={item.imageUrl} + /> + ); + })} + </div> + </div> <div className="bookList_wrapper"> - {midCategory?.map((e) => { - // console.log(e); - // setNameList(e.name); - return ( - <BookListSlide - key={e} - bigCategory={bigCategory} - midCategoryTitle={e} - /> - ); - })} + <div className="bookList_title_wrapper"> + <Title + key={midCategory[2]} + bigCategory={bigCategory} + title={midCategory[2]} + /> + </div> + <div className="bookList_slide_wrapper"> + {midCategoryList2.map((item) => { + return ( + <BookListSlide + key={item.isbn} + title={item.title} + author={item.author} + bigCategory={bigCategory} + imageUrl={item.imageUrl} + /> + ); + })} + </div> </div> + <div className="bookList_wrapper"> + <div className="bookList_title_wrapper"> + <Title + key={midCategory[3]} + bigCategory={bigCategory} + title={midCategory[3]} + /> + </div> + <div className="bookList_slide_wrapper"> + {midCategoryList3.map((item) => { + return ( + <BookListSlide + key={item.isbn} + title={item.title} + author={item.author} + bigCategory={bigCategory} + imageUrl={item.imageUrl} + /> + ); + })} + </div> + </div> */} </div> <Footer /> diff --git a/src/styles/BookCard.module.css b/src/styles/BookCard.module.css index 39cdba0..ebb9ffb 100644 --- a/src/styles/BookCard.module.css +++ b/src/styles/BookCard.module.css @@ -21,6 +21,11 @@ background: #d9d9d9; } +.book_thumbnail { + width: 148px; + height: 210px; +} + .book_info_wrapper { width: 148px; display: flex; diff --git a/src/styles/BookList.css b/src/styles/BookList.css index 5ab75da..aeb5911 100644 --- a/src/styles/BookList.css +++ b/src/styles/BookList.css @@ -32,3 +32,14 @@ width: 1338px; margin: 0 auto; } + +.bookList_title_wrapper { + margin-top: 30px; +} + +.bookList_slide_wrapper { + display: grid; + grid-template-columns: repeat(8, 1fr); + width: 100%; + /* overflow-x: scroll; */ +} diff --git a/src/styles/BookListSlide.module.css b/src/styles/BookListSlide.module.css index a81bbdb..d13f356 100644 --- a/src/styles/BookListSlide.module.css +++ b/src/styles/BookListSlide.module.css @@ -8,8 +8,8 @@ .container { padding: 0; - margin-top: 56px; - width: 1338px; + margin-top: 16px; + width: 200px; font-family: 'Pretendard-Regular'; font-weight: 700; } From 938621efd768d910937c2749d6ba8f4b0bb332fb Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Fri, 8 Mar 2024 10:02:03 +0900 Subject: [PATCH 05/31] =?UTF-8?q?Docs:=20App.js=EC=97=90=EC=84=9C=20LoginC?= =?UTF-8?q?ontext=EB=A5=BC=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 13f630c..ac1f6b7 100644 --- a/src/App.js +++ b/src/App.js @@ -29,7 +29,7 @@ import LoginFindResult from './pages/IdFindResult'; import PasswordFind from './pages/PasswordFind'; import PasswordFindResult from './pages/PasswordFindResult'; import IdFind from './pages/IdFind'; -import LoginContextProvider, { LoginContext } from './contexts/LoginContextProvider'; +import LoginContextProvider from './contexts/LoginContextProvider'; function App() { // 브라우저 새로고침 스크롤 이벤트 From 4341b6068b281236bde8a47915523fd87f9eff31 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Fri, 8 Mar 2024 14:08:36 +0900 Subject: [PATCH 06/31] =?UTF-8?q?Comment:=20=EC=A3=BC=EC=84=9D=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchResultList.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/SearchResultList.jsx b/src/components/SearchResultList.jsx index 252e637..aad18da 100644 --- a/src/components/SearchResultList.jsx +++ b/src/components/SearchResultList.jsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import '../styles/SearchResultList.css'; +// 구글 책 검색 const SearchResultList = ({ book, type, updateBook }) => { let listType = ['myBook'].includes(type) ? type : 'search'; // console.log('book: ',book); From 0bb91d30d295977100dbca9fc0dcd9d9d3a6453c Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Fri, 8 Mar 2024 14:10:35 +0900 Subject: [PATCH 07/31] =?UTF-8?q?Style:=20=EA=B2=80=EC=83=89=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=97=86?= =?UTF-8?q?=EC=9D=84=EC=8B=9C=20=EB=B0=B0=EA=B2=BD=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20width=20=EA=B0=92=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + src/styles/SearchResultList.css | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 4a1a14c..e6665b3 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ # misc .DS_Store +.env .env.local .env.development .env.development.local diff --git a/src/styles/SearchResultList.css b/src/styles/SearchResultList.css index 9380bf1..7713463 100644 --- a/src/styles/SearchResultList.css +++ b/src/styles/SearchResultList.css @@ -25,6 +25,8 @@ } .search-result-list img { + width: 70px; + background-color: rgb(192, 192, 192); border: 1px solid #d6d6d6; } From a7379e575ae56acbf526a0e8d6635d2bd9c9abb8 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Fri, 8 Mar 2024 14:18:15 +0900 Subject: [PATCH 08/31] =?UTF-8?q?:bulb:=20Comment:=20=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EC=A3=BC=EC=84=9D=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?=EB=B0=8F=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/BookList.jsx | 108 ++--------------------------------------- 1 file changed, 3 insertions(+), 105 deletions(-) diff --git a/src/pages/BookList.jsx b/src/pages/BookList.jsx index 269ce72..e6e7922 100644 --- a/src/pages/BookList.jsx +++ b/src/pages/BookList.jsx @@ -43,25 +43,13 @@ const BookList = () => { setBigCategory(title); api.get('/api/category/big').then((res) => { - // console.log(res.data[title]); setMidCategory(res.data[title]); }); api.get(`/api/book/list/big?name=${title}`).then((res) => { - res.data.map((list, idx) => { - // console.log(list); - // console.log(idx); - // bookList.concat(list); - // resMidBookList.length === 0 - // ? setResMidBookList(list) - // : setResMidBookList[idx](list); + res.data.map(() => { setResMidBookList(res.data); }); - setMidCategoryList0(res.data[0].bookList); - setMidCategoryList1(res.data[1].bookList); - setMidCategoryList2(res.data[2].bookList); - setMidCategoryList3(res.data[3].bookList); - setMidCategoryList4(res.data[4].bookList); }); }, []); @@ -79,8 +67,8 @@ const BookList = () => { /> {resMidBookList.map((list, idx) => { - // console.log(list.categoryName); return ( + // 중분류 타이틀 렌더링 <div className="bookList_wrapper" key={idx}> <div className="bookList_title_wrapper"> <Title @@ -90,8 +78,8 @@ const BookList = () => { /> </div> <div className="bookList_slide_wrapper"> + {/* 중분류에 해당하는 책 리스트 데이터 바인딩 */} {list.bookList.map((item) => { - // console.log(item); return ( <BookListSlide key={item.isbn} @@ -106,96 +94,6 @@ const BookList = () => { </div> ); })} - - {/* <div className="bookList_wrapper"> - <div className="bookList_title_wrapper"> - <Title - key={midCategory[0]} - bigCategory={bigCategory} - title={midCategory[0]} - /> - </div> - <div className="bookList_slide_wrapper"> - {midCategoryList0.map((item) => { - // console.log(resMidBookList); - return ( - <BookListSlide - key={item.isbn} - title={item.title} - author={item.author} - bigCategory={bigCategory} - imageUrl={item.imageUrl} - /> - ); - })} - </div> - </div> - <div className="bookList_wrapper"> - <div className="bookList_title_wrapper"> - <Title - key={midCategory[1]} - bigCategory={bigCategory} - title={midCategory[1]} - /> - </div> - <div className="bookList_slide_wrapper"> - {midCategoryList1.map((item) => { - return ( - <BookListSlide - key={item.isbn} - title={item.title} - author={item.author} - bigCategory={bigCategory} - imageUrl={item.imageUrl} - /> - ); - })} - </div> - </div> - <div className="bookList_wrapper"> - <div className="bookList_title_wrapper"> - <Title - key={midCategory[2]} - bigCategory={bigCategory} - title={midCategory[2]} - /> - </div> - <div className="bookList_slide_wrapper"> - {midCategoryList2.map((item) => { - return ( - <BookListSlide - key={item.isbn} - title={item.title} - author={item.author} - bigCategory={bigCategory} - imageUrl={item.imageUrl} - /> - ); - })} - </div> - </div> - <div className="bookList_wrapper"> - <div className="bookList_title_wrapper"> - <Title - key={midCategory[3]} - bigCategory={bigCategory} - title={midCategory[3]} - /> - </div> - <div className="bookList_slide_wrapper"> - {midCategoryList3.map((item) => { - return ( - <BookListSlide - key={item.isbn} - title={item.title} - author={item.author} - bigCategory={bigCategory} - imageUrl={item.imageUrl} - /> - ); - })} - </div> - </div> */} </div> <Footer /> From 7f5581cf0a058ed47825dc19317c70d0cb8ba965 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Fri, 8 Mar 2024 14:20:19 +0900 Subject: [PATCH 09/31] =?UTF-8?q?:package:=20Chore:=20react-slick=20?= =?UTF-8?q?=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 ++ yarn.lock | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/package.json b/package.json index 091d215..b35ec9c 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "react-hook-form": "^7.49.3", "react-router-dom": "6", "react-scripts": "5.0.1", + "react-slick": "^0.30.2", + "slick-carousel": "^1.8.1", "styled-components": "^6.1.6", "styled-reset": "^4.5.1", "swiper": "^11.0.5", diff --git a/yarn.lock b/yarn.lock index d073109..77ec5ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3543,6 +3543,11 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== +classnames@^2.2.5: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== + clean-css@^5.2.2: version "5.3.3" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd" @@ -4408,6 +4413,11 @@ enhanced-resolve@^5.15.0: graceful-fs "^4.2.4" tapable "^2.2.0" +enquire.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/enquire.js/-/enquire.js-2.1.6.tgz#3e8780c9b8b835084c3f60e166dbc3c2a3c89814" + integrity sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw== + entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" @@ -6758,6 +6768,13 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json2mq@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" + integrity sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA== + dependencies: + string-convert "^0.2.0" + json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -8599,6 +8616,17 @@ react-scripts@5.0.1: optionalDependencies: fsevents "^2.3.2" +react-slick@^0.30.2: + version "0.30.2" + resolved "https://registry.yarnpkg.com/react-slick/-/react-slick-0.30.2.tgz#b28e992f9c519bb516a0af8d37e82cb59fee08ce" + integrity sha512-XvQJi7mRHuiU3b9irsqS9SGIgftIfdV5/tNcURTb5LdIokRA5kIIx3l4rlq2XYHfxcSntXapoRg/GxaVOM1yfg== + dependencies: + classnames "^2.2.5" + enquire.js "^2.1.6" + json2mq "^0.2.0" + lodash.debounce "^4.0.8" + resize-observer-polyfill "^1.5.0" + react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -8768,6 +8796,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +resize-observer-polyfill@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -9156,6 +9189,11 @@ slash@^4.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== +slick-carousel@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/slick-carousel/-/slick-carousel-1.8.1.tgz#a4bfb29014887bb66ce528b90bd0cda262cc8f8d" + integrity sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA== + sockjs@^0.3.24: version "0.3.24" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" @@ -9296,6 +9334,11 @@ stop-iteration-iterator@^1.0.0: dependencies: internal-slot "^1.0.4" +string-convert@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" + integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== + string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" From e587f2f0d8fdf11fff264f26f5a7d9932d67b648 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Fri, 8 Mar 2024 14:30:17 +0900 Subject: [PATCH 10/31] =?UTF-8?q?Feat:=20=EA=B2=80=EC=83=89=20API=EC=97=90?= =?UTF-8?q?=20=EB=8C=80=ED=95=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchResultListModal.jsx | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/components/SearchResultListModal.jsx diff --git a/src/components/SearchResultListModal.jsx b/src/components/SearchResultListModal.jsx new file mode 100644 index 0000000..7049c9b --- /dev/null +++ b/src/components/SearchResultListModal.jsx @@ -0,0 +1,52 @@ +import React from 'react' +import "../styles/SearchResultList.css"; + +const SearchResultListModal = ({ book, type, updateBook }) => { + let listType = ["myBook"].includes(type) ? type : "search"; + + const updateBookTitle = (pickTitle) => { + updateBook(pickTitle); + }; + + return ( + <> + <div className={`${listType}-modal-container`}> + {book.map((item) => { + console.log(item); + // 작가에서 누구 지음 이걸 빼주도록 하기 -> 작가 이름을 어떻게 필터링 처리를 할까? + + let title = item && item.title; + let author = item && item.author; + let thumbnail = item && item.imageUrl; + + if (title !== undefined) { + return ( + <ul key={item.id} className={`${listType}-result-container`}> + <li + className={`${listType}-result-list`} + onClick={() => { + updateBookTitle(title); + }} + > + <img src={thumbnail} alt="" /> + <div className={`${listType}-result-item`}> + <h1 className={`${listType}-result-item-title`}>{title}</h1> + <h1 className={`${listType}-result-item-author`}> + {author} + </h1> + </div> + </li> + </ul> + ); + } + })} + </div> + </> + ); +} + +SearchResultListModal.defaultProps = { + type: "search", +}; + +export default SearchResultListModal \ No newline at end of file From f15253cc2406fe9baa0d12d4aaaf028a10b18ced Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Fri, 8 Mar 2024 15:38:25 +0900 Subject: [PATCH 11/31] =?UTF-8?q?Feat:=20=EC=B1=85=EC=A0=9C=EB=AA=A9,=20?= =?UTF-8?q?=EC=9E=91=EA=B0=80,=20=ED=82=A4=EC=9B=8C=EB=93=9C=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=EB=A7=88=EB=8B=A4=20=EA=B0=81=EA=B0=81=EC=9D=98=20api?= =?UTF-8?q?=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchResultListModal.jsx | 9 ++ src/pages/Search.jsx | 109 +++++++++++++---------- src/styles/SearchResultList.css | 2 +- src/styles/SearchStyles.css | 11 ++- 4 files changed, 82 insertions(+), 49 deletions(-) diff --git a/src/components/SearchResultListModal.jsx b/src/components/SearchResultListModal.jsx index 7049c9b..980aa54 100644 --- a/src/components/SearchResultListModal.jsx +++ b/src/components/SearchResultListModal.jsx @@ -18,7 +18,9 @@ const SearchResultListModal = ({ book, type, updateBook }) => { let title = item && item.title; let author = item && item.author; let thumbnail = item && item.imageUrl; + let keyword = item && item.name; + // 책 제목 && 작가 UI if (title !== undefined) { return ( <ul key={item.id} className={`${listType}-result-container`}> @@ -39,6 +41,13 @@ const SearchResultListModal = ({ book, type, updateBook }) => { </ul> ); } + + // 키워드 UI + if (keyword !== undefined) { + return ( + <p className={`${listType}-result-item-title`} style={{ fontSize: "20px", marginBottom: "10px" }}>{keyword}</p> + ); + } })} </div> </> diff --git a/src/pages/Search.jsx b/src/pages/Search.jsx index 4bb2f8a..be4c046 100644 --- a/src/pages/Search.jsx +++ b/src/pages/Search.jsx @@ -19,6 +19,8 @@ import bookImg8 from "../assets/category-book-언어.jpg"; import bookImg9 from "../assets/category-book-문학.png"; import bookImg10 from "../assets/category-book-역사.jpg"; import { LoginContext } from "../contexts/LoginContextProvider"; +import SearchResultListModal from './../components/SearchResultListModal'; +import api from "../services/api"; const Search = () => { const baseURL = "https://api.bookpharmacy.store/api"; @@ -26,6 +28,7 @@ const Search = () => { const [searchData, setSearchData] = useState([]); // 검색 결과 데이터 const [categories, setCategories] = useState([]); // 카테고리 데이터 const [isShow, setIsShow] = useState(false); // 검색창 모달창 + const [searchType, setSearchType] = useState("title"); // 검색 유형 상태 const { userId, userPwd } = useContext(LoginContext); const loginData = { username: userId, password: userPwd }; @@ -44,6 +47,8 @@ const Search = () => { { color: "#D6CABC", image: bookImg10 }, ]; + + // 카테고리 대분류, 중분류 GET 요청 및 요청 데이터 사용하기 쉽게 처리 useEffect(() => { let username = localStorage.getItem("id"); @@ -61,7 +66,7 @@ const Search = () => { // console.log('성공'); axios .get("https://api.bookpharmacy.store/api/category/big", { - // withCredentials: true, + withCredentials: true, }) .then((res) => { setCategories(res.data); @@ -70,6 +75,13 @@ const Search = () => { .catch((err) => { console.log(err); }); + axios + .get("https://api.bookpharmacy.store/api/category/big", { + withCredentials: true, + }) + .then((res) => { + setCategories(res.data); + }); } catch (error) { console.error("Error fetching categories:", error); } @@ -123,42 +135,11 @@ const Search = () => { "화장품", "하늘 높이 비상", "감정", - "해리포터", - "화장품", - "하늘 높이 비상", - "감정", - "해리포터", - "화장품", - "하늘 높이 비상", - "감정", - "해리포터", - "화장품", - "하늘 높이 비상", - "감정", - "해리포터", - "화장품", - "하늘 높이 비상", - "감정", - "해리포터", - "화장품", - "하늘 높이 비상", // Add more keywords as needed ]; // 사용자 추천 키워드 리스트 const userRecommendedKeywords = [ - "#감정", - "#해리포터", - "#화장품", - "#하늘 높이 비상", - "#감정", - "#해리포터", - "#화장품", - "#하늘 높이 비상", - "#감정", - "#해리포터", - "#화장품", - "#하늘 높이 비상", "#감정", "#해리포터", "#화장품", @@ -179,18 +160,29 @@ const Search = () => { const fetchBooks = async (searchInput) => { if (input.trim() === "") return; // 빈 문자열일 때 API 호출 방지 - try { - const response = await axios.get( - `https://www.googleapis.com/books/v1/volumes?q=${searchInput}&key=AIzaSyDUtFpAVpNPHCEW-pxSxpTHSACNjko_MCc&maxResults=10` - ); - const booksData = response.data.items - ? response.data.items.slice(0, 6) - : []; // 검색창에서 6개의 데이터만 보여줌 - - setSearchData(booksData); - } catch (error) { - console.error("Failed to fetch books:", error); + let endpoint = ""; + if (searchType === "title") { + endpoint = `/api/search/book?title=${searchInput}&target=modal`; } + if (searchType === "author") { + endpoint = `/api/search/book?author=${searchInput}&target=modal`; + } + if (searchType === "keyword") { + endpoint = `/api/search/keyword?name=${searchInput}&target=modal`; + } + + try { + const response = await api.get( + // `https://www.googleapis.com/books/v1/volumes?q=${searchInput}&key=AIzaSyDUtFpAVpNPHCEW-pxSxpTHSACNjko_MCc&maxResults=10` + // `https://api.bookpharmacy.store/api/search/book?author=${searchInput}&target=modal` + // `https://api.bookpharmacy.store/api/search/keyword?name=${searchInput}&target=modal` + endpoint + ); + console.log("test", searchType,response.data); + setSearchData(response.data); + } catch (error) { + console.error("Failed to fetch books:", error); + } }; // 검색창 엔터 및 버튼 이벤트 처리 @@ -209,6 +201,10 @@ const Search = () => { setIsShow(true); }; + const handleSelectChange = (e) => { + setSearchType(e.target.value); + }; + return ( <div onClick={handleSearchResultClose}> <Header /> @@ -227,11 +223,24 @@ const Search = () => { <div className="search-wrap-inner"> {/* 검색창에 라벨 적용해보기 */} {/* 책 렌더링했던 유튜브 영상을 활용해서 검색창 누르면 밑에 책보여주는 방법으로 활용하기 */} - <button + {/* <button className="search-button" onClick={searchBook} name="search-button" - /> + /> */} + <select + value={searchType} + onChange={handleSelectChange} + name="" + id="" + className="search-select" + > + <option value="title" selected> + 책제목 + </option> + <option value="author">작가</option> + <option value="keyword">키워드</option> + </select> <input type="text" placeholder="검색어를 입력하세요" @@ -254,8 +263,14 @@ const Search = () => { ) : null} </div> </label> - {input.length > 0 && isShow ? ( - <SearchResultList + {input.length > 0 && isShow && searchData.length > 0 ? ( + // <SearchResultList + // book={searchData} + // onClick={(e) => { + // e.stopPropagation(); + // }} + // /> + <SearchResultListModal book={searchData} onClick={(e) => { e.stopPropagation(); diff --git a/src/styles/SearchResultList.css b/src/styles/SearchResultList.css index 7713463..a0f8d59 100644 --- a/src/styles/SearchResultList.css +++ b/src/styles/SearchResultList.css @@ -6,7 +6,7 @@ box-sizing: border-box; border-radius: 16px; width: 1440px; - padding: 29px 29px 39px; + padding: 29px 29px; /* border: 1px solid #000; */ margin-top: 10px; background-color: #fff; diff --git a/src/styles/SearchStyles.css b/src/styles/SearchStyles.css index 2f8aff7..a0c0173 100644 --- a/src/styles/SearchStyles.css +++ b/src/styles/SearchStyles.css @@ -26,11 +26,20 @@ border-radius: 0.5rem; } -.search-button { +/* .search-button { width: 32px; height: 32px; background: url("../assets/search-icon.svg"); margin-top: 4px; +} */ + +.search-select { + border: none; + font-size: large; +} + +.search-select:focus { + outline: none; } .search-input { From b53f7c2e5662ba95caa22ad8cc1d3ef329701d53 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Fri, 8 Mar 2024 17:32:19 +0900 Subject: [PATCH 12/31] =?UTF-8?q?Feat:=20=ED=82=A4=EC=9B=8C=EB=93=9C=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EC=8B=9C,=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EC=B0=BD=EC=97=90=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchResultListModal.jsx | 9 +++- src/pages/Search.jsx | 62 +++++++++++++++--------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/components/SearchResultListModal.jsx b/src/components/SearchResultListModal.jsx index 980aa54..55ac391 100644 --- a/src/components/SearchResultListModal.jsx +++ b/src/components/SearchResultListModal.jsx @@ -1,7 +1,7 @@ import React from 'react' import "../styles/SearchResultList.css"; -const SearchResultListModal = ({ book, type, updateBook }) => { +const SearchResultListModal = ({ book, type, updateBook, addInput }) => { let listType = ["myBook"].includes(type) ? type : "search"; const updateBookTitle = (pickTitle) => { @@ -45,7 +45,12 @@ const SearchResultListModal = ({ book, type, updateBook }) => { // 키워드 UI if (keyword !== undefined) { return ( - <p className={`${listType}-result-item-title`} style={{ fontSize: "20px", marginBottom: "10px" }}>{keyword}</p> + <p + style={{ fontSize: "20px", marginBottom: "10px" }} + onClick={()=>addInput(`#${keyword}`)} + > + {keyword} + </p> ); } })} diff --git a/src/pages/Search.jsx b/src/pages/Search.jsx index be4c046..e8493f2 100644 --- a/src/pages/Search.jsx +++ b/src/pages/Search.jsx @@ -25,6 +25,7 @@ import api from "../services/api"; const Search = () => { const baseURL = "https://api.bookpharmacy.store/api"; const [input, setInput] = useState(""); // 검색 데이터 + const [inputKeyword, setInputKeyword] = useState([]); // 키워드 검색 데이터 const [searchData, setSearchData] = useState([]); // 검색 결과 데이터 const [categories, setCategories] = useState([]); // 카테고리 데이터 const [isShow, setIsShow] = useState(false); // 검색창 모달창 @@ -173,9 +174,6 @@ const Search = () => { try { const response = await api.get( - // `https://www.googleapis.com/books/v1/volumes?q=${searchInput}&key=AIzaSyDUtFpAVpNPHCEW-pxSxpTHSACNjko_MCc&maxResults=10` - // `https://api.bookpharmacy.store/api/search/book?author=${searchInput}&target=modal` - // `https://api.bookpharmacy.store/api/search/keyword?name=${searchInput}&target=modal` endpoint ); console.log("test", searchType,response.data); @@ -241,26 +239,43 @@ const Search = () => { <option value="author">작가</option> <option value="keyword">키워드</option> </select> - <input - type="text" - placeholder="검색어를 입력하세요" - className="search-input" - value={input} - onChange={(e) => { - setInput(e.target.value); - }} - onKeyPress={searchBook} - /> - {input.length > 0 ? ( - <button - className="search-close-button" - onClick={(e) => { - setInput(""); - }} - > - X - </button> - ) : null} + {searchType === "keyword" ? ( + <> + <input + type="text" + placeholder="검색어를 입력하세요" + className="search-input" + value={input} + onChange={(e) => { + setInput(e.target.value); + }} + onKeyPress={searchBook} + /> + </> + ) : ( + <> + <input + type="text" + placeholder="검색어를 입력하세요" + className="search-input" + value={input} + onChange={(e) => { + setInput(e.target.value); + }} + onKeyPress={searchBook} + /> + {input.length > 0 ? ( + <button + className="search-close-button" + onClick={(e) => { + setInput(""); + }} + > + X + </button> + ) : null} + </> + )} </div> </label> {input.length > 0 && isShow && searchData.length > 0 ? ( @@ -272,6 +287,7 @@ const Search = () => { // /> <SearchResultListModal book={searchData} + addInput={setInput} onClick={(e) => { e.stopPropagation(); }} From df5827e3f324a04a23495f9ce0aa734734a81635 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Fri, 8 Mar 2024 17:48:49 +0900 Subject: [PATCH 13/31] =?UTF-8?q?Feat:=20=EA=B2=80=EC=83=89=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=ED=81=B4=EB=A6=AD=20=EC=8B=9C,=20?= =?UTF-8?q?=ED=95=B4=EB=8B=B9=20=EC=B1=85=20=EC=83=81=EC=84=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchResultListModal.jsx | 29 ++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/components/SearchResultListModal.jsx b/src/components/SearchResultListModal.jsx index 55ac391..c36fd4d 100644 --- a/src/components/SearchResultListModal.jsx +++ b/src/components/SearchResultListModal.jsx @@ -1,5 +1,6 @@ import React from 'react' import "../styles/SearchResultList.css"; +import { Link } from 'react-router-dom'; const SearchResultListModal = ({ book, type, updateBook, addInput }) => { let listType = ["myBook"].includes(type) ? type : "search"; @@ -19,25 +20,25 @@ const SearchResultListModal = ({ book, type, updateBook, addInput }) => { let author = item && item.author; let thumbnail = item && item.imageUrl; let keyword = item && item.name; + console.log(`/book-detial/${title}`); // 책 제목 && 작가 UI if (title !== undefined) { return ( <ul key={item.id} className={`${listType}-result-container`}> - <li - className={`${listType}-result-list`} - onClick={() => { - updateBookTitle(title); - }} - > - <img src={thumbnail} alt="" /> - <div className={`${listType}-result-item`}> - <h1 className={`${listType}-result-item-title`}>{title}</h1> - <h1 className={`${listType}-result-item-author`}> - {author} - </h1> - </div> - </li> + <Link to={`/book-detial/${title}`}> + <li className={`${listType}-result-list`}> + <img src={thumbnail} alt="" /> + <div className={`${listType}-result-item`}> + <h1 className={`${listType}-result-item-title`}> + {title} + </h1> + <h1 className={`${listType}-result-item-author`}> + {author} + </h1> + </div> + </li> + </Link> </ul> ); } From 473e7d268ed8a28f22bf514f5146325737354505 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Fri, 8 Mar 2024 17:52:43 +0900 Subject: [PATCH 14/31] =?UTF-8?q?Feat:=20=EA=B2=80=EC=83=89=EC=B0=BD=20?= =?UTF-8?q?=EC=97=94=ED=84=B0=EC=8B=9C,=20=EA=B2=80=EC=83=89=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EC=B0=BD=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchResultListModal.jsx | 1 - src/pages/Search.jsx | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/SearchResultListModal.jsx b/src/components/SearchResultListModal.jsx index c36fd4d..c77de4f 100644 --- a/src/components/SearchResultListModal.jsx +++ b/src/components/SearchResultListModal.jsx @@ -20,7 +20,6 @@ const SearchResultListModal = ({ book, type, updateBook, addInput }) => { let author = item && item.author; let thumbnail = item && item.imageUrl; let keyword = item && item.name; - console.log(`/book-detial/${title}`); // 책 제목 && 작가 UI if (title !== undefined) { diff --git a/src/pages/Search.jsx b/src/pages/Search.jsx index e8493f2..5f7db68 100644 --- a/src/pages/Search.jsx +++ b/src/pages/Search.jsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from "react"; -import { Link } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import axios from "axios"; // COMPONENTS @@ -24,6 +24,7 @@ import api from "../services/api"; const Search = () => { const baseURL = "https://api.bookpharmacy.store/api"; + const navigate = useNavigate(); const [input, setInput] = useState(""); // 검색 데이터 const [inputKeyword, setInputKeyword] = useState([]); // 키워드 검색 데이터 const [searchData, setSearchData] = useState([]); // 검색 결과 데이터 @@ -186,8 +187,9 @@ const Search = () => { // 검색창 엔터 및 버튼 이벤트 처리 const searchBook = (evt) => { - if (evt.key === "Enter" || evt.target.name === "search-button") { + if (evt.key === "Enter") { fetchBooks(input); + navigate(`/search/result/${input}`) } }; From c17fbdee6f73a2a28a4544a05eb47d7541e3fba9 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Sun, 10 Mar 2024 22:44:44 +0900 Subject: [PATCH 15/31] =?UTF-8?q?Style:=20=EA=B2=80=EC=83=89=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EC=B0=BD=20=EC=99=80=EC=9D=B4=EC=96=B4=20=ED=94=84?= =?UTF-8?q?=EB=A0=88=EC=9E=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/SearchResult.jsx | 1035 +++++++----------------------------- 1 file changed, 205 insertions(+), 830 deletions(-) diff --git a/src/pages/SearchResult.jsx b/src/pages/SearchResult.jsx index 24982f0..7c93ac0 100644 --- a/src/pages/SearchResult.jsx +++ b/src/pages/SearchResult.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import Header from "../components/Header"; import styled from "styled-components"; @@ -8,24 +8,13 @@ import bookImg1 from "../assets/category-book-총류.jpg"; const SearchResult = () => { const { title } = useParams(); - console.log(title); + const [viewMode, setViewMode] = useState(true); let searchResultsCount = 1234; searchResultsCount = searchResultsCount.toLocaleString(); let searchResultsKeywordCount = 123; let bookTitle = "해리포터와 저주받은 아이"; let bookAuthor = "J.K. 롤링· 문학수첩"; - - // 키워드만큼 옵션을 추가하도록 구현 - // 별점 컴포넌트 구현 - // 버튼마다 게시판 / 카드 형식으로 보여주도록 구현 - // 검색에 엔터 누르면 이동되도록 라우팅 설정하기 - // api 연결 - - // 이 페이지 만의 컴포넌트 <CardUIItem {props} /> 이렇게 받게 하자 - - - return ( <> <Header /> @@ -76,6 +65,7 @@ const SearchResult = () => { width: "100%", display: "flex", justifyContent: "space-between", + alignItems: "center", paddingBottom: "20px", borderBottom: "1px solid #c4bebe", }} @@ -87,35 +77,80 @@ const SearchResult = () => { </span> </ContentTitle> <div> - <select name="" id=""> - <option value="" selected> - 인기순 - </option> - <option value="">평점순</option> - </select> - <select name="" id=""> - <option value="" selected> - 10개씩 보기 - </option> - <option value="" selected> - 50개씩 보기 - </option> - <option value="" selected> - 100개씩 보기 - </option> - </select> - <button> - <img - src="https://contents.kyobobook.co.kr/resources/fo/images/common/ink/ico_view_list_active.png" - alt="" - /> - </button> - <button> - <img - src="https://contents.kyobobook.co.kr/resources/fo/images/common/ink/ico_view_img_active.png" - alt="" - /> - </button> + <div style={{ display: "flex" }}> + <select + name="" + id="" + style={{ + width: "120px", + border: "1px solid #C0C0C0 ", + padding: "10px", + borderRadius: "5px", + // marginRight: "10px", + }} + > + <option value="" selected> + 인기순 + </option> + <option value="">평점순</option> + </select> + <select + name="" + id="" + style={{ + width: "120px", + border: "1px solid #C0C0C0 ", + padding: "10px", + borderRadius: "5px", + marginLeft: "10px", + }} + > + <option value="" selected> + 10개씩 보기 + </option> + <option value="" selected> + 50개씩 보기 + </option> + <option value="" selected> + 100개씩 보기 + </option> + </select> + <div + style={{ + display: "flex", + width: "75px", + border: "1px solid #C0C0C0", + borderRadius: "5px", + marginLeft: "10px", + }} + > + <button + onClick={() => setViewMode(true)} + style={{ + padding: "10px", + backgroundColor: "white", + borderRight: "1px solid #C0C0C0", + }} + > + <img + src="https://contents.kyobobook.co.kr/resources/fo/images/common/ink/ico_view_list_active.png" + alt="" + /> + </button> + <button + onClick={() => setViewMode(false)} + style={{ + padding: "10px", + backgroundColor: "white", + }} + > + <img + src="https://contents.kyobobook.co.kr/resources/fo/images/common/ink/ico_view_img_active.png" + alt="" + /> + </button> + </div> + </div> </div> </div> @@ -145,820 +180,156 @@ const SearchResult = () => { {/* 콘텐츠 영역 */} <div> - {/* <ul> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" + {viewMode ? ( + <ListUIWrap> + <li style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", + height: "310px", + display: "flex", + padding: "36px 20px", + borderBottom: "1px solid #A1A1A1", }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> + > + <img + src={bookImg1} + alt="책 표지 이미지" + style={{ + height: "240px", + width: "170px", + backgroundColor: "gray", + borderRadius: "5px", + }} + /> + <div style={{ padding: "1rem 0px 0px 1rem" }}> + <div> + <h3 + style={{ + fontSize: "20px", + fontWeight: "bold", + marginBottom: "8px", + }} + > + {bookTitle} + </h3> + <h4 + style={{ + fontSize: "1rem", + color: "gray", + marginBottom: "40px", + }} + > + {bookAuthor} + </h4> + </div> + <div style={{ marginBottom: "40px" }}> + <ul style={{ display: "flex" }}> + <BookKeyword>영미소설</BookKeyword> + <BookKeyword>판타지소설</BookKeyword> + <BookKeyword>해리포터</BookKeyword> + <BookKeyword>마법주문</BookKeyword> + <BookKeyword>저주</BookKeyword> + </ul> + </div> + <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> + 평균 ★5.0 <span style={{ color: "gray" }}>(12)</span> + </h1> + <div style={{ display: "flex", alignItems: "center" }}> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + </div> </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 <span style={{color:"gray"}}>(12)</span> + </li> + </ListUIWrap> + ) : ( + <CardUIWrap> + <li style={{ width: "170px" }}> + <img + src={bookImg1} + alt="책이미지" + style={{ + height: "240px", + width: "170px", + borderRadius: "5px", + backgroundColor: "gray", + marginBottom: "10px", + }} + /> + <h2 + style={{ + fontSize: "20px", + fontWeight: "bold", + marginBottom: "5px", + }} + > + {bookTitle} + </h2> + <h3 style={{ color: "#6B6B6B", marginBottom: "10px" }}> + {bookAuthor} + </h3> + <h1 style={{ marginBottom: "10px" }}> + 평균 ★5.0 <span style={{ color: "gray" }}>(12)</span> </h1> - <div style={{ display: "flex", alignItems: "center" }}> + <div + style={{ + display: "flex", + alignItems: "center", + marginBottom: "40px", + }} + > <img src={starIcon} alt="" - style={{ marginRight: "5px" }} + style={{ width: "20px", marginRight: "5px" }} /> <img src={starIcon} alt="" - style={{ marginRight: "5px" }} + style={{ width: "20px", marginRight: "5px" }} /> <img src={starIcon} alt="" - style={{ marginRight: "5px" }} + style={{ width: "20px", marginRight: "5px" }} /> <img src={starIcon} alt="" - style={{ marginRight: "5px" }} + style={{ width: "20px", marginRight: "5px" }} /> <img src={starIcon} alt="" - style={{ marginRight: "5px" }} + style={{ width: "20px", marginRight: "5px" }} /> </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", - }} - > - {bookTitle} - </h3> - <h4 - style={{ - fontSize: "1rem", - color: "gray", - marginBottom: "40px", - }} - > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 (12) - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - </ul> */} - <CardUIWrap> - <li> - <img src="" alt="" style={{height:"240px", width:"170px", borderRadius:"5px", backgroundColor:"gray", marginBottom:"10px"}}/> - <h2 style={{fontWeight:"bold", marginBottom:"5px"}}>{bookTitle}</h2> - <h3 style={{marginBottom:"10px"}}>{bookAuthor}</h3> - {/* 별 컴포넌트 */} - </li> - - - - </CardUIWrap> + {/* 별 컴포넌트 */} + </li> + </CardUIWrap> + )} </div> </section> </ContentsWrap> @@ -1040,6 +411,9 @@ const BookKeyword = styled.li` margin-right: 10px; `; +const ListUIWrap = styled.ul` +`; + const CardUIWrap = styled.ul` padding: 36px 20px; display: grid; @@ -1047,3 +421,4 @@ const CardUIWrap = styled.ul` grid-gap: 10px; `; + From 88ea92dcfa12edfc25643af41a92d6678c0a519b Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Sun, 10 Mar 2024 23:54:21 +0900 Subject: [PATCH 16/31] =?UTF-8?q?:recycle:=20Refactor:=20=EC=A4=91?= =?UTF-8?q?=EB=B6=84=EB=A5=98=20=EC=B1=85=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=8A=AC=EB=9D=BC=EC=9D=B4=EB=8D=94=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B0=94=EC=9D=B8?= =?UTF-8?q?=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BookListSlide.js | 44 +++++++++++++-- src/components/Slider.jsx | 83 +++++++++++++++-------------- src/pages/BookList.jsx | 31 +++++------ src/styles/BookList.css | 3 -- src/styles/BookListSlide.module.css | 13 ++++- src/styles/Slider.css | 16 +++--- 6 files changed, 118 insertions(+), 72 deletions(-) diff --git a/src/components/BookListSlide.js b/src/components/BookListSlide.js index 9df24c7..17a8396 100644 --- a/src/components/BookListSlide.js +++ b/src/components/BookListSlide.js @@ -1,4 +1,6 @@ import { useState, useEffect } from 'react'; +import Slider from 'react-slick'; +import { Swiper, SwiperSlide } from 'swiper/react'; import axios from 'axios'; // COMPONENTS @@ -7,21 +9,55 @@ import BookCard from './BookCard'; // STYLES import styles from '../styles/BookListSlide.module.css'; +import 'slick-carousel/slick/slick.css'; +import 'slick-carousel/slick/slick-theme.css'; +import 'swiper/css'; +import 'swiper/css/navigation'; +import 'swiper/css/pagination'; +import { set } from 'react-hook-form'; const BookListSlide = ({ + list, bigCategory, midCategoryTitle, title, author, imageUrl, }) => { + var settings = { + dots: true, + infinite: false, + speed: 500, + slidesToShow: 1, + slidesToScroll: 1, + }; + return ( <> - <div className={styles['container']}> - <div className={styles['slide']}> - <BookCard title={title} author={author} img={imageUrl} /> + <section className={styles['swiper-container']}> + <div className={styles['container']}> + <Swiper + spaceBetween={20} + slidesPerView={7} + slidesOffsetBefore={0} + id={'my-swiper'} + > + <div className={styles['slide']}> + {list.map((item) => { + return ( + <SwiperSlide> + <BookCard + title={item.title} + author={item.author} + img={item.imageUrl} + /> + </SwiperSlide> + ); + })} + </div> + </Swiper> </div> - </div> + </section> </> ); }; diff --git a/src/components/Slider.jsx b/src/components/Slider.jsx index 9549acb..e420533 100644 --- a/src/components/Slider.jsx +++ b/src/components/Slider.jsx @@ -1,49 +1,50 @@ -import React from "react"; -import { Swiper, SwiperSlide } from "swiper/react"; -import "swiper/css"; -import "../styles/Slider.css"; +import React from 'react'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; +import '../styles/Slider.css'; -import { Navigation, Pagination, Scrollbar, A11y } from "swiper/modules"; +import { Navigation, Pagination, Scrollbar, A11y } from 'swiper/modules'; -import "swiper/css"; -import "swiper/css/navigation"; -import "swiper/css/pagination"; -import "swiper/css/scrollbar"; +import 'swiper/css'; +import 'swiper/css/navigation'; +import 'swiper/css/pagination'; +import 'swiper/css/scrollbar'; const Slider = ({ title, subtitle, isBestSeller, bookTitle, bookAuthor }) => { - const numberOfSlides = 10; + const numberOfSlides = 10; - const slides = Array.from({ length: numberOfSlides }, (_, index) => ( - <SwiperSlide key={index}> - <div className="item-wrapper"> - <div className="item-image"></div> - <div className="item-detail"> - <div className="item-title">{bookTitle}</div> - <div className="item-author">{bookAuthor}</div> - </div> - </div> - {isBestSeller && <div className="item-rank">{index + 1}</div>} - </SwiperSlide> - )); + const slides = Array.from({ length: numberOfSlides }, (_, index) => ( + <SwiperSlide key={index}> + <div className="item-wrapper"> + <div className="item-image"></div> + <div className="item-detail"> + <div className="item-title">{bookTitle}</div> + <div className="item-author">{bookAuthor}</div> + </div> + </div> + {isBestSeller && <div className="item-rank">{index + 1}</div>} + </SwiperSlide> + )); - return ( - <div className="best"> - <div className="best-wrapper"> - <div className="title-wrapper"> - <div className="best-title">{title}</div> - <div className="best-subtitle">{subtitle}</div> - </div> - <Swiper - modules={[Navigation, Pagination, Scrollbar, A11y]} - spaceBetween={0} - slidesPerView={7} - navigation - > - {slides} - </Swiper> - </div> - </div> - ); -} + return ( + <div className="best"> + <div className="best-wrapper"> + <div className="title-wrapper"> + <div className="best-title">{title}</div> + <div className="best-subtitle">{subtitle}</div> + </div> + <Swiper + id="slider-swiper" + modules={[Navigation, Pagination, Scrollbar, A11y]} + spaceBetween={0} + slidesPerView={7} + navigation + > + {slides} + </Swiper> + </div> + </div> + ); +}; export default Slider; diff --git a/src/pages/BookList.jsx b/src/pages/BookList.jsx index e6e7922..51d9e2a 100644 --- a/src/pages/BookList.jsx +++ b/src/pages/BookList.jsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; +import Slider from 'react-slick'; import axios from 'axios'; // SERVICE @@ -14,8 +15,18 @@ import BookListSlide from '../components/BookListSlide'; // STYLES import '../styles/BookList.css'; +import 'slick-carousel/slick/slick.css'; +import 'slick-carousel/slick/slick-theme.css'; const BookList = () => { + var settings = { + dots: true, + infinite: true, + speed: 500, + slidesToShow: 1, + slidesToScroll: 1, + }; + // 대분류 let { title } = useParams(); const [bigCategory, setBigCategory] = useState(''); @@ -24,19 +35,6 @@ const BookList = () => { const [midCategory, setMidCategory] = useState([]); const [resMidBookList, setResMidBookList] = useState([]); - // 중분류에 따른 책 리스트 - const [midCategoryList0, setMidCategoryList0] = useState([]); - const [midCategoryList1, setMidCategoryList1] = useState([]); - const [midCategoryList2, setMidCategoryList2] = useState([]); - const [midCategoryList3, setMidCategoryList3] = useState([]); - const [midCategoryList4, setMidCategoryList4] = useState([]); - const [midCategoryList5, setMidCategoryList5] = useState([]); - const [midCategoryList6, setMidCategoryList6] = useState([]); - const [midCategoryList7, setMidCategoryList7] = useState([]); - const [midCategoryList8, setMidCategoryList8] = useState([]); - - const bookList = []; - // 초기에 랜더링될 때 한 번만 실행 useEffect(() => { // 대분류 지정 @@ -77,9 +75,12 @@ const BookList = () => { title={list.categoryName} /> </div> + <div className="bookList_slide_wrapper"> + <BookListSlide list={list.bookList} /> + {/* 중분류에 해당하는 책 리스트 데이터 바인딩 */} - {list.bookList.map((item) => { + {/* {list.bookList.map((item) => { return ( <BookListSlide key={item.isbn} @@ -89,7 +90,7 @@ const BookList = () => { imageUrl={item.imageUrl} /> ); - })} + })} */} </div> </div> ); diff --git a/src/styles/BookList.css b/src/styles/BookList.css index aeb5911..d40d3d0 100644 --- a/src/styles/BookList.css +++ b/src/styles/BookList.css @@ -38,8 +38,5 @@ } .bookList_slide_wrapper { - display: grid; - grid-template-columns: repeat(8, 1fr); - width: 100%; /* overflow-x: scroll; */ } diff --git a/src/styles/BookListSlide.module.css b/src/styles/BookListSlide.module.css index d13f356..bf38d89 100644 --- a/src/styles/BookListSlide.module.css +++ b/src/styles/BookListSlide.module.css @@ -12,10 +12,21 @@ width: 200px; font-family: 'Pretendard-Regular'; font-weight: 700; + /* display: grid; + grid-template-columns: repeat(8, 1fr); */ + width: 100%; } .slide { - display: flex; justify-content: space-around; margin-top: 20px; + width: 500px; +} + +.swiper-container .swiper { + padding: 0; +} + +#my-swiper .swiper { + padding-left: 0; } diff --git a/src/styles/Slider.css b/src/styles/Slider.css index a603afd..c98ad52 100644 --- a/src/styles/Slider.css +++ b/src/styles/Slider.css @@ -39,27 +39,27 @@ /* background-color: aqua; */ } -.swiper-button-prev, -.swiper-button-next { +#slider-swiper .swiper-button-prev, +#slider-swiper .swiper-button-next { color: #575757 !important; } -.swiper-button-prev:after, -.swiper-button-next:after { +#slider-swiper .swiper-button-prev:after, +#slider-swiper .swiper-button-next:after { font-size: 2rem !important; font-weight: 1000 !important; margin-bottom: 40px; } -.swiper-button-prev:after { +#slider-swiper .swiper-button-prev:after { margin-left: -25px; } -.swiper-button-next:after { +#slider-swiper .swiper-button-next:after { margin-right: -20px; } -.swiper { +#slider-swiper .swiper { padding-left: 30px; cursor: grab; -} \ No newline at end of file +} From 04270bff7e457927667f2cc76fb1733447fdfea1 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Mon, 11 Mar 2024 00:59:41 +0900 Subject: [PATCH 17/31] =?UTF-8?q?:sparkles:=20Feat:=20=20=EC=B1=85=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=EB=B3=B4=EA=B8=B0=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=BF=BC=EB=A6=AC=20=EC=8A=A4=ED=8A=B8=EB=A7=81=20?= =?UTF-8?q?=EA=B0=92=EC=9C=BC=EB=A1=9C=20api=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B0=94=EC=9D=B8?= =?UTF-8?q?=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 82 ++++++++++++++++--------------- src/components/BookDetailCard.jsx | 4 +- src/pages/BookDetail.jsx | 51 ++++++++++++++----- src/pages/SmallCategory.jsx | 1 + 4 files changed, 85 insertions(+), 53 deletions(-) diff --git a/src/App.js b/src/App.js index 13f630c..7b9df8a 100644 --- a/src/App.js +++ b/src/App.js @@ -29,7 +29,9 @@ import LoginFindResult from './pages/IdFindResult'; import PasswordFind from './pages/PasswordFind'; import PasswordFindResult from './pages/PasswordFindResult'; import IdFind from './pages/IdFind'; -import LoginContextProvider, { LoginContext } from './contexts/LoginContextProvider'; +import LoginContextProvider, { + LoginContext, +} from './contexts/LoginContextProvider'; function App() { // 브라우저 새로고침 스크롤 이벤트 @@ -40,47 +42,47 @@ function App() { }, []); https: return ( - <BrowserRouter> - <LoginContextProvider> - <div className="App"> - <GlobalStyles /> - <ScrollTop /> - <Routes> - <Route path="/" element={<Home />} /> - <Route path="/logout" element={<Home />} /> - <Route path="/main" element={<Main />} /> - <Route path="/feed" element={<Feed />} /> - <Route path="/search" element={<Search />} /> - <Route path="/mypage" element={<Mypage />} /> - <Route path="/myfeed" element={<MyFeed />} /> - <Route path="/edit" element={<Edit />} /> - <Route path="/edit/:page" element={<UserInfo />} /> + <BrowserRouter> + <LoginContextProvider> + <div className="App"> + <GlobalStyles /> + <ScrollTop /> + <Routes> + <Route path="/" element={<Home />} /> + <Route path="/logout" element={<Home />} /> + <Route path="/main" element={<Main />} /> + <Route path="/feed" element={<Feed />} /> + <Route path="/search" element={<Search />} /> + <Route path="/mypage" element={<Mypage />} /> + <Route path="/myfeed" element={<MyFeed />} /> + <Route path="/edit" element={<Edit />} /> + <Route path="/edit/:page" element={<UserInfo />} /> - <Route element={<LoginLayout />}> - <Route path="/id-find" element={<IdFind />} /> - <Route path="/id-find-result" element={<LoginFindResult />} /> - <Route path="/password-find" element={<PasswordFind />} /> - <Route - path="/password-find-result" - element={<PasswordFindResult />} - /> - </Route> - <Route path="/test" element={<Registration />} /> - <Route path="/login" element={<Login />} /> - <Route path="/signup" element={<Join />} /> - <Route path="/signup/1" element={<Signup2 />} /> - <Route path="/signup/2" element={<Signup3 />} /> - {/* <Route path="/find/user/info/:page" element={<FindUserInfo />} /> */} - <Route path="/test" element={<Registration />} /> + <Route element={<LoginLayout />}> + <Route path="/id-find" element={<IdFind />} /> + <Route path="/id-find-result" element={<LoginFindResult />} /> + <Route path="/password-find" element={<PasswordFind />} /> + <Route + path="/password-find-result" + element={<PasswordFindResult />} + /> + </Route> + <Route path="/test" element={<Registration />} /> + <Route path="/login" element={<Login />} /> + <Route path="/signup" element={<Join />} /> + <Route path="/signup/1" element={<Signup2 />} /> + <Route path="/signup/2" element={<Signup3 />} /> + {/* <Route path="/find/user/info/:page" element={<FindUserInfo />} /> */} + <Route path="/test" element={<Registration />} /> - <Route path="/book-detail" element={<BookDetail />} /> - <Route path="/book/list/:title" element={<BookList />} /> - <Route path="/book/:title/:category" element={<SmallCategory />} /> - </Routes> - </div> - </LoginContextProvider> - </BrowserRouter> - ); + <Route path="/book-detail" element={<BookDetail />} /> + <Route path="/book/list/:title" element={<BookList />} /> + <Route path="/book/:title/:category" element={<SmallCategory />} /> + </Routes> + </div> + </LoginContextProvider> + </BrowserRouter> + ); } export default App; diff --git a/src/components/BookDetailCard.jsx b/src/components/BookDetailCard.jsx index 3d40b50..5d7c72a 100644 --- a/src/components/BookDetailCard.jsx +++ b/src/components/BookDetailCard.jsx @@ -7,7 +7,7 @@ import HashTag from '../components/HashTag'; //STYLES import '../styles/BookDetailCard.css'; -const BookDetailCard = ({ title, author, imageUrl }) => { +const BookDetailCard = ({ title, author, imageUrl, isbn }) => { const [searchParams, setSearchParams] = useSearchParams(); const bookTitle = searchParams.get('title'); // console.log('title:', bookTitle); @@ -18,7 +18,7 @@ const BookDetailCard = ({ title, author, imageUrl }) => { return ( <> - <Link to={'/book-detail'}> + <Link to={`/book-detail?isbn=${isbn}`}> <div className="bookCard_container"> <div className="bookCard_wrapper"> <div className="bookCard_left_wrapper"> diff --git a/src/pages/BookDetail.jsx b/src/pages/BookDetail.jsx index bbf6405..4b267c3 100644 --- a/src/pages/BookDetail.jsx +++ b/src/pages/BookDetail.jsx @@ -1,4 +1,8 @@ -import React, { useRef } from 'react'; +import React, { useState, useRef, useEffect } from 'react'; +import { useParams, useSearchParams } from 'react-router-dom'; + +// SERVICE +import api from '../services/api'; // COMPONENTS import Header from '../components/Header'; @@ -11,7 +15,6 @@ import Footer from '../components/Footer'; // STYLES import '../styles/BookDetail.css'; -import { Link } from 'react-router-dom'; const BookDetail = () => { const scrollRef = useRef([]); @@ -19,6 +22,26 @@ const BookDetail = () => { ref.scrollIntoView({ behavior: 'smooth' }); }; + const [searchParams, setSearchParams] = useSearchParams(); + const [bookInfo, setBookInfo] = useState([]); + const [bookKeywordList, setBookKeywordList] = useState([]); + + const getIsbn = () => { + let isbn = searchParams.get('isbn'); + console.log(isbn); + + api.get(`/api/book/detail?isbn=${isbn}`).then((res) => { + console.log(res.data.title); + console.log(res.data); + setBookInfo(res.data); + setBookKeywordList(res.data.bookKeywordList); + }); + }; + + useEffect(() => { + getIsbn(); + }, []); + return ( <> <Header /> @@ -26,13 +49,19 @@ const BookDetail = () => { <section className="bookSummary"> <div className="bookSummary_wrapper"> <div className="summary_left_wrapper"> - <div className="summary_left_img"></div> + <div> + <img + className="summary_left_img" + src={bookInfo.imageUrl} + alt={`${bookInfo.title}썸네일`} + /> + </div> </div> <div className="summary_right_wrapper"> <div className="summary_right_up_wrapper"> <div className="right_up_left_wrapper"> - <div className="up_left_book_title">해리포터와 불의 잔</div> - <div className="up_left_book_author">J. K. 롤링 </div> + <div className="up_left_book_title">{bookInfo.title}</div> + <div className="up_left_book_author">{bookInfo.author}</div> </div> <div className="right_up_right_wrapper"> <div className="up_right_exp"> @@ -41,10 +70,9 @@ const BookDetail = () => { </div> </div> <div className="summary_left_mid_wrapper"> - <HashTag text={'#마법학교'} /> - <HashTag text={'#판타지'} /> - <HashTag text={'#해리포터'} /> - <HashTag text={'#소설원작'} /> + {bookKeywordList.map((item) => { + return <HashTag key={item.name} text={item.name} />; + })} </div> <div className="summary_left_bottom_wrapper"> <nav className="left_bottom_text_wrapper"> @@ -88,7 +116,8 @@ const BookDetail = () => { > <div className="bookInfo_title">책 정보</div> <div className="bookInfo_content"> - <p className="content_bold"> + <p className="content_normal">{bookInfo.content}</p> + {/* <p className="content_bold"> 해리 포터 세대의, 해리 포터 세대를 위한, 해리 포터 세대에 의한 새 번역!‘ 21세기 대표 아이콘’에 걸맞은 완성도 높은 작품으로 재탄생하다! @@ -139,7 +168,7 @@ const BookDetail = () => { 말투의 미세한 뉘앙스까지 점검했다. 『해리 포터』의 세계에 처음 발을 들여놓는 독자는 물론, 그동안 『해리 포터』의 세계를 즐겨 찾아왔던 독자 모두에게 완성도 높은 만족과 감동을 선사할 것이다. - </p> + </p> */} </div> </div> </section> diff --git a/src/pages/SmallCategory.jsx b/src/pages/SmallCategory.jsx index 0d06234..1083fcf 100644 --- a/src/pages/SmallCategory.jsx +++ b/src/pages/SmallCategory.jsx @@ -51,6 +51,7 @@ const SmallCategory = () => { // console.log(data); return ( <Card + isbn={data.isbn} title={data.title} author={data.author} key={data.isbn} From eff74dcc2a464dd2a2475b85ceefbecae8ae9583 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Mon, 11 Mar 2024 13:28:53 +0900 Subject: [PATCH 18/31] =?UTF-8?q?Feat:=20=EC=A0=84=EB=8B=AC=EB=90=9C=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B2=B0=EA=B3=BC=EB=A1=9C=20=EC=B1=85=20?= =?UTF-8?q?API=20=EC=97=B0=EB=8F=99=20=EB=B0=8F=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchResultList.jsx | 1 + src/pages/SearchResult.jsx | 373 ++++++++++++++++------------ 2 files changed, 218 insertions(+), 156 deletions(-) diff --git a/src/components/SearchResultList.jsx b/src/components/SearchResultList.jsx index 252e637..194edf3 100644 --- a/src/components/SearchResultList.jsx +++ b/src/components/SearchResultList.jsx @@ -49,6 +49,7 @@ const SearchResultList = ({ book, type, updateBook }) => { </ul> ); } + return null; })} </div> </> diff --git a/src/pages/SearchResult.jsx b/src/pages/SearchResult.jsx index 7c93ac0..e8e8e58 100644 --- a/src/pages/SearchResult.jsx +++ b/src/pages/SearchResult.jsx @@ -1,19 +1,39 @@ import React, { useEffect, useState } from "react"; -import { useParams } from "react-router-dom"; +import { Link, useParams } from "react-router-dom"; import Header from "../components/Header"; import styled from "styled-components"; import closeIcon from "../assets/closeIconRound.svg"; import starIcon from "../assets/icons8-별-30 (1).png"; -import bookImg1 from "../assets/category-book-총류.jpg"; +import api from "./../services/api"; const SearchResult = () => { const { title } = useParams(); const [viewMode, setViewMode] = useState(true); + const [books, setBooks] = useState([]); + const [size, setSize] = useState(10); let searchResultsCount = 1234; searchResultsCount = searchResultsCount.toLocaleString(); let searchResultsKeywordCount = 123; - let bookTitle = "해리포터와 저주받은 아이"; - let bookAuthor = "J.K. 롤링· 문학수첩"; + let reviewCount = 123; + + useEffect(() => { + const getSearchResults = async () => { + try { + const response = await api.get( + `/api/search/book?title=${title}&target=page&page=0&size=${size}` + ); + console.log(response.data) + setBooks(response.data); + } catch (error) { + console.error("책 데이터 GET 요청 실패", error); + } + }; + getSearchResults(); + }, [size]); + + const handleSizeChange = (event) => { + setSize(event.target.value); + }; return ( <> @@ -82,9 +102,9 @@ const SearchResult = () => { name="" id="" style={{ - width: "120px", + width: "130px", border: "1px solid #C0C0C0 ", - padding: "10px", + padding: "0px 10px", borderRadius: "5px", // marginRight: "10px", }} @@ -98,22 +118,20 @@ const SearchResult = () => { name="" id="" style={{ - width: "120px", + width: "130px", border: "1px solid #C0C0C0 ", - padding: "10px", + padding: "0px 10px", borderRadius: "5px", marginLeft: "10px", }} + onChange={handleSizeChange} + value={size} > - <option value="" selected> + <option value="10" selected> 10개씩 보기 </option> - <option value="" selected> - 50개씩 보기 - </option> - <option value="" selected> - 100개씩 보기 - </option> + <option value="50">50개씩 보기</option> + <option value="100">100개씩 보기</option> </select> <div style={{ @@ -182,152 +200,187 @@ const SearchResult = () => { <div> {viewMode ? ( <ListUIWrap> - <li - style={{ - height: "310px", - display: "flex", - padding: "36px 20px", - borderBottom: "1px solid #A1A1A1", - }} - > - <img - src={bookImg1} - alt="책 표지 이미지" - style={{ - height: "240px", - width: "170px", - backgroundColor: "gray", - borderRadius: "5px", - }} - /> - <div style={{ padding: "1rem 0px 0px 1rem" }}> - <div> - <h3 + {books.map((book, index) => ( + <Link to={`/book-detail/${book.title}`}> + <li + key={index} + style={{ + height: "310px", + display: "flex", + padding: "36px 20px", + borderBottom: "1px solid #A1A1A1", + }} + > + <img + src={book.imageUrl} + alt="책 표지 이미지" + style={{ + height: "240px", + width: "170px", + backgroundColor: "gray", + borderRadius: "5px", + objectFit: "cover", + }} + /> + <div style={{ padding: "1rem 0px 0px 1rem" }}> + <div> + <h3 + style={{ + fontSize: "20px", + fontWeight: "bold", + marginBottom: "8px", + }} + > + {book.title} + </h3> + <h4 + style={{ + fontSize: "1rem", + color: "gray", + marginBottom: "40px", + }} + > + {book.author} + </h4> + </div> + <div style={{ marginBottom: "40px" }}> + <ul style={{ display: "flex", flexWrap: "wrap" }}> + <BookKeyword> + {book.middleCategoryName} + </BookKeyword> + {book.bookKeywordList.map((keyword, index) => { + return ( + <BookKeyword key={index}> + {keyword.name} + </BookKeyword> + ); + })} + </ul> + </div> + <h1 + style={{ + fontWeight: "bold", + marginBottom: "10px", + }} + > + 평균 ★{book.rating}{" "} + <span style={{ color: "gray" }}> + ({reviewCount}) + </span> + </h1> + <div + style={{ display: "flex", alignItems: "center" }} + > + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ marginRight: "5px" }} + /> + </div> + </div> + </li> + </Link> + ))} + </ListUIWrap> + ) : ( + <CardUIWrap> + {books.map((book, index) => ( + <Link to={`/book-detail/${book.title}`}> + <li key={index} style={{ width: "170px" }}> + <div style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "8px", + height: "240px", + width: "170px", + borderRadius: "5px", + backgroundColor: "gray", + marginBottom: "10px", + display: "inline-block", }} > - {bookTitle} + <img + src={book.imageUrl} + alt="책 표지 이미지" + style={{ + width: "100%", + height: "100%", + objectFit: "cover", + border: "1px solid #c0c0c0", + }} + /> + </div> + <BookTitle> + {book.title} + </BookTitle> + <h3 style={{ color: "#6B6B6B", marginBottom: "10px" }}> + {book.author} </h3> - <h4 + <h1 style={{ marginBottom: "10px" }}> + 평균 ★{book.rating}{" "} + <span style={{ color: "gray" }}> + ({reviewCount}) + </span> + </h1> + <div style={{ - fontSize: "1rem", - color: "gray", + display: "flex", + alignItems: "center", marginBottom: "40px", }} > - {bookAuthor} - </h4> - </div> - <div style={{ marginBottom: "40px" }}> - <ul style={{ display: "flex" }}> - <BookKeyword>영미소설</BookKeyword> - <BookKeyword>판타지소설</BookKeyword> - <BookKeyword>해리포터</BookKeyword> - <BookKeyword>마법주문</BookKeyword> - <BookKeyword>저주</BookKeyword> - </ul> - </div> - <h1 style={{ fontWeight: "bold", marginBottom: "10px" }}> - 평균 ★5.0 <span style={{ color: "gray" }}>(12)</span> - </h1> - <div style={{ display: "flex", alignItems: "center" }}> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ marginRight: "5px" }} - /> - </div> - </div> - </li> - </ListUIWrap> - ) : ( - <CardUIWrap> - <li style={{ width: "170px" }}> - <img - src={bookImg1} - alt="책이미지" - style={{ - height: "240px", - width: "170px", - borderRadius: "5px", - backgroundColor: "gray", - marginBottom: "10px", - }} - /> - <h2 - style={{ - fontSize: "20px", - fontWeight: "bold", - marginBottom: "5px", - }} - > - {bookTitle} - </h2> - <h3 style={{ color: "#6B6B6B", marginBottom: "10px" }}> - {bookAuthor} - </h3> - <h1 style={{ marginBottom: "10px" }}> - 평균 ★5.0 <span style={{ color: "gray" }}>(12)</span> - </h1> - <div - style={{ - display: "flex", - alignItems: "center", - marginBottom: "40px", - }} - > - <img - src={starIcon} - alt="" - style={{ width: "20px", marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ width: "20px", marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ width: "20px", marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ width: "20px", marginRight: "5px" }} - /> - <img - src={starIcon} - alt="" - style={{ width: "20px", marginRight: "5px" }} - /> - </div> + <img + src={starIcon} + alt="" + style={{ + width: "20px", + marginRight: "5px", + }} + /> + <img + src={starIcon} + alt="" + style={{ width: "20px", marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ width: "20px", marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ width: "20px", marginRight: "5px" }} + /> + <img + src={starIcon} + alt="" + style={{ width: "20px", marginRight: "5px" }} + /> + </div> - {/* 별 컴포넌트 */} - </li> + {/* 별 컴포넌트 */} + </li> + </Link> + ))} </CardUIWrap> )} </div> @@ -411,14 +464,22 @@ const BookKeyword = styled.li` margin-right: 10px; `; -const ListUIWrap = styled.ul` -`; +const ListUIWrap = styled.ul``; const CardUIWrap = styled.ul` padding: 36px 20px; display: grid; - grid-template-columns: repeat(5,1fr); + grid-template-columns: repeat(5, 1fr); grid-gap: 10px; - `; +const BookTitle = styled.h2` + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; /* 원하는 라인 수 */ + overflow: hidden; + text-overflow: ellipsis; + font-size: 20px; + font-weight: bold; + margin-bottom: 5px; +`; \ No newline at end of file From 21954b5e5bc98a32543e64114b7a5e52d478f811 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Mon, 11 Mar 2024 13:32:13 +0900 Subject: [PATCH 19/31] =?UTF-8?q?Feat:=20=EA=B2=80=EC=83=89=EC=B0=BD=20?= =?UTF-8?q?=EB=A9=94=EB=89=B4=20=EC=84=A0=ED=83=9D=EC=8B=9C,=20=EA=B8=B0?= =?UTF-8?q?=EC=A1=B4=20=EC=9E=85=EB=A0=A5=EB=90=9C=20=EA=B2=83=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Search.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/Search.jsx b/src/pages/Search.jsx index 5f7db68..10def8f 100644 --- a/src/pages/Search.jsx +++ b/src/pages/Search.jsx @@ -203,6 +203,7 @@ const Search = () => { const handleSelectChange = (e) => { setSearchType(e.target.value); + setInput(""); }; return ( From c52f3ec80e7f85b0f0ee46679eb1258a7e52a68b Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Mon, 11 Mar 2024 14:49:22 +0900 Subject: [PATCH 20/31] =?UTF-8?q?:sparkles:=20Feat:=20=EC=A4=91=EB=B6=84?= =?UTF-8?q?=EB=A5=98=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=B1=85=20=EC=83=81=EC=84=B8=EB=B3=B4=EA=B8=B0=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BookCard.js | 22 +++++++++++++--------- src/components/BookListSlide.js | 1 + src/pages/BookDetail.jsx | 6 +++--- src/styles/BookCard.module.css | 1 + 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/components/BookCard.js b/src/components/BookCard.js index 7034343..965897c 100644 --- a/src/components/BookCard.js +++ b/src/components/BookCard.js @@ -1,18 +1,22 @@ +import { Link } from 'react-router-dom'; + // Styles import styles from '../styles/BookCard.module.css'; -const BookCard = ({ title, author, img }) => { +const BookCard = ({ title, author, img, isbn }) => { return ( <> - <div className={styles['card_container']}> - <div className={styles['book_img']}> - <img className={styles['book_thumbnail']} src={img} alt="썸네일" /> - </div> - <div className={styles['book_info_wrapper']}> - <div className={styles['book_title']}>{title}</div> - <div className={styles['book_author']}>{author}</div> + <Link to={`/book-detail?isbn=${isbn}`}> + <div className={styles['card_container']}> + <div className={styles['book_img']}> + <img className={styles['book_thumbnail']} src={img} alt="썸네일" /> + </div> + <div className={styles['book_info_wrapper']}> + <div className={styles['book_title']}>{title}</div> + <div className={styles['book_author']}>{author}</div> + </div> </div> - </div> + </Link> </> ); }; diff --git a/src/components/BookListSlide.js b/src/components/BookListSlide.js index 17a8396..f23b313 100644 --- a/src/components/BookListSlide.js +++ b/src/components/BookListSlide.js @@ -50,6 +50,7 @@ const BookListSlide = ({ title={item.title} author={item.author} img={item.imageUrl} + isbn={item.isbn} /> </SwiperSlide> ); diff --git a/src/pages/BookDetail.jsx b/src/pages/BookDetail.jsx index 4b267c3..ea5cb98 100644 --- a/src/pages/BookDetail.jsx +++ b/src/pages/BookDetail.jsx @@ -28,11 +28,11 @@ const BookDetail = () => { const getIsbn = () => { let isbn = searchParams.get('isbn'); - console.log(isbn); + // console.log(isbn); api.get(`/api/book/detail?isbn=${isbn}`).then((res) => { - console.log(res.data.title); - console.log(res.data); + // console.log(res.data.title); + // console.log(res.data); setBookInfo(res.data); setBookKeywordList(res.data.bookKeywordList); }); diff --git a/src/styles/BookCard.module.css b/src/styles/BookCard.module.css index ebb9ffb..4d55c2d 100644 --- a/src/styles/BookCard.module.css +++ b/src/styles/BookCard.module.css @@ -12,6 +12,7 @@ display: flex; flex-direction: column; align-items: center; + cursor: pointer; } .book_img { From 9a9e395653eec6fcd8f60c8d5521151090bf14b1 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Mon, 11 Mar 2024 16:58:16 +0900 Subject: [PATCH 21/31] =?UTF-8?q?:sparkles:=20Feat:=20=EC=A4=91=EB=B6=84?= =?UTF-8?q?=EB=A5=98=20=EC=B1=85=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90=20?= =?UTF-8?q?=ED=82=A4=EC=9B=8C=EB=93=9C=20=EB=B3=B4=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BookDetailCard.jsx | 10 +++++----- src/pages/SmallCategory.jsx | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/BookDetailCard.jsx b/src/components/BookDetailCard.jsx index 5d7c72a..d721369 100644 --- a/src/components/BookDetailCard.jsx +++ b/src/components/BookDetailCard.jsx @@ -7,7 +7,7 @@ import HashTag from '../components/HashTag'; //STYLES import '../styles/BookDetailCard.css'; -const BookDetailCard = ({ title, author, imageUrl, isbn }) => { +const BookDetailCard = ({ title, author, imageUrl, isbn, bookKeywordList }) => { const [searchParams, setSearchParams] = useSearchParams(); const bookTitle = searchParams.get('title'); // console.log('title:', bookTitle); @@ -38,10 +38,10 @@ const BookDetailCard = ({ title, author, imageUrl, isbn }) => { <div className="right_up_author">{author}</div> </div> <div className="bookCard_right_bottom_wrapper"> - <HashTag text={'행복'} type="sm-category" /> - <HashTag text={'해피니스'} type="sm-category" /> - <HashTag text={'클로버'} type="sm-category" /> - <HashTag text={'해쉬태그4'} type="sm-category" /> + {bookKeywordList.map((keyword) => { + // console.log(keyword.name); + return <HashTag text={keyword.name} type="sm-category" />; + })} </div> </div> </div> diff --git a/src/pages/SmallCategory.jsx b/src/pages/SmallCategory.jsx index 1083fcf..00b1cd2 100644 --- a/src/pages/SmallCategory.jsx +++ b/src/pages/SmallCategory.jsx @@ -56,6 +56,7 @@ const SmallCategory = () => { author={data.author} key={data.isbn} imageUrl={data.imageUrl} + bookKeywordList={data.bookKeywordList} // onClick={() => { // setSearchParams({ // title: data[title], From 2344b40d3b439b7a2dc15a357a1d19932e2a700e Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Mon, 11 Mar 2024 17:03:29 +0900 Subject: [PATCH 22/31] =?UTF-8?q?:bulb:=20Comment:=20=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EC=A3=BC=EC=84=9D=20=EB=B0=8F=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BookDetailCard.jsx | 23 ++++++++++------------- src/pages/SmallCategory.jsx | 24 +----------------------- 2 files changed, 11 insertions(+), 36 deletions(-) diff --git a/src/components/BookDetailCard.jsx b/src/components/BookDetailCard.jsx index d721369..543c051 100644 --- a/src/components/BookDetailCard.jsx +++ b/src/components/BookDetailCard.jsx @@ -1,5 +1,5 @@ -import React, { useState, useEffect } from 'react'; -import { Link, useSearchParams } from 'react-router-dom'; +import React from 'react'; +import { Link } from 'react-router-dom'; //COMPONENTS import HashTag from '../components/HashTag'; @@ -8,14 +8,6 @@ import HashTag from '../components/HashTag'; import '../styles/BookDetailCard.css'; const BookDetailCard = ({ title, author, imageUrl, isbn, bookKeywordList }) => { - const [searchParams, setSearchParams] = useSearchParams(); - const bookTitle = searchParams.get('title'); - // console.log('title:', bookTitle); - - // useEffect(() => { - // setSearchParams({ who: 'bb' }); - // }); - return ( <> <Link to={`/book-detail?isbn=${isbn}`}> @@ -38,9 +30,14 @@ const BookDetailCard = ({ title, author, imageUrl, isbn, bookKeywordList }) => { <div className="right_up_author">{author}</div> </div> <div className="bookCard_right_bottom_wrapper"> - {bookKeywordList.map((keyword) => { - // console.log(keyword.name); - return <HashTag text={keyword.name} type="sm-category" />; + {bookKeywordList.map((keyword, idx) => { + return ( + <HashTag + key={`${isbn}keyword-${idx}`} + text={keyword.name} + type="sm-category" + /> + ); })} </div> </div> diff --git a/src/pages/SmallCategory.jsx b/src/pages/SmallCategory.jsx index 00b1cd2..464322c 100644 --- a/src/pages/SmallCategory.jsx +++ b/src/pages/SmallCategory.jsx @@ -1,11 +1,9 @@ import React, { useState, useEffect } from 'react'; -import { useParams, useSearchParams } from 'react-router-dom'; +import { useParams } from 'react-router-dom'; import axios from 'axios'; // COMPONENTS import Header from '../components/Header'; -import Footer from '../components/Footer'; -import Btn from '../components/Button'; import Card from '../components/BookDetailCard'; // STYLES @@ -28,12 +26,9 @@ const SmallCategory = () => { ) .then((res) => { setSmCategoryBookList(res.data); - console.log(res.data); }); }, []); - const [searchParams, setSearchParams] = useSearchParams(); - return ( <> <Header /> @@ -48,7 +43,6 @@ const SmallCategory = () => { <div className="smCategory_card_wrapper"> <div className="smCategory_card_slide"> {smCategoryBookList.map((data) => { - // console.log(data); return ( <Card isbn={data.isbn} @@ -57,26 +51,10 @@ const SmallCategory = () => { key={data.isbn} imageUrl={data.imageUrl} bookKeywordList={data.bookKeywordList} - // onClick={() => { - // setSearchParams({ - // title: data[title], - // author: data[author], - // }); - // }} /> ); })} </div> - {/* <div className="smCategory_card_slide"> - <Card /> - <Card /> - <Card /> - </div> - <div className="smCategory_card_slide"> - <Card /> - <Card /> - <Card /> - </div> */} </div> </div> </> From 4ac2cc279a61c325fcacdded0ad8130412c76b85 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Mon, 11 Mar 2024 17:33:56 +0900 Subject: [PATCH 23/31] =?UTF-8?q?:lipstick:=20Style:=20=EC=A4=91=EB=B6=84?= =?UTF-8?q?=EB=A5=98=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20ArrowTitle=20=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/ArrowTitle.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/ArrowTitle.module.css b/src/styles/ArrowTitle.module.css index dc344ef..f16f105 100644 --- a/src/styles/ArrowTitle.module.css +++ b/src/styles/ArrowTitle.module.css @@ -33,7 +33,7 @@ } .default_wrapper { - width: 1338px; + width: 100%; height: 55px; display: flex; justify-content: space-between; From f9a981c901879091fa156cddded87bdb211e0257 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Mon, 11 Mar 2024 17:35:18 +0900 Subject: [PATCH 24/31] =?UTF-8?q?:bug:=20Fix:=20bookListSlide,=20SwiperSli?= =?UTF-8?q?de=20key=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BookDetailCard.jsx | 2 ++ src/components/BookListSlide.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/BookDetailCard.jsx b/src/components/BookDetailCard.jsx index 543c051..6746840 100644 --- a/src/components/BookDetailCard.jsx +++ b/src/components/BookDetailCard.jsx @@ -22,6 +22,7 @@ const BookDetailCard = ({ title, author, imageUrl, isbn, bookKeywordList }) => { /> </div> </div> + <div className="bookCard_right_wrapper"> <div className="bookCard_right_up_wrapper"> <div className="right_up_title" title={title}> @@ -29,6 +30,7 @@ const BookDetailCard = ({ title, author, imageUrl, isbn, bookKeywordList }) => { </div> <div className="right_up_author">{author}</div> </div> + <div className="bookCard_right_bottom_wrapper"> {bookKeywordList.map((keyword, idx) => { return ( diff --git a/src/components/BookListSlide.js b/src/components/BookListSlide.js index f23b313..b5babc9 100644 --- a/src/components/BookListSlide.js +++ b/src/components/BookListSlide.js @@ -45,8 +45,9 @@ const BookListSlide = ({ <div className={styles['slide']}> {list.map((item) => { return ( - <SwiperSlide> + <SwiperSlide key={item.isbn}> <BookCard + key={item.isbn} title={item.title} author={item.author} img={item.imageUrl} From dcd74459874cef039060817d70f753aaa423b272 Mon Sep 17 00:00:00 2001 From: Daewony <alexnori.com@gmail.com> Date: Mon, 11 Mar 2024 20:25:44 +0900 Subject: [PATCH 25/31] =?UTF-8?q?Feat:=20=EA=B2=80=EC=83=89=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=ED=8E=98=EC=9D=B4=EC=A7=80=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Pagination.jsx | 51 +++++++++++ src/components/SearchBox.jsx | 145 ++++++++++++++++++++++++++++++ src/pages/Search.jsx | 4 +- src/pages/SearchResult.jsx | 163 +++++++++++++++++++++++++++------- src/services/books.js | 7 ++ src/styles/SearchStyles.css | 4 +- 6 files changed, 338 insertions(+), 36 deletions(-) create mode 100644 src/components/Pagination.jsx create mode 100644 src/components/SearchBox.jsx create mode 100644 src/services/books.js diff --git a/src/components/Pagination.jsx b/src/components/Pagination.jsx new file mode 100644 index 0000000..4b25e64 --- /dev/null +++ b/src/components/Pagination.jsx @@ -0,0 +1,51 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import styled from "styled-components"; + +const Pagination = ({ booksPerPage, totalBooks, paginate, bookTitle }) => { + const pageNumbers = []; + console.log(totalBooks, booksPerPage); + for (let i = 1; i <= Math.ceil(totalBooks / booksPerPage); i++) { + pageNumbers.push(i); + console.log(pageNumbers); + } + + return ( + <nav> + <PaginationContainer className="pagination"> + {pageNumbers.map((number) => { + return ( + <li + key={number} + className="page-item" + style={{ + textAlign: "center", + marginTop: "30px", + marginBottom: "60px", + padding: "4px", + }} + > + {/* <a onClick={()=>paginate(number)} href={bookTitle} className="page-link"> */} + <Link + onClick={() => { + window.scrollTo(0, 0); + paginate(number); + }} + > + {number} + </Link> + {/* </a> */} + </li> + ); + })} + </PaginationContainer> + </nav> + ); +}; + +export default Pagination; + +const PaginationContainer = styled.ul` + display: flex; + justify-content: center; +`; diff --git a/src/components/SearchBox.jsx b/src/components/SearchBox.jsx new file mode 100644 index 0000000..6eb091b --- /dev/null +++ b/src/components/SearchBox.jsx @@ -0,0 +1,145 @@ +import React, { useState } from 'react' +import SearchResultListModal from './SearchResultListModal'; + +// style +import "../styles/SearchStyles.css"; +import styled from 'styled-components'; + +const SearchBox = ({ + input, + setInput, + searchType, + setSearchType, + searchBook, + isShow, + setIsShow, + searchData, +}) => { + + + return ( + <section + className="search-wrapper" + onClick={(e) => { + e.stopPropagation(); + // handleSearchResultShow(); + setIsShow(true); + }} + > + <label> + <SearchInputWrap> + {/* 검색창에 라벨 적용해보기 */} + {/* 책 렌더링했던 유튜브 영상을 활용해서 검색창 누르면 밑에 책보여주는 방법으로 활용하기 */} + {/* <button + className="search-button" + onClick={searchBook} + name="search-button" + /> */} + <SelectMenu + value={searchType} + onChange={(e) => setSearchType(e.target.value)} + name="" + id="" + // className="search-select" + > + <option value="title" selected> + 책제목 + </option> + <option value="author">작가</option> + <option value="keyword">키워드</option> + </SelectMenu> + {searchType === "keyword" ? ( + <> + <SearchInput + type="text" + placeholder="검색어를 입력하세요" + // className="search-input" + value={input} + onChange={(e) => { + setInput(e.target.value); + }} + onKeyPress={searchBook} + /> + </> + ) : ( + <> + <SearchInput + type="text" + placeholder="검색어를 입력하세요" + // className="search-input" + value={input} + onChange={(e) => { + setInput(e.target.value); + }} + onKeyPress={searchBook} + /> + </> + )} + {input.length > 0 ? ( + <button + className="search-close-button" + onClick={(e) => { + setInput(""); + }} + > + X + </button> + ) : null} + </SearchInputWrap> + </label> + {input.length > 0 && isShow && searchData.length > 0 ? ( + // <SearchResultList + // book={searchData} + // onClick={(e) => { + // e.stopPropagation(); + // }} + // /> + <SearchResultListModal + book={searchData} + addInput={setInput} + onClick={(e) => { + e.stopPropagation(); + }} + /> + ) : null} + </section> + ); +}; + +export default SearchBox; + +const SearchInputWrap = styled.div` + width: 100%; + height: 60px; + box-shadow: 0px 2px 4px #00000033; + padding: 10px 0px 10px 1rem; + border-radius: 5px; + border: 1px solid #b0b0b0; + display: flex; + align-items: center; + font-size: 20px; + /* margin-bottom: 40px; */ +`; + +const SelectMenu = styled.select` + width: 140px; + font-size: 20px; + border: none; + /* padding-left: 10px; */ + text-align: center; + &:focus { + outline: none; + } +`; + +const SearchInput = styled.input` + border: none; + border-left: 1px solid #c0c0c0; + margin-left: 1rem; + padding-left: 1rem; + font-size: 20px; + width: 100%; + &:focus { + outline: none; + } +`; \ No newline at end of file diff --git a/src/pages/Search.jsx b/src/pages/Search.jsx index 10def8f..d1bacbc 100644 --- a/src/pages/Search.jsx +++ b/src/pages/Search.jsx @@ -4,7 +4,7 @@ import axios from "axios"; // COMPONENTS import Header from "../components/Header"; -import SearchResultList from "../components/SearchResultList"; +import SearchResultListModal from "../components/SearchResultListModal"; // STYLES import "../styles/SearchStyles.css"; @@ -19,9 +19,9 @@ import bookImg8 from "../assets/category-book-언어.jpg"; import bookImg9 from "../assets/category-book-문학.png"; import bookImg10 from "../assets/category-book-역사.jpg"; import { LoginContext } from "../contexts/LoginContextProvider"; -import SearchResultListModal from './../components/SearchResultListModal'; import api from "../services/api"; + const Search = () => { const baseURL = "https://api.bookpharmacy.store/api"; const navigate = useNavigate(); diff --git a/src/pages/SearchResult.jsx b/src/pages/SearchResult.jsx index e8e8e58..ca55c50 100644 --- a/src/pages/SearchResult.jsx +++ b/src/pages/SearchResult.jsx @@ -1,46 +1,112 @@ import React, { useEffect, useState } from "react"; -import { Link, useParams } from "react-router-dom"; +import { Link, useNavigate, useParams } from "react-router-dom"; import Header from "../components/Header"; import styled from "styled-components"; import closeIcon from "../assets/closeIconRound.svg"; import starIcon from "../assets/icons8-별-30 (1).png"; import api from "./../services/api"; +import Pagination from "../components/Pagination"; +import SearchBox from "../components/SearchBox"; const SearchResult = () => { - const { title } = useParams(); - const [viewMode, setViewMode] = useState(true); - const [books, setBooks] = useState([]); - const [size, setSize] = useState(10); - let searchResultsCount = 1234; - searchResultsCount = searchResultsCount.toLocaleString(); - let searchResultsKeywordCount = 123; - let reviewCount = 123; + const navigate = useNavigate(); + const { title } = useParams(); // path로 책 제목 가져오기 + const [viewMode, setViewMode] = useState(true); // 책 뷰 선택(리스트/카드) + const [books, setBooks] = useState([]); // 책 정보 + const [currentPage, setCurrentPage] = useState(1); // 현재 페이지 + const [booksPerPage, setBooksPerPage] = useState(10); // 페이지당 책 수 + const [loading, setLoading] = useState(false); // 로딩 + + const [input, setInput] = useState(""); // 검색 데이터 + const [searchType, setSearchType] = useState("title"); // 검색 유형 상태 + const [searchData, setSearchData] = useState([]); // 검색 결과 데이터 + const [isShow, setIsShow] = useState(false); // 검색창 모달창 + + useEffect(() => { + const timer = setTimeout(() => { + fetchBooks(input); + }, 100); + + // cleanup 함수를 반환하여 컴포넌트가 언마운트될 때 타이머를 해제합니다. + return () => clearTimeout(timer); + }, [input]); + + const fetchBooks = async (searchInput) => { + if (input.trim() === "") return; // 빈 문자열일 때 API 호출 방지 + + let endpoint = ""; + if (searchType === "title") { + endpoint = `/api/search/book?title=${searchInput}&target=modal`; + } + if (searchType === "author") { + endpoint = `/api/search/book?author=${searchInput}&target=modal`; + } + if (searchType === "keyword") { + endpoint = `/api/search/keyword?name=${searchInput}&target=modal`; + } + + try { + const response = await api.get(endpoint); + console.log("test", searchType, response.data); + setSearchData(response.data); + } catch (error) { + console.error("Failed to fetch books:", error); + } + }; + + const searchBook = (evt) => { + if (evt.key === "Enter") { + fetchBooks(input); + if (input.length > 0) navigate(`/search/result/${input}`); + setIsShow(false); + } + }; + + // 현재 책들 정보 + const indexOfLastBook = currentPage * booksPerPage; + const indexOfFirstBook = indexOfLastBook - booksPerPage; + console.log(indexOfFirstBook, indexOfLastBook); + const currentBooks = books.slice(indexOfFirstBook, indexOfLastBook); + + // 페이지 변경 + const paginate = (pageNumber) => setCurrentPage(pageNumber); + + console.log(books.length); + console.log(currentBooks); useEffect(() => { const getSearchResults = async () => { + setLoading(true); try { const response = await api.get( - `/api/search/book?title=${title}&target=page&page=0&size=${size}` + // `/api/search/book?title=${title}&target=page&page=${currentPage-1}&size=${booksPerPage}` + `/api/search/book?title=${title}&target=page&page=0&size=999` ); - console.log(response.data) + console.log(response.data); setBooks(response.data); + setLoading(false); } catch (error) { console.error("책 데이터 GET 요청 실패", error); } }; getSearchResults(); - }, [size]); + }, [title]); + + let searchResultsCount = books.length; + searchResultsCount = searchResultsCount.toLocaleString(); + let searchResultsKeywordCount = 123; + let reviewCount = 123; - const handleSizeChange = (event) => { - setSize(event.target.value); - }; + const handleSizeChange = (event) => { + setBooksPerPage(event.target.value); + }; return ( <> <Header /> - <Main> + <Main onClick={() => setIsShow(false)}> {/* 검색창 컴포넌트 만들어야함 */} - <SearchInputWrap> + {/* <SearchInputWrap> <SelectMenu> <option value="title" selected> 제목 @@ -49,7 +115,17 @@ const SearchResult = () => { <option value="keyword">키워드</option> </SelectMenu> <SearchInput type="text" placeholder="검색어를 입력하세요" /> - </SearchInputWrap> + </SearchInputWrap> */} + <SearchBox + input={input} + setInput={setInput} + searchType={searchType} + setSearchType={setSearchType} + isShow={isShow} + setIsShow={setIsShow} + searchBook={searchBook} + searchData={searchData} + /> <section id="search-title" style={{ marginBottom: "80px" }}> <h1 style={{ fontSize: "30px", fontWeight: "bold" }}> @@ -125,7 +201,7 @@ const SearchResult = () => { marginLeft: "10px", }} onChange={handleSizeChange} - value={size} + value={booksPerPage} > <option value="10" selected> 10개씩 보기 @@ -200,7 +276,8 @@ const SearchResult = () => { <div> {viewMode ? ( <ListUIWrap> - {books.map((book, index) => ( + {/* {books.map((book, index) => ( */} + {currentBooks.map((book, index) => ( <Link to={`/book-detail/${book.title}`}> <li key={index} @@ -219,7 +296,8 @@ const SearchResult = () => { width: "170px", backgroundColor: "gray", borderRadius: "5px", - objectFit: "cover", + // objectFit: "cover", + border: "1px solid #c0c0c0", }} /> <div style={{ padding: "1rem 0px 0px 1rem" }}> @@ -245,12 +323,27 @@ const SearchResult = () => { </div> <div style={{ marginBottom: "40px" }}> <ul style={{ display: "flex", flexWrap: "wrap" }}> - <BookKeyword> + <BookKeyword + onClick={(e) => { + e.preventDefault(); + navigate( + `/search/result/${book.middleCategoryName}` + ); + }} + > {book.middleCategoryName} </BookKeyword> {book.bookKeywordList.map((keyword, index) => { return ( - <BookKeyword key={index}> + <BookKeyword + key={index} + onClick={(e) => { + e.preventDefault(); + navigate( + `/search/result/${keyword.name}` + ); + }} + > {keyword.name} </BookKeyword> ); @@ -304,7 +397,8 @@ const SearchResult = () => { </ListUIWrap> ) : ( <CardUIWrap> - {books.map((book, index) => ( + {/* {books.map((book, index) => ( */} + {currentBooks.map((book, index) => ( <Link to={`/book-detail/${book.title}`}> <li key={index} style={{ width: "170px" }}> <div @@ -323,22 +417,18 @@ const SearchResult = () => { style={{ width: "100%", height: "100%", - objectFit: "cover", + // objectFit: "cover", border: "1px solid #c0c0c0", }} /> </div> - <BookTitle> - {book.title} - </BookTitle> + <BookTitle>{book.title}</BookTitle> <h3 style={{ color: "#6B6B6B", marginBottom: "10px" }}> {book.author} </h3> <h1 style={{ marginBottom: "10px" }}> 평균 ★{book.rating}{" "} - <span style={{ color: "gray" }}> - ({reviewCount}) - </span> + <span style={{ color: "gray" }}>({reviewCount})</span> </h1> <div style={{ @@ -384,6 +474,12 @@ const SearchResult = () => { </CardUIWrap> )} </div> + <Pagination + booksPerPage={booksPerPage} + totalBooks={books.length} + paginate={paginate} + bookTitle={title} + /> </section> </ContentsWrap> </Main> @@ -418,6 +514,9 @@ const SelectMenu = styled.select` border: none; /* padding-left: 10px; */ text-align: center; + &:focus { + outline: none; + } `; const SearchInput = styled.input` @@ -482,4 +581,4 @@ const BookTitle = styled.h2` font-size: 20px; font-weight: bold; margin-bottom: 5px; -`; \ No newline at end of file +`; diff --git a/src/services/books.js b/src/services/books.js new file mode 100644 index 0000000..b3a770c --- /dev/null +++ b/src/services/books.js @@ -0,0 +1,7 @@ +import React from 'react' + +export const books = (page, limit) => { + let array = []; + + return +} diff --git a/src/styles/SearchStyles.css b/src/styles/SearchStyles.css index a0c0173..428c1bd 100644 --- a/src/styles/SearchStyles.css +++ b/src/styles/SearchStyles.css @@ -58,8 +58,8 @@ width: 50px; height: 40px; font-size: 1.5rem; - position: relative; - right: 0; + position: absolute; + right: 70px; background-color: #fff; } From c2322ef2232ef0985be543e8ebd03038d78c0119 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Tue, 12 Mar 2024 00:51:28 +0900 Subject: [PATCH 26/31] =?UTF-8?q?:art:=20Design:=20=EA=B2=BD=ED=97=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EA=B8=B0=20=EB=AA=A8=EB=8B=AC?= =?UTF-8?q?=EC=B0=BD=20=EB=94=94=EC=9E=90=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BookDetailCard.jsx | 116 +++++++++++++++++++-------- src/components/Button.jsx | 2 +- src/components/Modal/Experience.jsx | 44 +++++++++++ src/pages/BookDetail.jsx | 19 ++++- src/styles/BookDetailCard.css | 90 +++++++++++++++++++++ src/styles/Experience.css | 117 ++++++++++++++++++++++++++++ 6 files changed, 353 insertions(+), 35 deletions(-) create mode 100644 src/components/Modal/Experience.jsx create mode 100644 src/styles/Experience.css diff --git a/src/components/BookDetailCard.jsx b/src/components/BookDetailCard.jsx index 6746840..13f7d7d 100644 --- a/src/components/BookDetailCard.jsx +++ b/src/components/BookDetailCard.jsx @@ -7,45 +7,95 @@ import HashTag from '../components/HashTag'; //STYLES import '../styles/BookDetailCard.css'; -const BookDetailCard = ({ title, author, imageUrl, isbn, bookKeywordList }) => { - return ( - <> - <Link to={`/book-detail?isbn=${isbn}`}> - <div className="bookCard_container"> - <div className="bookCard_wrapper"> - <div className="bookCard_left_wrapper"> - <div className="left_img_wrapper"> - <img - className="img_wrapper_thumbnail" - src={imageUrl} - alt="썸네일" - /> - </div> - </div> +const BookDetailCard = ({ + title, + author, + imageUrl, + isbn, + bookKeywordList, + type, +}) => { + let cardType = ['expModal'].includes(type) ? type : ''; - <div className="bookCard_right_wrapper"> - <div className="bookCard_right_up_wrapper"> - <div className="right_up_title" title={title}> - {title} + const renderCard = (type) => { + if (type === 'expModal') { + return ( + <> + <Link to={`/book-detail?isbn=${isbn}`}> + <div className="expModal_bookCard_container"> + <div className="expModal_bookCard_wrapper"> + <div className="expModal_bookCard_left_wrapper"> + <div className="expModal_left_img_wrapper"> + <img + className="expModal_img_wrapper_thumbnail" + src={imageUrl} + alt="썸네일" + /> + </div> </div> - <div className="right_up_author">{author}</div> - </div> - <div className="bookCard_right_bottom_wrapper"> - {bookKeywordList.map((keyword, idx) => { - return ( - <HashTag - key={`${isbn}keyword-${idx}`} - text={keyword.name} - type="sm-category" + <div className="expModal_bookCard_right_wrapper"> + <div className="expModal_bookCard_right_up_wrapper"> + <div className="expModal_right_up_title" title={title}> + {title} + </div> + <div className="expModal_right_up_author">{author}</div> + </div> + + <div className="expModal_bookCard_right_bottom_wrapper"></div> + </div> + </div> + </div> + </Link> + </> + ); + } else { + return ( + <> + <Link to={`/book-detail?isbn=${isbn}`}> + <div className="bookCard_container"> + <div className="bookCard_wrapper"> + <div className="bookCard_left_wrapper"> + <div className="left_img_wrapper"> + <img + className="img_wrapper_thumbnail" + src={imageUrl} + alt="썸네일" /> - ); - })} + </div> + </div> + + <div className="bookCard_right_wrapper"> + <div className="bookCard_right_up_wrapper"> + <div className="right_up_title" title={title}> + {title} + </div> + <div className="right_up_author">{author}</div> + </div> + + <div className="bookCard_right_bottom_wrapper"> + {bookKeywordList.map((keyword, idx) => { + return ( + <HashTag + key={`${isbn}keyword-${idx}`} + text={keyword.name} + type="sm-category" + /> + ); + })} + </div> + </div> </div> </div> - </div> - </div> - </Link> + </Link> + </> + ); + } + }; + + return ( + <> + <div>{renderCard(cardType)}</div> </> ); }; diff --git a/src/components/Button.jsx b/src/components/Button.jsx index f1934ba..487e0be 100644 --- a/src/components/Button.jsx +++ b/src/components/Button.jsx @@ -39,7 +39,7 @@ const Button = ({ text, type }) => { }; const renderButton = (url, type) => { - if (type === 'add' || type === 'delete') { + if (type === 'add' || type === 'delete' || type === 'exp') { return <button className={styles[`Btn-${type}`]}>{text}</button>; } else { if (type === 'logout') { diff --git a/src/components/Modal/Experience.jsx b/src/components/Modal/Experience.jsx new file mode 100644 index 0000000..134702d --- /dev/null +++ b/src/components/Modal/Experience.jsx @@ -0,0 +1,44 @@ +import React, { useState } from 'react'; + +// COMPONENTS +import BookInfoCard from '../BookDetailCard'; + +// STYLE +import '../../styles/Experience.css'; + +const Experience = ({ onClose }) => { + // 모달 창 닫는 함수 + const handleClose = () => { + onClose?.(); + }; + + return ( + <> + <div className="expModal_overlay"> + <div className="expModal_wrapper"> + <div className="expModal_title_wrapper"> + 리뷰작성 + <div className="close_btn" onClick={handleClose}> + X + </div> + </div> + <div className="expModal_content_wrapper"> + <div className="bookInfo_content_wrapper"> + <BookInfoCard type="expModal" title={'해리포터'} /> + </div> + <div className="inputReview_wrapper"> + <div className="inputReview_title">리뷰작성</div> + <input type="text" className="inputReview_box" /> + </div> + <div className="expModal_button_wrapper"> + <button className="review_btn">리뷰 남기기</button> + <button className="later_btn">피드만 나중에</button> + </div> + </div> + </div> + </div> + </> + ); +}; + +export default Experience; diff --git a/src/pages/BookDetail.jsx b/src/pages/BookDetail.jsx index ea5cb98..266b1ba 100644 --- a/src/pages/BookDetail.jsx +++ b/src/pages/BookDetail.jsx @@ -12,6 +12,9 @@ import Review from '../components/Review'; import Title from '../components/ArrowTitle'; import BookCard from '../components/BookCard'; import Footer from '../components/Footer'; +import ModalPortal from '../components/Modal/Portal'; +import ExpModal from '../components/Modal/Experience'; +import MyListModal from '../components/Modal/MyListModal'; // STYLES import '../styles/BookDetail.css'; @@ -22,6 +25,12 @@ const BookDetail = () => { ref.scrollIntoView({ behavior: 'smooth' }); }; + const [modalOn, setModalOn] = useState(false); + + const handleModal = () => { + setModalOn(!modalOn); + }; + const [searchParams, setSearchParams] = useSearchParams(); const [bookInfo, setBookInfo] = useState([]); const [bookKeywordList, setBookKeywordList] = useState([]); @@ -65,8 +74,16 @@ const BookDetail = () => { </div> <div className="right_up_right_wrapper"> <div className="up_right_exp"> - <Btn text={'경험 추가하기'} type="exp" /> + {/* <Btn + text={'경험 추가하기'} + type="exp" + onClick={handleModal} + /> */} + <div onClick={handleModal}>경험추가하기</div> </div> + <ModalPortal> + {modalOn && <ExpModal onClose={handleModal} />} + </ModalPortal> </div> </div> <div className="summary_left_mid_wrapper"> diff --git a/src/styles/BookDetailCard.css b/src/styles/BookDetailCard.css index c15183b..e4780e7 100644 --- a/src/styles/BookDetailCard.css +++ b/src/styles/BookDetailCard.css @@ -84,3 +84,93 @@ padding-top: 60px; overflow: auto; } + +/* 경험 추가하기 모달창 */ + +.expModal_bookCard_container { + width: 639px; + height: 200px; + background: #ffffff; + margin: 10px; + cursor: pointer; + + /* Drop Shadow */ + /* box-shadow: 6px 6px 30px rgba(119, 119, 119, 0.466667); */ + box-shadow: 0px 1px 13px rgba(119, 119, 119, 0.466667); + border-radius: 15px; +} + +/* .expModal_bookCard_container:hover { + background: #a4d6dd; +} */ + +.expModal_bookCard_wrapper { + display: flex; + align-items: center; + padding: 14px 10px; +} + +.expModal_bookCard_left_wrapper { + padding-left: 5px; +} + +.expModal_left_img_wrapper { + width: 120px; + height: 170px; + background: #a1a1a1; + + box-shadow: 2px 2px 4px rgba(119, 119, 119, 0.25); + border: solid #a1a1a1; + border-radius: 5px; +} + +.expModal_img_wrapper_thumbnail { + width: 120px; + height: 170px; + border-radius: 5px; +} + +.expModal_bookCard_right_wrapper { + height: 170px; + display: flex; + flex-direction: column; + margin-left: 20px; +} + +.expModal_bookCard_right_up_wrapper { + display: flex; + flex-direction: column; +} + +.expModal_right_up_title { + width: 260px; + + /* Font */ + font-family: var(--basic-font); + font-style: normal; + font-weight: 700; + font-size: 18px; + line-height: 21px; + color: #000; + + /* 말 줄임 */ + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.expModal_right_up_author { + font-family: var(--basic-font); + font-style: normal; + font-weight: 500; + font-size: 16px; + line-height: 19px; + color: #000; +} + +.expModal_bookCard_right_bottom_wrapper { + width: 260px; + height: 130px; + padding-top: 60px; + overflow: auto; +} diff --git a/src/styles/Experience.css b/src/styles/Experience.css new file mode 100644 index 0000000..ab4e33e --- /dev/null +++ b/src/styles/Experience.css @@ -0,0 +1,117 @@ +.expModal_overlay { + position: fixed; + width: 100%; + height: 100%; + top: 0; + bottom: 0; + left: 0; + right: 0; + background: rgba(0, 0, 0, 0.2); + z-index: 9999; +} + +.expModal_wrapper { + width: 690px; + height: 600px; + display: flex; + flex-direction: column; + align-items: center; + padding: 30px 30px; + border-radius: 15px; + background-color: #fff; + position: absolute; + top: 53%; + left: 50%; + transform: translate(-50%, -50%); +} + +.expModal_title_wrapper { + display: flex; + width: 630px; + justify-content: space-between; + + /* Font */ + font-family: var(--basic-font); + font-style: normal; + font-weight: 600; + font-size: 24px; + line-height: 0px; +} + +.expModal_title_wrapper .close_btn { + cursor: pointer; + + /* Font */ + font-family: var(--basic-font); + font-style: normal; + font-weight: 200; + font-size: 24px; + line-height: 0px; + color: #575757; +} + +.expModal_content_wrapper { + display: flex; + flex-direction: column; + align-items: center; + width: 660px; + height: 570px; + margin-top: 20px; +} + +.bookInfo_content_wrapper { + width: 100%; +} + +.inputReview_wrapper { + display: flex; + flex-direction: column; + margin-top: 35px; +} + +.inputReview_title { + /* Font */ + font-family: var(--basic-font); + font-style: normal; + font-weight: 600; + font-size: 18px; + line-height: 21px; +} + +.inputReview_box { + width: 640px; + height: 125px; + border: 1px solid #868686; + border-radius: 15px; + margin-top: 15px; + + /* Font */ + font-family: var(--basic-font); + font-style: normal; + font-weight: 700; + font-size: 14px; + line-height: 0px; +} + +.expModal_button_wrapper { + display: flex; + justify-content: space-around; + width: 100%; + margin-top: 40px; +} + +.review_btn, +.later_btn { + width: 300px; + height: 60px; + background-color: #c8edf2; + border-radius: 10px; + + /* Font */ + text-align: center; + font-family: var(--basic-font); + font-size: 20px; + font-weight: 600; + font-style: normal; + line-height: 0px; +} From e16d2fa8c239ead806f1cfbf937c12853e7046b3 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Tue, 12 Mar 2024 17:54:07 +0900 Subject: [PATCH 27/31] =?UTF-8?q?:art:=20Design:=20=EA=B2=BD=ED=97=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EA=B8=B0=20=EB=AA=A8=EB=8B=AC?= =?UTF-8?q?=EC=B0=BD=20=EC=8A=A4=ED=81=AC=EB=A1=A4=EB=B0=94=20=EB=94=94?= =?UTF-8?q?=EC=9E=90=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BookDetailCard.jsx | 38 ++++++++++++++--------------- src/components/Modal/Experience.jsx | 37 +++++++++++++++++++++++++--- src/styles/BookDetailCard.css | 9 ++----- src/styles/Experience.css | 28 +++++++++++++++++++-- 4 files changed, 80 insertions(+), 32 deletions(-) diff --git a/src/components/BookDetailCard.jsx b/src/components/BookDetailCard.jsx index 13f7d7d..3e2f88e 100644 --- a/src/components/BookDetailCard.jsx +++ b/src/components/BookDetailCard.jsx @@ -21,32 +21,30 @@ const BookDetailCard = ({ if (type === 'expModal') { return ( <> - <Link to={`/book-detail?isbn=${isbn}`}> - <div className="expModal_bookCard_container"> - <div className="expModal_bookCard_wrapper"> - <div className="expModal_bookCard_left_wrapper"> - <div className="expModal_left_img_wrapper"> - <img - className="expModal_img_wrapper_thumbnail" - src={imageUrl} - alt="썸네일" - /> - </div> + <div className="expModal_bookCard_container"> + <div className="expModal_bookCard_wrapper"> + <div className="expModal_bookCard_left_wrapper"> + <div className="expModal_left_img_wrapper"> + <img + className="expModal_img_wrapper_thumbnail" + src={imageUrl} + alt="썸네일" + /> </div> + </div> - <div className="expModal_bookCard_right_wrapper"> - <div className="expModal_bookCard_right_up_wrapper"> - <div className="expModal_right_up_title" title={title}> - {title} - </div> - <div className="expModal_right_up_author">{author}</div> + <div className="expModal_bookCard_right_wrapper"> + <div className="expModal_bookCard_right_up_wrapper"> + <div className="expModal_right_up_title" title={title}> + {title} </div> - - <div className="expModal_bookCard_right_bottom_wrapper"></div> + <div className="expModal_right_up_author">{author}</div> </div> + + <div className="expModal_bookCard_right_bottom_wrapper"></div> </div> </div> - </Link> + </div> </> ); } else { diff --git a/src/components/Modal/Experience.jsx b/src/components/Modal/Experience.jsx index 134702d..beec330 100644 --- a/src/components/Modal/Experience.jsx +++ b/src/components/Modal/Experience.jsx @@ -1,4 +1,8 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; +import { useSearchParams } from 'react-router-dom'; + +// SERVICE +import api from '../../services/api'; // COMPONENTS import BookInfoCard from '../BookDetailCard'; @@ -12,6 +16,21 @@ const Experience = ({ onClose }) => { onClose?.(); }; + const [bookInfo, setBookInfo] = useState([]); + const [searchParams, setSearchParams] = useSearchParams(); + + const getIsbn = () => { + let isbn = searchParams.get('isbn'); + + api.get(`/api/book/detail?isbn=${isbn}`).then((res) => { + setBookInfo(res.data); + }); + }; + + useEffect(() => { + getIsbn(); + }, []); + return ( <> <div className="expModal_overlay"> @@ -24,11 +43,23 @@ const Experience = ({ onClose }) => { </div> <div className="expModal_content_wrapper"> <div className="bookInfo_content_wrapper"> - <BookInfoCard type="expModal" title={'해리포터'} /> + <BookInfoCard + type="expModal" + title={bookInfo.title} + author={bookInfo.author} + imageUrl={bookInfo.imageUrl} + isbn={bookInfo.isbn} + /> </div> <div className="inputReview_wrapper"> <div className="inputReview_title">리뷰작성</div> - <input type="text" className="inputReview_box" /> + <textarea + name="contents" + rows="10" + cols="50" + type="text" + className="inputReview_box" + /> </div> <div className="expModal_button_wrapper"> <button className="review_btn">리뷰 남기기</button> diff --git a/src/styles/BookDetailCard.css b/src/styles/BookDetailCard.css index e4780e7..0e45a7e 100644 --- a/src/styles/BookDetailCard.css +++ b/src/styles/BookDetailCard.css @@ -92,7 +92,6 @@ height: 200px; background: #ffffff; margin: 10px; - cursor: pointer; /* Drop Shadow */ /* box-shadow: 6px 6px 30px rgba(119, 119, 119, 0.466667); */ @@ -115,12 +114,8 @@ } .expModal_left_img_wrapper { - width: 120px; height: 170px; - background: #a1a1a1; - box-shadow: 2px 2px 4px rgba(119, 119, 119, 0.25); - border: solid #a1a1a1; border-radius: 5px; } @@ -164,8 +159,8 @@ font-style: normal; font-weight: 500; font-size: 16px; - line-height: 19px; - color: #000; + line-height: 29px; + color: #868686; } .expModal_bookCard_right_bottom_wrapper { diff --git a/src/styles/Experience.css b/src/styles/Experience.css index ab4e33e..bede7c7 100644 --- a/src/styles/Experience.css +++ b/src/styles/Experience.css @@ -82,15 +82,39 @@ width: 640px; height: 125px; border: 1px solid #868686; - border-radius: 15px; + border-radius: 5px; margin-top: 15px; + padding: 10px 10px; + resize: none; + overflow: auto; /* Font */ font-family: var(--basic-font); font-style: normal; font-weight: 700; font-size: 14px; - line-height: 0px; + line-height: 1.5em; +} + +.inputReview_box::-webkit-scrollbar { + width: 10px; +} + +.inputReview_box::-webkit-scrollbar-button { + display: none; +} + +.inputReview_box::-webkit-scrollbar-thumb { + background-color: #67b6c1; + border-radius: 20px; + background-clip: padding-box; + border: 2px solid transparent; +} + +.inputReview_box::-webkit-scrollbar-track { + background-color: #fff; + border-radius: 20px; + box-shadow: inset 0px 0px 5px #fff; } .expModal_button_wrapper { From 69188ec78eb604ba52c10ae11019aaad84cc8302 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Tue, 12 Mar 2024 18:14:19 +0900 Subject: [PATCH 28/31] =?UTF-8?q?:lipstick:=20Style:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EC=A0=84=20=ED=99=88=ED=99=94=EB=A9=B4=20=ED=97=A4?= =?UTF-8?q?=EB=8D=94=20=EA=B3=A0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/HomeStyles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/HomeStyles.css b/src/styles/HomeStyles.css index 001bef6..f4e7b8a 100644 --- a/src/styles/HomeStyles.css +++ b/src/styles/HomeStyles.css @@ -16,7 +16,7 @@ width: 100%; z-index: 100; background-color: hsla(0, 0%, 100%, 0.9); - /* top: 0; */ + top: 0; } .home_header { From 7d2e6a2ae7141c488d69f3388396f6aa19073db9 Mon Sep 17 00:00:00 2001 From: Youngbae1126 <rcplaza2663@gmail.com> Date: Wed, 13 Mar 2024 13:53:04 +0900 Subject: [PATCH 29/31] =?UTF-8?q?:sparkles:=20Feat:=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20api=20=EC=9A=94=EC=B2=AD=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Login.jsx | 534 +++++++++++++++++++++--------------------- src/pages/Signup2.jsx | 39 ++- 2 files changed, 302 insertions(+), 271 deletions(-) diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index 0c2ed75..6ceaa52 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -1,88 +1,88 @@ -import React, { useContext, useEffect, useState } from "react"; -import { Link, useNavigate } from "react-router-dom"; -import axios from "axios"; +import React, { useContext, useEffect, useState } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import axios from 'axios'; // SERVICE -import api from "../services/api"; +import api from '../services/api'; // COMPONENTS -import Btn from "../components/Button"; +import Btn from '../components/Button'; // ASSETS -import kakaoIcon from "../assets/kakao-icon.jpg"; -import naverIcon from "../assets/naver-icon.jpg"; -import banner from "../assets/Login-Banner.png"; +import kakaoIcon from '../assets/kakao-icon.jpg'; +import naverIcon from '../assets/naver-icon.jpg'; +import banner from '../assets/Login-Banner.png'; // STYLE -import { styled } from "styled-components"; -import { login } from "../services/login"; -import { LoginContext } from "../contexts/LoginContextProvider"; +import { styled } from 'styled-components'; +import { login } from '../services/login'; +import { LoginContext } from '../contexts/LoginContextProvider'; export default function Login() { - const { setUserId, setUserPwd } = useContext(LoginContext); - const [id, setId] = useState(""); - const [pwd, setPwd] = useState(""); - const router = useNavigate(); - const [notAllow, setNotAllow] = useState(true); - - const [idValid, setIdValid] = useState(false); - const [pwdValid, setPwdValid] = useState(false); - - const handleInputChange = (e) => { - const { name, value } = e.target; - - if (name === "id") { - setId(value); - if (value.length >= 1) { - setIdValid(true); - } else { - setIdValid(false); - } - } - - if (name === "password") { - setPwd(value); - const regex = - /^(?=.*[a-zA-z])(?=.*[0-9])(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+])(?!.*[^a-zA-z0-9$`~!@$!%*#^?&\\(\\)\-_=+]).{8,20}$/; - if (regex.test(value)) { - setPwdValid(true); - } else { - setPwdValid(false); - } - } - }; - - const handleDeleteButtonClick = (inputType) => { - if (inputType === "Id") { - setId(""); - setIdValid(false); - } else if (inputType === "password") { - setPwd(""); - setPwdValid(false); - } - }; - - // 나중에 상태관리 사용해서 로그인 관리하도록 하기 - // refresh에 대한 post 요청 api 추가해야할거같음 - useEffect(() => { - localStorage.clear(); - }); - - const loginData = { username: id, password: pwd }; - - const postLogin = () => { - // console.log('아이디:', id, '비번:', pwd); - setUserId(id); - setUserPwd(pwd); - if (id.length > 0 && pwd.length > 0) { - api - .post("/login", loginData, { - withCredentials: true, - }) - .then((res) => { - // console.log(res); - localStorage.setItem("id", id); - localStorage.setItem("password", pwd); + const { setUserId, setUserPwd } = useContext(LoginContext); + const [id, setId] = useState(''); + const [pwd, setPwd] = useState(''); + const router = useNavigate(); + const [notAllow, setNotAllow] = useState(true); + + const [idValid, setIdValid] = useState(false); + const [pwdValid, setPwdValid] = useState(false); + + const handleInputChange = (e) => { + const { name, value } = e.target; + + if (name === 'id') { + setId(value); + if (value.length >= 1) { + setIdValid(true); + } else { + setIdValid(false); + } + } + + if (name === 'password') { + setPwd(value); + const regex = + /^(?=.*[a-zA-z])(?=.*[0-9])(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+])(?!.*[^a-zA-z0-9$`~!@$!%*#^?&\\(\\)\-_=+]).{8,20}$/; + if (regex.test(value)) { + setPwdValid(true); + } else { + setPwdValid(false); + } + } + }; + + const handleDeleteButtonClick = (inputType) => { + if (inputType === 'Id') { + setId(''); + setIdValid(false); + } else if (inputType === 'password') { + setPwd(''); + setPwdValid(false); + } + }; + + // 나중에 상태관리 사용해서 로그인 관리하도록 하기 + // refresh에 대한 post 요청 api 추가해야할거같음 + useEffect(() => { + localStorage.clear(); + }); + + const loginData = { username: id, password: pwd }; + + const postLogin = () => { + // console.log('아이디:', id, '비번:', pwd); + setUserId(id); + setUserPwd(pwd); + if (id.length > 0 && pwd.length > 0) { + api + .post('/login', loginData, { + withCredentials: true, + }) + .then((res) => { + // console.log(res); + localStorage.setItem('id', id); + localStorage.setItem('password', pwd); window.location.replace('/main'); }) @@ -97,65 +97,65 @@ export default function Login() { window.open('https://api.bookpharmacy.store/oauth2/authorization/naver'); }; - useEffect(() => { - if (idValid && pwdValid) { - setNotAllow(false); - return; - } - setNotAllow(true); - }, [idValid, pwdValid]); - - return ( - <LoginContainer> - <ImageContent /> - <LoginContent> - <Title>Login - - - - {id.length > 0 && ( - handleDeleteButtonClick("Id")}> - X - - )} - - - {!idValid && id.length > 0 && ( -
    -

    4글자 이상 입력해주세요.

    -
    - )} -
    - - - - {pwd.length > 0 && ( - handleDeleteButtonClick("password")}> - X - - )} - - - {!pwdValid && pwd.length > 0 && ( -
    -

    영문, 숫자, 특수문자 포함 8자 이상 입력해주세요.

    -
    - )} -
    - - {/* 로그인 */} + useEffect(() => { + if (idValid && pwdValid) { + setNotAllow(false); + return; + } + setNotAllow(true); + }, [idValid, pwdValid]); + + return ( + + + + Login + + + + {id.length > 0 && ( + handleDeleteButtonClick('Id')}> + X + + )} + + + {!idValid && id.length > 0 && ( +
    +

    4글자 이상 입력해주세요.

    +
    + )} +
    + + + + {pwd.length > 0 && ( + handleDeleteButtonClick('password')}> + X + + )} + + + {!pwdValid && pwd.length > 0 && ( +
    +

    영문, 숫자, 특수문자 포함 8자 이상 입력해주세요.

    +
    + )} +
    + + {/* 로그인 */} { @@ -192,73 +192,73 @@ export default function Login() { } const LoginContainer = styled.div` - display: flex; - height: 100vh; - color: black; + display: flex; + height: 100vh; + color: black; `; const ImageContent = styled.div` - flex: 1; - max-width: 50%; - box-sizing: border-box; - background-image: url("../../public/Login-Banner.png"); - background: url(${banner}); - background-size: cover; - background-repeat: no-repeat; - background-position: center; + flex: 1; + max-width: 50%; + box-sizing: border-box; + background-image: url('../../public/Login-Banner.png'); + background: url(${banner}); + background-size: cover; + background-repeat: no-repeat; + background-position: center; `; const LoginContent = styled.div` - flex: 1; - max-width: 50%; - box-sizing: border-box; - height: 100%; - background: #fff; - padding: 128px 60px; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - overflow-y: auto; + flex: 1; + max-width: 50%; + box-sizing: border-box; + height: 100%; + background: #fff; + padding: 128px 60px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + overflow-y: auto; `; const Title = styled.h1` - font-size: 60px; - font-weight: 700; - margin-bottom: 60px; + font-size: 60px; + font-weight: 700; + margin-bottom: 60px; `; const InputWrap = styled.div` - margin-bottom: 15px; - position: relative; + margin-bottom: 15px; + position: relative; `; const ErrorMessageWrap = styled.div` - color: red; - font-weight: bold; - margin-bottom: 10px; - p { - font-size: 16px; - } + color: red; + font-weight: bold; + margin-bottom: 10px; + p { + font-size: 16px; + } `; const InputDelete = styled.button` - position: absolute; - right: 20px; - top: 50%; - transform: translateY(-50%); - background: none; - border: none; - font-size: 20px; - cursor: pointer; + position: absolute; + right: 20px; + top: 50%; + transform: translateY(-50%); + background: none; + border: none; + font-size: 20px; + cursor: pointer; `; const Input = styled.input` - box-sizing: border-box; - width: 100%; - height: 75px; - padding: 10px 12px; - border: 1px solid #000; - border-radius: 4px; - font-family: var(--basic-font); - font-size: 20px; + box-sizing: border-box; + width: 100%; + height: 75px; + padding: 10px 12px; + border: 1px solid #000; + border-radius: 4px; + font-family: var(--basic-font); + font-size: 20px; `; // const LoginButton = styled.button` @@ -276,103 +276,103 @@ const Input = styled.input` // `; const LoginButton = styled.button` - width: 100%; - height: 74px; - border-radius: 10px; - background: #c8edf2; - - /* Font */ - font-family: var(--basic-font); - font-style: normal; - font-weight: 600; - font-size: 32px; - line-height: 38px; - color: #525252; - - &:hover { - cursor: pointer; - } + width: 100%; + height: 74px; + border-radius: 10px; + background: #c8edf2; + + /* Font */ + font-family: var(--basic-font); + font-style: normal; + font-weight: 600; + font-size: 32px; + line-height: 38px; + color: #525252; + + &:hover { + cursor: pointer; + } `; const LoginSubMenu = styled.ul` - list-style: none; - display: flex; - justify-content: center; - margin: 20px; + list-style: none; + display: flex; + justify-content: center; + margin: 20px; `; const LoginSubMenuItem = styled.li` - a { - color: #818181; - font-size: 20px; - font-weight: 400; - position: relative; - margin: 0px 8px; - } - - &:not(:last-child) a::after { - content: ""; - height: 20px; - width: 1px; - background-color: #8b8b8b; - position: absolute; - top: 50%; - transform: translateY(-50%); - right: -8px; /* 위 a 마진만큼 - */ - } + a { + color: #818181; + font-size: 20px; + font-weight: 400; + position: relative; + margin: 0px 8px; + } + + &:not(:last-child) a::after { + content: ''; + height: 20px; + width: 1px; + background-color: #8b8b8b; + position: absolute; + top: 50%; + transform: translateY(-50%); + right: -8px; /* 위 a 마진만큼 - */ + } `; const Or = styled.div` - display: flex; - justify-content: center; - align-items: center; - color: #a5a5a5; - margin-bottom: 20px; - position: relative; - - p { - text-align: center; - font-size: 13px; - word-break: keep-all; - padding: 0px 24px; - background-color: white; - } - p::before { - content: ""; - display: block; - position: absolute; - height: 1px; - width: 45%; - top: 50%; - left: 0; - background-color: #a5a5a5; - } - p::after { - content: ""; - display: block; - position: absolute; - height: 1px; - width: 45%; - top: 50%; - right: 0; - background-color: #a5a5a5; - } + display: flex; + justify-content: center; + align-items: center; + color: #a5a5a5; + margin-bottom: 20px; + position: relative; + + p { + text-align: center; + font-size: 13px; + word-break: keep-all; + padding: 0px 24px; + background-color: white; + } + p::before { + content: ''; + display: block; + position: absolute; + height: 1px; + width: 45%; + top: 50%; + left: 0; + background-color: #a5a5a5; + } + p::after { + content: ''; + display: block; + position: absolute; + height: 1px; + width: 45%; + top: 50%; + right: 0; + background-color: #a5a5a5; + } `; const SnsList = styled.div` - display: flex; - justify-content: center; - align-items: center; - height: 50px; - - button { - padding: 0; - margin: 0px 10px; - height: 100%; - } - - img { - width: 50px; - height: 100%; - } + display: flex; + justify-content: center; + align-items: center; + height: 50px; + + button { + padding: 0; + margin: 0px 10px; + height: 100%; + } + + img { + width: 50px; + height: 100%; + } `; diff --git a/src/pages/Signup2.jsx b/src/pages/Signup2.jsx index 6671eae..145b884 100644 --- a/src/pages/Signup2.jsx +++ b/src/pages/Signup2.jsx @@ -2,6 +2,9 @@ import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { useForm, rules } from 'react-hook-form'; +// SERVICE +import api from '../services/api'; + // ASSETS import banner from '../assets/Login-Banner.png'; @@ -274,6 +277,9 @@ const Signup2 = () => { const [emailDomain, setEmailDomain] = useState(''); const [isInputEnabled, setIsInputEnabled] = useState(false); + // 직업 정보 + const [job, setJob] = useState(''); + // 모든 것을 작성해야 가입하기 버튼 클릭 활성화 const [isButtonEnabled, setIsButtonEnabled] = useState(true); @@ -323,6 +329,11 @@ const Signup2 = () => { setBirthDate(e.target.value); }; + const handleJobChange = (e) => { + // console.log(e.target.value); + setJob(e.target.value); + }; + const handleGenderButtonClick = (gender) => { if (gender === 'male') { setIsMaleClicked(true); @@ -358,7 +369,27 @@ const Signup2 = () => { // setEmailDomain이 변경될 때마다 실행 setEmail(`${emailUsername}@${emailDomain}`); }, [emailUsername, emailDomain]); - console.log(emailDomain); + // console.log(emailDomain); + + const signUpData = { + username: id, + password: pwd, + name: name, + nickname: nickname, + email: email, + gender: gender, + occupation: job, + }; + + const postSignup = () => { + api + .post('/signup', signUpData, { + withCredentials: true, + }) + .then((res) => { + console.log(res.data); + }); + }; return ( @@ -541,7 +572,7 @@ const Signup2 = () => {

    직업 선택

    - + @@ -554,8 +585,8 @@ const Signup2 = () => {
    - - 네, 동의합니다 + + {/* 네, 동의합니다 */}
    From 23964854342aca07a5d7949af159327a6075d3b3 Mon Sep 17 00:00:00 2001 From: Youngbae1126 Date: Wed, 13 Mar 2024 14:59:59 +0900 Subject: [PATCH 30/31] =?UTF-8?q?:sparkles:=20Feat:=20=EB=AC=B4=ED=95=9C?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/FeedCard.js | 10 +++--- src/pages/Feed.jsx | 66 ++++++++++++++++++++++++++++++++++++-- src/styles/Feed.css | 10 +++--- src/styles/FeedCard.css | 18 ++++++++--- 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/src/components/FeedCard.js b/src/components/FeedCard.js index c9d17f2..b9d7496 100644 --- a/src/components/FeedCard.js +++ b/src/components/FeedCard.js @@ -3,7 +3,7 @@ import React from 'react'; //STYLES import '../styles/FeedCard.css'; -const FeedCard = ({ book_name, book_author, user_nickname }) => { +const FeedCard = ({ title, author, nickname, imgUrl }) => { return ( <>
    @@ -16,10 +16,12 @@ const FeedCard = ({ book_name, book_author, user_nickname }) => {
    -
    +
    + +
    -
    서시
    -
    윤동주
    +
    {title}
    +
    {author}
    diff --git a/src/pages/Feed.jsx b/src/pages/Feed.jsx index 4013942..74bda8d 100644 --- a/src/pages/Feed.jsx +++ b/src/pages/Feed.jsx @@ -1,13 +1,65 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; // COMPONENTS import Header from '../components/Header'; import FeedGrid from '../components/FeedGrid'; +import FeedCard from '../components/FeedCard'; // STYLES import '../styles/Feed.css'; const Feed = () => { + const [dogArr, setDogArr] = useState([]); + const [page, setPage] = useState(0); + const [isLoading, setIsLoading] = useState(false); + + // Intersection Observer 설정 + + const handleObserver = (entries) => { + // console.log(entries); + const target = entries[0]; + if (target.isIntersecting && !isLoading) { + setPage((prevPage) => prevPage + 1); + } + }; + + useEffect(() => { + const observer = new IntersectionObserver(handleObserver, { + threshold: 0, + }); + // 최하단 요소를 관찰 대상으로 지정함 + const observerTarget = document.getElementById('observer'); + // 관찰 시작 + if (observerTarget) { + observer.observe(observerTarget); + } + }, []); + + // page 변경 감지에 따른 API호출 + useEffect(() => { + fetchData(); + // console.log(page); + }, [page]); + + // API를 호출하는 부분 + const fetchData = async () => { + setIsLoading(true); + try { + const API_URL = `https://api.thedogapi.com/v1/images/search?size=small&format=json&has_breeds=true&order=ASC&page=${page}&limit=10`; + const response = await axios.get(API_URL); + const newData = response.data.map((dogImg) => ({ + id: dogImg.id, + dogUrl: dogImg.url, + })); + // 불러온 데이터를 배열에 추가 + setDogArr((prevData) => [...prevData, ...newData]); + } catch (error) { + console.log(error); + } + setIsLoading(false); + }; + return ( <>
    @@ -16,7 +68,17 @@ const Feed = () => {
    추천 피드
    - + {dogArr.map((item, idx) => { + return ( + + ); + })} +
    diff --git a/src/styles/Feed.css b/src/styles/Feed.css index 175c5c7..b06b2f6 100644 --- a/src/styles/Feed.css +++ b/src/styles/Feed.css @@ -10,20 +10,20 @@ margin: 0 auto; max-width: 1440px; padding: 24px; - height: 1000vh; + height: 100vh; display: flex; flex-direction: column; } .feed_title_wrapper { - width: auto; + width: 100%; height: 50px; padding: 10px; } .feed_title { color: #000; - font-family: 'Pretendard-Regular'; + font-family: var(--basic-font); font-size: 24px; font-style: normal; font-weight: 700; @@ -31,7 +31,9 @@ } .feed_content_wrapper { - max-width: 1440px; + display: grid; + grid-template-columns: repeat(4, 1fr); + width: 1440px; height: 500px; -ms-flex-align: center; align-items: center; diff --git a/src/styles/FeedCard.css b/src/styles/FeedCard.css index a7d612b..e8fdb86 100644 --- a/src/styles/FeedCard.css +++ b/src/styles/FeedCard.css @@ -9,7 +9,7 @@ .FeedCardContainer { position: static; box-sizing: border-box; - width: 310px; + width: 340px; height: 280px; /* border-radius: 10px; background: linear-gradient(111deg, #cafadf 0%, #d5e0ff 100%); @@ -20,11 +20,12 @@ /* Drop Shadow */ box-shadow: 2px 2px 4px 0px rgba(119, 119, 119, 0.25); + margin-top: 20px; } .feed_up_wrapper { display: flex; - width: 310px; + width: 340px; height: 240px; } @@ -55,7 +56,7 @@ .review_book_wrapper { position: absolute; display: flex; - width: 310px; + width: 340px; height: 115px; background: rgba(255, 255, 255, 0.35); margin-top: 160px; @@ -64,12 +65,19 @@ z-index: 1; } +.feed_book_img_wrapper { + width: 74px; + height: 106px; + background: #6f6f6f; + border-radius: 5px; +} + .feed_book_img { width: 74px; height: 106px; flex-shrink: 0; border-radius: 5px; - background: #6f6f6f; + object-fit: fill; } .feed_book_text_wrapper { @@ -166,7 +174,7 @@ position: absolute; z-index: 2; display: flex; - width: 311px; + width: 341px; height: 40px; padding: 4px 0; align-items: center; From b8c4232bc8200fd7450c4c526b0bb5c127e384e2 Mon Sep 17 00:00:00 2001 From: Youngbae1126 Date: Sat, 16 Mar 2024 16:07:50 +0900 Subject: [PATCH 31/31] =?UTF-8?q?:sparkels:=20Feat:=20/api/feeds/all=20api?= =?UTF-8?q?=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/FeedCard.js | 8 ++---- src/pages/Feed.jsx | 56 ++++++++++++++++++++++++++++---------- src/styles/Feed.css | 4 +-- src/styles/FeedCard.css | 1 - 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/components/FeedCard.js b/src/components/FeedCard.js index b9d7496..cbd42c1 100644 --- a/src/components/FeedCard.js +++ b/src/components/FeedCard.js @@ -3,16 +3,14 @@ import React from 'react'; //STYLES import '../styles/FeedCard.css'; -const FeedCard = ({ title, author, nickname, imgUrl }) => { +const FeedCard = ({ title, author, nickname, imgUrl, comment }) => { return ( <>
    -

    - 죽는 날까지 하늘을 우러러 한 점 부끄럼이 없기를 -

    +

    {comment}

    @@ -29,7 +27,7 @@ const FeedCard = ({ title, author, nickname, imgUrl }) => {
    -
    별헤는밤
    +
    {nickname}
    diff --git a/src/pages/Feed.jsx b/src/pages/Feed.jsx index 74bda8d..f194a65 100644 --- a/src/pages/Feed.jsx +++ b/src/pages/Feed.jsx @@ -1,6 +1,9 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; +// SERVICES +import api from '../services/api'; + // COMPONENTS import Header from '../components/Header'; import FeedGrid from '../components/FeedGrid'; @@ -11,11 +14,11 @@ import '../styles/Feed.css'; const Feed = () => { const [dogArr, setDogArr] = useState([]); + const [feedArr, setFeedArr] = useState([]); const [page, setPage] = useState(0); const [isLoading, setIsLoading] = useState(false); // Intersection Observer 설정 - const handleObserver = (entries) => { // console.log(entries); const target = entries[0]; @@ -39,21 +42,44 @@ const Feed = () => { // page 변경 감지에 따른 API호출 useEffect(() => { fetchData(); - // console.log(page); + console.log(page); }, [page]); + let feedFetchData = { page: { page }, size: 9 }; + // API를 호출하는 부분 const fetchData = async () => { setIsLoading(true); try { - const API_URL = `https://api.thedogapi.com/v1/images/search?size=small&format=json&has_breeds=true&order=ASC&page=${page}&limit=10`; - const response = await axios.get(API_URL); - const newData = response.data.map((dogImg) => ({ - id: dogImg.id, - dogUrl: dogImg.url, + // api.get('/api/feeds/all', feedFetchData).then((res) => { + // // console.log(res.data.content); + // setFeedArr(res.data.content); + // setFeedArr((prevData) => [...prevData, ...res.data.content]); + // }); + const API_URL = + 'https://port-0-backend-book-pharmacy-umnqdut2blqqhv7sd.sel5.cloudtype.app/api/feeds/all?page=0&size=9'; + + const response = await axios.get(API_URL, feedFetchData); + // .then((res) => { + // // console.log(res.data.content); + // setFeedArr(res.data.content); + // }); + + // const newData = response.data.map((dogImg) => ({ + // id: dogImg.id, + // dogUrl: dogImg.url, + // })); + + const newData = response.data.content.map((item) => ({ + title: item.bookTitle, + author: item.bookAuthor, + comment: item.comment, + image: item.imgUrl, + nickName: item.clientNickname, })); - // 불러온 데이터를 배열에 추가 - setDogArr((prevData) => [...prevData, ...newData]); + + // //불러온 데이터를 배열에 추가 + setFeedArr((prevData) => [...prevData, ...newData]); } catch (error) { console.log(error); } @@ -68,18 +94,20 @@ const Feed = () => {
    추천 피드
    - {dogArr.map((item, idx) => { + {feedArr.map((item, idx) => { return ( ); })} -
    +
    ); diff --git a/src/styles/Feed.css b/src/styles/Feed.css index b06b2f6..d1a024d 100644 --- a/src/styles/Feed.css +++ b/src/styles/Feed.css @@ -10,7 +10,7 @@ margin: 0 auto; max-width: 1440px; padding: 24px; - height: 100vh; + /* height: 108vh; */ display: flex; flex-direction: column; } @@ -34,7 +34,7 @@ display: grid; grid-template-columns: repeat(4, 1fr); width: 1440px; - height: 500px; + /* height: 860px; */ -ms-flex-align: center; align-items: center; margin-left: auto; diff --git a/src/styles/FeedCard.css b/src/styles/FeedCard.css index e8fdb86..ed0da25 100644 --- a/src/styles/FeedCard.css +++ b/src/styles/FeedCard.css @@ -31,7 +31,6 @@ .feed_review_wrapper { display: flex; - flex-direction: column; align-items: center; }