From a3265db1c79b2c6e87f507bd4d3115cf68377fd1 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Fri, 27 Feb 2026 16:11:32 +0900 Subject: [PATCH 1/5] feat: add hasJob query using /api/v3/users/job --- apps/client/src/shared/apis/axios.ts | 11 ++++++++++- apps/client/src/shared/apis/queries.ts | 12 ++++++++++++ apps/client/src/shared/types/api.ts | 4 ++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/client/src/shared/apis/axios.ts b/apps/client/src/shared/apis/axios.ts index efec01f..d4f4755 100644 --- a/apps/client/src/shared/apis/axios.ts +++ b/apps/client/src/shared/apis/axios.ts @@ -1,5 +1,9 @@ import apiRequest from '@shared/apis/setting/axiosInstance'; -import { EditArticleRequest, JobsResponse } from '@shared/types/api'; +import { + EditArticleRequest, + HasJobResponse, + JobsResponse, +} from '@shared/types/api'; import { formatLocalDateTime } from '@shared/utils/formatDateTime'; export const getDashboardCategories = async () => { @@ -84,6 +88,11 @@ export const getMyProfile = async () => { return data.data; }; +export const getHasJob = async (): Promise => { + const { data } = await apiRequest.get('/api/v3/users/job'); + return data.data; +}; + export const getJobs = async (): Promise => { const { data } = await apiRequest.get('/api/v3/enums/jobs'); return data.data; diff --git a/apps/client/src/shared/apis/queries.ts b/apps/client/src/shared/apis/queries.ts index 47481df..af43673 100644 --- a/apps/client/src/shared/apis/queries.ts +++ b/apps/client/src/shared/apis/queries.ts @@ -5,6 +5,7 @@ import { getArticleDetail, getDashboardCategories, getGoogleProfile, + getHasJob, getJobs, getMyProfile, patchUserJob, @@ -22,6 +23,7 @@ import { ArticleReadStatusResponse, DashboardCategoriesResponse, EditArticleRequest, + HasJobResponse, JobsResponse, } from '@shared/types/api'; import { fetchOGData } from '@shared/utils/fetchOgData'; @@ -182,6 +184,16 @@ export const useGetMyProfile = () => { }); }; +export const useGetHasJob = ( + enabled = true +): UseQueryResult => { + return useQuery({ + queryKey: ['hasJob'], + queryFn: getHasJob, + enabled, + }); +}; + export const useGetJobs = (): UseQueryResult => { return useQuery({ queryKey: ['jobs'], diff --git a/apps/client/src/shared/types/api.ts b/apps/client/src/shared/types/api.ts index 340b7ad..b0d2e3c 100644 --- a/apps/client/src/shared/types/api.ts +++ b/apps/client/src/shared/types/api.ts @@ -50,3 +50,7 @@ export interface JobOption { export interface JobsResponse { jobs: JobOption[]; } + +export interface HasJobResponse { + hasJob: boolean; +} From 18bc517cede604c6d8bd54f92280c2ec0400c82e Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Fri, 27 Feb 2026 16:11:45 +0900 Subject: [PATCH 2/5] feat: gate job selection funnel in layout by auth hasJob state --- apps/client/src/layout/Layout.tsx | 31 ++++++++++++++++++++++--- apps/client/src/pages/remind/Remind.tsx | 14 ----------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/apps/client/src/layout/Layout.tsx b/apps/client/src/layout/Layout.tsx index 4b997da..97e9b72 100644 --- a/apps/client/src/layout/Layout.tsx +++ b/apps/client/src/layout/Layout.tsx @@ -1,19 +1,35 @@ import { Outlet, useLocation } from 'react-router-dom'; import { Sidebar } from '@shared/components/sidebar/Sidebar'; import { ROUTES_CONFIG } from '@routes/routesConfig'; +import { useGetHasJob } from '@shared/apis/queries'; +import JobSelectionFunnel from '@shared/components/jobSelectionFunnel/JobSelectionFunnel'; +import { useQueryClient } from '@tanstack/react-query'; const Layout = () => { const location = useLocation(); + const queryClient = useQueryClient(); const isPolicyPage = location.pathname === ROUTES_CONFIG.privacyPolicy.path || location.pathname === ROUTES_CONFIG.termsOfService.path; - const isSidebarHidden = + const isAuthPage = location.pathname.startsWith(ROUTES_CONFIG.onboarding.path) || location.pathname.startsWith(ROUTES_CONFIG.login.path) || - location.pathname.startsWith(ROUTES_CONFIG.onboardingCallback.path) || - isPolicyPage; + location.pathname.startsWith(ROUTES_CONFIG.onboardingCallback.path); + + const isSidebarHidden = isAuthPage || isPolicyPage; + const isLoggedIn = !!localStorage.getItem('token'); + + const { data: hasJobData, isLoading: isHasJobLoading } = useGetHasJob( + isLoggedIn && !isAuthPage + ); + + const shouldShowJobSelectionFunnel = + isLoggedIn && + !isAuthPage && + !isHasJobLoading && + hasJobData?.hasJob === false; return ( <> @@ -23,6 +39,15 @@ const Layout = () => { + {shouldShowJobSelectionFunnel && ( +
+ { + queryClient.invalidateQueries({ queryKey: ['hasJob'] }); + }} + /> +
+ )} ); }; diff --git a/apps/client/src/pages/remind/Remind.tsx b/apps/client/src/pages/remind/Remind.tsx index e14703c..285963c 100644 --- a/apps/client/src/pages/remind/Remind.tsx +++ b/apps/client/src/pages/remind/Remind.tsx @@ -20,7 +20,6 @@ import { useGetArticleDetail, usePutArticleReadStatus, } from '@shared/apis/queries'; -import JobSelectionFunnel from '@shared/components/jobSelectionFunnel/JobSelectionFunnel'; import TooltipCard from '@shared/components/tooltipCard/TooltipCard'; import { useInfiniteScroll } from '@shared/hooks/useInfiniteScroll'; import { useQueryClient } from '@tanstack/react-query'; @@ -35,9 +34,6 @@ const Remind = () => { const [activeBadge, setActiveBadge] = useState<'read' | 'notRead'>('notRead'); const [isDeleteOpen, setIsDeleteOpen] = useState(false); const [deleteTargetId, setDeleteTargetId] = useState(null); - const [showJobSelectionFunnel, setShowJobSelectionFunnel] = useState( - () => localStorage.getItem('hasJob') !== 'true' - ); const scrollContainerRef = useRef(null); const formattedDate = useMemo(() => { @@ -254,16 +250,6 @@ const Remind = () => { )} - - {showJobSelectionFunnel && ( -
- { - setShowJobSelectionFunnel(false); - }} - /> -
- )} ); }; From 8893f154a681592fe595639551b8535150efe5b1 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Fri, 27 Feb 2026 16:23:53 +0900 Subject: [PATCH 3/5] feat: invalidate hasJob query after updating user job --- apps/client/src/shared/apis/queries.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/client/src/shared/apis/queries.ts b/apps/client/src/shared/apis/queries.ts index af43673..affd778 100644 --- a/apps/client/src/shared/apis/queries.ts +++ b/apps/client/src/shared/apis/queries.ts @@ -211,7 +211,14 @@ export const useSuspenseGetJobs = () => { }; export const usePatchUserJob = () => { + const queryClient = useQueryClient(); + return useMutation({ mutationFn: (data: patchUserJobRequest) => patchUserJob(data), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: ['hasJob'], + }); + }, }); }; From b4d5053d99c463d26ca1a96cf3917a18f01ef2a0 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Fri, 27 Feb 2026 16:24:01 +0900 Subject: [PATCH 4/5] feat: clear query cache and userId on logout --- .../src/shared/components/profilePopup/ProfilePopup.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/client/src/shared/components/profilePopup/ProfilePopup.tsx b/apps/client/src/shared/components/profilePopup/ProfilePopup.tsx index b1ffc70..4206d72 100644 --- a/apps/client/src/shared/components/profilePopup/ProfilePopup.tsx +++ b/apps/client/src/shared/components/profilePopup/ProfilePopup.tsx @@ -1,5 +1,6 @@ import { Icon } from '@pinback/design-system/icons'; import { Button } from '@pinback/design-system/ui'; +import { useQueryClient } from '@tanstack/react-query'; import formatRemindTime from '@shared/utils/formatRemindTime'; import { useEffect, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -22,6 +23,7 @@ export default function ProfilePopup({ remindTime, }: ProfilePopupProps) { const navigate = useNavigate(); + const queryClient = useQueryClient(); const popupRef = useRef(null); useEffect(() => { @@ -42,6 +44,8 @@ export default function ProfilePopup({ const handleLogout = () => { localStorage.removeItem('token'); localStorage.removeItem('email'); + localStorage.removeItem('userId'); + queryClient.clear(); const sendExtensionLogout = () => { window.postMessage( { From 78f5e54521a12097edf296066121645161b1b55e Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Sat, 28 Feb 2026 13:09:49 +0900 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20jobfunnel=20show=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=EC=97=90=20isPolicyPage=EB=8F=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/layout/Layout.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/client/src/layout/Layout.tsx b/apps/client/src/layout/Layout.tsx index 97e9b72..bab2469 100644 --- a/apps/client/src/layout/Layout.tsx +++ b/apps/client/src/layout/Layout.tsx @@ -1,9 +1,9 @@ -import { Outlet, useLocation } from 'react-router-dom'; -import { Sidebar } from '@shared/components/sidebar/Sidebar'; import { ROUTES_CONFIG } from '@routes/routesConfig'; import { useGetHasJob } from '@shared/apis/queries'; import JobSelectionFunnel from '@shared/components/jobSelectionFunnel/JobSelectionFunnel'; +import { Sidebar } from '@shared/components/sidebar/Sidebar'; import { useQueryClient } from '@tanstack/react-query'; +import { Outlet, useLocation } from 'react-router-dom'; const Layout = () => { const location = useLocation(); @@ -28,6 +28,7 @@ const Layout = () => { const shouldShowJobSelectionFunnel = isLoggedIn && !isAuthPage && + !isPolicyPage && !isHasJobLoading && hasJobData?.hasJob === false;