From 282dcdad12e659eb06f26cbda9e7eb8db1f33319 Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Thu, 5 Feb 2026 13:45:05 +0900 Subject: [PATCH 01/11] =?UTF-8?q?design:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20toast=20=EB=B0=8F=20=EB=B6=81=EB=A7=88=ED=81=AC=20s?= =?UTF-8?q?kelton=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/components/InterestPage.tsx | 6 +----- src/pages/mypage/MyInterstListPage.tsx | 2 ++ src/shared/SystemHeader.tsx | 6 +++++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/pages/home/components/InterestPage.tsx b/src/pages/home/components/InterestPage.tsx index 8644f1d..da6c4b6 100644 --- a/src/pages/home/components/InterestPage.tsx +++ b/src/pages/home/components/InterestPage.tsx @@ -17,11 +17,7 @@ export const InterestPage = ({ return ( <> - {isRefreshing ? ( - // 반복되는 Skeleton UI는 별도 컴포넌트로 빼면 깔끔합니다. - ) : ( - - )} + {isRefreshing ? : } ); }; diff --git a/src/pages/mypage/MyInterstListPage.tsx b/src/pages/mypage/MyInterstListPage.tsx index 8eaf540..fe3b807 100644 --- a/src/pages/mypage/MyInterstListPage.tsx +++ b/src/pages/mypage/MyInterstListPage.tsx @@ -3,6 +3,7 @@ import { MYPAGE_TAP } from "../../constants/tab"; import { TabSelectList } from "../home/components/TabSelectList"; import { CardItem } from "../../shared/CardItem"; import { useInfiniteBookmarkPosts } from "../../hooks/useGetInfiniteBookmarkList"; +import { Loading } from "../../shared/Loading"; // mypage 관심사 list export const MyIntersListPage = () => { @@ -54,6 +55,7 @@ export const MyIntersListPage = () => { ); })} + {isFetchingNextPage && }
); diff --git a/src/shared/SystemHeader.tsx b/src/shared/SystemHeader.tsx index e9a8757..601a77b 100644 --- a/src/shared/SystemHeader.tsx +++ b/src/shared/SystemHeader.tsx @@ -11,6 +11,7 @@ import { postLogout } from "../lib/auth"; import { useGetMyProfile } from "../lib/my"; import { toast } from "react-toastify"; import Alert from "@/assets/icons/alert2.svg"; +import Logout from "@/assets/icons/confirm.svg"; export const SystemHeader = () => { const navigate = useNavigate(); @@ -25,6 +26,9 @@ export const SystemHeader = () => { const handleLogout = async () => { try { await postLogout(); + toast.info(`로그아웃 되었습니다.`, { + icon: logout, + }); } catch (error) { console.error("로그아웃 실패:", error); } finally { @@ -102,7 +106,7 @@ export const SystemHeader = () => { className="size-10 cursor-pointer rounded-full" onClick={() => { if (!isLogin) { - toast.info(`로그인이 sss필요한 서비스입니다.`, { + toast.info(`로그인이 필요한 서비스입니다.`, { icon: login으로 이동, }); navigate("/login"); From 96c1d2bb961239b9ca82b4f93998098fcce599fc Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Thu, 5 Feb 2026 13:46:51 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20=EA=B2=80=EC=83=89=ED=95=A0=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=EC=97=90=EB=8F=84=20main=20tab=20=EB=B3=B4?= =?UTF-8?q?=EC=9D=B4=EA=B2=8C=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20onboardin?= =?UTF-8?q?g=20loading=20ux=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/HomePage.tsx | 31 ++++++++++++++------------ src/pages/onboarding/OnboardingTag.tsx | 9 ++++++-- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/pages/home/HomePage.tsx b/src/pages/home/HomePage.tsx index f08e91e..3540a44 100644 --- a/src/pages/home/HomePage.tsx +++ b/src/pages/home/HomePage.tsx @@ -6,7 +6,6 @@ import { useCompanyStore } from "../../store/uesCompanyStore"; import { useGetCompany } from "../../lib/company"; import { usePostRecommendPostList } from "../../lib/recommendation"; import { TAB_MAP } from "../../constants/tab"; -import { Loading } from "../../shared/Loading"; import { useNavigate, useSearchParams } from "react-router-dom"; import { useDebounce } from "../../hooks/useDebouce"; import { SearchPostList } from "./components/SearchPostList"; @@ -26,13 +25,14 @@ export const HomePage = () => { const maxCompany = companyData?.companies.slice(0, 8) ?? []; - const [searchParams] = useSearchParams(); + const [searchParams, setSearchParams] = useSearchParams(); const searchQuery = searchParams.get("search"); - // console.log(searchQuery); const debouncedInput = useDebounce(searchQuery, 200); + const isSearching = debouncedInput && debouncedInput.trim() !== ""; const { user } = useUserStore(); const isLogin = !!user?.accessToken; const navigate = useNavigate(); + const handleTabChange = (tab: number) => { if (tab === 1 && !isLogin) { toast.info("로그인이 필요한 서비스입니다.", { @@ -41,25 +41,28 @@ export const HomePage = () => { navigate("/login"); return; } + if (isSearching) { + setSearchParams({}); //검색 종료 + } setSelectedTab(tab); }; return (
setModal(false)}> - {/* */} + {debouncedInput && debouncedInput.trim() !== "" ? ( - }> - - + <> + }> + + + ) : ( <> - - {selectedTab === 0 && ( <> { const navigate = useNavigate(); @@ -17,6 +18,7 @@ export const OnboardingTag = () => { const { tag, toggleTag, getApiPayload } = useTagStore(); const { nickname, aboutMe, email } = useOnboardingStore(); const handleForm = useSubmitOnboarding(); + const isSubmitting = handleForm.isPending; const initialOpenedIndices = useMemo(() => { return TAG.map((name, index) => { @@ -68,7 +70,6 @@ export const OnboardingTag = () => {

선택한 기술:

- {/* store의 상태로 선택 개수 표시 */}

{tag.length}

@@ -129,7 +130,11 @@ export const OnboardingTag = () => { 이전
From 21e2fbc5ae96f5d5cc973db8afce77da35d7f793 Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Thu, 5 Feb 2026 13:47:27 +0900 Subject: [PATCH 03/11] =?UTF-8?q?design:=20btn=20text=EA=B5=B5=EA=B8=B0?= =?UTF-8?q?=EC=99=80=20=EB=AC=B8=EC=9D=98=ED=95=98=EA=B8=B0=20hover?= =?UTF-8?q?=EC=B6=AB=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/confirm.svg | 1 + src/pages/home/components/TabSelectList.tsx | 2 +- src/pages/mypage/AskPage.tsx | 2 +- src/pages/mypage/EditInterestPage.tsx | 2 +- src/pages/mypage/components/ProfileHeader.tsx | 2 +- src/pages/onboarding/components/OnboardingHeader.tsx | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 src/assets/icons/confirm.svg diff --git a/src/assets/icons/confirm.svg b/src/assets/icons/confirm.svg new file mode 100644 index 0000000..33c90dd --- /dev/null +++ b/src/assets/icons/confirm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/pages/home/components/TabSelectList.tsx b/src/pages/home/components/TabSelectList.tsx index f15f0a4..0d48a92 100644 --- a/src/pages/home/components/TabSelectList.tsx +++ b/src/pages/home/components/TabSelectList.tsx @@ -3,7 +3,7 @@ import clsx from "clsx"; interface TabSelectList { className?: string; - selected?: number; + selected?: number | null; onChange: (idx: number) => void; tagList: string[]; } diff --git a/src/pages/mypage/AskPage.tsx b/src/pages/mypage/AskPage.tsx index 886f59b..5a623ad 100644 --- a/src/pages/mypage/AskPage.tsx +++ b/src/pages/mypage/AskPage.tsx @@ -71,7 +71,7 @@ export const AskPage = () => { {ASK_MAP.map(askItem => { return (

handleAsk(e, askItem)} > {askItem} diff --git a/src/pages/mypage/EditInterestPage.tsx b/src/pages/mypage/EditInterestPage.tsx index f383a60..0f9e1fd 100644 --- a/src/pages/mypage/EditInterestPage.tsx +++ b/src/pages/mypage/EditInterestPage.tsx @@ -105,7 +105,7 @@ export const EditInterestPage = () => { From 98f4ddb4a3ceb27039026eac02a16421325f7061 Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Thu, 5 Feb 2026 18:32:10 +0900 Subject: [PATCH 08/11] =?UTF-8?q?fix:=20=EB=B9=84=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EC=82=AC=EC=9A=A9=EC=9E=90=EB=8A=94=20=EC=9D=BD?= =?UTF-8?q?=EC=9D=80=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20post=20=EB=A7=89?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/CardItem.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/CardItem.tsx b/src/shared/CardItem.tsx index 6df2340..bbd865c 100644 --- a/src/shared/CardItem.tsx +++ b/src/shared/CardItem.tsx @@ -79,6 +79,7 @@ export const CardItem = forwardRef( if (!id || !url) return; try { + if (!isLogin) return; await readPostMutation.mutateAsync({ postId: id, readAt: new Date().toISOString(), From 189e68e9c519a15f8c8fbd27b0e99a8550636787 Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Thu, 5 Feb 2026 19:43:41 +0900 Subject: [PATCH 09/11] =?UTF-8?q?refactor:=20=EC=BA=90=EC=8B=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useGetInfiniteActivityPostList.ts | 3 ++- src/hooks/useGetInfiniteCompaniesList.ts | 2 ++ src/hooks/useGetInfinitePostList.ts | 2 ++ src/lib/activity.ts | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/hooks/useGetInfiniteActivityPostList.ts b/src/hooks/useGetInfiniteActivityPostList.ts index 403a05c..9c15ba6 100644 --- a/src/hooks/useGetInfiniteActivityPostList.ts +++ b/src/hooks/useGetInfiniteActivityPostList.ts @@ -4,6 +4,7 @@ import { getActivityPostList, type ActivityPostType } from "../lib/activity"; export const useInfiniteActivityPosts = (type: ActivityPostType, size = 20) => { return useSuspenseInfiniteQuery({ queryKey: ["posts", "activity", type], + queryFn: ({ pageParam }) => getActivityPostList(type, { pageParam, @@ -21,6 +22,6 @@ export const useInfiniteActivityPosts = (type: ActivityPostType, size = 20) => { }, select: res => res.pages, - staleTime: 0, + gcTime: 1000 * 60 * 5, }); }; diff --git a/src/hooks/useGetInfiniteCompaniesList.ts b/src/hooks/useGetInfiniteCompaniesList.ts index 50c2ae6..99a3fe1 100644 --- a/src/hooks/useGetInfiniteCompaniesList.ts +++ b/src/hooks/useGetInfiniteCompaniesList.ts @@ -31,5 +31,7 @@ export const useInfiniteCompaniesPosts = ({ }, select: res => res.pages, + staleTime: 1000 * 60 * 5, + gcTime: 1000 * 60 * 10, }); }; diff --git a/src/hooks/useGetInfinitePostList.ts b/src/hooks/useGetInfinitePostList.ts index 962efc9..a30ecf4 100644 --- a/src/hooks/useGetInfinitePostList.ts +++ b/src/hooks/useGetInfinitePostList.ts @@ -50,5 +50,7 @@ export const useInfinitePosts = ({ }, select: res => res.pages, + staleTime: 1000 * 60 * 5, + gcTime: 1000 * 60 * 10, }); }; diff --git a/src/lib/activity.ts b/src/lib/activity.ts index 8155d09..b6e2f02 100644 --- a/src/lib/activity.ts +++ b/src/lib/activity.ts @@ -36,7 +36,7 @@ export const usePostBookmark = () => { return { previousQueries }; }, onError: () => queryClient.invalidateQueries({ queryKey: ["posts"] }), - onSettled: () => queryClient.invalidateQueries({ queryKey: ["posts"] }), + // onSettled: () => queryClient.invalidateQueries({ queryKey: ["posts"] }), }); }; @@ -67,7 +67,7 @@ export const useDeleteBookmark = () => { return { previousQueries }; }, onError: () => queryClient.invalidateQueries({ queryKey: ["posts"] }), - onSettled: () => queryClient.invalidateQueries({ queryKey: ["posts"] }), + // onSettled: () => queryClient.invalidateQueries({ queryKey: ["posts"] }), }); }; From 23347776c241bccfcc31302955599295e389ab7d Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Thu, 5 Feb 2026 19:44:48 +0900 Subject: [PATCH 10/11] =?UTF-8?q?fix:=20=EB=82=99=EA=B4=80=EC=A0=81=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=B6=81=EB=A7=88?= =?UTF-8?q?=ED=81=AC=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/queryUpdata.ts | 105 +++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/src/utils/queryUpdata.ts b/src/utils/queryUpdata.ts index ac33ce8..5f1fccd 100644 --- a/src/utils/queryUpdata.ts +++ b/src/utils/queryUpdata.ts @@ -1,13 +1,71 @@ -//낙관적 업데이트 export const updateBookmarkState = ( old: any, postId: number, isBookmarked: boolean, ) => { - // console.log("업뎃데이터", old); if (!old) return old; - //데이터 구조에 따른 분기 + // 무한 스크롤 + if (old.pages && Array.isArray(old.pages)) { + return { + ...old, + pages: old.pages.map((page: any) => { + const dataKey = page.data?.posts + ? "posts" + : page.data?.readPosts + ? "readPosts" + : page.data?.bookmarks + ? "bookmarks" + : null; + + if (!dataKey || !page.data[dataKey]) return page; + + // 북마크 리스트 filter + // 나머지는 상태만 업데이트 + if (dataKey === "bookmarks" && !isBookmarked) { + return { + ...page, + data: { + ...page.data, + [dataKey]: page.data[dataKey].filter( + (post: any) => post.id !== postId && post.postId !== postId, + ), + }, + }; + } + return { + ...page, + data: { + ...page.data, + [dataKey]: page.data[dataKey].map((post: any) => + post.id === postId || post.postId === postId + ? { ...post, isBookmarked } + : post, + ), + }, + }; + }), + }; + } + + // 2. 추천 게시글 + const isRec = old.recommendations || (old.data && old.data.recommendations); + if (isRec) { + const isRoot = !!old.recommendations; + const target = isRoot ? old : old.data; + + const updated = { + ...target, + recommendations: target.recommendations.map((post: any) => + post.postId === postId || post.id === postId + ? { ...post, isBookmarked } + : post, + ), + }; + return isRoot ? updated : { ...old, data: updated }; + } + + // 3. 일반 배열 구조 또는 data 속성 내 배열 구조 if (Array.isArray(old)) { return old.map((post: any) => post.id === postId || post.postId === postId @@ -15,6 +73,7 @@ export const updateBookmarkState = ( : post, ); } + if (old.data && Array.isArray(old.data)) { return { ...old, @@ -25,46 +84,6 @@ export const updateBookmarkState = ( ), }; } - if (old.pages) { - return { - ...old, - pages: old.pages.map((page: any) => ({ - ...page, - data: { - ...page.data, - posts: page.data.posts.map((post: any) => - post.id === postId || post.postId === postId - ? { ...post, isBookmarked } - : post, - ), - }, - })), - }; - } - if (old.recommendations) { - return { - ...old, - recommendations: old.recommendations.map((post: any) => - post.postId === postId || post.id === postId - ? { ...post, isBookmarked } - : post, - ), - }; - } - - if (old.data && old.data.recommendations) { - return { - ...old, - data: { - ...old.data, - recommendations: old.data.recommendations.map((post: any) => - post.postId === postId || post.id === postId - ? { ...post, isBookmarked } - : post, - ), - }, - }; - } return old; }; From c04a304c3a7e996e40e887ed6cb92d54498b1334 Mon Sep 17 00:00:00 2001 From: JeonSuna Date: Thu, 5 Feb 2026 21:39:32 +0900 Subject: [PATCH 11/11] =?UTF-8?q?fix:=20home=EC=9C=BC=EB=A1=9C=20=EB=8F=8C?= =?UTF-8?q?=EC=95=84=EC=98=AC=EB=95=8C=20store=20=EB=B9=84=EC=9B=8C?= =?UTF-8?q?=EB=91=90=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/HomePage.tsx | 25 ++++++++++++++++++------- src/shared/SystemHeader.tsx | 6 ++++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/pages/home/HomePage.tsx b/src/pages/home/HomePage.tsx index 3540a44..d131547 100644 --- a/src/pages/home/HomePage.tsx +++ b/src/pages/home/HomePage.tsx @@ -1,7 +1,7 @@ import { TabSelectList } from "./components/TabSelectList"; import { CompanyFilterList } from "./components/CompanyFilterList"; import { PostCardList } from "./components/PostCardList"; -import { Suspense, useState } from "react"; +import { Suspense, useEffect, useState } from "react"; import { useCompanyStore } from "../../store/uesCompanyStore"; import { useGetCompany } from "../../lib/company"; import { usePostRecommendPostList } from "../../lib/recommendation"; @@ -14,10 +14,11 @@ import { toast } from "react-toastify"; import Alert from "@/assets/icons/alert2.svg"; import { SkeletonList } from "../../shared/SkeletonList"; import { InterestPage } from "./components/InterestPage"; +import { Loading } from "../../shared/Loading"; export const HomePage = () => { const [selectedTab, setSelectedTab] = useState(0); const [modal, setModal] = useState(false); - const { companies, toggleCompany } = useCompanyStore(); + const { companies, toggleCompany, resetCompanies } = useCompanyStore(); const { data: companyData } = useGetCompany(); const { mutate: postRecommendList, isPending: isRefreshing } = @@ -35,22 +36,32 @@ export const HomePage = () => { const handleTabChange = (tab: number) => { if (tab === 1 && !isLogin) { + // resetCompanies(); toast.info("로그인이 필요한 서비스입니다.", { icon: login으로 이동, }); + navigate("/login"); + return; } - if (isSearching) { - setSearchParams({}); //검색 종료 - } + setSearchParams({}); setSelectedTab(tab); }; + useEffect(() => { + //store비우긴 + return () => { + resetCompanies(); + }; + }, []); + return (

setModal(false)}> { )} {/* 나와맞는 게시글 */} {selectedTab === 1 && isLogin && ( - }> + }> { const isLogin = !!user?.accessToken; const { data } = useGetMyProfile(isLogin); + const [searchParams] = useSearchParams(); + const searchQuery = searchParams.get("search") ?? ""; const handleLogout = async () => { try { @@ -92,7 +94,7 @@ export const SystemHeader = () => { type="text" placeholder="검색어 또는 태그명 입력" className="w-full px-3 py-2 focus:outline-none outline-none" - value={input} + value={searchQuery} onChange={e => setInput(e.target.value)} />