Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/components/common/admin/sidebar/AdminSidebar.styled.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import styled from 'styled-components';

export const SidebarContainer = styled.section`
export const LayoutContainer = styled.div`
height: 100vh;
display: flex;
`;

export const ContainerArea = styled.section`
flex: 1;
padding: 2rem;
`;

export const SidebarContainer = styled.section`
padding: 1rem;
width: 15rem;
border-right: 1px solid ${({ theme }) => theme.color.grey};
Expand Down
57 changes: 35 additions & 22 deletions src/components/common/admin/sidebar/AdminSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,53 @@ import logoutIcon from '../../../../assets/logout.svg';
import AdminSidebarList from './sidebarList/AdminSidebarList';
import ContentBorder from '../../contentBorder/ContentBorder';
import useAuthStore from '../../../../store/authStore';
import { useNavigate } from 'react-router-dom';
import { Outlet, useNavigate } from 'react-router-dom';
import { ROUTES } from '../../../../constants/routes';
import { useModal } from '../../../../hooks/useModal';
import Modal from '../../modal/Modal';
import { MODAL_MESSAGE } from '../../../../constants/user/modalMessage';

export default function AdminSidebar() {
const navigate = useNavigate();
const logout = useAuthStore((state) => state.logout);
const { isOpen, message, handleModalOpen, handleModalClose } = useModal();

const handleClickLogout = () => {
logout();
handleModalOpen(MODAL_MESSAGE.needAuth);
setTimeout(() => {
logout();
navigate(ROUTES.main);
}, 1000);
};
Comment on lines 19 to 25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

로그아웃 로직의 UX 개선을 제안합니다.

현재 구현에서 몇 가지 개선점이 있습니다:

  1. 하드코딩된 1초 지연이 사용자에게 혼란을 줄 수 있습니다
  2. 모달 메시지가 MODAL_MESSAGE.needAuth로 설정되어 있는데, 로그아웃 확인에는 부적절해 보입니다

다음과 같이 개선을 제안합니다:

  const handleClickLogout = () => {
-    handleModalOpen(MODAL_MESSAGE.needAuth);
-    setTimeout(() => {
-      logout();
-      navigate(ROUTES.main);
-    }, 1000);
+    if (window.confirm('로그아웃 하시겠습니까?')) {
+      logout();
+      navigate(ROUTES.main);
+    }
  };

또는 모달을 사용하려면 적절한 확인/취소 버튼이 있는 확인 모달을 구현하는 것이 좋습니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleClickLogout = () => {
logout();
handleModalOpen(MODAL_MESSAGE.needAuth);
setTimeout(() => {
logout();
navigate(ROUTES.main);
}, 1000);
};
const handleClickLogout = () => {
if (window.confirm('로그아웃 하시겠습니까?')) {
logout();
navigate(ROUTES.main);
}
};
🤖 Prompt for AI Agents
In src/components/common/admin/sidebar/AdminSidebar.tsx around lines 19 to 25,
improve the logout UX by removing the hardcoded 1-second delay and replacing the
modal message from MODAL_MESSAGE.needAuth to a more appropriate logout
confirmation message. Implement a confirmation modal with explicit confirm and
cancel buttons to handle user consent before logging out, and only call logout()
and navigate() after the user confirms.


return (
<S.SidebarContainer>
<S.SidebarLogoWrapper>
<S.SidebarLogoImg src={logo} alt='logo' />
<S.LogoutButton
type='button'
onClick={handleClickLogout}
aria-label='관리자 로그아웃'
title='로그아웃'
>
<S.LogoutImg src={logoutIcon} alt='logout icon' />
<S.LogoutSpan>Logout</S.LogoutSpan>
</S.LogoutButton>
</S.SidebarLogoWrapper>
<ContentBorder />
<S.MovedListContainerAll>
<AdminSidebarList title='' list={SIDEBAR_LIST.main} />
<AdminSidebarList title='서비스 관리' list={SIDEBAR_LIST.service} />
<AdminSidebarList title='사용자 관리' list={SIDEBAR_LIST.user} />
</S.MovedListContainerAll>
</S.SidebarContainer>
<S.LayoutContainer>
<S.SidebarContainer>
<S.SidebarLogoWrapper>
<S.SidebarLogoImg src={logo} alt='logo' />
<S.LogoutButton
type='button'
onClick={handleClickLogout}
aria-label='관리자 로그아웃'
title='로그아웃'
>
<S.LogoutImg src={logoutIcon} alt='logout icon' />
<S.LogoutSpan>Logout</S.LogoutSpan>
</S.LogoutButton>
</S.SidebarLogoWrapper>
<ContentBorder />
<S.MovedListContainerAll>
<AdminSidebarList title='' list={SIDEBAR_LIST.main} />
<AdminSidebarList title='서비스 관리' list={SIDEBAR_LIST.service} />
<AdminSidebarList title='사용자 관리' list={SIDEBAR_LIST.user} />
</S.MovedListContainerAll>
</S.SidebarContainer>
<S.ContainerArea>
<Outlet />
</S.ContainerArea>
<Modal isOpen={isOpen} onClose={handleModalClose}>
{message}
</Modal>
</S.LayoutContainer>
);
}
9 changes: 9 additions & 0 deletions src/components/common/admin/title/AdminTitle.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import styled from 'styled-components';

export const TitleContainer = styled.header``;

export const TitleWrapper = styled.div`
margin-bottom: 2rem;
`;

export const Title = styled.h1``;
17 changes: 17 additions & 0 deletions src/components/common/admin/title/AdminTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import ContentBorder from '../../contentBorder/ContentBorder';
import * as S from './AdminTitle.styled';

interface AdminTitleProps {
title: string;
}

export default function AdminTitle({ title }: AdminTitleProps) {
return (
<S.TitleContainer>
<S.TitleWrapper>
<S.Title>{title}</S.Title>
</S.TitleWrapper>
<ContentBorder />
</S.TitleContainer>
);
}
4 changes: 2 additions & 2 deletions src/components/user/customerService/CustomerServiceHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { MagnifyingGlassIcon, XCircleIcon } from '@heroicons/react/24/outline';
import * as S from './CustomerServiceHeader.styled';
import MovedInquiredLink from './MoveInquiredLink';
import { Outlet, useLocation, useSearchParams } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { Outlet, useSearchParams } from 'react-router-dom';
import { useState } from 'react';
import Modal from '../../common/modal/Modal';
import { useModal } from '../../../hooks/useModal';
import { MODAL_MESSAGE_CUSTOMER_SERVICE } from '../../../constants/user/customerService';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function NoticeDetailBundle() {
createdAt=''
viewCount={0}
/>
<ListButton />
<ListButton keyword='' />
</S.Container>
);
}
Expand Down
3 changes: 3 additions & 0 deletions src/pages/admin/adminAllUser/AdminAllUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AdminAllUser() {
return <div></div>;
}
Comment on lines +1 to +3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

플레이스홀더 컴포넌트에 대한 개선 제안

현재 빈 컴포넌트로 구현되어 있는데, 다음과 같은 개선을 제안합니다:

  1. TODO 주석을 추가하여 향후 구현 계획을 명시
  2. 컴포넌트의 역할을 설명하는 주석 추가
  3. 개발 중임을 나타내는 임시 콘텐츠 표시
+// TODO: 전체 사용자 관리 페이지 구현 필요
+// 기능: 사용자 목록 조회, 검색, 필터링, 상태 관리
export default function AdminAllUser() {
-  return <div></div>;
+  return (
+    <div>
+      <h2>전체 사용자 관리</h2>
+      <p>개발 중입니다...</p>
+    </div>
+  );
}
🤖 Prompt for AI Agents
In src/pages/admin/adminAllUser/AdminAllUser.tsx at lines 1 to 3, the component
is currently empty without any indication of future work. Add a TODO comment at
the top to specify that implementation is pending, include a brief comment
explaining the component's intended role, and add temporary placeholder content
inside the div to indicate that the component is under development.

3 changes: 3 additions & 0 deletions src/pages/admin/adminBanner/AdminBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AdminBanner() {
return <div></div>;
}
Comment on lines +1 to +3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

플레이스홀더 컴포넌트 일관성 개선

AdminAllUser와 동일한 패턴의 빈 컴포넌트입니다. 일관성을 위해 동일한 개선사항을 적용하는 것을 제안합니다.

+// TODO: 배너 관리 페이지 구현 필요  
+// 기능: 배너 등록, 수정, 삭제, 순서 변경, 활성화/비활성화
export default function AdminBanner() {
-  return <div></div>;
+  return (
+    <div>
+      <h2>배너 관리</h2>
+      <p>개발 중입니다...</p>
+    </div>
+  );
}
🤖 Prompt for AI Agents
In src/pages/admin/adminBanner/AdminBanner.tsx at lines 1 to 3, the AdminBanner
component is a placeholder but does not follow the same pattern as AdminAllUser.
To improve consistency, refactor AdminBanner to match the structure and style
used in AdminAllUser's empty component, such as adding any standard comments,
default exports, or wrapping elements as per the existing pattern.

3 changes: 3 additions & 0 deletions src/pages/admin/adminInquiries/AdminInquiries.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import styled from 'styled-components';

export const AdminInquiriesContainer = styled.div``;
5 changes: 5 additions & 0 deletions src/pages/admin/adminInquiries/AdminInquiries.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as S from './AdminInquires.styled';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

import 경로의 파일명 불일치를 수정하세요.

import 경로에서 './AdminInquires.styled'로 되어 있지만, 파일명과 styled component명을 고려할 때 './AdminInquiries.styled'가 되어야 합니다.

다음과 같이 수정하세요:

-import * as S from './AdminInquires.styled';
+import * as S from './AdminInquiries.styled';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import * as S from './AdminInquires.styled';
import * as S from './AdminInquiries.styled';
🤖 Prompt for AI Agents
In src/pages/admin/adminInquiries/AdminInquiries.tsx at line 1, the import path
'./AdminInquires.styled' has a filename typo. Change it to
'./AdminInquiries.styled' to match the actual filename and styled component
naming convention.


export default function AdminInquires() {
return <S.AdminInquiriesContainer></S.AdminInquiriesContainer>;
}
Comment on lines +3 to +5
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

함수명 불일치를 수정하고 컴포넌트 구조를 확인하세요.

함수명이 AdminInquires로 되어 있지만 파일명과 일치시키기 위해 AdminInquiries로 변경해야 합니다. 또한 현재 컴포넌트가 빈 컨테이너만 렌더링하고 있는데, 이것이 의도된 스캐폴딩인지 확인이 필요합니다.

함수명을 수정하세요:

-export default function AdminInquires() {
+export default function AdminInquiries() {
   return <S.AdminInquiriesContainer></S.AdminInquiriesContainer>;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default function AdminInquires() {
return <S.AdminInquiriesContainer></S.AdminInquiriesContainer>;
}
export default function AdminInquiries() {
return <S.AdminInquiriesContainer></S.AdminInquiriesContainer>;
}
🤖 Prompt for AI Agents
In src/pages/admin/adminInquiries/AdminInquiries.tsx at lines 3 to 5, rename the
function from AdminInquires to AdminInquiries to match the file name. Also,
verify if rendering an empty S.AdminInquiriesContainer is intentional
scaffolding; if not, update the component to include the intended content or
structure.

3 changes: 3 additions & 0 deletions src/pages/admin/adminMain/AdminMain.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AdminMain() {
return <div></div>;
}
Comment on lines +1 to +3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

관리자 메인 페이지 플레이스홀더 개선

이 컴포넌트는 관리자 섹션의 메인(인덱스) 페이지로 사용되므로, 더 명확한 플레이스홀더 콘텐츠가 필요합니다.

+// TODO: 관리자 대시보드 메인 페이지 구현
+// 기능: 주요 통계, 최근 활동, 빠른 링크 등
export default function AdminMain() {
-  return <div></div>;
+  return (
+    <div>
+      <h1>관리자 대시보드</h1>
+      <p>관리자 메인 페이지 개발 중입니다...</p>
+      {/* TODO: 대시보드 위젯들 추가 예정 */}
+    </div>
+  );
}

메인 페이지이므로 향후 대시보드 기능(통계, 차트, 빠른 액세스 링크 등)을 포함할 계획을 고려해주세요.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default function AdminMain() {
return <div></div>;
}
// TODO: 관리자 대시보드 메인 페이지 구현
// 기능: 주요 통계, 최근 활동, 빠른 링크 등
export default function AdminMain() {
return (
<div>
<h1>관리자 대시보드</h1>
<p>관리자 메인 페이지 개발 중입니다...</p>
{/* TODO: 대시보드 위젯들 추가 예정 */}
</div>
);
}
🤖 Prompt for AI Agents
In src/pages/admin/adminMain/AdminMain.tsx at lines 1 to 3, the AdminMain
component currently returns an empty div as a placeholder. Replace this with a
more descriptive placeholder content indicating it is the admin main page, such
as a heading or message. Also, structure the component to allow easy addition of
future dashboard features like statistics, charts, or quick access links.

3 changes: 3 additions & 0 deletions src/pages/admin/adminManage/AdminManage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AdminManage() {
return <div></div>;
}
3 changes: 3 additions & 0 deletions src/pages/admin/adminNotice/AdminNotice.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import styled from 'styled-components';

export const Container = styled.div``;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

빈 스타일 컴포넌트 검토 필요

현재 스타일이 정의되지 않은 Container 컴포넌트가 있습니다.

AdminNotice 컴포넌트에서 실제로 사용되는지와 필요한 스타일이 있는지 확인해주세요.

만약 아직 스타일이 필요하지 않다면, 임시로 주석을 추가하거나 향후 구현 계획을 명시하는 것을 제안합니다:

import styled from 'styled-components';

+// TODO: AdminNotice 페이지 레이아웃에 필요한 스타일 추가 예정
export const Container = styled.div``;

🏁 Script executed:

#!/bin/bash
# AdminNotice 컴포넌트에서 Container 사용 여부 확인
rg -A 5 -B 5 "Container" src/pages/admin/adminNotice/

Length of output: 883


AdminNotice Container styled-component 검토 및 스타일 추가 필요

AdminNotice.tsx에서 <S.Container>로 사용되고 있어 제거할 수는 없으나, 현재 스타일이 비어 있어 레이아웃이나 디자인 요구사항에 따라 아래 조치가 필요합니다.

  • src/pages/admin/adminNotice/AdminNotice.styled.ts
    export const Container = styled.div\`;부분 검토 – 필요한 레이아웃/여백/스타일이 있다면 해당 CSS를 추가 – 당장 스타일이 없고 향후 구현 계획이 있다면// TODO:주석으로 의도 명시 – 정말 불필요하다면 styled-component 자체를 삭제하고 JSX에서 일반
    `로 교체

예시 (TODO 주석 추가):

 import styled from 'styled-components';
 
+// TODO: AdminNotice 레이아웃에 맞춰 Container 스타일 정의 예정
 export const Container = styled.div``;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const Container = styled.div``;
import styled from 'styled-components';
// TODO: AdminNotice 레이아웃에 맞춰 Container 스타일 정의 예정
export const Container = styled.div``;
🤖 Prompt for AI Agents
In src/pages/admin/adminNotice/AdminNotice.styled.ts at line 3, the Container
styled-component is currently empty but used in AdminNotice.tsx. Review the
design requirements and either add the necessary CSS styles for layout or
spacing, or if no styles are needed yet, add a clear TODO comment above the
export to indicate future styling plans. If the component is truly unnecessary,
remove the styled-component and replace its usage with a standard div in the
JSX.

12 changes: 12 additions & 0 deletions src/pages/admin/adminNotice/AdminNotice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import AdminTitle from '../../../components/common/admin/title/AdminTitle';
import * as S from './AdminNotice.styled';

export default function AdminNotice() {
console.log('공지사항 렌더');

return (
<S.Container>
<AdminTitle title='공지사항' />
</S.Container>
);
}
3 changes: 3 additions & 0 deletions src/pages/admin/adminReports/AdminReports.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AdminReports() {
return <div></div>;
}
3 changes: 3 additions & 0 deletions src/pages/admin/adminTags/AdminTags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AdminTags() {
return <div></div>;
}
Comment on lines +1 to +3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

모든 관리자 플레이스홀더 컴포넌트에 일관된 패턴을 적용하세요.

다른 관리자 컴포넌트들과 동일한 접근성 문제가 있습니다. 모든 관리자 페이지 컴포넌트에 일관된 구조를 적용하는 것을 권장합니다.

다음과 같이 개선하고, 다른 관리자 컴포넌트들도 동일한 패턴으로 통일해주세요:

export default function AdminTags() {
-  return <div></div>;
+  return (
+    <main>
+      <h1>태그 관리</h1>
+      <p>태그 관리 기능을 개발 중입니다.</p>
+    </main>
+  );
}

모든 관리자 컴포넌트(AdminReports, AdminManage, AdminTags 등)에 동일한 패턴을 적용하여 일관성을 유지해주세요.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default function AdminTags() {
return <div></div>;
}
export default function AdminTags() {
return (
<main>
<h1>태그 관리</h1>
<p>태그 관리 기능을 개발 중입니다.</p>
</main>
);
}
🤖 Prompt for AI Agents
In src/pages/admin/adminTags/AdminTags.tsx lines 1 to 3, the AdminTags component
is a placeholder but lacks the consistent structure and accessibility patterns
used in other admin components like AdminReports and AdminManage. Refactor
AdminTags to follow the same component pattern as other admin pages, including
consistent layout, accessibility attributes, and any shared wrappers or styles
to ensure uniformity across all admin components.

41 changes: 41 additions & 0 deletions src/routes/AdminRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import ProtectAdminRoute from './ProtectAdminRoute';
const Sidebar = lazy(
() => import('../components/common/admin/sidebar/AdminSidebar')
);
const Main = lazy(() => import('../pages/admin/adminMain/AdminMain'));
const Notice = lazy(() => import('../pages/admin/adminNotice/AdminNotice'));
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 Reports = lazy(() => import('../pages/admin/adminReports/AdminReports'));
const Inquiries = lazy(
() => import('../pages/admin/adminInquiries/AdminInquiries')
);
const Manage = lazy(() => import('../pages/admin/adminManage/AdminManage'));

export const AdminRoutes = () => {
const routeList = [
Expand All @@ -16,6 +26,37 @@ export const AdminRoutes = () => {
<Sidebar />
</ProtectAdminRoute>
),
children: [
{ index: true, element: <Main /> },
{
path: ADMIN_ROUTE.notice,
element: <Notice />,
},
{
path: ADMIN_ROUTE.banner,
element: <Banner />,
},
{
path: ADMIN_ROUTE.tags,
element: <Tags />,
},
{
path: ADMIN_ROUTE.allUser,
element: <AllUser />,
},
{
path: ADMIN_ROUTE.reports,
element: <Reports />,
},
{
path: ADMIN_ROUTE.inquiries,
element: <Inquiries />,
},
{
path: ADMIN_ROUTE.manage,
element: <Manage />,
},
],
},
];

Expand Down