Skip to content
Merged
66 changes: 66 additions & 0 deletions src/hooks/useLikeToggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useState, useEffect } from "react";
import {
getLikedCompanies,
likeCompany,
unlikeCompany,
} from "@/apis/company/getLikedCompanies";
import useAuthStore from "@/store/authStore";
import useLikeStore from "@/store/useLikeStore";

export const useLikeToggle = (companyId) => {
const { isLoggedIn } = useAuthStore();
const [isLiked, setIsLiked] = useState(false);
const [loading, setLoading] = useState(true);
const [showLoginModal, setShowLoginModal] = useState(false);

const { likedMap, setLike } = useLikeStore();

// 로그인 및 좋아요 여부 확인
useEffect(() => {
const check = async () => {
if (isLoggedIn && companyId) {
const likedList = await getLikedCompanies();
const liked = likedList.some(
(c) => String(c.companyId) === String(companyId),
);
setIsLiked(liked);
setLike(companyId, liked);
}
setLoading(false);
};

if (companyId) check();
}, [companyId]);

// 좋아요 토글 함수
const toggleLike = async () => {
if (!isLoggedIn) {
setShowLoginModal(true);
return;
}

try {
const currentLiked = likedMap[companyId] ?? false;

if (currentLiked) {
await unlikeCompany(companyId);
} else {
await likeCompany(companyId);
}
const newLiked = !currentLiked;
setIsLiked(newLiked);
setLike(companyId, newLiked);
} catch (e) {
console.error("좋아요 토글 실패:", e);
}
};

return {
isLiked,
isLoggedIn,
loading,
toggleLike,
showLoginModal,
setShowLoginModal,
};
};
2 changes: 1 addition & 1 deletion src/pages/map/components/review/ReviewContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const ReviewContent = ({ item, hasBorder = true }) => {
item.reviewCategories?.includes(tag.value)
);

const profileIconSrc = `/svgs/profile/${item.profileColor || "gray"}.svg`;
const profileIconSrc = `/svgs/profile/${item?.profileColor || "gray"}.svg`;

return (
<div
Expand Down
25 changes: 17 additions & 8 deletions src/pages/myPageDetail/MyPageDetailPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useGetReviews, useGetCheers } from "@/apis/myPage/queries";
import ReviewItem from "@/pages/myPageDetail/components/ReviewItem";
import StoryItem from "@/pages/myPageDetail/components/StoryItem";
import noResult from "/svgs/myPage/noResult.svg";
import Spinner from "@/components/common/Spinner";

const MyPageDetailPage = () => {
const navigate = useNavigate();
Expand All @@ -20,6 +21,14 @@ const MyPageDetailPage = () => {
});
// const { data: heartsData, isLoading: isLoadingHearts } = useGetHearts({ enabled: kind === "찜" });

if (isLoadingReviews || isLoadingCheers) {
return (
<div className="flex justify-center items-center container">
<Spinner />
</div>
);
}

return (
<div className="flex flex-col pt-5 container overflow-y-auto scrollbar-hide">
<div className="mt-10 px-5 mb-4" onClick={() => navigate(-1)}>
Expand All @@ -38,7 +47,7 @@ const MyPageDetailPage = () => {

{kind === "찜" && (
<div className="flex justify-between items-center px-5">
<div className="flex gap-2 items-center">
<div className="flex gap-2 items-center my-2">
<img src={heart} className="w-8 h-8" />
<p className="h3">저장한 장소</p>
</div>
Expand All @@ -48,7 +57,7 @@ const MyPageDetailPage = () => {

{kind === "응원" && (
<div className="flex justify-between items-center px-5">
<div className="flex gap-2 items-center">
<div className="flex gap-2 items-center my-2">
<img src={cheer} className="w-8 h-8" />
<p className="h3">내가 응원한 이야기</p>
</div>
Expand All @@ -59,37 +68,37 @@ const MyPageDetailPage = () => {
<div className="flex flex-col gap-4 w-full bg-gray-2 p-5 min-h-screen">
{kind === "리뷰" && (
<>
{reviewsData?.length > 0 ? (
{!isLoadingReviews && reviewsData?.length > 0 ? (
reviewsData.map((item, idx) => (
<ReviewItem data={item} key={idx} />
))
) : (
) : !isLoadingReviews && reviewsData?.length === 0 ? (
<div className="flex flex-col justify-center items-center mt-36">
<img src={noResult} />
<p className="h4 text-gray-9 text-center py-8">
아직 작성한 리뷰가
<br /> 없어요
</p>
</div>
)}
) : null}
</>
)}

{kind === "응원" && (
<>
{cheersData?.length > 0 ? (
{!isLoadingCheers && cheersData?.length > 0 ? (
cheersData.map((item) => (
<StoryItem item={item} key={item.storyId} />
))
) : (
) : !isLoadingCheers && cheersData?.length === 0 ? (
<div className="flex flex-col justify-center items-center mt-36">
<img src={noResult} />
<p className="h4 text-gray-9 text-center py-8">
아직 응원한 이야기가
<br /> 없어요
</p>
</div>
)}
) : null}
</>
)}
</div>
Expand Down
79 changes: 7 additions & 72 deletions src/pages/myPageDetail/components/ReviewItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,93 +2,28 @@ import ReviewContent from "@/pages/map/components/review/ReviewContent";
import { useNavigate } from "react-router-dom";
import { useGetCompanyPreview } from "@/apis/company/queries";
import { businessTypeNameMap } from "@/constants/categoryMap";
import { useState, useEffect } from "react";
import {
getLikedCompanies,
likeCompany,
unlikeCompany,
} from "@/apis/company/getLikedCompanies";
import useAuthStore from "@/store/authStore";

import useLikeStore from "@/store/useLikeStore";
import HaveToLoginModal from "@/components/common/HaveToLoginModal";
import useUserInfoStore from "@/store/userInfoStore";

const dummyReviewItem = {
name: "김소영",
profileColor: "pink",
temperature: 74.6,
reviewContent:
"제품 품질도 후드러고 청건하게 잘 관리되어 있어요. 다시 방문하고 싶어요!",
reviewCategories: ["GOOD_QUALITY", "CLEAN", "REVISIT"],
};
import { useLikeToggle } from "@/hooks/useLikeToggle";

const ReviewItem = ({ data }) => {
const navigate = useNavigate();
const { data: companyData } = useGetCompanyPreview(data.companyId);
const [showLoginModal, setShowLoginModal] = useState(false);
const [isLiked, setIsLiked] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [loading, setLoading] = useState(true);

const { userInfo } = useUserInfoStore();

const { likedMap, setLike } = useLikeStore();
const { likedMap } = useLikeStore();
const isGloballyLiked = likedMap[data.companyId] ?? false;

const { isLoggedIn, toggleLike } = useLikeToggle(data.companyId);

const combinedReviews = {
...data,
name: userInfo.name,
profileColor: userInfo.profileColor,
};

useEffect(() => {
const checkLoginAndLiked = async () => {
const isAuthenticated = await useAuthStore.getState().checkAuth();
setIsLoggedIn(isAuthenticated);

if (isAuthenticated && data?.companyId) {
const likedList = await getLikedCompanies();
const liked = likedList.some(
(c) => String(c.companyId) === String(data.companyId)
);
setIsLiked(liked);
setLike(data.companyId, liked);
}
setLoading(false);
};

if (data?.companyId) checkLoginAndLiked();
}, [data?.companyId]);

const handleLikeClick = async () => {
const isAuthenticated = await useAuthStore.getState().checkAuth();
setIsLoggedIn(isAuthenticated);

if (!isAuthenticated) {
setShowLoginModal(true);
return;
}

try {
setLoading(true);
const currentLiked = likedMap[data.companyId] ?? false;

if (currentLiked) {
await unlikeCompany(data.companyId);
} else {
await likeCompany(data.companyId);
}

const newLiked = !currentLiked;
setIsLiked(newLiked);
setLike(data.companyId, newLiked);
} catch (e) {
console.error("좋아요 토글 실패:", e);
} finally {
setLoading(false);
}
};

return (
<div
className="flex flex-col rounded-md pt-6 px-5 bg-white"
Expand All @@ -107,14 +42,14 @@ const ReviewItem = ({ data }) => {
<button
onClick={(e) => {
e.stopPropagation();
handleLikeClick();
toggleLike();
}}
>
<img
src={
isLoggedIn && isGloballyLiked
? "/svgs/storeReview/fullHeartIcon.svg"
: "/svgs/Ic_Heart-Empty.svg"
: "/svgs/common/Ic_Heart-Empty.svg"
}
alt="좋아요 버튼"
className="w-6 h-6"
Expand Down
79 changes: 22 additions & 57 deletions src/pages/review/components/PlaceInfo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,25 @@ import {
companyTypeNameMap,
companyTypeIconMap,
} from "@constants/categoryMap";
import { useState, useEffect } from "react";
import { usePaymentStore } from "@/store/paymentStore";
import {
getLikedCompanies,
likeCompany,
unlikeCompany,
} from "@apis/company/getLikedCompanies";
import HaveToLoginModal from "@components/common/HaveToLoginModal";
import { openNaverMapRoute } from "@pages/map/utils/openNaverMapRoute";
import { useUserCoords } from "@pages/search/hooks/useUserCoords";
import useAuthStore from "@/store/authStore";
import Spinner from "@/components/common/Spinner";
import { useLikeToggle } from "@/hooks/useLikeToggle";

const PlaceInfo = ({ placeInfo }) => {
const userCoords = useUserCoords();

const [showLoginModal, setShowLoginModal] = useState(false);
const [isLiked, setIsLiked] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [loading, setLoading] = useState(true);

const { companyId } = usePaymentStore();

// 로그인 여부 + 찜 여부 확인
useEffect(() => {
const checkLoginAndLiked = async () => {
const isAuthenticated = await useAuthStore.getState().checkAuth();
setIsLoggedIn(isAuthenticated);

if (isAuthenticated && companyId) {
const likedList = await getLikedCompanies();
const liked = likedList.some(
(c) => String(c.companyId) === String(companyId)
);
setIsLiked(liked);
}
setLoading(false);
};

if (companyId) checkLoginAndLiked();
}, [companyId]);

const handleLikeClick = async () => {
const isAuthenticated = await useAuthStore.getState().checkAuth();
setIsLoggedIn(isAuthenticated);

if (!isAuthenticated) {
setShowLoginModal(true);
return;
}

try {
setLoading(true);
if (isLiked) {
await unlikeCompany(companyId);
} else {
await likeCompany(companyId);
}
setIsLiked((prev) => !prev);
} catch (e) {
console.error("좋아요 토글 실패:", e);
} finally {
setLoading(false);
}
};
const {
isLiked,
isLoggedIn,
loading,
toggleLike,
showLoginModal,
setShowLoginModal,
} = useLikeToggle(companyId);

const handleRouteClick = (e) => {
e.preventDefault();
Expand All @@ -89,6 +44,13 @@ const PlaceInfo = ({ placeInfo }) => {
}
};

if (loading) {
return (
<div className="flex justify-center items-center container">
<Spinner />
</div>
);
}
return (
<div className="w-full px-5">
<div className="flex justify-between items-start mt-4 w-full">
Expand Down Expand Up @@ -153,14 +115,17 @@ const PlaceInfo = ({ placeInfo }) => {
</a>

<button
onClick={handleLikeClick}
onClick={(e) => {
e.preventDefault();
toggleLike();
}}
className="w-12 h-12 flex items-center justify-center rounded-md bg-[#FAFAF9] shrink-0"
>
<img
src={
isLoggedIn && isLiked
? "/svgs/storeReview/fullHeartIcon.svg"
: "/svgs/Ic_Heart-Empty.svg"
: "/svgs/common/Ic_Heart-Empty.svg"
}
alt="좋아요 버튼"
className="w-6 h-6"
Expand Down
Loading