From 95b94757c14c2d759051db9e889361713cff1699 Mon Sep 17 00:00:00 2001 From: yunhwancho Date: Sat, 28 Sep 2024 17:10:26 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat=20:=20tag=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/search/[keyword]/page.tsx | 2 +- src/components/ootd/OotdDetail.tsx | 318 +++++++++++-------- src/components/pages/ootd/RecentOotdPost.tsx | 66 ++-- src/components/search/sortingBar.tsx | 40 +-- src/services/search.ts | 3 +- 5 files changed, 228 insertions(+), 201 deletions(-) diff --git a/src/app/search/[keyword]/page.tsx b/src/app/search/[keyword]/page.tsx index 0cd119ec..6f350757 100644 --- a/src/app/search/[keyword]/page.tsx +++ b/src/app/search/[keyword]/page.tsx @@ -92,7 +92,7 @@ const SearchPage = () => { setNicknameList(nicknameListData); setBlogList(blogListData); - // 초기 선택 타입 설정 (우선순위: POST -> OOTD -> NICKNAME -> BLOG) + console.log(ootdListData); if (postListData.length > 0) { setPosts(postListData); setSelectedSearchType("POST"); diff --git a/src/components/ootd/OotdDetail.tsx b/src/components/ootd/OotdDetail.tsx index 98793e2e..c0fce909 100644 --- a/src/components/ootd/OotdDetail.tsx +++ b/src/components/ootd/OotdDetail.tsx @@ -3,7 +3,11 @@ import React, { useEffect, useState } from "react"; import { useQuery } from "react-query"; import Slider from "react-slick"; -import { deleteOotdPost, fetchOotdPostDetail, fetchRecommendedSpots } from "@/services/ootd.ts/ootdGet"; +import { + deleteOotdPost, + fetchOotdPostDetail, + fetchRecommendedSpots, +} from "@/services/ootd.ts/ootdGet"; import { OotdDetailGetResponse } from "@/types/ootd"; import { useUserStore } from "@/store/useUserStore"; import "slick-carousel/slick/slick.css"; @@ -21,12 +25,17 @@ import Swal from "sweetalert2"; import CabapIcon from "../../../public/cabap-icon2.svg"; import BookmarkIcon from "../../../public/icon_bookmark.svg"; import BookmarkedIcon from "../../../public/bookmark-fill.svg"; -import { addBookmark, deleteBookmark, fetchIsBookmarked } from "@/services/bookmark/bookmark"; +import { + addBookmark, + deleteBookmark, + fetchIsBookmarked, +} from "@/services/bookmark/bookmark"; import WeatherIcon from "../../../public/WeatherIcon.svg"; import DefaultImage from "../../../public/defaultImage.svg"; import { getWeatherStatusInfo } from "@/constants/weatherTransition"; import RecommendedSpots from "./RecommendedSpot"; import RecommendedSpot from "./RecommendedSpot"; +import { searchTag } from "@/services/search"; interface OotdDetailProps { id: number; @@ -37,23 +46,23 @@ const OotdDetail: React.FC = ({ id }) => { ["ootdPostDetail", id], () => fetchOotdPostDetail(id), { - refetchOnWindowFocus: true, - refetchOnMount: true, - staleTime: 0, + refetchOnWindowFocus: true, + refetchOnMount: true, + staleTime: 0, } ); - console.log('Current post id:', id); + console.log("Current post id:", id); - const { data: recommendedSpots, isLoading: isSpotsLoading, error: spotsError } = useQuery( - ['recommendedSpots', id], - () => fetchRecommendedSpots(id), - { - enabled: !!id, - refetchOnWindowFocus: false, - } - ); - console.log('추천', recommendedSpots); + const { + data: recommendedSpots, + isLoading: isSpotsLoading, + error: spotsError, + } = useQuery(["recommendedSpots", id], () => fetchRecommendedSpots(id), { + enabled: !!id, + refetchOnWindowFocus: false, + }); + console.log("추천", recommendedSpots); const [isBookmarked, setIsBookmarked] = useState(false); @@ -80,11 +89,11 @@ const OotdDetail: React.FC = ({ id }) => { } await refetch(); } catch (error) { - console.error('북마크 처리 중 오류가 발생했습니다:', error); + console.error("북마크 처리 중 오류가 발생했습니다:", error); } }; - - const accessToken = Cookies.get('accessToken'); + + const accessToken = Cookies.get("accessToken"); const userInfo = useUserStore((state) => state.userInfo); @@ -114,53 +123,51 @@ const OotdDetail: React.FC = ({ id }) => { const handleDeleteClick = async () => { if (!data || !data.result) { await Swal.fire( - '오류 발생', - '게시물 데이터를 불러오는 중 문제가 발생했습니다. 다시 시도해주세요.', - 'error' + "오류 발생", + "게시물 데이터를 불러오는 중 문제가 발생했습니다. 다시 시도해주세요.", + "error" ); return; } - + const result = await Swal.fire({ - title: '정말 삭제하시겠습니까?', - icon: 'warning', - iconColor: '#FB3463', + title: "정말 삭제하시겠습니까?", + icon: "warning", + iconColor: "#FB3463", showCancelButton: true, - confirmButtonText: '네', - cancelButtonText: '아니오', - confirmButtonColor: '#FB3463', + confirmButtonText: "네", + cancelButtonText: "아니오", + confirmButtonColor: "#FB3463", customClass: { - popup: 'swal-custom-popup', - icon: 'swal-custom-icon' - } + popup: "swal-custom-popup", + icon: "swal-custom-icon", + }, }); - + if (result.isConfirmed) { try { await deleteOotdPost(data.result.post.id); await Swal.fire({ - icon: 'success', - title: '게시글을 삭제하였습니다.', - confirmButtonText: '확인', - confirmButtonColor: '#FB3463', + icon: "success", + title: "게시글을 삭제하였습니다.", + confirmButtonText: "확인", + confirmButtonColor: "#FB3463", customClass: { - popup: 'swal-custom-popup', - icon: 'swal-custom-icon' - } - } - ); - router.push('/ootd'); + popup: "swal-custom-popup", + icon: "swal-custom-icon", + }, + }); + router.push("/ootd"); } catch (error) { await Swal.fire( - '오류 발생', - '삭제하는 중 문제가 발생했습니다. 다시 시도해주세요.', - 'error' + "오류 발생", + "삭제하는 중 문제가 발생했습니다. 다시 시도해주세요.", + "error" ); } } }; - if (isLoading) { return null; } @@ -177,7 +184,6 @@ const OotdDetail: React.FC = ({ id }) => { const weatherInfo = getWeatherStatusInfo(ootdItem.ootd.weatherStatus); - const SampleNextArrow = (props: any) => { const { className, style, onClick, currentSlide, slideCount } = props; return ( @@ -219,123 +225,157 @@ const OotdDetail: React.FC = ({ id }) => { prevArrow: , }; + const handleTagClick = (tag: string) => { + router.push(`/search/${encodeURIComponent(tag)}`); // Redirect to the search page with the clicked tag + }; + return ( <>
-
- {/* 왼쪽 사용자 정보 및 location/weather 부분 */} -
-
- 사용자 프로필 -
-
- - {ootdItem.member.nickName} - -
-
- location -
-
- {ootdItem.post.location || '정보 없음'} -
+
+ {/* 왼쪽 사용자 정보 및 location/weather 부분 */} +
+
+ 사용자 프로필
-
- weather - - {weatherInfo.label === '정보 없음' ? ( - '정보 없음' - ) : ( - <> - {weatherInfo.label}, {ootdItem.ootd.weatherTemp}°C {' '} l {' '} - {formatDate(ootdItem.ootd.date)} - - )} +
+ + {ootdItem.member.nickName} +
+
+ location +
+
+ + {ootdItem.post.location || "정보 없음"} + +
+
+
+ weather + + {weatherInfo.label === "정보 없음" ? ( + "정보 없음" + ) : ( + <> + {weatherInfo.label}, {ootdItem.ootd.weatherTemp}°C l{" "} + {formatDate(ootdItem.ootd.date)} + + )} + +
-
- {/* 오른쪽 팔로우 버튼 및 아이콘들 */} -
- - {/* 북마크 및 메뉴 아이콘 */} -
- bookmark + -
- {data.result.post.bookmarkCount} -
-
- - {userMemberId === data.result.member.memberId && ( -
+ {/* 북마크 및 메뉴 아이콘 */} +
cabap - {isMenuOpen && ( -
-
- 삭제 -
-
-
router.push(`/edit/${id}`)}> - 수정 -
-
- - )} +
+ {data.result.post.bookmarkCount} +
- )} -
-
-
- - {ootdItem.post.images.map((image, index) => ( -
-
+ + {userMemberId === data.result.member.memberId && ( +
{`OOTD + {isMenuOpen && ( +
+
+ 삭제 +
+
+
router.push(`/edit/${id}`)} + > + 수정 +
+
+ )}
-
- ))} - - + )} +
+
+
+ + {ootdItem.post.images.map((image, index) => ( +
+
+ {`OOTD +
+
+ ))} +
-
') }}>
+
"), + }} + >
{ootdItem.post.tags.map((tag: string, index: number) => ( { + handleTagClick(tag); + }} > {tag} diff --git a/src/components/pages/ootd/RecentOotdPost.tsx b/src/components/pages/ootd/RecentOotdPost.tsx index b8e1c2e0..863bcb22 100644 --- a/src/components/pages/ootd/RecentOotdPost.tsx +++ b/src/components/pages/ootd/RecentOotdPost.tsx @@ -21,15 +21,16 @@ import CommentIcon1 from "../../../../public/commentIcon-default.svg"; import { TagContainerProps } from "@/types/tag"; import Cookies from "js-cookie"; -import SkeletonRecommendOotdPost from './SkeletonRecommendOotdPost'; -import SkeletonRecentOotdPost from './SkeletonRecentOotdPost'; - +import SkeletonRecommendOotdPost from "./SkeletonRecommendOotdPost"; +import SkeletonRecentOotdPost from "./SkeletonRecentOotdPost"; +import { searchTag } from "@/services/search"; const PAGE_SIZE = 12; const TagContainer: React.FC = ({ item }) => { const containerRef = useRef(null); const [visibleTags, setVisibleTags] = useState(item.post.tags); + const router = useRouter(); useEffect(() => { const container = containerRef.current; @@ -51,6 +52,10 @@ const TagContainer: React.FC = ({ item }) => { setVisibleTags(item.post.tags.slice(0, visibleCount)); }, [item.post.tags]); + const handleTagClick = (tag: string) => { + router.push(`/search/${encodeURIComponent(tag)}`); // Redirect to the search page with the clicked tag + }; + return (
@@ -60,7 +65,7 @@ const TagContainer: React.FC = ({ item }) => { {visibleTags.map((tag, index) => ( { - searchTag(tag); + handleTagClick(tag); }} key={index} className="tag-item px-4 py-1 bg-neutral-100 rounded-3xl text-xl justify-center items-center gap-2.5 inline-flex text-[#9d9d9d]" @@ -185,23 +190,22 @@ const RecentOotdPost: React.FC = () => { router.push("/login"); }; - const [showSkeleton, setShowSkeleton] = useState(true); useEffect(() => { - if (typeof window !== 'undefined') { // 클라이언트에서만 실행되도록 체크 - const delay = setTimeout(() => { - setShowSkeleton(false); - }, 1000); // 스켈레톤을 1초 동안 유지 - - return () => clearTimeout(delay); + if (typeof window !== "undefined") { + // 클라이언트에서만 실행되도록 체크 + const delay = setTimeout(() => { + setShowSkeleton(false); + }, 1000); // 스켈레톤을 1초 동안 유지 + + return () => clearTimeout(delay); } -}, [isLoading]); - - if (loading || showSkeleton || isLoading) { - return ; - } + }, [isLoading]); + if (loading || showSkeleton || isLoading) { + return ; + } return (
@@ -213,26 +217,22 @@ const RecentOotdPost: React.FC = () => {
)} -
{userInfo && ( - - handleTabChange("ALL")} - > - 전체글 - - + handleTabChange("ALL")} + > + 전체글 + )} - { userInfo && ( - handleTabChange('FOLLOWING')} - > - 팔로잉 - - + {userInfo && ( + handleTabChange("FOLLOWING")} + > + 팔로잉 + )}
void; @@ -11,7 +12,6 @@ interface SortingBarProps { } const SortingBar: React.FC = ({ - selectedSearchType, onSelectSearchType, selectedSortOrder, @@ -22,17 +22,21 @@ const SortingBar: React.FC = ({ { label: "OOTD", value: "OOTD" }, { label: "사용자 이름", value: "NICKNAME" }, { label: "블로그 이름", value: "BLOG" }, - ]; const sortOrders = [ { label: "최신순", value: "newest" }, { label: "인기순", value: "popular" }, ]; + const [page, setPage] = useState(0); + const handleOrderTypeChange = (value: string) => { + setOrderType(value); + setPage(0); + }; const router = useRouter(); + const [orderType, setOrderType] = useState("LATEST"); return ( -
))} +
+ +
{/* 정렬 방식 선택 */} -
- -
); }; diff --git a/src/services/search.ts b/src/services/search.ts index 27fe2172..1107e4b1 100644 --- a/src/services/search.ts +++ b/src/services/search.ts @@ -3,14 +3,13 @@ import { useUserStore } from "@/store/useUserStore"; import { useFollowingStore } from "@/store/useFollowingStore"; const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL; -let accessToken = ""; export async function searchTag(tag: string) { try { const response = await axios.get( `${backendUrl}//api/search/tag?tags=${tag}&postType=OOTD&page=0&size=1` ); - console.log("API Response:", response.data); + console.log("API Response tag~:", response.data); const postsData = response.data.result; } catch (error) { From fd997dc7a67f30f0934e5c9f2802ac9dece1caba Mon Sep 17 00:00:00 2001 From: yunhwancho Date: Sat, 28 Sep 2024 17:37:39 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix=20:=20=EC=B6=A9=EB=8F=8C=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ootd/OotdDetail.tsx | 142 +++++++++++------------------ 1 file changed, 52 insertions(+), 90 deletions(-) diff --git a/src/components/ootd/OotdDetail.tsx b/src/components/ootd/OotdDetail.tsx index f1d19463..e3eba070 100644 --- a/src/components/ootd/OotdDetail.tsx +++ b/src/components/ootd/OotdDetail.tsx @@ -35,9 +35,6 @@ import DefaultImage from "../../../public/defaultImage.svg"; import { getWeatherStatusInfo } from "@/constants/weatherTransition"; import RecommendedSpots from "./RecommendedSpot"; import RecommendedSpot from "./RecommendedSpot"; - - - import { RecommendedSpotsResponse } from "@/types/recommend"; import SkeletonRecommendOotdPost from "../pages/ootd/SkeletonRecommendOotdPost"; import SkeletonOotdDetailRecommend from "../pages/ootd/SkeletonOotdDetailRecommend"; @@ -60,17 +57,18 @@ const OotdDetail: React.FC = ({ id }) => { console.log("Current post id:", id); - - const { data: recommendedSpots, isLoading: isSpotsLoading, error: spotsError } = useQuery( - ['recommendedSpots', id], + const { + data: recommendedSpots, + isLoading: isSpotsLoading, + error: spotsError, + } = useQuery( + ["recommendedSpots", id], () => fetchRecommendedSpots(id), { enabled: !!id, refetchOnWindowFocus: false, } ); - - const [isBookmarked, setIsBookmarked] = useState(false); @@ -115,6 +113,10 @@ const OotdDetail: React.FC = ({ id }) => { const router = useRouter(); + const handleTagClick = (tag: string) => { + router.push(`/search/${encodeURIComponent(tag)}`); // Redirect to the search page with the clicked tag + }; + const handleProfileClick = () => { if (accessToken) { if (ootdItem.member.memberId == userInfo?.memberId) { @@ -176,25 +178,22 @@ const OotdDetail: React.FC = ({ id }) => { } }; - const handleLocationClick = (location: string) => { if (!location) return; - + if (isKoreanLocation(location)) { // 카카오맵으로 이동 (한국 주소) const encodedLocation = encodeURIComponent(location); const kakaoMapUrl = `https://map.kakao.com/link/search/${encodedLocation}`; - window.open(kakaoMapUrl, '_blank'); + window.open(kakaoMapUrl, "_blank"); } else { // 구글맵으로 이동 (해외 주소) const encodedLocation = encodeURIComponent(location); const googleMapUrl = `https://www.google.com/maps/search/?api=1&query=${encodedLocation}`; - window.open(googleMapUrl, '_blank'); + window.open(googleMapUrl, "_blank"); } }; - - if (isLoading) { return null; } @@ -242,8 +241,8 @@ const OotdDetail: React.FC = ({ id }) => { }; const settings = { - dots: ootdItem.post.images.length > 1, - infinite: ootdItem.post.images.length > 1, + dots: ootdItem.post.images.length > 1, + infinite: ootdItem.post.images.length > 1, speed: 500, slidesToShow: 1, slidesToScroll: 1, @@ -252,48 +251,22 @@ const OotdDetail: React.FC = ({ id }) => { prevArrow: , }; - const handleTagClick = (tag: string) => { - router.push(`/search/${encodeURIComponent(tag)}`); // Redirect to the search page with the clicked tag - }; - return ( <>
- -
- {/* 왼쪽 사용자 정보 및 location/weather 부분 */} -
-
- 사용자 프로필 -
-
- - {ootdItem.member.nickName} - -
-
- location -
-
- handleLocationClick(ootdItem.post.location || '정보 없음')} - > - {ootdItem.post.location || '정보 없음'} - -
- +
+ {/* 왼쪽 사용자 정보 및 location/weather 부분 */} +
+
+ 사용자 프로필
= ({ id }) => { />
- + + handleLocationClick( + ootdItem.post.location || "정보 없음" + ) + } + > {ootdItem.post.location || "정보 없음"}
@@ -338,28 +318,14 @@ const OotdDetail: React.FC = ({ id }) => {
- - {/* 오른쪽 팔로우 버튼 및 아이콘들 */} -
- - {/* 북마크 및 메뉴 아이콘 */} -
- bookmark + -
- {data.result.post.bookmarkCount} -
-
- - {userMemberId === data.result.member.memberId && ( -
- + {/* 북마크 및 메뉴 아이콘 */} +
bookmark = ({ id }) => {
{userMemberId === data.result.member.memberId && ( -
+
cabap = ({ id }) => { ))}
-
"), }} >
-
-
+
+
{ootdItem.post.tags.map((tag: string, index: number) => ( { handleTagClick(tag); }} @@ -445,11 +410,10 @@ const OotdDetail: React.FC = ({ id }) => { ))}
-
+
{formatDate(ootdItem.post.createDateTime)}
-
@@ -462,13 +426,11 @@ const OotdDetail: React.FC = ({ id }) => { refetchPostDetail={refetch} />
- { - isSpotsLoading ? ( - - ) : ( - - ) - } + {isSpotsLoading ? ( + + ) : ( + + )}
);