diff --git a/src/components/admin/mainCard/MainCard.styled.ts b/src/components/admin/mainCard/MainCard.styled.ts index 99bad462..544cd54a 100644 --- a/src/components/admin/mainCard/MainCard.styled.ts +++ b/src/components/admin/mainCard/MainCard.styled.ts @@ -32,8 +32,18 @@ export const ShowAllButton = styled.span` export const ArrowRight = styled.img``; -export const Line = styled.hr``; +export const Line = styled.hr` + color: ${({ theme }) => theme.color.grey}; +`; -export const Wrapper = styled.div``; +export const Wrapper = styled.div` + flex: 1; + display: flex; +`; -export const MainContent = styled.div``; +export const MainContent = styled.div` + display: flex; + flex: 1; + justify-content: center; + align-items: center; +`; diff --git a/src/components/admin/mainCard/MainCard.tsx b/src/components/admin/mainCard/MainCard.tsx index 6fa48641..f19bb069 100644 --- a/src/components/admin/mainCard/MainCard.tsx +++ b/src/components/admin/mainCard/MainCard.tsx @@ -1,6 +1,7 @@ import * as S from './MainCard.styled'; import arrowRight from '../../../assets/ArrowRight.svg'; import React from 'react'; +import ContentBorder from '../../common/contentBorder/ContentBorder'; interface MainCardProps { title: string; @@ -20,7 +21,7 @@ const MainCard = ({ title, moreLink, children }: MainCardProps) => { )} - + {children} diff --git a/src/components/admin/previewComponent/allUserPreview/AllUserPreview.styled.ts b/src/components/admin/previewComponent/allUserPreview/AllUserPreview.styled.ts index a68e5081..e1244e06 100644 --- a/src/components/admin/previewComponent/allUserPreview/AllUserPreview.styled.ts +++ b/src/components/admin/previewComponent/allUserPreview/AllUserPreview.styled.ts @@ -2,8 +2,13 @@ import { Link } from 'react-router-dom'; import styled from 'styled-components'; export const Container = styled.div` + width: 100%; +`; + +export const SpinnerContainer = styled.div` display: flex; - flex-direction: column; + justify-content: center; + align-items: center; `; export const Wrapper = styled.div` diff --git a/src/components/admin/previewComponent/allUserPreview/AllUserPreview.tsx b/src/components/admin/previewComponent/allUserPreview/AllUserPreview.tsx index 00c91d60..2af5e580 100644 --- a/src/components/admin/previewComponent/allUserPreview/AllUserPreview.tsx +++ b/src/components/admin/previewComponent/allUserPreview/AllUserPreview.tsx @@ -3,14 +3,18 @@ import * as S from './AllUserPreview.styled'; import Avatar from '../../../common/avatar/Avatar'; import { ADMIN_ROUTE } from '../../../../constants/routes'; import arrow_right from '../../../../assets/ArrowRight.svg'; -import LoadingSpinner from '../../../common/loadingSpinner/LoadingSpinner'; import { useGetAllUsersPreview } from '../../../../hooks/admin/useGetAllUsersPreview'; +import { Spinner } from '../../../common/loadingSpinner/LoadingSpinner.styled'; const AllUserPreview = () => { const { allUserData, isLoading, isFetching } = useGetAllUsersPreview(); if (isLoading || isFetching) { - return ; + return ( + + + + ); } if (!allUserData || allUserData.length === 0) { @@ -22,9 +26,9 @@ const AllUserPreview = () => { {allUserData?.map((user) => ( - + - {user.user.nickname} + {user.nickname} {user.email} diff --git a/src/components/admin/previewComponent/inquiresPreview/InquiresPreview.styled.ts b/src/components/admin/previewComponent/inquiresPreview/InquiresPreview.styled.ts index 216304c5..7d0b9775 100644 --- a/src/components/admin/previewComponent/inquiresPreview/InquiresPreview.styled.ts +++ b/src/components/admin/previewComponent/inquiresPreview/InquiresPreview.styled.ts @@ -1,11 +1,13 @@ import { Link } from 'react-router-dom'; import styled from 'styled-components'; +import { SpinnerContainer } from '../allUserPreview/AllUserPreview.styled'; export const Container = styled.div` - display: flex; - flex-direction: column; + width: 100%; `; +export const SpinnerWrapper = styled(SpinnerContainer)``; + export const Wrapper = styled.div` display: flex; justify-content: space-between; diff --git a/src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx b/src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx index 3b4968b4..57cea21c 100644 --- a/src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx +++ b/src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx @@ -3,28 +3,26 @@ import { useGetAllInquiries } from '../../../../hooks/admin/useGetAllInquiries'; import Avatar from '../../../common/avatar/Avatar'; import { ADMIN_ROUTE } from '../../../../constants/routes'; import arrow_right from '../../../../assets/ArrowRight.svg'; -import LoadingSpinner from '../../../common/loadingSpinner/LoadingSpinner'; +import Spinner from '../../../user/mypage/Spinner'; const InquiresPreview = () => { const { allInquiriesData, isLoading, isFetching } = useGetAllInquiries(); if (isLoading || isFetching) { - return ; + return ( + + + + ); } if (!allInquiriesData || allInquiriesData.length === 0) { return 등록된 문의가 없습니다.; } - const previewList = allInquiriesData - ? allInquiriesData.length > 6 - ? allInquiriesData.slice(0, 4) - : allInquiriesData - : []; - return ( - {previewList?.map((inquiry) => ( + {allInquiriesData?.map((inquiry) => ( {/* { const { noticeData, isLoading, isFetching } = useGetNotice({ @@ -11,7 +10,11 @@ const NoticePreview = () => { }); if (isLoading || isFetching) { - return ; + return ( + + + + ); } if (!noticeData?.notices || noticeData.notices.length === 0) { diff --git a/src/components/admin/previewComponent/reportsPreview/ReportsPreview.styled.ts b/src/components/admin/previewComponent/reportsPreview/ReportsPreview.styled.ts index 5ae6b91a..1fa6d3d6 100644 --- a/src/components/admin/previewComponent/reportsPreview/ReportsPreview.styled.ts +++ b/src/components/admin/previewComponent/reportsPreview/ReportsPreview.styled.ts @@ -1,11 +1,13 @@ import { Link } from 'react-router-dom'; import styled from 'styled-components'; +import { SpinnerContainer } from '../allUserPreview/AllUserPreview.styled'; export const Container = styled.div` - display: flex; - flex-direction: column; + width: 100%; `; +export const SpinnerWrapper = styled(SpinnerContainer)``; + export const Wrapper = styled.div` display: flex; justify-content: space-between; diff --git a/src/components/admin/previewComponent/reportsPreview/ReportsPreview.tsx b/src/components/admin/previewComponent/reportsPreview/ReportsPreview.tsx index 794d952d..eda68d8d 100644 --- a/src/components/admin/previewComponent/reportsPreview/ReportsPreview.tsx +++ b/src/components/admin/previewComponent/reportsPreview/ReportsPreview.tsx @@ -3,19 +3,22 @@ import { useGetAllReports } from '../../../../hooks/admin/useGetAllReports'; import Avatar from '../../../common/avatar/Avatar'; import arrow_right from '../../../../assets/ArrowRight.svg'; import { ADMIN_ROUTE } from '../../../../constants/routes'; +import { Spinner } from '../../../common/loadingSpinner/LoadingSpinner.styled'; const ReportsPreview = () => { - const { allReportsData } = useGetAllReports(); + const { allReportsData, isLoading, isFetching } = useGetAllReports(); - const previewList = allReportsData - ? allReportsData.length > 6 - ? allReportsData.slice(0, 4) - : allReportsData - : []; + if (isLoading || isFetching) { + return ( + + + + ); + } return ( - {previewList?.map((report) => ( + {allReportsData?.map((report) => ( diff --git a/src/components/admin/userCard/UserCard.styled.ts b/src/components/admin/userCard/UserCard.styled.ts index 1bc8839e..d70929e1 100644 --- a/src/components/admin/userCard/UserCard.styled.ts +++ b/src/components/admin/userCard/UserCard.styled.ts @@ -35,7 +35,7 @@ export const TextLabel = styled.label` export const TextContent = styled.p<{ $userState?: UserState; }>` - font-size: 14px; + font-size: 13px; color: ${({ theme, $userState }) => $userState === UserState.ONLINE ? theme.color.green @@ -43,7 +43,7 @@ export const TextContent = styled.p<{ ? theme.color.blue : $userState === UserState.SUSPENDED ? theme.color.red - : theme.color.white}; + : theme.color.primary}; margin-left: 15px; `; diff --git a/src/components/admin/userCard/UserCard.tsx b/src/components/admin/userCard/UserCard.tsx index 27bf9b5b..d51db4c2 100644 --- a/src/components/admin/userCard/UserCard.tsx +++ b/src/components/admin/userCard/UserCard.tsx @@ -2,6 +2,7 @@ import React from 'react'; import * as S from './UserCard.styled'; import Avatar from '../../common/avatar/Avatar'; import { type AllUser } from '../../../models/auth'; +import { formatDate } from '../../../util/formatDate'; interface UserCardProps { userData: AllUser; @@ -11,34 +12,38 @@ const UserCard = ({ userData }: UserCardProps) => { return ( - - {userData.user.nickname} + + {userData.nickname} 이메일 {userData.email} 회원 상태 - + {/* {userData.userState} - + */} 경고 횟수 - {userData.reportedCount === 0 - ? '없음' - : `${userData.reportedCount}번`} + {userData.warning === 0 ? '없음' : `${userData.warning}번`} 포지션 - {userData.position.map((position) => position.name).join(', ')} + {userData.position + ? userData.position.map((position) => position.name).join(', ') + : '선택된 포지션이 없습니다.'} 대표 스킬 - - {userData.skill.map((skillTag) => ( - - ))} - + {userData.skill ? ( + + {userData.skill.map((skillTag) => ( + + ))} + + ) : ( + 선택된 스킬이 없습니다. + )} 계정 생성 날짜 - {userData.createdAt} + {formatDate(userData.createdAt)} ); diff --git a/src/constants/admin/sidebar.ts b/src/constants/admin/sidebar.ts index 146d4e83..541e8f49 100644 --- a/src/constants/admin/sidebar.ts +++ b/src/constants/admin/sidebar.ts @@ -38,8 +38,8 @@ export const SIDEBAR_LIST = { user: [ { name: 'allUser', - title: '전체 회원 조회', - router: ADMIN_ROUTE.allUser, + title: '회원 조회', + router: ADMIN_ROUTE.users, }, { name: 'reports', diff --git a/src/constants/routes.ts b/src/constants/routes.ts index d27463c3..d93d7150 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -38,11 +38,16 @@ export const ADMIN_ROUTE = { faq: 'faq', banner: 'banner', tags: 'tags', - allUser: 'all-user', + users: 'users', reports: 'reports', inquiries: 'inquiries', manage: 'manage', detail: 'detail', write: 'write', modification: 'modification', + basic: 'basic', + log: 'log', + joinedProject: 'joined-project', + createdProject: 'created-project', + appliedProject: 'apply-project', }; diff --git a/src/hooks/admin/useGetAllInquiries.ts b/src/hooks/admin/useGetAllInquiries.ts index 4abb9aa3..8f1d21b9 100644 --- a/src/hooks/admin/useGetAllInquiries.ts +++ b/src/hooks/admin/useGetAllInquiries.ts @@ -10,6 +10,7 @@ export const useGetAllInquiries = () => { } = useQuery({ queryKey: [Inquiries.allInquiries], queryFn: () => getAllInquiries(), + select: (allInquiries) => allInquiries.slice(0, 5), }); return { allInquiriesData, isLoading, isFetching }; diff --git a/src/hooks/admin/useGetAllReports.ts b/src/hooks/admin/useGetAllReports.ts index de128ee5..951f30b9 100644 --- a/src/hooks/admin/useGetAllReports.ts +++ b/src/hooks/admin/useGetAllReports.ts @@ -3,10 +3,15 @@ import { ReportData } from '../queries/keys'; import { getAllReports } from '../../api/report.api'; export const useGetAllReports = () => { - const { data: allReportsData, isLoading } = useQuery({ + const { + data: allReportsData, + isLoading, + isFetching, + } = useQuery({ queryKey: [ReportData.allReports], queryFn: () => getAllReports(), + select: (allReports) => allReports.slice(0, 5), }); - return { allReportsData, isLoading }; + return { allReportsData, isLoading, isFetching }; }; diff --git a/src/hooks/queries/keys.ts b/src/hooks/queries/keys.ts index 36e571a6..8caeccc2 100644 --- a/src/hooks/queries/keys.ts +++ b/src/hooks/queries/keys.ts @@ -67,4 +67,5 @@ export const ReportData = { export const UserData = { allUser: ['AllUser'], allUserPreview: ['AllUserPreview'], + userInfo: ['userInfo'], }; diff --git a/src/mock/adminMock.ts b/src/mock/adminMock.ts new file mode 100644 index 00000000..ab8da6f6 --- /dev/null +++ b/src/mock/adminMock.ts @@ -0,0 +1,33 @@ +import { http, HttpResponse, passthrough } from 'msw'; +import mockReports from './mockReports.json'; +import mockUsers from './mockUsers.json'; +import mockAllUsers from './mockAllUser.json'; + +export const reportsAll = http.get( + `${import.meta.env.VITE_APP_API_BASE_URL}reports`, + () => { + return HttpResponse.json(mockReports, { status: 200 }); + } +); + +export const userAllPreview = http.get( + `${import.meta.env.VITE_APP_API_BASE_URL}users/preview`, + () => { + return HttpResponse.json(mockUsers, { status: 200 }); + } +); + +export const userAll = http.get( + `${import.meta.env.VITE_APP_API_BASE_URL}users`, + () => { + return HttpResponse.json(mockAllUsers, { status: 200 }); + } +); + +export const passthroughAllGet = http.get(`*`, () => { + return passthrough(); +}); + +export const passthroughAllPost = http.post(`*`, () => { + return passthrough(); +}); diff --git a/src/mock/browser.ts b/src/mock/browser.ts index caac0f09..d0319fd9 100644 --- a/src/mock/browser.ts +++ b/src/mock/browser.ts @@ -7,7 +7,7 @@ import { passNonPass, passNonPassList, } from './applicant'; -import { projectDetail, reportsAll } from './projectDetail'; +import { projectDetail } from './projectDetail'; import { myPageAppliedProjectList, mypageEditProfile, @@ -16,12 +16,7 @@ import { myPageProfile, myPageSkillTag, } from './mypage'; -import { - userAll, - userAllPreview, - userPageAppliedProjectList, - userPageProfile, -} from './userpage'; +import { userPageAppliedProjectList, userPageProfile } from './userpage'; import { login } from './auth'; import { fetchProjectLists, fetchProjectStatistic } from './projectLists'; import { @@ -30,6 +25,13 @@ import { fetchSkillTag, } from './projectSearchFiltering'; import { createProject } from './createProject.ts'; +import { + passthroughAllGet, + passthroughAllPost, + reportsAll, + userAll, + userAllPreview, +} from './adminMock.ts'; export const handlers = [ fetchProjectLists, @@ -59,6 +61,8 @@ export const handlers = [ reportsAll, userAll, userAllPreview, + passthroughAllGet, + passthroughAllPost, ]; export const worker = setupWorker(...handlers); diff --git a/src/mock/projectDetail.ts b/src/mock/projectDetail.ts index bf6c51ea..697d999d 100644 --- a/src/mock/projectDetail.ts +++ b/src/mock/projectDetail.ts @@ -1,6 +1,5 @@ import { http, HttpResponse } from 'msw'; import mockPrjectDetail from './mockProjectDetail.json'; -import mockReports from './mockReports.json'; export const projectDetail = http.get( `${import.meta.env.VITE_APP_API_BASE_URL}project/:projectId`, @@ -10,10 +9,3 @@ export const projectDetail = http.get( }); } ); - -export const reportsAll = http.get( - `${import.meta.env.VITE_APP_API_BASE_URL}reports`, - () => { - return HttpResponse.json(mockReports, { status: 200 }); - } -); diff --git a/src/mock/userpage.ts b/src/mock/userpage.ts index 94b9d8a9..4ba9916e 100644 --- a/src/mock/userpage.ts +++ b/src/mock/userpage.ts @@ -1,8 +1,6 @@ import { http, HttpResponse } from 'msw'; import mockUserpageProfileData from './mockUserpageProfileData.json'; import mockUserpageAppliedProjectListData from './mockUserpageAppliedProjectListData.json'; -import mockUsers from './mockUsers.json'; -import mockAllUsers from './mockAllUser.json'; export const userPageProfile = http.get( `${import.meta.env.VITE_APP_API_BASE_URL}user/:id`, @@ -21,17 +19,3 @@ export const userPageAppliedProjectList = http.get( }); } ); - -export const userAllPreview = http.get( - `${import.meta.env.VITE_APP_API_BASE_URL}users/preview`, - () => { - return HttpResponse.json(mockUsers, { status: 200 }); - } -); - -export const userAll = http.get( - `${import.meta.env.VITE_APP_API_BASE_URL}users`, - () => { - return HttpResponse.json(mockAllUsers, { status: 200 }); - } -); diff --git a/src/models/auth.ts b/src/models/auth.ts index 6069ffad..aa4e95d6 100644 --- a/src/models/auth.ts +++ b/src/models/auth.ts @@ -45,9 +45,11 @@ export interface ApiGetAllUsersPreview extends ApiCommonType { } export interface AllUserPreview { id: number; + nickname: string; email: string; - user: User; - userState: UserState; + profileImg: string; + // userState: UserState; + warning: number; createdAt: string; } @@ -58,10 +60,9 @@ export interface ApiGetAllUsers extends ApiCommonType { export interface AllUser extends AllUserPreview { skill: SkillTag[]; position: PositionTag[]; - reportedCount: number; } export interface AllUserList { - allUsers: AllUser[]; + users: AllUser[]; totalPages: number; } diff --git a/src/pages/admin/adminAllUser/AdminAllUser.tsx b/src/pages/admin/adminAllUser/AdminAllUser.tsx deleted file mode 100644 index 927d43ad..00000000 --- a/src/pages/admin/adminAllUser/AdminAllUser.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import * as S from './AdminAllUser.styled'; -import AdminTitle from '../../../components/common/admin/title/AdminTitle'; -import { useGetAllUsers } from '../../../hooks/admin/useGetAllUsers'; -import LoadingSpinner from '../../../components/common/loadingSpinner/LoadingSpinner'; -import UserCard from '../../../components/admin/userCard/UserCard'; -import ScrollPreventor from '../../../components/common/modal/ScrollPreventor'; -import SearchBar from '../../../components/common/admin/searchBar/SearchBar'; -import Pagination from '../../../components/common/pagination/Pagination'; -import useSearchBar from '../../../hooks/admin/useSearchBar'; -import { ADMIN_MODAL_MESSAGE } from '../../../constants/admin/adminModal'; - -const AdminAllUser = () => { - const { searchUnit, value, handleGetKeyword, handleChangePagination } = - useSearchBar(); - const { allUserData, isLoading, isFetching } = useGetAllUsers(searchUnit); - - if (isLoading || isFetching) { - return ; - } - - if (!allUserData || allUserData.allUsers.length === 0) { - return {ADMIN_MODAL_MESSAGE.NO_RESULT}; - } - - return ( - - - - - - - - - - - {allUserData.allUsers?.map((userData) => ( - - ))} - - - - - - ); -}; - -export default AdminAllUser; diff --git a/src/pages/admin/adminAllUser/AdminAllUser.styled.ts b/src/pages/admin/adminUser/AdminUser.styled.ts similarity index 100% rename from src/pages/admin/adminAllUser/AdminAllUser.styled.ts rename to src/pages/admin/adminUser/AdminUser.styled.ts diff --git a/src/pages/admin/adminUser/AdminUser.tsx b/src/pages/admin/adminUser/AdminUser.tsx new file mode 100644 index 00000000..cac91bb4 --- /dev/null +++ b/src/pages/admin/adminUser/AdminUser.tsx @@ -0,0 +1,69 @@ +import * as S from './AdminUser.styled'; +import AdminTitle from '../../../components/common/admin/title/AdminTitle'; +import { useGetAllUsers } from '../../../hooks/admin/useGetAllUsers'; +import LoadingSpinner from '../../../components/common/loadingSpinner/LoadingSpinner'; +import UserCard from '../../../components/admin/userCard/UserCard'; +import ScrollPreventor from '../../../components/common/modal/ScrollPreventor'; +import SearchBar from '../../../components/common/admin/searchBar/SearchBar'; +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'; + +const AdminUser = () => { + const { searchUnit, value, handleGetKeyword, handleChangePagination } = + useSearchBar(); + const { allUserData, isLoading, isFetching } = useGetAllUsers(searchUnit); + + if (isLoading || isFetching) { + return ; + } + + if (!allUserData || allUserData.users.length === 0) { + return {ADMIN_MODAL_MESSAGE.NO_RESULT}; + } + + return ( + <> + + + + + + + + + + {allUserData.users.map((userData) => ( + + + + ))} + + + + + + + + ); +}; + +export default AdminUser; diff --git a/src/routes/AdminRoutes.tsx b/src/routes/AdminRoutes.tsx index ea63ca29..f60a7d1c 100644 --- a/src/routes/AdminRoutes.tsx +++ b/src/routes/AdminRoutes.tsx @@ -2,6 +2,12 @@ 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 Sidebar = lazy( @@ -28,7 +34,7 @@ const FAQWrite = lazy( ); const Banner = lazy(() => import('../pages/admin/adminBanner/AdminBanner')); const Tags = lazy(() => import('../pages/admin/adminTags/AdminTags')); -const AllUser = lazy(() => import('../pages/admin/adminAllUser/AdminAllUser')); +const AdminUser = lazy(() => import('../pages/admin/adminUser/AdminUser')); const Reports = lazy(() => import('../pages/admin/adminReports/AdminReports')); const Inquiries = lazy( () => import('../pages/admin/adminInquiries/AdminInquiries') @@ -70,7 +76,7 @@ export const AdminRoutes = () => { children: [ { index: true, - element: , + element:
, }, { path: ADMIN_ROUTE.notice, @@ -112,8 +118,38 @@ export const AdminRoutes = () => { element: , }, { - path: ADMIN_ROUTE.allUser, - element: , + path: ADMIN_ROUTE.users, + element: , + }, + { + path: `${ADMIN_ROUTE.users}/:userId`, + element: , + children: [ + { + index: true, + element: , + }, + { + path: `${ADMIN_ROUTE.basic}`, + element: , + }, + { + path: `${ADMIN_ROUTE.log}`, + element: , + }, + { + path: `${ADMIN_ROUTE.appliedProject}`, + element: , + }, + { + path: `${ADMIN_ROUTE.joinedProject}`, + element: , + }, + { + path: `${ADMIN_ROUTE.createdProject}`, + element: , + }, + ], }, { path: ADMIN_ROUTE.reports,