From 31add2f5916d95ff6c595eb924f56bd9af2dccb0 Mon Sep 17 00:00:00 2001 From: Cho SeungYeon <111514472+layout-SY@users.noreply.github.com> Date: Thu, 19 Jun 2025 10:33:49 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat=20:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=8B=A0=EA=B3=A0=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=BF=BC=EB=A6=AC=20=ED=82=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/queries/keys.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/queries/keys.ts b/src/hooks/queries/keys.ts index 8caeccc2..59bee92a 100644 --- a/src/hooks/queries/keys.ts +++ b/src/hooks/queries/keys.ts @@ -62,6 +62,7 @@ export const CustomerService = { export const ReportData = { allReports: ['AllReports'], + allReportsPreview: ['AllReportsPreview'], }; export const UserData = { From 14498eb27f6b7ed24d8f7e90f6dd29cd45621b4f Mon Sep 17 00:00:00 2001 From: Cho SeungYeon <111514472+layout-SY@users.noreply.github.com> Date: Thu, 19 Jun 2025 10:34:19 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat=20:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20"?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C"?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=20lazy=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?=EB=B0=8F=20"=EC=8B=A0=EA=B3=A0=20=EA=B2=80=ED=86=A0"=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=9D=BC=EC=9A=B0=ED=8C=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/AdminRoutes.tsx | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/routes/AdminRoutes.tsx b/src/routes/AdminRoutes.tsx index 91572af7..33ddab86 100644 --- a/src/routes/AdminRoutes.tsx +++ b/src/routes/AdminRoutes.tsx @@ -2,14 +2,25 @@ import NotFoundPage from '../pages/notFoundPage/NotFoundPage'; import { lazy, Suspense } from 'react'; import { ADMIN_ROUTE } from '../constants/routes'; import ProtectAdminRoute from './ProtectAdminRoute'; -import AdminUserDetail from '../components/admin/adminUserDetail/AdminUserDetail'; -import UserProjects from '../components/user/userPage/userProjectList/UserProjectList'; import Profile from '../components/user/mypage/myProfile/profile/Profile'; import { Navigate } from 'react-router-dom'; -import ActivityLog from '../components/user/mypage/activityLog/ActivityLog'; -import Notifications from '../components/user/mypage/notifications/Notifications'; import { Spinner } from '../components/common/loadingSpinner/LoadingSpinner.styled'; +const AdminUserDetail = lazy( + () => import('../components/admin/adminUserDetail/AdminUserDetail') +); +const UserProjects = lazy( + () => import('../components/user/userPage/userProjectList/UserProjectList') +); +const ActivityLog = lazy( + () => import('../components/user/mypage/activityLog/ActivityLog') +); +const Notifications = lazy( + () => import('../components/user/mypage/notifications/Notifications') +); +const AdminReportDetail = lazy( + () => import('../components/admin/adminUserReport/AdminReportDetail') +); const Sidebar = lazy( () => import('../components/common/admin/sidebar/AdminSidebar') ); @@ -206,6 +217,10 @@ export const AdminRoutes = () => { path: ADMIN_ROUTE.reports, element: , }, + { + path: `${ADMIN_ROUTE.reports}/:id`, + element: , + }, { path: ADMIN_ROUTE.inquiries, element: , From 74f82c61fd938296c2c041b59927163bfb320a90 Mon Sep 17 00:00:00 2001 From: Cho SeungYeon <111514472+layout-SY@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:48:12 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat=20:=20"=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C"?= =?UTF-8?q?=20API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/admin/user.api.ts | 48 +++++++++++++++ src/api/admin/userActivity.api.ts | 14 +++++ src/api/mypage.api.ts | 2 +- .../admin/adminUserDetail/AdminUserDetail.tsx | 32 ++++------ src/components/user/mypage/ContentTab.tsx | 30 ++++----- .../commentsActivity/CommentsActivity.tsx | 24 ++++++-- .../activityLog/inquiries/Inquiries.tsx | 15 ++++- .../activityLog/inquiries/inquiry/Inquiry.tsx | 3 +- .../appliedProjects/AppliedProjects.tsx | 14 +++-- src/constants/routes.ts | 2 +- src/hooks/admin/useGetAllUserActivity.ts | 58 ++++++++++++++++++ src/hooks/admin/useGetUserProjectData.ts | 26 ++++++++ src/hooks/queries/keys.ts | 2 + src/models/admin/userDetail/routing.ts | 1 + src/models/admin/userDetail/userActivity.ts | 31 ++++++++++ .../admin/userDetail/userDetail.applicants.ts | 40 ++++++++++++ .../admin/userDetail/userProjectData.ts | 61 +++++++++++++++++++ src/models/userProject.ts | 2 +- src/pages/admin/adminUser/AdminUser.tsx | 12 +--- .../adminUser/AdminUserProjectsLayout.tsx | 36 +++++++++++ src/routes/AdminRoutes.tsx | 31 +++------- 21 files changed, 399 insertions(+), 85 deletions(-) create mode 100644 src/api/admin/user.api.ts create mode 100644 src/api/admin/userActivity.api.ts create mode 100644 src/hooks/admin/useGetAllUserActivity.ts create mode 100644 src/hooks/admin/useGetUserProjectData.ts create mode 100644 src/models/admin/userDetail/routing.ts create mode 100644 src/models/admin/userDetail/userActivity.ts create mode 100644 src/models/admin/userDetail/userDetail.applicants.ts create mode 100644 src/models/admin/userDetail/userProjectData.ts create mode 100644 src/pages/admin/adminUser/AdminUserProjectsLayout.tsx diff --git a/src/api/admin/user.api.ts b/src/api/admin/user.api.ts new file mode 100644 index 00000000..0ce6d90c --- /dev/null +++ b/src/api/admin/user.api.ts @@ -0,0 +1,48 @@ +import { ApiUserApplicantsData } from '../../models/admin/userDetail/userDetail.applicants'; +import { ApiUserProjectDataResponse } from '../../models/admin/userDetail/userProjectData'; +import { httpClient } from '../http.api'; + +export const postBanUser = async (id: string) => { + try { + await httpClient.post(`/ban/${id}`); + } catch (e) { + console.error(e); + throw e; + } +}; + +export const postWarningUser = async (id: string) => { + try { + await httpClient.post(`/warning/${id}`); + } catch (e) { + console.error(e); + throw e; + } +}; + +export const getUserApplicants = async ( + projectId: number, + applicantId: number +) => { + try { + const response = await httpClient.get( + `/admin/project/${projectId}/full?applicantId=${applicantId}` + ); + return response.data; + } catch (e) { + console.error(e); + throw e; + } +}; + +export const getUserProjectData = async (userId: number) => { + try { + const response = await httpClient.get( + `/users/${userId}/projects` + ); + return response.data.data.appliedProjects; + } catch (e) { + console.error(e); + throw e; + } +}; diff --git a/src/api/admin/userActivity.api.ts b/src/api/admin/userActivity.api.ts new file mode 100644 index 00000000..458b0b37 --- /dev/null +++ b/src/api/admin/userActivity.api.ts @@ -0,0 +1,14 @@ +import { httpClient } from '../http.api'; +import { ApiUserActivityResponse } from '../../models/admin/userDetail/userActivity'; + +export const getUserActivityData = async (userId: number) => { + try { + const response = await httpClient.get( + `/users/${userId}/activities` + ); + return response.data; + } catch (e) { + console.error(e); + throw e; + } +}; diff --git a/src/api/mypage.api.ts b/src/api/mypage.api.ts index ea03a835..c3778531 100644 --- a/src/api/mypage.api.ts +++ b/src/api/mypage.api.ts @@ -72,7 +72,7 @@ export const getMyAppliedStatusList = async () => { '/user/applications' ); - return response.data; + return response.data.data; } catch (error) { console.error('내가 지원한 프로젝트 리스트: ', error); throw error; diff --git a/src/components/admin/adminUserDetail/AdminUserDetail.tsx b/src/components/admin/adminUserDetail/AdminUserDetail.tsx index 743aad64..a1a3ff32 100644 --- a/src/components/admin/adminUserDetail/AdminUserDetail.tsx +++ b/src/components/admin/adminUserDetail/AdminUserDetail.tsx @@ -12,14 +12,19 @@ import useGetUserInfo from '../../../hooks/admin/useGetUserInfo'; import Spinner from '../../user/mypage/Spinner'; import Sidebar from '../../common/sidebar/Sidebar'; import ScrollPreventor from '../../common/modal/ScrollPreventor'; - -type TabKey = 'basic' | 'log' | 'inquiry' | 'joined' | 'created' | 'applied'; +import useGetUserProjectData from '../../../hooks/admin/useGetUserProjectData'; +import { TabKey } from '../../../models/admin/userDetail/routing'; const AdminUserDetail = () => { const { userId } = useParams(); const { userData, isLoading, isFetching } = useGetUserInfo(Number(userId)); + const { + userData: projectData, + isLoading: projectLoading, + isFetching: projectFetching, + } = useGetUserProjectData(Number(userId)); - if (isLoading || isFetching) { + if (isLoading || isFetching || projectLoading || projectFetching) { return ( @@ -36,7 +41,7 @@ const AdminUserDetail = () => { { key: 'basic', label: '기본 정보', - path: `/admin/users/${userId}/${ADMIN_ROUTE.basic}`, + path: `/admin/users/${userId}`, icon: , }, { @@ -46,23 +51,11 @@ const AdminUserDetail = () => { icon: , }, { - key: 'joined', - label: '참여 프로젝트', - path: `/admin/users/${userId}/${ADMIN_ROUTE.joinedProject}`, - icon: , - }, - { - key: 'created', - label: '기획 프로젝트', - path: `/admin/users/${userId}/${ADMIN_ROUTE.createdProject}`, + key: 'projects', + label: '지원/참여/기획한 프로젝트', + path: `/admin/users/${userId}/${ADMIN_ROUTE.projects}`, icon: , }, - { - key: 'applied', - label: '지원한 프로젝트', - path: `/admin/users/${userId}/${ADMIN_ROUTE.appliedProject}`, - icon: , - }, ]; return ( @@ -88,6 +81,7 @@ const AdminUserDetail = () => { diff --git a/src/components/user/mypage/ContentTab.tsx b/src/components/user/mypage/ContentTab.tsx index 2c2329f6..d9661f7d 100644 --- a/src/components/user/mypage/ContentTab.tsx +++ b/src/components/user/mypage/ContentTab.tsx @@ -1,7 +1,6 @@ import { useEffect, useState } from 'react'; import * as S from './ContentTab.styled'; import { Link, Outlet, useLocation } from 'react-router-dom'; -import { ROUTES } from '../../../constants/routes'; import ScrollWrapper from './ScrollWrapper'; import MovedInquiredLink from '../customerService/MoveInquiredLink'; @@ -22,25 +21,20 @@ export default function ContentTab({ filter, $justifyContent }: ContentProps) { const [filterId, setFilterId] = useState(); const isAdmin = pathname.includes('/admin'); - function handleChangeId(id: number) { - setFilterId(id); - } useEffect(() => { - if ( - pathname.includes(ROUTES.notificationsAppliedProjects) || - pathname.includes(ROUTES.activityInquiries) - ) { - return setFilterId(1); - } else if (pathname.includes(ROUTES.notificationsCheckedApplicants)) { - return setFilterId(2); - } else if ( - pathname.includes(`${ROUTES.myPageNotifications}/${ROUTES.comments}`) - ) { - return setFilterId(3); + const currentFilter = filter.find((item) => + pathname.includes(item.url.split('/').pop() || '') + ); + if (currentFilter && currentFilter.id !== undefined) { + setFilterId(currentFilter.id); } else { - return setFilterId(0); + setFilterId(filter[0]?.id || 0); } - }, [setFilterId, pathname]); + }, [pathname, filter]); + + function handleChangeId(id: number) { + setFilterId(id); + } return ( @@ -64,7 +58,7 @@ export default function ContentTab({ filter, $justifyContent }: ContentProps) { - + diff --git a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx index 2b7ad066..c1be0f63 100644 --- a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx +++ b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx @@ -3,10 +3,18 @@ import Spinner from '../../Spinner'; import CommentActivity from './commentActivity/CommentActivity'; import * as S from './CommentsActivity.styled'; import NoContent from '../../../../common/noContent/NoContent'; -import { useGetMyComments } from '../../../../../hooks/user/useGetMyComments'; +import useGetUserActivity from '../../../../../hooks/admin/useGetAllUserActivity'; +import { useParams } from 'react-router-dom'; +import { MyComments } from '../../../../../models/activityLog'; +import { UserComment } from '../../../../../models/admin/userDetail/userActivity'; export default function CommentsActivity() { - const { myCommentsData, isLoading } = useGetMyComments(); + const { userId } = useParams(); + + const { userActivityData, isLoading } = useGetUserActivity( + Number(userId), + 'comments' + ); if (isLoading) { return ( @@ -16,7 +24,11 @@ export default function CommentsActivity() { ); } - if (!myCommentsData || myCommentsData.length === 0) { + if ( + !userActivityData || + !Array.isArray(userActivityData) || + userActivityData.length === 0 + ) { return ( @@ -24,13 +36,15 @@ export default function CommentsActivity() { ); } + const commentsData = userActivityData as MyComments[] | UserComment[]; + return ( - {myCommentsData.map((list, idx: number) => ( + {commentsData.map((list: MyComments | UserComment, idx: number) => ( - {idx !== myCommentsData.length - 1 && ( + {idx !== commentsData.length - 1 && ( )} diff --git a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx index 338eaa9e..b9f8e6b0 100644 --- a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx +++ b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx @@ -1,12 +1,19 @@ -import { useGetMyInquiries } from '../../../../../hooks/user/useGetMyInquiries'; +import { useParams } from 'react-router-dom'; +import useGetUserActivity from '../../../../../hooks/admin/useGetAllUserActivity'; import ContentBorder from '../../../../common/contentBorder/ContentBorder'; import NoContent from '../../../../common/noContent/NoContent'; import Spinner from '../../Spinner'; import * as S from './Inquiries.styled'; import Inquiry from './inquiry/Inquiry'; +import { MyInquiries } from '../../../../../models/activityLog'; +import { UserInquiry } from '../../../../../models/admin/userDetail/userActivity'; export default function Inquiries() { - const { myInquiriesData, isLoading } = useGetMyInquiries(); + const { userId } = useParams(); + const { userActivityData, isLoading } = useGetUserActivity( + Number(userId), + 'inquiries' + ); if (isLoading) { return ( @@ -16,13 +23,15 @@ export default function Inquiries() { ); } - if (!myInquiriesData || myInquiriesData?.length === 0) + if (!userActivityData || userActivityData?.length === 0) return ( ); + const myInquiriesData = userActivityData as MyInquiries[] | UserInquiry[]; + return ( diff --git a/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.tsx b/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.tsx index 832d042a..eb9e0360 100644 --- a/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.tsx +++ b/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.tsx @@ -4,9 +4,10 @@ import * as S from './Inquiry.styled'; import { My_INQUIRIES_MESSAGE } from '../../../../../../constants/user/customerService'; import ContentBorder from '../../../../../common/contentBorder/ContentBorder'; import { ChevronRightIcon } from '@heroicons/react/24/outline'; +import { UserInquiry } from '../../../../../../models/admin/userDetail/userActivity'; interface InquiryProps { - list: MyInquiries; + list: MyInquiries | UserInquiry; no: number; } diff --git a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx index 4454ca87..59959a76 100644 --- a/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx +++ b/src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx @@ -1,13 +1,17 @@ -import { Link } from 'react-router-dom'; +import { Link, useParams } from 'react-router-dom'; import * as S from './AppliedProjects.styled'; import Spinner from '../../Spinner'; import AppliedProjectsStatus from './appliedProjectsStatus/AppliedProjectsStatus'; import NoContent from '../../../../common/noContent/NoContent'; -import { useMyAppliedStatusList } from '../../../../../hooks/user/useMyInfo'; import { ROUTES } from '../../../../../constants/routes'; +import useGetUserProjectData from '../../../../../hooks/admin/useGetUserProjectData'; export default function AppliedProjects() { - const { myAppliedStatusListData, isLoading } = useMyAppliedStatusList(); + const { userId } = useParams(); + + const { userData: userProjectData, isLoading } = useGetUserProjectData( + Number(userId) + ); if (isLoading) { return ( @@ -17,7 +21,7 @@ export default function AppliedProjects() { ); } - if (!myAppliedStatusListData || myAppliedStatusListData.length === 0) { + if (!userProjectData || userProjectData.length === 0) { return ( @@ -28,7 +32,7 @@ export default function AppliedProjects() { return ( - {myAppliedStatusListData.map((data) => ( + {userProjectData.map((data) => ( diff --git a/src/constants/routes.ts b/src/constants/routes.ts index ddadceb3..3bb5951f 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -45,8 +45,8 @@ export const ADMIN_ROUTE = { detail: 'detail', write: 'write', modification: 'modification', - basic: 'basic', log: 'log', + projects: 'projects', joinedProject: 'joined-project', createdProject: 'created-project', appliedProject: 'apply-project', diff --git a/src/hooks/admin/useGetAllUserActivity.ts b/src/hooks/admin/useGetAllUserActivity.ts new file mode 100644 index 00000000..8c2ea5d9 --- /dev/null +++ b/src/hooks/admin/useGetAllUserActivity.ts @@ -0,0 +1,58 @@ +import { useQuery } from '@tanstack/react-query'; +import { useLocation } from 'react-router-dom'; +import { ActivityLog, UserData } from '../queries/keys'; +import { getUserActivityData } from '../../api/admin/userActivity.api'; +import { getMyComments, getMyInquiries } from '../../api/activityLog.api'; +import useAuthStore from '../../store/authStore'; +import { MyComments, MyInquiries } from '../../models/activityLog'; +import { + UserComment, + UserInquiry, +} from '../../models/admin/userDetail/userActivity'; + +export function useGetUserActivity( + userId: number, + type: 'comments' | 'inquiries' +) { + const userLoginId = useAuthStore.getState().userData?.id; + const { pathname } = useLocation(); + const isAdmin = pathname.includes('/admin'); + + const getQueryKey = () => { + if (isAdmin) return [UserData.userActivity, userId, type]; + return [ + type === 'comments' ? ActivityLog.myComments : ActivityLog.myInquiries, + userLoginId, + ]; + }; + + const getQueryFn = async () => { + if (isAdmin) { + const response = await getUserActivityData(userId); + return type === 'comments' + ? response.data.comments + : response.data.inquiries; + } + if (type === 'comments') { + return await getMyComments(); + } + return await getMyInquiries(); + }; + + const { data, isLoading, isFetching } = useQuery< + MyComments[] | MyInquiries[] | UserComment[] | UserInquiry[] + >({ + queryKey: getQueryKey(), + queryFn: getQueryFn, + staleTime: 60 * 1000, + enabled: isAdmin ? !!userId : true, + }); + + return { + userActivityData: data, + isLoading, + isFetching, + }; +} + +export default useGetUserActivity; diff --git a/src/hooks/admin/useGetUserProjectData.ts b/src/hooks/admin/useGetUserProjectData.ts new file mode 100644 index 00000000..c9305be5 --- /dev/null +++ b/src/hooks/admin/useGetUserProjectData.ts @@ -0,0 +1,26 @@ +import { useQuery } from '@tanstack/react-query'; +import useAuthStore from '../../store/authStore'; +import { ProjectListKey, UserData } from '../queries/keys'; +import { getUserProjectData } from '../../api/admin/user.api'; +import { useLocation } from 'react-router-dom'; +import { getMyAppliedStatusList } from '../../api/mypage.api'; +import type { AppliedProject } from '../../models/userProject'; + +const useGetUserProjectData = (userId: number) => { + const isAdmin = useLocation().pathname.includes('admin'); + const isLoggedIn = useAuthStore.getState().isLoggedIn; + + const { data, isLoading, isFetching } = useQuery({ + queryKey: isAdmin + ? [UserData.userJoinedProjectList, userId] + : [ProjectListKey.myAppliedStatusList, userId], + queryFn: () => + isAdmin ? getUserProjectData(userId) : getMyAppliedStatusList(), + staleTime: 1 * 60 * 1000, + enabled: isLoggedIn || !!userId, + }); + + return { userData: data, isLoading, isFetching }; +}; + +export default useGetUserProjectData; diff --git a/src/hooks/queries/keys.ts b/src/hooks/queries/keys.ts index 59bee92a..8b97b74f 100644 --- a/src/hooks/queries/keys.ts +++ b/src/hooks/queries/keys.ts @@ -69,4 +69,6 @@ export const UserData = { allUser: ['AllUser'], allUserPreview: ['AllUserPreview'], userInfo: ['userInfo'], + userJoinedProjectList: ['userJoinedProjectList'], + userActivity: ['userActivity'], }; diff --git a/src/models/admin/userDetail/routing.ts b/src/models/admin/userDetail/routing.ts new file mode 100644 index 00000000..5f95f1ac --- /dev/null +++ b/src/models/admin/userDetail/routing.ts @@ -0,0 +1 @@ +export type TabKey = 'basic' | 'log' | 'inquiry' | 'projects'; diff --git a/src/models/admin/userDetail/userActivity.ts b/src/models/admin/userDetail/userActivity.ts new file mode 100644 index 00000000..c958e15d --- /dev/null +++ b/src/models/admin/userDetail/userActivity.ts @@ -0,0 +1,31 @@ +import { ApiCommonType, User } from '../../apiCommon'; + +export interface UserInquiry { + id: number; + title: string; + content: string; + category: string; + state: boolean; + answer?: string; + imageUrls: string[]; + createdAt: string; + updatedAt: string; + user: User; +} + +export interface UserComment { + id: number; + content: string; + createdAt: string; + projectId: number; + projectTitle: string; +} + +export interface UserActivityData { + inquiries: UserInquiry[]; + comments: UserComment[]; +} + +export interface ApiUserActivityResponse extends ApiCommonType { + data: UserActivityData; +} diff --git a/src/models/admin/userDetail/userDetail.applicants.ts b/src/models/admin/userDetail/userDetail.applicants.ts new file mode 100644 index 00000000..c2027bfb --- /dev/null +++ b/src/models/admin/userDetail/userDetail.applicants.ts @@ -0,0 +1,40 @@ +import { ApiCommonType, User } from '../../apiCommon'; +import { Career } from '../../applicant'; +import { SkillTag } from '../../tags'; + +export interface Applicant { + id: number; + userId: number; + projectId: number; + message: string; + email: string; + phoneNumber: string; + career: Career[]; + status: 'WAITING' | 'ACCEPTED' | 'REJECTED'; + createAt: string; + updatedAt: string; + user: User; +} + +export interface ApplicantDetail { + email: string; + phoneNumber: string; + message: string; + skills: SkillTag[]; + career: Career[]; +} + +export interface ApplicantResult { + accepted: Applicant[]; + rejected: Applicant[]; +} + +export interface UserApplicantsData { + applicants: Applicant[]; + detail: ApplicantDetail; + results: ApplicantResult[]; +} + +export interface ApiUserApplicantsData extends ApiCommonType { + data: UserApplicantsData; +} diff --git a/src/models/admin/userDetail/userProjectData.ts b/src/models/admin/userDetail/userProjectData.ts new file mode 100644 index 00000000..eda7e563 --- /dev/null +++ b/src/models/admin/userDetail/userProjectData.ts @@ -0,0 +1,61 @@ +import { ApiCommonType } from '../../apiCommon'; +import { MethodTag, PositionTag, SkillTag } from '../../tags'; +import { AppliedProject, JoinedProject } from '../../userProject'; + +export interface AuthoredProject { + id: number; + title: string; + description: string; + totalMember: number; + startDate: string; + estimatedPeriod: string; + authorId: number; + views: number; + isBeginner: boolean; + isDone: boolean; + recruitmentStartDate: string; + recruitmentEndDate: string; + createAt: string; + updateAt: string; + methodType: MethodTag; + positions: PositionTag[]; + skills: SkillTag[]; + canEvaluate: boolean; + isAllEvaluated: boolean; +} + +export interface OwnedProject { + id: number; + title: string; + recruitmentEndDate: string; + totalMember: number; + isBeginner: boolean; + isDone: boolean; + skills: SkillTag[]; + canEvaluate: boolean; + isAllEvaluated: boolean; +} + +export interface MyJoinedProject { + id: number; + title: string; + recruitmentEndDate: string; + totalMember: number; + isBeginner: boolean; + isDone: boolean; + skills: SkillTag[]; + canEvaluate: boolean; + isAllEvaluated: boolean; +} + +export interface UserProjectData { + authoredProjects: AuthoredProject[]; + ownedProjects: OwnedProject[]; + joinedProjects: JoinedProject[]; + appliedProjects: AppliedProject[]; + myJoinedProjects: MyJoinedProject[]; +} + +export interface ApiUserProjectDataResponse extends ApiCommonType { + data: UserProjectData; +} diff --git a/src/models/userProject.ts b/src/models/userProject.ts index d2c67097..6c96fef3 100644 --- a/src/models/userProject.ts +++ b/src/models/userProject.ts @@ -24,7 +24,7 @@ export interface AppliedProject { } export interface ApiAppliedProject extends ApiCommonType { - data: AppliedProject[] | null; + data: AppliedProject[]; } export interface ApiUserProject extends ApiCommonType { diff --git a/src/pages/admin/adminUser/AdminUser.tsx b/src/pages/admin/adminUser/AdminUser.tsx index a1243f5d..224bd1ae 100644 --- a/src/pages/admin/adminUser/AdminUser.tsx +++ b/src/pages/admin/adminUser/AdminUser.tsx @@ -8,7 +8,6 @@ import Pagination from '../../../components/common/pagination/Pagination'; import useSearchBar from '../../../hooks/admin/useSearchBar'; import { ADMIN_MODAL_MESSAGE } from '../../../constants/admin/adminModal'; import { Link } from 'react-router-dom'; -import { ADMIN_ROUTE } from '../../../constants/routes'; import Spinner from '../../../components/user/mypage/Spinner'; const AdminUser = () => { @@ -38,20 +37,13 @@ const AdminUser = () => { - + {allUserData.users.map((userData) => ( - + ({ + ...tab, + url: tab.url.replace(':userId', userId ?? ''), + })); + + return ( +
+ +
+ ); +} diff --git a/src/routes/AdminRoutes.tsx b/src/routes/AdminRoutes.tsx index 33ddab86..986c4c88 100644 --- a/src/routes/AdminRoutes.tsx +++ b/src/routes/AdminRoutes.tsx @@ -5,6 +5,7 @@ import ProtectAdminRoute from './ProtectAdminRoute'; import Profile from '../components/user/mypage/myProfile/profile/Profile'; import { Navigate } from 'react-router-dom'; import { Spinner } from '../components/common/loadingSpinner/LoadingSpinner.styled'; +import AdminUserProjectsLayout from '../pages/admin/adminUser/AdminUserProjectsLayout'; const AdminUserDetail = lazy( () => import('../components/admin/adminUserDetail/AdminUserDetail') @@ -157,10 +158,6 @@ export const AdminRoutes = () => { children: [ { index: true, - element: , - }, - { - path: `${ADMIN_ROUTE.basic}`, element: , }, { @@ -182,35 +179,27 @@ export const AdminRoutes = () => { ], }, { - path: `${ADMIN_ROUTE.appliedProject}`, - element: , + path: `${ADMIN_ROUTE.projects}`, + element: , children: [ { index: true, - element: , + element: , }, { - path: `${ADMIN_ROUTE.checkingApplicant}`, - element: , + path: `${ADMIN_ROUTE.appliedProject}`, + element: , }, { - path: `${ADMIN_ROUTE.comments}`, - element: , + path: `${ADMIN_ROUTE.joinedProject}`, + element: , }, { - path: `${ADMIN_ROUTE.applyingProject}`, - element: , + path: `${ADMIN_ROUTE.createdProject}`, + element: , }, ], }, - { - path: `${ADMIN_ROUTE.joinedProject}`, - element: , - }, - { - path: `${ADMIN_ROUTE.createdProject}`, - element: , - }, ], }, { From 7bf082f844db6187b8ba331d6d8da4045211b815 Mon Sep 17 00:00:00 2001 From: Cho SeungYeon <111514472+layout-SY@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:22:46 +0900 Subject: [PATCH 4/9] =?UTF-8?q?refactor=20:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/activityLog.api.ts | 1 - .../admin/adminUserDetail/AdminUserDetail.tsx | 2 +- .../activityLog/inquiries/Inquiries.tsx | 3 +- .../activityLog/inquiries/inquiry/Inquiry.tsx | 5 +- src/hooks/admin/useGetAllUserActivity.ts | 10 +--- src/hooks/admin/useGetUserProjectData.ts | 2 +- src/models/admin/userDetail/routing.ts | 2 +- src/models/admin/userDetail/userActivity.ts | 18 ++----- .../admin/userDetail/userDetail.applicants.ts | 2 +- .../admin/userDetail/userProjectData.ts | 51 ++++++------------- 10 files changed, 27 insertions(+), 69 deletions(-) diff --git a/src/api/activityLog.api.ts b/src/api/activityLog.api.ts index 3a2498b0..b16adef5 100644 --- a/src/api/activityLog.api.ts +++ b/src/api/activityLog.api.ts @@ -1,4 +1,3 @@ -import { ApiAllInquiries } from '../models/admin/mainPreview'; import type { ApiMyComments, ApiMyInquiries } from './../models/activityLog'; import { httpClient } from './http.api'; diff --git a/src/components/admin/adminUserDetail/AdminUserDetail.tsx b/src/components/admin/adminUserDetail/AdminUserDetail.tsx index a1a3ff32..bcbae330 100644 --- a/src/components/admin/adminUserDetail/AdminUserDetail.tsx +++ b/src/components/admin/adminUserDetail/AdminUserDetail.tsx @@ -39,7 +39,7 @@ const AdminUserDetail = () => { icon: React.ReactNode; }[] = [ { - key: 'basic', + key: 'profile', label: '기본 정보', path: `/admin/users/${userId}`, icon: , diff --git a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx index b9f8e6b0..b20c3022 100644 --- a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx +++ b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx @@ -6,7 +6,6 @@ import Spinner from '../../Spinner'; import * as S from './Inquiries.styled'; import Inquiry from './inquiry/Inquiry'; import { MyInquiries } from '../../../../../models/activityLog'; -import { UserInquiry } from '../../../../../models/admin/userDetail/userActivity'; export default function Inquiries() { const { userId } = useParams(); @@ -30,7 +29,7 @@ export default function Inquiries() {
); - const myInquiriesData = userActivityData as MyInquiries[] | UserInquiry[]; + const myInquiriesData = userActivityData as MyInquiries[]; return ( diff --git a/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.tsx b/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.tsx index eb9e0360..21881354 100644 --- a/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.tsx +++ b/src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.tsx @@ -1,13 +1,12 @@ -import React, { useRef, useState } from 'react'; +import { useRef, useState } from 'react'; import type { MyInquiries } from '../../../../../../models/activityLog'; import * as S from './Inquiry.styled'; import { My_INQUIRIES_MESSAGE } from '../../../../../../constants/user/customerService'; import ContentBorder from '../../../../../common/contentBorder/ContentBorder'; import { ChevronRightIcon } from '@heroicons/react/24/outline'; -import { UserInquiry } from '../../../../../../models/admin/userDetail/userActivity'; interface InquiryProps { - list: MyInquiries | UserInquiry; + list: MyInquiries; no: number; } diff --git a/src/hooks/admin/useGetAllUserActivity.ts b/src/hooks/admin/useGetAllUserActivity.ts index 8c2ea5d9..5c27c393 100644 --- a/src/hooks/admin/useGetAllUserActivity.ts +++ b/src/hooks/admin/useGetAllUserActivity.ts @@ -1,22 +1,16 @@ import { useQuery } from '@tanstack/react-query'; -import { useLocation } from 'react-router-dom'; import { ActivityLog, UserData } from '../queries/keys'; import { getUserActivityData } from '../../api/admin/userActivity.api'; import { getMyComments, getMyInquiries } from '../../api/activityLog.api'; import useAuthStore from '../../store/authStore'; import { MyComments, MyInquiries } from '../../models/activityLog'; -import { - UserComment, - UserInquiry, -} from '../../models/admin/userDetail/userActivity'; export function useGetUserActivity( userId: number, type: 'comments' | 'inquiries' ) { const userLoginId = useAuthStore.getState().userData?.id; - const { pathname } = useLocation(); - const isAdmin = pathname.includes('/admin'); + const isAdmin = useAuthStore((state) => state.userData?.admin) ?? false; const getQueryKey = () => { if (isAdmin) return [UserData.userActivity, userId, type]; @@ -40,7 +34,7 @@ export function useGetUserActivity( }; const { data, isLoading, isFetching } = useQuery< - MyComments[] | MyInquiries[] | UserComment[] | UserInquiry[] + MyComments[] | MyInquiries[] >({ queryKey: getQueryKey(), queryFn: getQueryFn, diff --git a/src/hooks/admin/useGetUserProjectData.ts b/src/hooks/admin/useGetUserProjectData.ts index c9305be5..c29abce1 100644 --- a/src/hooks/admin/useGetUserProjectData.ts +++ b/src/hooks/admin/useGetUserProjectData.ts @@ -17,7 +17,7 @@ const useGetUserProjectData = (userId: number) => { queryFn: () => isAdmin ? getUserProjectData(userId) : getMyAppliedStatusList(), staleTime: 1 * 60 * 1000, - enabled: isLoggedIn || !!userId, + enabled: isAdmin ? !!userId : isLoggedIn, }); return { userData: data, isLoading, isFetching }; diff --git a/src/models/admin/userDetail/routing.ts b/src/models/admin/userDetail/routing.ts index 5f95f1ac..66ab7ac0 100644 --- a/src/models/admin/userDetail/routing.ts +++ b/src/models/admin/userDetail/routing.ts @@ -1 +1 @@ -export type TabKey = 'basic' | 'log' | 'inquiry' | 'projects'; +export type TabKey = 'profile' | 'log' | 'projects'; diff --git a/src/models/admin/userDetail/userActivity.ts b/src/models/admin/userDetail/userActivity.ts index c958e15d..3d2ff697 100644 --- a/src/models/admin/userDetail/userActivity.ts +++ b/src/models/admin/userDetail/userActivity.ts @@ -1,17 +1,5 @@ -import { ApiCommonType, User } from '../../apiCommon'; - -export interface UserInquiry { - id: number; - title: string; - content: string; - category: string; - state: boolean; - answer?: string; - imageUrls: string[]; - createdAt: string; - updatedAt: string; - user: User; -} +import { MyInquiries } from '../../activityLog'; +import { ApiCommonType } from '../../apiCommon'; export interface UserComment { id: number; @@ -22,7 +10,7 @@ export interface UserComment { } export interface UserActivityData { - inquiries: UserInquiry[]; + inquiries: MyInquiries[]; comments: UserComment[]; } diff --git a/src/models/admin/userDetail/userDetail.applicants.ts b/src/models/admin/userDetail/userDetail.applicants.ts index c2027bfb..f2d8ff29 100644 --- a/src/models/admin/userDetail/userDetail.applicants.ts +++ b/src/models/admin/userDetail/userDetail.applicants.ts @@ -11,7 +11,7 @@ export interface Applicant { phoneNumber: string; career: Career[]; status: 'WAITING' | 'ACCEPTED' | 'REJECTED'; - createAt: string; + createdAt: string; updatedAt: string; user: User; } diff --git a/src/models/admin/userDetail/userProjectData.ts b/src/models/admin/userDetail/userProjectData.ts index eda7e563..699f6748 100644 --- a/src/models/admin/userDetail/userProjectData.ts +++ b/src/models/admin/userDetail/userProjectData.ts @@ -2,32 +2,10 @@ import { ApiCommonType } from '../../apiCommon'; import { MethodTag, PositionTag, SkillTag } from '../../tags'; import { AppliedProject, JoinedProject } from '../../userProject'; -export interface AuthoredProject { +export interface BaseProject { id: number; title: string; - description: string; - totalMember: number; - startDate: string; - estimatedPeriod: string; - authorId: number; - views: number; - isBeginner: boolean; - isDone: boolean; - recruitmentStartDate: string; - recruitmentEndDate: string; - createAt: string; - updateAt: string; - methodType: MethodTag; - positions: PositionTag[]; - skills: SkillTag[]; - canEvaluate: boolean; - isAllEvaluated: boolean; -} - -export interface OwnedProject { - id: number; - title: string; - recruitmentEndDate: string; + recruitmentEndDate?: string; totalMember: number; isBeginner: boolean; isDone: boolean; @@ -36,24 +14,25 @@ export interface OwnedProject { isAllEvaluated: boolean; } -export interface MyJoinedProject { - id: number; - title: string; - recruitmentEndDate: string; - totalMember: number; - isBeginner: boolean; - isDone: boolean; - skills: SkillTag[]; - canEvaluate: boolean; - isAllEvaluated: boolean; +export interface AuthoredProject extends BaseProject { + description: string; + startDate: string; + estimatedPeriod: string; + authorId: number; + views: number; + recruitmentStartDate: string; + createdAt: string; + updatedAt: string; + methodType: MethodTag; + positions: PositionTag[]; } export interface UserProjectData { authoredProjects: AuthoredProject[]; - ownedProjects: OwnedProject[]; + ownedProjects: BaseProject[]; joinedProjects: JoinedProject[]; appliedProjects: AppliedProject[]; - myJoinedProjects: MyJoinedProject[]; + myJoinedProjects: BaseProject[]; } export interface ApiUserProjectDataResponse extends ApiCommonType { From 821d359b96534d8ff9a16dd65dcb4ba30af92e49 Mon Sep 17 00:00:00 2001 From: Cho SeungYeon <111514472+layout-SY@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:31:52 +0900 Subject: [PATCH 5/9] =?UTF-8?q?refactor=20:=20=EC=A0=84=EC=97=AD=20?= =?UTF-8?q?=EC=83=81=ED=83=9C(AuthStore)=EB=A5=BC=20=ED=86=B5=ED=95=B4=20?= =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20URL=EC=9D=84?= =?UTF-8?q?=20=ED=86=B5=ED=95=9C=20=EA=B4=80=EB=A6=AC=EC=9E=90=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=EB=A5=BC=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=ED=95=9C=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=EC=9D=98=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/sidebar/Sidebar.styled.ts | 2 +- src/components/common/sidebar/Sidebar.tsx | 2 +- src/components/user/mypage/ContentTab.tsx | 3 ++- src/components/user/mypage/activityLog/ActivityLog.tsx | 5 ++--- .../user/userPage/userProjectList/UserProjectList.tsx | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/common/sidebar/Sidebar.styled.ts b/src/components/common/sidebar/Sidebar.styled.ts index 544831ef..016f3201 100644 --- a/src/components/common/sidebar/Sidebar.styled.ts +++ b/src/components/common/sidebar/Sidebar.styled.ts @@ -1,6 +1,6 @@ import styled from 'styled-components'; -export const Container = styled.div<{ $isAdmin: boolean }>` +export const Container = styled.div<{ $isAdmin: boolean | undefined }>` display: flex; flex-direction: column; border: 2px solid #f0f0f0; diff --git a/src/components/common/sidebar/Sidebar.tsx b/src/components/common/sidebar/Sidebar.tsx index 754607a8..fbcbeeca 100644 --- a/src/components/common/sidebar/Sidebar.tsx +++ b/src/components/common/sidebar/Sidebar.tsx @@ -22,9 +22,9 @@ interface SidebarProps { const Sidebar = ({ menuItems, profileImage, nickname }: SidebarProps) => { const isLoggedIn = useAuthStore((state) => state.isLoggedIn); const location = useLocation(); + const isAdmin = useAuthStore().userData?.admin; const isUserPage = location.pathname.includes('/user'); const isManagePage = location.pathname.includes('/manage'); - const isAdmin = location.pathname.includes('/admin'); const isMyProfile = isLoggedIn && !isUserPage && !isManagePage; const getActiveIndex = useCallback(() => { diff --git a/src/components/user/mypage/ContentTab.tsx b/src/components/user/mypage/ContentTab.tsx index d9661f7d..1765a7c9 100644 --- a/src/components/user/mypage/ContentTab.tsx +++ b/src/components/user/mypage/ContentTab.tsx @@ -3,6 +3,7 @@ import * as S from './ContentTab.styled'; import { Link, Outlet, useLocation } from 'react-router-dom'; import ScrollWrapper from './ScrollWrapper'; import MovedInquiredLink from '../customerService/MoveInquiredLink'; +import useAuthStore from '../../../store/authStore'; interface Filter { title: string; @@ -18,8 +19,8 @@ interface ContentProps { export default function ContentTab({ filter, $justifyContent }: ContentProps) { const { pathname } = useLocation(); + const isAdmin = useAuthStore().userData?.admin; const [filterId, setFilterId] = useState(); - const isAdmin = pathname.includes('/admin'); useEffect(() => { const currentFilter = filter.find((item) => diff --git a/src/components/user/mypage/activityLog/ActivityLog.tsx b/src/components/user/mypage/activityLog/ActivityLog.tsx index 62bd6087..f0c827f9 100644 --- a/src/components/user/mypage/activityLog/ActivityLog.tsx +++ b/src/components/user/mypage/activityLog/ActivityLog.tsx @@ -1,13 +1,12 @@ -import { useLocation } from 'react-router-dom'; import { ACTIVITY_FILTER, ACTIVITY_FILTER_ADMIN, } from '../../../../constants/user/myPageFilter'; import ContentTab from '../ContentTab'; +import useAuthStore from '../../../../store/authStore'; export default function ActivityLog() { - const { pathname } = useLocation(); - const isAdmin = pathname.includes('/admin'); + const isAdmin = useAuthStore().userData?.admin; return ( Date: Fri, 27 Jun 2025 09:44:21 +0900 Subject: [PATCH 6/9] =?UTF-8?q?fix=20:=20"=ED=9A=8C=EC=9B=90=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A1=B0=ED=9A=8C"=20=EB=B6=80=EB=B6=84=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=A7=80=EC=9B=90/=EC=B0=B8=EC=97=AC/=EA=B8=B0?= =?UTF-8?q?=ED=9A=8D=ED=95=9C=20=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20?= =?UTF-8?q?=ED=83=AD=20=EB=B6=80=EB=B6=84=EC=9D=98=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=EB=90=9C=20=ED=83=AD=EC=97=90=20=EC=A0=81=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/user/mypage/ContentTab.tsx | 27 ++++++++++++----- .../admin/userDetailContentHeader.ts | 19 ++++++++++++ .../adminUser/AdminUserProjectsLayout.tsx | 30 ++----------------- 3 files changed, 41 insertions(+), 35 deletions(-) create mode 100644 src/constants/admin/userDetailContentHeader.ts diff --git a/src/components/user/mypage/ContentTab.tsx b/src/components/user/mypage/ContentTab.tsx index 1765a7c9..7fec2878 100644 --- a/src/components/user/mypage/ContentTab.tsx +++ b/src/components/user/mypage/ContentTab.tsx @@ -4,6 +4,7 @@ import { Link, Outlet, useLocation } from 'react-router-dom'; import ScrollWrapper from './ScrollWrapper'; import MovedInquiredLink from '../customerService/MoveInquiredLink'; import useAuthStore from '../../../store/authStore'; +import { ADMIN_ROUTE, ROUTES } from '../../../constants/routes'; interface Filter { title: string; @@ -23,15 +24,26 @@ export default function ContentTab({ filter, $justifyContent }: ContentProps) { const [filterId, setFilterId] = useState(); useEffect(() => { - const currentFilter = filter.find((item) => - pathname.includes(item.url.split('/').pop() || '') - ); - if (currentFilter && currentFilter.id !== undefined) { - setFilterId(currentFilter.id); + if ( + pathname.includes(ROUTES.notificationsAppliedProjects) || + pathname.includes(ROUTES.activityInquiries) || + pathname.includes(ADMIN_ROUTE.appliedProject) + ) { + return setFilterId(1); + } else if ( + pathname.includes(ROUTES.notificationsCheckedApplicants) || + pathname.includes(ADMIN_ROUTE.joinedProject) + ) { + return setFilterId(2); + } else if ( + pathname.includes(`${ROUTES.myPageNotifications}/${ROUTES.comments}`) || + pathname.includes(ADMIN_ROUTE.createdProject) + ) { + return setFilterId(3); } else { - setFilterId(filter[0]?.id || 0); + return setFilterId(0); } - }, [pathname, filter]); + }, [setFilterId, pathname]); function handleChangeId(id: number) { setFilterId(id); @@ -46,6 +58,7 @@ export default function ContentTab({ filter, $justifyContent }: ContentProps) { to={filter.url} onClick={() => handleChangeId(filter.id as number)} > + {' '} {filter.title} diff --git a/src/constants/admin/userDetailContentHeader.ts b/src/constants/admin/userDetailContentHeader.ts new file mode 100644 index 00000000..233c9ad0 --- /dev/null +++ b/src/constants/admin/userDetailContentHeader.ts @@ -0,0 +1,19 @@ +import { ADMIN_ROUTE } from '../routes'; + +export const PROJECT_TABS = [ + { + title: '지원한 프로젝트', + url: `${ADMIN_ROUTE.appliedProject}`, + id: 1, + }, + { + title: '참여한 프로젝트', + url: `${ADMIN_ROUTE.joinedProject}`, + id: 2, + }, + { + title: '기획한 프로젝트', + url: `${ADMIN_ROUTE.createdProject}`, + id: 3, + }, +] as const; diff --git a/src/pages/admin/adminUser/AdminUserProjectsLayout.tsx b/src/pages/admin/adminUser/AdminUserProjectsLayout.tsx index 2c281415..4e1bc106 100644 --- a/src/pages/admin/adminUser/AdminUserProjectsLayout.tsx +++ b/src/pages/admin/adminUser/AdminUserProjectsLayout.tsx @@ -1,36 +1,10 @@ -import { useParams } from 'react-router-dom'; import ContentTab from '../../../components/user/mypage/ContentTab'; -import { ADMIN_ROUTE } from '../../../constants/routes'; - -const PROJECT_TABS = [ - { - title: '지원한 프로젝트', - url: `/admin/users/:userId/${ADMIN_ROUTE.projects}/${ADMIN_ROUTE.appliedProject}`, - id: 0, - }, - { - title: '참여한 프로젝트', - url: `/admin/users/:userId/${ADMIN_ROUTE.projects}/${ADMIN_ROUTE.joinedProject}`, - id: 1, - }, - { - title: '기획한 프로젝트', - url: `/admin/users/:userId/${ADMIN_ROUTE.projects}/${ADMIN_ROUTE.createdProject}`, - id: 2, - }, -]; +import { PROJECT_TABS } from '../../../constants/admin/userDetailContentHeader'; export default function AdminUserProjectsLayout() { - const { userId } = useParams(); - - const filter = PROJECT_TABS.map((tab) => ({ - ...tab, - url: tab.url.replace(':userId', userId ?? ''), - })); - return (
- +
); } From f2aca0901bf18e9135e86def6c891bfc28a70359 Mon Sep 17 00:00:00 2001 From: Cho SeungYeon <111514472+layout-SY@users.noreply.github.com> Date: Sun, 29 Jun 2025 22:46:41 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat=20:=20pathname=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A0=8C=EB=8D=94=EB=A7=81=20?= =?UTF-8?q?=EB=A1=A4=EB=B0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/sidebar/Sidebar.tsx | 2 +- src/components/user/mypage/ContentTab.tsx | 3 +-- src/components/user/mypage/activityLog/ActivityLog.tsx | 5 +++-- .../user/userPage/userProjectList/UserProjectList.tsx | 6 +++--- src/hooks/admin/useGetAllUserActivity.ts | 4 +++- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/components/common/sidebar/Sidebar.tsx b/src/components/common/sidebar/Sidebar.tsx index fbcbeeca..50575864 100644 --- a/src/components/common/sidebar/Sidebar.tsx +++ b/src/components/common/sidebar/Sidebar.tsx @@ -22,7 +22,7 @@ interface SidebarProps { const Sidebar = ({ menuItems, profileImage, nickname }: SidebarProps) => { const isLoggedIn = useAuthStore((state) => state.isLoggedIn); const location = useLocation(); - const isAdmin = useAuthStore().userData?.admin; + const isAdmin = location.pathname.includes('/admin'); const isUserPage = location.pathname.includes('/user'); const isManagePage = location.pathname.includes('/manage'); diff --git a/src/components/user/mypage/ContentTab.tsx b/src/components/user/mypage/ContentTab.tsx index 7fec2878..9f11a91d 100644 --- a/src/components/user/mypage/ContentTab.tsx +++ b/src/components/user/mypage/ContentTab.tsx @@ -3,7 +3,6 @@ import * as S from './ContentTab.styled'; import { Link, Outlet, useLocation } from 'react-router-dom'; import ScrollWrapper from './ScrollWrapper'; import MovedInquiredLink from '../customerService/MoveInquiredLink'; -import useAuthStore from '../../../store/authStore'; import { ADMIN_ROUTE, ROUTES } from '../../../constants/routes'; interface Filter { @@ -20,7 +19,7 @@ interface ContentProps { export default function ContentTab({ filter, $justifyContent }: ContentProps) { const { pathname } = useLocation(); - const isAdmin = useAuthStore().userData?.admin; + const isAdmin = pathname.includes('/admin'); const [filterId, setFilterId] = useState(); useEffect(() => { diff --git a/src/components/user/mypage/activityLog/ActivityLog.tsx b/src/components/user/mypage/activityLog/ActivityLog.tsx index f0c827f9..0350be96 100644 --- a/src/components/user/mypage/activityLog/ActivityLog.tsx +++ b/src/components/user/mypage/activityLog/ActivityLog.tsx @@ -3,10 +3,11 @@ import { ACTIVITY_FILTER_ADMIN, } from '../../../../constants/user/myPageFilter'; import ContentTab from '../ContentTab'; -import useAuthStore from '../../../../store/authStore'; +import { useLocation } from 'react-router-dom'; export default function ActivityLog() { - const isAdmin = useAuthStore().userData?.admin; + const { pathname } = useLocation(); + const isAdmin = pathname.includes('/admin'); return ( state.userData?.admin) ?? false; + const { pathname } = useLocation(); + const isAdmin = pathname.includes('/admin'); const getQueryKey = () => { if (isAdmin) return [UserData.userActivity, userId, type]; From dade3723ccf9cab5d86988b560049456db596899 Mon Sep 17 00:00:00 2001 From: Cho SeungYeon <111514472+layout-SY@users.noreply.github.com> Date: Sun, 29 Jun 2025 22:55:53 +0900 Subject: [PATCH 8/9] =?UTF-8?q?refactor=20:=20=EB=AA=A8=EB=8D=B8=EC=97=90?= =?UTF-8?q?=EC=84=9C=20import=ED=95=9C=20=ED=83=80=EC=9E=85=EC=97=90=20typ?= =?UTF-8?q?e=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/admin/customerService/FAQ.api.ts | 2 +- src/api/admin/user.api.ts | 4 ++-- src/api/admin/userActivity.api.ts | 2 +- src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx | 2 +- src/components/admin/adminUserDetail/AdminUserDetail.tsx | 2 +- .../mypage/activityLog/commentsActivity/CommentsActivity.tsx | 4 ++-- .../user/mypage/activityLog/inquiries/Inquiries.tsx | 2 +- src/components/user/mypage/myProfile/profile/Profile.tsx | 2 +- src/components/user/notificationLive/NotificationProvider.tsx | 2 +- src/context/SseContext.tsx | 2 +- src/hooks/admin/useAdminNotice.ts | 2 +- src/hooks/admin/useGetAllUserActivity.ts | 2 +- src/hooks/admin/useGetUserInfo.ts | 2 +- src/hooks/user/ProjectHooks/useApplyProject.ts | 2 +- src/hooks/user/ProjectHooks/useTagSelectors.ts | 4 ++-- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/api/admin/customerService/FAQ.api.ts b/src/api/admin/customerService/FAQ.api.ts index 85bf8995..09e008da 100644 --- a/src/api/admin/customerService/FAQ.api.ts +++ b/src/api/admin/customerService/FAQ.api.ts @@ -1,4 +1,4 @@ -import { ApiCommonBasicType } from '../../../models/apiCommon'; +import type { ApiCommonBasicType } from '../../../models/apiCommon'; import type { ApiFAQDetail, WriteBody } from '../../../models/customerService'; import { httpClient } from '../../http.api'; diff --git a/src/api/admin/user.api.ts b/src/api/admin/user.api.ts index 0ce6d90c..20bbb081 100644 --- a/src/api/admin/user.api.ts +++ b/src/api/admin/user.api.ts @@ -1,5 +1,5 @@ -import { ApiUserApplicantsData } from '../../models/admin/userDetail/userDetail.applicants'; -import { ApiUserProjectDataResponse } from '../../models/admin/userDetail/userProjectData'; +import type { ApiUserApplicantsData } from '../../models/admin/userDetail/userDetail.applicants'; +import type { ApiUserProjectDataResponse } from '../../models/admin/userDetail/userProjectData'; import { httpClient } from '../http.api'; export const postBanUser = async (id: string) => { diff --git a/src/api/admin/userActivity.api.ts b/src/api/admin/userActivity.api.ts index 458b0b37..465207e0 100644 --- a/src/api/admin/userActivity.api.ts +++ b/src/api/admin/userActivity.api.ts @@ -1,5 +1,5 @@ import { httpClient } from '../http.api'; -import { ApiUserActivityResponse } from '../../models/admin/userDetail/userActivity'; +import type { ApiUserActivityResponse } from '../../models/admin/userDetail/userActivity'; export const getUserActivityData = async (userId: number) => { try { diff --git a/src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx b/src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx index fc38e43a..0283739c 100644 --- a/src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx +++ b/src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx @@ -1,7 +1,7 @@ import { useOutletContext } from 'react-router-dom'; import * as S from './AdminInquiryAnswerWrite.styled'; import React, { useEffect, useRef, useState } from 'react'; -import { InquiryAnswerBody } from '../../../models/inquiry'; +import type { InquiryAnswerBody } from '../../../models/inquiry'; import { UseMutationResult } from '@tanstack/react-query'; import { AxiosError } from 'axios'; import Modal from '../../common/modal/Modal'; diff --git a/src/components/admin/adminUserDetail/AdminUserDetail.tsx b/src/components/admin/adminUserDetail/AdminUserDetail.tsx index bcbae330..c4400b33 100644 --- a/src/components/admin/adminUserDetail/AdminUserDetail.tsx +++ b/src/components/admin/adminUserDetail/AdminUserDetail.tsx @@ -13,7 +13,7 @@ import Spinner from '../../user/mypage/Spinner'; import Sidebar from '../../common/sidebar/Sidebar'; import ScrollPreventor from '../../common/modal/ScrollPreventor'; import useGetUserProjectData from '../../../hooks/admin/useGetUserProjectData'; -import { TabKey } from '../../../models/admin/userDetail/routing'; +import type { TabKey } from '../../../models/admin/userDetail/routing'; const AdminUserDetail = () => { const { userId } = useParams(); diff --git a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx index c1be0f63..135cf017 100644 --- a/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx +++ b/src/components/user/mypage/activityLog/commentsActivity/CommentsActivity.tsx @@ -5,8 +5,8 @@ import * as S from './CommentsActivity.styled'; import NoContent from '../../../../common/noContent/NoContent'; import useGetUserActivity from '../../../../../hooks/admin/useGetAllUserActivity'; import { useParams } from 'react-router-dom'; -import { MyComments } from '../../../../../models/activityLog'; -import { UserComment } from '../../../../../models/admin/userDetail/userActivity'; +import type { MyComments } from '../../../../../models/activityLog'; +import type { UserComment } from '../../../../../models/admin/userDetail/userActivity'; export default function CommentsActivity() { const { userId } = useParams(); diff --git a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx index b20c3022..dd8ba511 100644 --- a/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx +++ b/src/components/user/mypage/activityLog/inquiries/Inquiries.tsx @@ -5,7 +5,7 @@ import NoContent from '../../../../common/noContent/NoContent'; import Spinner from '../../Spinner'; import * as S from './Inquiries.styled'; import Inquiry from './inquiry/Inquiry'; -import { MyInquiries } from '../../../../../models/activityLog'; +import type { MyInquiries } from '../../../../../models/activityLog'; export default function Inquiries() { const { userId } = useParams(); diff --git a/src/components/user/mypage/myProfile/profile/Profile.tsx b/src/components/user/mypage/myProfile/profile/Profile.tsx index 4035fa7d..5ff6c2b4 100644 --- a/src/components/user/mypage/myProfile/profile/Profile.tsx +++ b/src/components/user/mypage/myProfile/profile/Profile.tsx @@ -9,7 +9,7 @@ import { ROUTES } from '../../../../../constants/routes'; import 'chart.js/auto'; import { chartOptions } from '../../../../../constants/evaluationChartData'; import { formatDate } from '../../../../../util/formatDate'; -import { UserInfoAll } from '../../../../../models/userInfo'; +import type { UserInfoAll } from '../../../../../models/userInfo'; export default function Profile() { const { diff --git a/src/components/user/notificationLive/NotificationProvider.tsx b/src/components/user/notificationLive/NotificationProvider.tsx index 307dcdf3..b0b0328f 100644 --- a/src/components/user/notificationLive/NotificationProvider.tsx +++ b/src/components/user/notificationLive/NotificationProvider.tsx @@ -1,5 +1,5 @@ import { ReactNode, useState } from 'react'; -import { AlarmLive } from '../../../models/alarm'; +import type { AlarmLive } from '../../../models/alarm'; import { SseContext } from '../../../context/SseContext'; export const NotificationProvider = ({ children }: { children: ReactNode }) => { diff --git a/src/context/SseContext.tsx b/src/context/SseContext.tsx index d30064f8..7ecb7f42 100644 --- a/src/context/SseContext.tsx +++ b/src/context/SseContext.tsx @@ -1,5 +1,5 @@ import { createContext, useContext } from 'react'; -import { AlarmLive } from '../models/alarm'; +import type { AlarmLive } from '../models/alarm'; export interface SseContextProps { signalData: AlarmLive | null; diff --git a/src/hooks/admin/useAdminNotice.ts b/src/hooks/admin/useAdminNotice.ts index e4345710..0b8b8c21 100644 --- a/src/hooks/admin/useAdminNotice.ts +++ b/src/hooks/admin/useAdminNotice.ts @@ -8,7 +8,7 @@ import { AxiosError } from 'axios'; import { CustomerService } from '../queries/keys'; import { useNavigate } from 'react-router-dom'; import { ADMIN_MODAL_MESSAGE } from '../../constants/admin/adminModal'; -import { WriteBody } from '../../models/customerService'; +import type { WriteBody } from '../../models/customerService'; type State = 'success' | 'fail'; diff --git a/src/hooks/admin/useGetAllUserActivity.ts b/src/hooks/admin/useGetAllUserActivity.ts index 4f1a6e58..ea9ecf8a 100644 --- a/src/hooks/admin/useGetAllUserActivity.ts +++ b/src/hooks/admin/useGetAllUserActivity.ts @@ -3,7 +3,7 @@ import { ActivityLog, UserData } from '../queries/keys'; import { getUserActivityData } from '../../api/admin/userActivity.api'; import { getMyComments, getMyInquiries } from '../../api/activityLog.api'; import useAuthStore from '../../store/authStore'; -import { MyComments, MyInquiries } from '../../models/activityLog'; +import type { MyComments, MyInquiries } from '../../models/activityLog'; import { useLocation } from 'react-router-dom'; export function useGetUserActivity( diff --git a/src/hooks/admin/useGetUserInfo.ts b/src/hooks/admin/useGetUserInfo.ts index b109461f..cf31679d 100644 --- a/src/hooks/admin/useGetUserInfo.ts +++ b/src/hooks/admin/useGetUserInfo.ts @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/react-query'; -import { ApiUserInfo } from '../../models/userInfo'; +import type { ApiUserInfo } from '../../models/userInfo'; import { getUserInfo } from '../../api/userpage.api'; import { userInfoKey } from '../queries/keys'; diff --git a/src/hooks/user/ProjectHooks/useApplyProject.ts b/src/hooks/user/ProjectHooks/useApplyProject.ts index 60dfe985..aab99141 100644 --- a/src/hooks/user/ProjectHooks/useApplyProject.ts +++ b/src/hooks/user/ProjectHooks/useApplyProject.ts @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { ProjectListKey, userInfoKey } from '../../queries/keys'; import { useNavigate } from 'react-router-dom'; import { postApplicantProject } from '../../../api/joinProject.api'; -import { joinProject } from '../../../models/joinProject'; +import type { joinProject } from '../../../models/joinProject'; import { MODAL_MESSAGE } from '../../../constants/user/modalMessage'; import { ROUTES } from '../../../constants/routes'; diff --git a/src/hooks/user/ProjectHooks/useTagSelectors.ts b/src/hooks/user/ProjectHooks/useTagSelectors.ts index 8007ef18..b8217187 100644 --- a/src/hooks/user/ProjectHooks/useTagSelectors.ts +++ b/src/hooks/user/ProjectHooks/useTagSelectors.ts @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { UseFormSetValue } from 'react-hook-form'; -import { CreateProjectFormValues } from '../../../models/createProject'; -import { PositionTag, SkillTag } from '../../../models/tags'; +import type { CreateProjectFormValues } from '../../../models/createProject'; +import type { PositionTag, SkillTag } from '../../../models/tags'; interface useTagSelectorsProps { apiTagData?: SkillTag[] | PositionTag[] | number; setValue: UseFormSetValue; From 8290df914d09237a232eaa306822dfc0fa1ca7b6 Mon Sep 17 00:00:00 2001 From: Cho SeungYeon <111514472+layout-SY@users.noreply.github.com> Date: Mon, 30 Jun 2025 21:57:49 +0900 Subject: [PATCH 9/9] =?UTF-8?q?refactor=20:=20=EB=AA=A8=EB=8D=B8=20import?= =?UTF-8?q?=EC=97=90=20type=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/admin/userDetail/userActivity.ts | 4 ++-- src/models/admin/userDetail/userDetail.applicants.ts | 6 +++--- src/models/admin/userDetail/userProjectData.ts | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/models/admin/userDetail/userActivity.ts b/src/models/admin/userDetail/userActivity.ts index 3d2ff697..3ca889c3 100644 --- a/src/models/admin/userDetail/userActivity.ts +++ b/src/models/admin/userDetail/userActivity.ts @@ -1,5 +1,5 @@ -import { MyInquiries } from '../../activityLog'; -import { ApiCommonType } from '../../apiCommon'; +import type { MyInquiries } from '../../activityLog'; +import type { ApiCommonType } from '../../apiCommon'; export interface UserComment { id: number; diff --git a/src/models/admin/userDetail/userDetail.applicants.ts b/src/models/admin/userDetail/userDetail.applicants.ts index f2d8ff29..c087b441 100644 --- a/src/models/admin/userDetail/userDetail.applicants.ts +++ b/src/models/admin/userDetail/userDetail.applicants.ts @@ -1,6 +1,6 @@ -import { ApiCommonType, User } from '../../apiCommon'; -import { Career } from '../../applicant'; -import { SkillTag } from '../../tags'; +import type { ApiCommonType, User } from '../../apiCommon'; +import type { Career } from '../../applicant'; +import type { SkillTag } from '../../tags'; export interface Applicant { id: number; diff --git a/src/models/admin/userDetail/userProjectData.ts b/src/models/admin/userDetail/userProjectData.ts index 699f6748..97d4bb9a 100644 --- a/src/models/admin/userDetail/userProjectData.ts +++ b/src/models/admin/userDetail/userProjectData.ts @@ -1,6 +1,6 @@ -import { ApiCommonType } from '../../apiCommon'; -import { MethodTag, PositionTag, SkillTag } from '../../tags'; -import { AppliedProject, JoinedProject } from '../../userProject'; +import type { ApiCommonType } from '../../apiCommon'; +import type { MethodTag, PositionTag, SkillTag } from '../../tags'; +import type { AppliedProject, JoinedProject } from '../../userProject'; export interface BaseProject { id: number;