diff --git a/src/components/DetailSectionBottom/DetailReviews.tsx b/src/components/DetailSectionBottom/DetailReviews.tsx index 7eddf34e..fe0e7e83 100644 --- a/src/components/DetailSectionBottom/DetailReviews.tsx +++ b/src/components/DetailSectionBottom/DetailReviews.tsx @@ -25,6 +25,8 @@ import ReviewItem from './ReviewItem'; import ToastPopUp from '@components/common/toastpopup/ToastPopUp'; import EditDelete from '@components/common/modal/children/EditDelete'; import MyAlert from '@components/common/modal/children/MyAlert'; +import { alertTypeState } from '@recoil/modal'; + interface reviewProps { reviewData: any; } @@ -45,6 +47,7 @@ export default function DetailReviews({ reviewData }: reviewProps) { const setIsModifyingReview = useSetRecoilState(isModifyingReviewState); const [toastPopUp, setToastPopUp] = useRecoilState(toastPopUpState); const modalChildren = useRecoilValue(modalChildrenState); + const alertType = useRecoilValue(alertTypeState); const { data: toursReviews, @@ -129,7 +132,7 @@ export default function DetailReviews({ reviewData }: reviewProps) { {reviewDataLength == 0 && (
{Array.from({ length: 5 }, (_, index) => ( @@ -179,9 +182,15 @@ export default function DetailReviews({ reviewData }: reviewProps) { {modalChildren === 'EditDelete' && } - {modalChildren === 'MyAlert' && ( + {modalChildren === 'MyAlert' && alertType === 'DeleteReview' && ( )} + {modalChildren === 'MyAlert' && alertType === 'LoginReview' && ( + + )} ); diff --git a/src/components/DetailSectionBottom/ReviewItem.tsx b/src/components/DetailSectionBottom/ReviewItem.tsx index a8c61a7d..4bc2caec 100644 --- a/src/components/DetailSectionBottom/ReviewItem.tsx +++ b/src/components/DetailSectionBottom/ReviewItem.tsx @@ -111,25 +111,25 @@ const Item: React.FC = (props: ItemProps) => { }; return ( - <> -
-
-
- {!( - authorProfileImageUrl === 'http://asiduheimage.jpg' || - authorProfileImageUrl === null - ) ? ( - 유저 프로필 - ) : ( - - )} -
-
-
{authorNickname}
+
+
+
+ {!( + authorProfileImageUrl === 'http://asiduheimage.jpg' || + authorProfileImageUrl === null + ) ? ( + 유저 프로필 + ) : ( + + )} +
+
+
{authorNickname}
+
{Array.from({ length: 5 }, (_, index) => ( = (props: ItemProps) => { /> ))}
+
+ {formatCreatedTime(createdTime)} +
-
- {formatCreatedTime(createdTime)} +
+ + {isAuthor && ( +
openModal('내 리뷰', reviewId, e)}> +
- {isAuthor && ( + )} +
+ {canTextOverflow ? ( +
+ {content.length > 55 ? `${content.slice(0, 55)}...` : content} +
+ ) : ( +
{content}
+ )} + +
+
+ {!showMoreKeywords && + keywords.slice(0, 2).map((keyword, idx) => ( +
+ {getEmoji(keyword.content)} {keyword.content} +
+ ))} + {keywords.length > 2 && !showMoreKeywords && (
openModal('내 리뷰', reviewId, e)}> - + className="rounded-md bg-gray1 px-2 py-1 text-xs text-gray6" + onClick={(e) => { + handleClickPlusButton(e); + }}> + +{keywords.length - 2}
)}
- {canTextOverflow ? ( -
- {content.length > 75 ? `${content.slice(0, 75)}...` : content} -
- ) : ( -
{content}
- )} - -
-
- {!showMoreKeywords && - keywords.slice(0, 2).map((keyword, idx) => ( +
+ {showMoreKeywords && + Array.from({ length: Math.ceil(keywords.length / 2) }).map( + (_, lineIdx) => (
- {getEmoji(keyword.content)} {keyword.content} + key={lineIdx} + className={`flex gap-2 ${ + lineIdx === Math.ceil(keywords.length / 2) - 1 + ? '' + : ' mb-3' + }`}> + {keywords + .slice(lineIdx * 2, lineIdx * 2 + 2) + .map((keyword, idx) => ( +
+ {getEmoji(keyword.content)} {keyword.content} +
+ ))}
- ))} - {keywords.length > 2 && !showMoreKeywords && ( -
{ - handleClickPlusButton(e); - }}> - +{keywords.length - 2} -
+ ), )} -
-
- {showMoreKeywords && - Array.from({ length: Math.ceil(keywords.length / 2) }).map( - (_, lineIdx) => ( -
- {keywords - .slice(lineIdx * 2, lineIdx * 2 + 2) - .map((keyword, idx) => ( -
- {getEmoji(keyword.content)} {keyword.content} -
- ))} -
- ), - )} -
+
-
- -
{commentCount}
-
+
+ +
{commentCount}
- +
); }; diff --git a/src/components/DetailSectionTop/DetailAddSchedule.tsx b/src/components/DetailSectionTop/DetailAddSchedule.tsx index 136f5ad0..d805968c 100644 --- a/src/components/DetailSectionTop/DetailAddSchedule.tsx +++ b/src/components/DetailSectionTop/DetailAddSchedule.tsx @@ -13,9 +13,9 @@ const DetailAddSchedule = () => { return ( - diff --git a/src/components/DetailSectionTop/DetailToursButtons.tsx b/src/components/DetailSectionTop/DetailToursButtons.tsx index 8947bb35..85a44d0c 100644 --- a/src/components/DetailSectionTop/DetailToursButtons.tsx +++ b/src/components/DetailSectionTop/DetailToursButtons.tsx @@ -1,11 +1,14 @@ import DetailAddSchedule from '@components/DetailSectionTop/DetailAddSchedule'; import { PenIcon } from '@components/common/icons/Icons'; -import { Modal } from '@components/common/modal'; -import MyAlert from '@components/common/modal/children/MyAlert'; -import { isModalOpenState, modalChildrenState } from '@recoil/modal'; +import { + isModalOpenState, + modalChildrenState, + alertTypeState, +} from '@recoil/modal'; import { isModifyingReviewState } from '@recoil/review'; import { useNavigate, useParams } from 'react-router-dom'; -import { useRecoilState, useSetRecoilState } from 'recoil'; +import { useSetRecoilState } from 'recoil'; +import { getItem } from '@utils/localStorageFun'; interface reviewProps { reviewData: any; @@ -17,45 +20,35 @@ export default function DetailTourButtons({ reviewData }: reviewProps) { const tourItemId = Number(params.id); const navigate = useNavigate(); const setIsModifyingReview = useSetRecoilState(isModifyingReviewState); - const [isModalOpen, setIsModalOpen] = useRecoilState(isModalOpenState); - const [modalChildren, setModalChildren] = useRecoilState(modalChildrenState); + const setIsModalOpen = useSetRecoilState(isModalOpenState); + const setModalChildren = useSetRecoilState(modalChildrenState); + const setAlertType = useSetRecoilState(alertTypeState); const handlePostingReivew = () => { - const accessToken = localStorage.getItem('accessToken'); - if (accessToken) { + const token = getItem('accessToken'); + if (token) { navigate(`/reviewPosting/${tourItemId}`, { state: { title, contentTypeId }, }); } else { + setModalChildren('MyAlert'); + setAlertType('LoginReview'); setIsModifyingReview(false); - setModalChildren('EditDelete'); setIsModalOpen(true); } }; - const closeModal = () => { - setIsModalOpen(false); - }; - return ( <>
-
- - {modalChildren === 'MyAlert' && ( - - )} - ); } diff --git a/src/components/Review/CommentItem.tsx b/src/components/Review/CommentItem.tsx index 7305ed3f..c4e4d264 100644 --- a/src/components/Review/CommentItem.tsx +++ b/src/components/Review/CommentItem.tsx @@ -56,7 +56,7 @@ const CommentItem: React.FC = (props: ItemProps) => { return (
-
+
{!( authorProfileImageUrl === 'http://asiduheimage.jpg' || @@ -65,15 +65,15 @@ const CommentItem: React.FC = (props: ItemProps) => { 유저 프로필 ) : ( - + )}
{authorNickname}
-
+
{formatCreatedTime(createdTime)}
@@ -85,7 +85,7 @@ const CommentItem: React.FC = (props: ItemProps) => {
)}
-
{content}
+
{content}
); }; diff --git a/src/components/Review/DetailReview.tsx b/src/components/Review/DetailReview.tsx index 9e1db449..8d5539e7 100644 --- a/src/components/Review/DetailReview.tsx +++ b/src/components/Review/DetailReview.tsx @@ -8,21 +8,19 @@ export default function DetailReview() { const { item, tourItemId } = state; return ( -
- -
+ ); } diff --git a/src/components/Review/MyReview.tsx b/src/components/Review/MyReview.tsx index c6cca236..1db45243 100644 --- a/src/components/Review/MyReview.tsx +++ b/src/components/Review/MyReview.tsx @@ -19,6 +19,8 @@ import ReviewItem from '@components/DetailSectionBottom/ReviewItem'; import ToastPopUp from '@components/common/toastpopup/ToastPopUp'; import EditDelete from '@components/common/modal/children/EditDelete'; import MyAlert from '@components/common/modal/children/MyAlert'; +import { alertTypeState } from '@recoil/modal'; +import { PenIcon } from '@components/common/icons/Icons'; export default function MyReview() { const [reviewDataLength, setReviewDataLength] = useState(0); @@ -31,6 +33,8 @@ export default function MyReview() { const setIsModifyingReview = useSetRecoilState(isModifyingReviewState); const [toastPopUp, setToastPopUp] = useRecoilState(toastPopUpState); const modalChildren = useRecoilValue(modalChildrenState); + const [alertType] = useRecoilValue(alertTypeState); + const { data: myReviews, fetchNextPage, @@ -103,9 +107,16 @@ export default function MyReview() { 나의 리뷰{reviewDataLength}
{reviewDataLength == 0 && ( -
-
작성한 리뷰가 없습니다
-
다녀온 여행지의 리뷰를 남겨보세요!
+
+
+ +
+
+ 작성한 리뷰가 없습니다 +
+
+ 다녀온 여행지의 리뷰를 남겨보세요! +
)} {modalChildren === 'EditDelete' && } - {modalChildren === 'MyAlert' && ( + {modalChildren === 'MyAlert' && alertType === 'DeleteReview' && ( )} diff --git a/src/components/Review/ReviewComments.tsx b/src/components/Review/ReviewComments.tsx index fbdc53ae..8cde28ec 100644 --- a/src/components/Review/ReviewComments.tsx +++ b/src/components/Review/ReviewComments.tsx @@ -11,6 +11,7 @@ import InfiniteScroll from 'react-infinite-scroller'; import EditDelete from '@components/common/modal/children/EditDelete'; import MyAlert from '@components/common/modal/children/MyAlert'; import { commentState } from '@recoil/review'; +import { alertTypeState } from '@recoil/modal'; export default function ReviewComments() { const params = useParams(); @@ -21,6 +22,7 @@ export default function ReviewComments() { const [commentDataLength, setCommentDataLength] = useState(0); const modalChildren = useRecoilValue(modalChildrenState); const setComment = useSetRecoilState(commentState); + const alertType = useRecoilValue(alertTypeState); const { data: reviewComments, @@ -46,9 +48,10 @@ export default function ReviewComments() { } const closeModal = () => { - setIsModalOpen(false); setComment(''); + setIsModalOpen(false); }; + useEffect(() => { { reviewComments?.pages.map((group) => { @@ -57,11 +60,12 @@ export default function ReviewComments() { } console.log('reviewComments', reviewComments); }, [reviewComments]); + return ( <> -
+
댓글 - {commentDataLength} + {commentDataLength}
{commentDataLength == 0 && ( @@ -104,9 +108,15 @@ export default function ReviewComments() {
{modalChildren === 'EditDelete' && } - {modalChildren === 'MyAlert' && ( + {modalChildren === 'MyAlert' && alertType === 'DeleteReview' && ( )} + {modalChildren === 'MyAlert' && alertType === 'LoginComment' && ( + + )} ); diff --git a/src/components/common/icons/Icons.tsx b/src/components/common/icons/Icons.tsx index 52355fba..18f154b1 100644 --- a/src/components/common/icons/Icons.tsx +++ b/src/components/common/icons/Icons.tsx @@ -268,6 +268,7 @@ export const PenIcon: React.FC = ({ size = 25, color = 'black', fill = 'none', + className, }) => { return ( = ({ height={size} viewBox="0 0 21 21" fill={fill} + className={className} xmlns="http://www.w3.org/2000/svg"> diff --git a/src/components/common/modal/children/EditDelete.tsx b/src/components/common/modal/children/EditDelete.tsx index 84754048..28908345 100644 --- a/src/components/common/modal/children/EditDelete.tsx +++ b/src/components/common/modal/children/EditDelete.tsx @@ -4,6 +4,7 @@ import { isModalOpenState, titleState, modalChildrenState, + alertTypeState, } from '@recoil/modal'; import { contentState, @@ -37,7 +38,7 @@ const EditDelete: React.FC = () => { const setIsModalOpen = useSetRecoilState(isModalOpenState); const setModalChildren = useSetRecoilState(modalChildrenState); const setComment = useSetRecoilState(commentState); - + const setAlertType = useSetRecoilState(alertTypeState); const queryClient = useQueryClient(); const handleEdit = () => { @@ -71,6 +72,7 @@ const EditDelete: React.FC = () => { const handleDelete = async () => { if (title === '내 리뷰') { setModalChildren('MyAlert'); + setAlertType('DeleteReview'); } else if (title === '내 댓글') { await deleteCommentMutate(targetCommentId); setIsModalOpen(false); diff --git a/src/components/common/modal/children/MyAlert.tsx b/src/components/common/modal/children/MyAlert.tsx index 4257612a..e5f50f7e 100644 --- a/src/components/common/modal/children/MyAlert.tsx +++ b/src/components/common/modal/children/MyAlert.tsx @@ -5,6 +5,7 @@ import { toastPopUpState, targetReviewIdState, tourItemIdState, + commentState, } from '@recoil/review'; import { useNavigate } from 'react-router-dom'; import { useRecoilValue, useSetRecoilState } from 'recoil'; @@ -21,6 +22,7 @@ const MyAlert: React.FC = ({ title, content }) => { const setIsModalOpen = useSetRecoilState(isModalOpenState); const setToastPopUp = useSetRecoilState(toastPopUpState); const queryClient = useQueryClient(); + const setComment = useSetRecoilState(commentState); const { mutate: deleteReviewMutate } = useMutation({ mutationFn: (targetReviewId: number) => deleteReview(targetReviewId), @@ -52,23 +54,29 @@ const MyAlert: React.FC = ({ title, content }) => { } } } else if (title == '로그인') { + setComment(''); setIsModalOpen(false); navigate(`/login`); } }; + const closeModal = () => { + setComment(''); + setIsModalOpen(false); + }; + return (
{title}
-
- {content} +
+ {content.split('. ').map((sentence, index) => ( +
+ {sentence} +
+ ))}
- { - setIsModalOpen(false); - }} - className="text-sm"> + 취소 diff --git a/src/components/common/nav/InputComment.tsx b/src/components/common/nav/InputComment.tsx index 76fbba1f..eb21cbf6 100644 --- a/src/components/common/nav/InputComment.tsx +++ b/src/components/common/nav/InputComment.tsx @@ -2,10 +2,16 @@ import { KeyboardEvent, ChangeEvent } from 'react'; import { postComments } from '@api/comments'; import { useParams } from 'react-router-dom'; import { commentState } from '@recoil/review'; -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; import { putComments } from '@api/comments'; import { isModifyingCommentState, targetCommentIdState } from '@recoil/review'; import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { getItem } from '@utils/localStorageFun'; +import { + isModalOpenState, + modalChildrenState, + alertTypeState, +} from '@recoil/modal'; interface InputCommentProps { classNameName?: string; @@ -30,6 +36,9 @@ export const InputComment: React.FC = () => { ); const targetCommentId = useRecoilValue(targetCommentIdState); const queryClient = useQueryClient(); + const setIsModalOpen = useSetRecoilState(isModalOpenState); + const setModalChildren = useSetRecoilState(modalChildrenState); + const setAlertType = useSetRecoilState(alertTypeState); const { mutate: postReviewMutate } = useMutation({ mutationFn: ({ comment, reviewId }: PostCommentMutationParams) => @@ -64,13 +73,20 @@ export const InputComment: React.FC = () => { }; const handleSubmit = async () => { - if (isModifyingComment) { - await editReviewMutate({ comment, targetCommentId }); - setIsModifyingComment(false); + const token = getItem('accessToken'); + if (token) { + if (isModifyingComment) { + await editReviewMutate({ comment, targetCommentId }); + setIsModifyingComment(false); + } else { + await postReviewMutate({ comment, reviewId }); + } + setComment(''); } else { - await postReviewMutate({ comment, reviewId }); + setModalChildren('MyAlert'); + setAlertType('LoginComment'); + setIsModalOpen(true); } - setComment(''); }; const handleKeyPress = (event: KeyboardEvent) => { if (event.key === 'Enter') { diff --git a/src/recoil/modal.ts b/src/recoil/modal.ts index eecef4b1..a687f33b 100644 --- a/src/recoil/modal.ts +++ b/src/recoil/modal.ts @@ -14,3 +14,8 @@ export const modalChildrenState = atom({ key: 'modalChildrenState', default: '', }); + +export const alertTypeState = atom({ + key: 'alertTypeState', + default: '', +});