Skip to content

Commit

Permalink
Merge pull request #54 from FinalDoubleTen/FE-6--feat/Tours
Browse files Browse the repository at this point in the history
Feat: 인기여행지 구현
  • Loading branch information
suehub authored Jan 4, 2024
2 parents c852b42 + acfaf0f commit bbbe049
Show file tree
Hide file tree
Showing 41 changed files with 314 additions and 925 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
- Chore : 빌드 관련 코드 수정
- Rename : 파일 및 폴더명 수정.
- Remove : 파일 삭제.
...
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"react-dom": "^18.2.0",
"react-infinite-scroller": "^1.2.6",
"react-kakao-maps-sdk": "^1.1.24",
"react-modal": "^3.16.1",
"react-router-dom": "^6.21.1",
"recoil": "^0.7.7",
"styled-components": "^6.1.3",
Expand All @@ -35,7 +34,6 @@
"@types/react-dom": "^18.2.17",
"@types/react-infinite-scroller": "^1.2.5",
"@types/uuid": "^9.0.7",
"@types/react-modal": "^3.16.3",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"@vitejs/plugin-react": "^4.2.1",
Expand Down
6 changes: 3 additions & 3 deletions src/api/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ import client from './client';
// 댓글 관련 API

// 댓글수정
export const putComments = async (content: string, commentId: number) => {
export const putComments = async (content: string, commentId: string) => {
const res = await client.put(`comments/${commentId}`, {
content,
});
return res;
};

// 댓글삭제
export const deleteComments = async (commentId: number) => {
export const deleteComments = async (commentId: string) => {
const res = await client.delete(`comments/${commentId}`);
return res;
};

// 댓글작성
export const postComments = async (content: string, reviewId: number) => {
const res = await client.post(`comments`, {
const res = await client.post(`comments/`, {
content: content,
reviewId: reviewId,
});
Expand Down
4 changes: 2 additions & 2 deletions src/api/member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const getMemberReviews = async () => {
};

// 나의 관심 여행지 삭제
export const deleteMemberTours = async (tourItemId: number) => {
const res = await client.delete(`member/tours/${tourItemId}`);
export const deleteMemberTours = async (tourId: number) => {
const res = await client.delete(`member/tours/${tourId}`);
return res;
};
4 changes: 2 additions & 2 deletions src/api/review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const getReviewComments = async (reviewId: number) => {
};

// 리뷰키워드조회
export const getReviewKeywords = async (keywordType: string) => {
const res = await client.get(`reviews/keywords?keywordType=${keywordType}`);
export const getReviewKeywords = async (code: number) => {
const res = await client.get(`reviews/keywords?code=${code}`);
return res;
};
2 changes: 2 additions & 0 deletions src/api/tours.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export const getDetailTours = async (tourItemId: number) => {
// 여행 상품 리뷰 조회
export const getToursReviews = async (tourItemId: number) => {
const res = await client.get(`tours/${tourItemId}/reviews`);
console.log('res', res);
console.log('res.data.data.reviewInfos', res.data.data.reviewInfos);
return res;
};

Expand Down
85 changes: 85 additions & 0 deletions src/components/DetailSectionBottom/DetailReview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// import { getToursReviews } from '@api/tours';
// import { useEffect, useState } from 'react';
// import InfiniteScroll from 'react-infinite-scroller';
// import { useInfiniteQuery } from '@tanstack/react-query';
// import ReviewItem from './ReviewItem';
// import { StarIcon } from '@components/common/icons/Icons';

// export default function DetailReview() {
// const [reviewDataLength, setReviewDataLength] = useState<number>(0);
// const tourItemId = 1;

// const {
// data: toursReviews,
// fetchNextPage,
// hasNextPage,
// } = useInfiniteQuery({
// queryKey: ['toursReviews'],
// queryFn: ({ pageParam }) => getToursReviews(tourItemId),
// initialPageParam: 0,
// getNextPageParam: (lastPage, allPages, lastPageParam) => {
// const lastData = lastPage?.data?.data?.reviewInfos;
// return lastData && lastData.length === 4 ? lastPageParam + 1 : undefined;
// },
// });

// useEffect(() => {
// if (toursReviews) {
// const totalCount = toursReviews.pages.reduce(
// (accumulator, page) =>
// accumulator + (page?.data?.data?.reviewInfos?.length || 0),
// 0,
// );
// setReviewDataLength(totalCount);
// }
// }, [toursReviews]);

// return (
// <>
// <div className="mb-4 mt-2 text-lg font-bold">
// 리뷰 <span className="text-gray3">{reviewDataLength}</span>
// </div>
// {reviewDataLength > 0 && (
// <InfiniteScroll
// hasMore={hasNextPage}
// loadMore={() => fetchNextPage()}
// initialLoad={false}>
// {toursReviews?.pages?.map((page, pageIndex) => (
// <div key={pageIndex}>
// {page?.data?.data?.reviewInfos?.map(
// (item: any, index: number) => (
// <ReviewItem
// key={item.reviewId}
// authorNickname={item.authorNickname}
// authorProfileImageUrl={item.authorProfileImageUrl}
// rating={item.rating}
// createdTime={item.createdTime}
// content={item.content}
// keywords={item.keywords} // keywordId, content, type
// commentCount={2} //commentCount가 swagger에는 있는데 response에는 없음
// />
// ),
// )}
// </div>
// ))}
// </InfiniteScroll>
// )}
// {reviewDataLength == 0 && (
// <div className="flex flex-col items-center justify-center">
// <div className="mb-2 flex">
// {Array.from({ length: 5 }, (_, index) => (
// <StarIcon
// key={index}
// size={30}
// color="none"
// fill={'#EDEDED'}
// className="cursor-pointer"
// />
// ))}
// </div>
// <div className="text-sm text-gray3">첫번째 리뷰를 남겨주세요!</div>
// </div>
// )}
// </>
// );
// }
29 changes: 8 additions & 21 deletions src/components/DetailSectionBottom/DetailSectionBottom.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
import { DetailReviews, DetailReviewStats } from '.';
import { useParams } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { getDetailTours } from '@api/tours';
import { useEffect } from 'react';
import { DetailReviewStats } from '.';

// 담당 컴포넌트들 호출하는 컴포넌트(분업 때문에 페이지 느낌으로 나눠봤습니다), API 호출 컴포넌트,
export default function DetailSectionBottom() {
const params = useParams();
const tourItemId = Number(params.id);
const { isError, isLoading, isFetching, data } = useQuery({
queryKey: ['details', tourItemId],
queryFn: () => getDetailTours(tourItemId),
});
if (data) {
return (
<>
<DetailReviewStats />
<DetailReviews reviewData={data} />
</>
);
}

if (isError) console.log('error');
return (
<>
<DetailReviewStats />
{/* <DetailReview /> */}
</>
);
}
139 changes: 47 additions & 92 deletions src/components/DetailSectionBottom/ReviewItem.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
import { useEffect } from 'react';
import { StarIcon, ChatIcon, MoreIcon } from '@components/common/icons/Icons';
import { useSetRecoilState, useRecoilState } from 'recoil';
import { isModalOpenState, titleState } from '@recoil/modal';
import {
ratingState,
keywordsState,
contentState,
targetReviewIdState,
tourItemIdState,
contentTypeIdState,
} from '@recoil/review';
import { StarIcon, ChatIcon } from '@components/common/icons/Icons';

interface Keyword {
keywordId: number;
Expand All @@ -18,55 +8,25 @@ interface Keyword {
}

interface ItemProps {
reviewId: number;
authorNickname: string;
authorProfileImageUrl: string;
rating: number;
createdTime: any;
content: string;
keywords: Keyword[]; // keywordId, content, type
commentCount: number;
onClick?: () => void;
tourItemId: number;
contentTypeId?: number;
}

const Item: React.FC<ItemProps> = (props: ItemProps) => {
const {
reviewId,
authorNickname,
// authorProfileImageUrl,
rating,
createdTime,
content,
keywords,
commentCount,
onClick,
tourItemId,
contentTypeId,
} = props;
const [isModalOpen, setIsModalOpen] = useRecoilState(isModalOpenState);

const setRating = useSetRecoilState(ratingState);
const setKeywords = useSetRecoilState(keywordsState);
const setContent = useSetRecoilState(contentState);
const setTitle = useSetRecoilState(titleState);
const setTourItemId = useSetRecoilState(tourItemIdState);
const setContentTypeId = useSetRecoilState(contentTypeIdState);
const setTargetReviewId = useSetRecoilState(targetReviewIdState);
const openModal = (title: string, reviewId: number, e: React.MouseEvent) => {
e.stopPropagation();
setTitle(title);
setTourItemId(tourItemId);
if (contentTypeId) {
setContentTypeId(contentTypeId);
}
setRating(rating);
setKeywords(keywords);
setContent(content);
setTargetReviewId(reviewId);
setIsModalOpen(true);
};

const formatCreatedTime = (timeString: string): string => {
const date = new Date(timeString);
Expand All @@ -78,63 +38,58 @@ const Item: React.FC<ItemProps> = (props: ItemProps) => {

return formattedDate;
};

useEffect(() => {
console.log('commentCount', commentCount);
}, []);
return (
<>
<div className="mb-8 cursor-pointer" onClick={onClick}>
<div className=" mb-5 flex items-center">
{/* {authorProfileImageUrl} */}
<div className="mr-2">
<img
src={
'https://img.freepik.com/free-photo/portrait-of-a-cute-little-girl-in-a-blue-hat-3d-rendering_1142-38897.jpg?w=740&t=st=1704099517~exp=1704100117~hmac=49bf38020d3b7a61618f4db96fa5fdfa20a7c263be7f73b9987054b12f9d5027'
}
alt="유저 프로필"
className="w-12 rounded-full"
/>
</div>
<div className=" mr-2 flex flex-col gap-1">
<div className="font-bold">{authorNickname}</div>
<div className="flex">
{Array.from({ length: 5 }, (_, index) => (
<StarIcon
key={index}
size={20}
color="none"
fill={index < rating ? '#FFEC3E' : '#EDEDED'}
/>
))}
</div>
</div>
<div className="mb-0.5 mt-auto text-sm text-gray4">
{formatCreatedTime(createdTime)}
</div>
<div
className="ml-auto cursor-pointer"
onClick={(e) => openModal('내 리뷰', reviewId, e)}>
<MoreIcon fill="#888888" color="none" />
<div className="mb-4">
<div className=" mb-5 flex items-center">
{/* {authorProfileImageUrl} */}
<div className="mr-2">
<img
src={
'https://img.freepik.com/free-photo/portrait-of-a-cute-little-girl-in-a-blue-hat-3d-rendering_1142-38897.jpg?w=740&t=st=1704099517~exp=1704100117~hmac=49bf38020d3b7a61618f4db96fa5fdfa20a7c263be7f73b9987054b12f9d5027'
}
alt="유저 프로필"
className="w-12 rounded-full"
/>
</div>
<div className=" mr-2 flex flex-col gap-1">
<div className="font-bold">{authorNickname}</div>
<div className="flex">
{Array.from({ length: 5 }, (_, index) => (
<StarIcon
key={index}
size={20}
color="none"
fill={index < rating ? '#FFEC3E' : '#EDEDED'}
/>
))}
</div>
</div>
<div className=" mb-4 text-gray7">{content}</div>
<div className="mb-0.5 mt-auto text-sm text-gray3">
{formatCreatedTime(createdTime)}
</div>
</div>
<div className=" mb-4 text-gray7">{content}</div>
<div className="flex">
<div className="flex">
<div className="flex gap-2">
{keywords.map((keyword, idx) => {
return (
<div
key={idx}
className="rounded-md bg-gray1 px-2 py-1 text-sm text-gray6">
{keyword.content}
</div>
);
})}
</div>
<div className="ml-auto flex items-center justify-between">
<ChatIcon size={20} color="#5E5E5E" />
<div className="ml-1 text-gray5">{commentCount}</div>
</div>
{keywords.map((keyword, idx) => {
return (
<div
key={idx}
className="rounded-md bg-gray-100 px-2 py-1 text-sm">
{keyword.content}
</div>
);
})}
</div>
<div className="ml-auto flex items-center justify-between">
<ChatIcon size={20} />
<div className="ml-1">{commentCount}</div>
</div>
</div>
</>
</div>
);
};

Expand Down
3 changes: 1 addition & 2 deletions src/components/DetailSectionBottom/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import DetailReviewStats from './DetailReviewStats';
import DetailReviews from './DetailReviews';

export { DetailReviews, DetailReviewStats };
export { DetailReviewStats };
Loading

0 comments on commit bbbe049

Please sign in to comment.