From d4dbfa6774452707bce6f224c631bde15ccce5e3 Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Sat, 6 Jan 2024 10:53:21 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20=EA=B4=80=EC=8B=AC=20=EC=97=AC?= =?UTF-8?q?=ED=96=89=EC=A7=80=20=EB=93=B1=EB=A1=9D,=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/tours.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/api/tours.ts b/src/api/tours.ts index 87ed8604..ce8d0e49 100644 --- a/src/api/tours.ts +++ b/src/api/tours.ts @@ -32,6 +32,36 @@ export const getDetailTours = async (tourItemId: number) => { } }; +// 관심 여행지 등록 +export const postLikedTours = async (options: { id: number }) => { + try { + const { id } = options; + + let query = `/liked/${id}`; + + const res = await client.post(query); + + return res; + } catch (e) { + console.error(e); + } +}; + +// 관심 여행지 삭제 +export const deleteLikedTours = async (options: { id: number }) => { + try { + const { id } = options; + + let query = `/liked/${id}`; + + const res = await client.delete(query); + + return res; + } catch (e) { + console.error(e); + } +}; + // 여행 상품 리뷰 조회 export const getToursReviews = async (tourItemId: number) => { const res = await client.get(`tours/${tourItemId}/reviews`); From 324104461272ecbd99d4e5c1c9f248dcf16d4c33 Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Sat, 6 Jan 2024 10:53:40 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20scroll=EC=9A=A9=20id=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/components/DetailSectionBottom/DetailReviews.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DetailSectionBottom/DetailReviews.tsx b/src/components/DetailSectionBottom/DetailReviews.tsx index 87893173..8538957d 100644 --- a/src/components/DetailSectionBottom/DetailReviews.tsx +++ b/src/components/DetailSectionBottom/DetailReviews.tsx @@ -75,7 +75,7 @@ export default function DetailReviews({ reviewData }: reviewProps) { return ( <> -
+
리뷰{reviewDataLength}
{reviewDataLength > 0 && ( From a59b8c9e4cb4561456163834bb5d5ce8638948eb Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Sat, 6 Jan 2024 10:54:12 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=EC=83=81=EC=84=B8=20=EA=B4=80?= =?UTF-8?q?=EC=8B=AC=20=EC=97=AC=ED=96=89=EC=A7=80=20=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?=EB=B0=8F=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=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 --- .../DetailSectionTop/DetailToursInfo.tsx | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/components/DetailSectionTop/DetailToursInfo.tsx b/src/components/DetailSectionTop/DetailToursInfo.tsx index b48a5343..3b024d45 100644 --- a/src/components/DetailSectionTop/DetailToursInfo.tsx +++ b/src/components/DetailSectionTop/DetailToursInfo.tsx @@ -1,11 +1,52 @@ import { HeartIcon } from '@components/common/icons/Icons'; +import { postLikedTours, deleteLikedTours } from '@api/tours'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useNavigate } from 'react-router-dom'; +import { useState } from 'react'; interface DetailToursInfoProps { infoData: tourDetail; } export default function DetailToursInfo({ infoData }: DetailToursInfoProps) { - const { title, liked, originalThumbnailUrl } = infoData; + const { title, liked, originalThumbnailUrl, id } = infoData; + + const [isLiked, setIsLiked] = useState(liked); + + const navigate = useNavigate(); + const queryClient = useQueryClient(); + + const { mutate: likeMutate } = useMutation({ + mutationFn: (id: number) => postLikedTours({ id }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['details'] }); + setIsLiked(true); + }, + onError: () => console.log('error'), + }); + + const { mutate: unlikeMutate } = useMutation({ + mutationFn: (id: number) => deleteLikedTours({ id }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['details'] }); + setIsLiked(false); + }, + onError: () => console.log('error'), + }); + + const onClickLikeButton = () => { + const token = localStorage.getItem('accessToken'); + if (!token) { + // 비로그인 알람창 처리 필요 + navigate('/signin'); + } else { + if (liked === false) { + likeMutate(id); + } else { + unlikeMutate(id); + } + } + }; return ( <> @@ -20,15 +61,14 @@ export default function DetailToursInfo({ infoData }: DetailToursInfoProps) {

{title}

- {liked ? ( -
- -
- ) : ( -
- -
- )} +
+ +
); From 4b1d6e5e57a5cebde51e7edd39b10b2882371539 Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Sat, 6 Jan 2024 10:54:30 +0900 Subject: [PATCH 4/9] =?UTF-8?q?style:=20=EB=A6=AC=EB=B7=B0=20=EA=B4=84?= =?UTF-8?q?=ED=98=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DetailSectionTop/DetailToursMap.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/DetailSectionTop/DetailToursMap.tsx b/src/components/DetailSectionTop/DetailToursMap.tsx index 2c1de11f..7105f7d6 100644 --- a/src/components/DetailSectionTop/DetailToursMap.tsx +++ b/src/components/DetailSectionTop/DetailToursMap.tsx @@ -48,7 +48,9 @@ export default function DetailToursMap({ mapData }: DetailToursMapProps) { )} - +
+ +
Date: Sat, 6 Jan 2024 10:54:43 +0900 Subject: [PATCH 5/9] =?UTF-8?q?style:=20=EB=A6=AC=EB=B7=B0=20=EA=B4=84?= =?UTF-8?q?=ED=98=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DetailSectionTop/DetailToursRating.tsx | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/components/DetailSectionTop/DetailToursRating.tsx b/src/components/DetailSectionTop/DetailToursRating.tsx index db9a9f5b..0178f248 100644 --- a/src/components/DetailSectionTop/DetailToursRating.tsx +++ b/src/components/DetailSectionTop/DetailToursRating.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; - +import { Link } from 'react-scroll'; interface ReviewData { ratingAverage: number; reviewTotalCount: number; @@ -35,38 +35,40 @@ export default function DetailToursRating({ }, []); return ( -
- {STAR_IDX_ARR.map((item, idx) => { - return ( - - - - - - - - - - ); - })} + +
+ {STAR_IDX_ARR.map((item, idx) => { + return ( + + + + + + + + + + ); + })} -
-

- {reviewTotalCount} -

+
+

+ ({reviewTotalCount}) +

+
-
+ ); } From 3a4a53601a129fd9dccc8e7054c1287b743a5e59 Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Sat, 6 Jan 2024 10:55:14 +0900 Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DetailSectionTop/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/DetailSectionTop/index.tsx b/src/components/DetailSectionTop/index.tsx index 150b6ffd..ca314b0c 100644 --- a/src/components/DetailSectionTop/index.tsx +++ b/src/components/DetailSectionTop/index.tsx @@ -3,7 +3,6 @@ import DetailToursRating from './DetailToursRating'; import DetailToursMap from './DetailToursMap'; import DetailToursButtons from './DetailToursButtons'; - export { DetailToursInfo, DetailToursRating, From e0afebf5c6763a6473bc8c1aa020eed65f782b0b Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Sat, 6 Jan 2024 10:55:45 +0900 Subject: [PATCH 7/9] =?UTF-8?q?refactor:=20clipPath=20=EB=93=B1=20?= =?UTF-8?q?=EB=AC=B8=EB=B2=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/icons/Icons.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/common/icons/Icons.tsx b/src/components/common/icons/Icons.tsx index 61b2cc99..83536fc9 100644 --- a/src/components/common/icons/Icons.tsx +++ b/src/components/common/icons/Icons.tsx @@ -120,9 +120,11 @@ export const HeartIcon: React.FC = ({ size = 25, color = 'black', fill = 'none', + onClick, }) => { return ( = ({ xmlns="http://www.w3.org/2000/svg"> + clipPath="url(#clip0_447_1104)"> Date: Sat, 6 Jan 2024 10:55:58 +0900 Subject: [PATCH 8/9] =?UTF-8?q?feat:=20react-scroll=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 52 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index ee1cecd4..431978a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "react-kakao-maps-sdk": "^1.1.24", "react-modal": "^3.16.1", "react-router-dom": "^6.21.1", + "react-scroll": "^1.9.0", "recoil": "^0.7.7", "styled-components": "^6.1.3", "uuid": "^9.0.1" @@ -33,6 +34,7 @@ "@types/react-dom": "^18.2.17", "@types/react-infinite-scroller": "^1.2.5", "@types/react-modal": "^3.16.3", + "@types/react-scroll": "^1.8.10", "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^6.14.0", "@typescript-eslint/parser": "^6.14.0", @@ -3614,6 +3616,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-scroll": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/@types/react-scroll/-/react-scroll-1.8.10.tgz", + "integrity": "sha512-RD4Z7grbdNGOKwKnUBKar6zNxqaW3n8m9QSrfvljW+gmkj1GArb8AFBomVr6xMOgHPD3v1uV3BrIf01py57daQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -6086,6 +6097,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -7205,6 +7221,19 @@ "react-dom": ">=16.8" } }, + "node_modules/react-scroll": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/react-scroll/-/react-scroll-1.9.0.tgz", + "integrity": "sha512-mamNcaX9Ng+JeSbBu97nWwRhYvL2oba+xR2GxvyXsbDeGP+gkYIKZ+aDMMj/n20TbV9SCWm/H7nyuNTSiXA6yA==", + "dependencies": { + "lodash.throttle": "^4.1.1", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "^15.5.4 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.5.4 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -10617,6 +10646,15 @@ "@types/react": "*" } }, + "@types/react-scroll": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/@types/react-scroll/-/react-scroll-1.8.10.tgz", + "integrity": "sha512-RD4Z7grbdNGOKwKnUBKar6zNxqaW3n8m9QSrfvljW+gmkj1GArb8AFBomVr6xMOgHPD3v1uV3BrIf01py57daQ==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -12341,6 +12379,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -13052,6 +13095,15 @@ "react-router": "6.21.1" } }, + "react-scroll": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/react-scroll/-/react-scroll-1.9.0.tgz", + "integrity": "sha512-mamNcaX9Ng+JeSbBu97nWwRhYvL2oba+xR2GxvyXsbDeGP+gkYIKZ+aDMMj/n20TbV9SCWm/H7nyuNTSiXA6yA==", + "requires": { + "lodash.throttle": "^4.1.1", + "prop-types": "^15.7.2" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index d2479fde..bec03869 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "react-kakao-maps-sdk": "^1.1.24", "react-modal": "^3.16.1", "react-router-dom": "^6.21.1", + "react-scroll": "^1.9.0", "recoil": "^0.7.7", "styled-components": "^6.1.3", "uuid": "^9.0.1" @@ -34,8 +35,9 @@ "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@types/react-infinite-scroller": "^1.2.5", - "@types/uuid": "^9.0.7", "@types/react-modal": "^3.16.3", + "@types/react-scroll": "^1.8.10", + "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^6.14.0", "@typescript-eslint/parser": "^6.14.0", "@vitejs/plugin-react": "^4.2.1", From 8b8d986004d1c27f132ee4ee7fbf43d387bf503c Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Sat, 6 Jan 2024 20:14:26 +0900 Subject: [PATCH 9/9] =?UTF-8?q?feat:=20=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DetailSectionTop/DetailToursInfo.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/components/DetailSectionTop/DetailToursInfo.tsx b/src/components/DetailSectionTop/DetailToursInfo.tsx index 3b024d45..c4a0edf9 100644 --- a/src/components/DetailSectionTop/DetailToursInfo.tsx +++ b/src/components/DetailSectionTop/DetailToursInfo.tsx @@ -2,7 +2,6 @@ import { HeartIcon } from '@components/common/icons/Icons'; import { postLikedTours, deleteLikedTours } from '@api/tours'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; -import { useState } from 'react'; interface DetailToursInfoProps { infoData: tourDetail; @@ -11,8 +10,6 @@ interface DetailToursInfoProps { export default function DetailToursInfo({ infoData }: DetailToursInfoProps) { const { title, liked, originalThumbnailUrl, id } = infoData; - const [isLiked, setIsLiked] = useState(liked); - const navigate = useNavigate(); const queryClient = useQueryClient(); @@ -20,7 +17,6 @@ export default function DetailToursInfo({ infoData }: DetailToursInfoProps) { mutationFn: (id: number) => postLikedTours({ id }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['details'] }); - setIsLiked(true); }, onError: () => console.log('error'), }); @@ -29,7 +25,6 @@ export default function DetailToursInfo({ infoData }: DetailToursInfoProps) { mutationFn: (id: number) => deleteLikedTours({ id }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['details'] }); - setIsLiked(false); }, onError: () => console.log('error'), }); @@ -63,8 +58,7 @@ export default function DetailToursInfo({ infoData }: DetailToursInfoProps) {