Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import AppRoutes from './routes/AppRoutes';
import { ThemeProvider } from 'styled-components';
import { GlobalStyle } from './style/global';
import { defaultTheme } from './style/theme';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { SearchFilteringProvider } from './context/SearchFilteringContext';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import MergeRoutes from './routes/MergeRoutes';

const queryClient = new QueryClient({
defaultOptions: {
Expand All @@ -22,7 +22,7 @@ function App() {
<SearchFilteringProvider>
<GlobalStyle />
<QueryClientProvider client={queryClient}>
<AppRoutes />
<MergeRoutes />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</SearchFilteringProvider>
Expand Down
1 change: 0 additions & 1 deletion src/api/http.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export const createClient = (config?: AxiosRequestConfig) => {
// }

logout();
useAuthStore.persist.clearStorage();
window.location.href = '/login';
return Promise.reject(error);
}
Expand Down
22 changes: 22 additions & 0 deletions src/assets/logout.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions src/components/common/admin/sidebar/AdminSidebar.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import styled from 'styled-components';

export const SidebarContainer = styled.section`
padding: 1rem;
width: 15rem;
`;

export const SidebarLogoWrapper = styled.div`
display: flex;
justify-content: space-around;
align-items: flex-end;
margin: 0 1.5rem 1.5rem 0;
`;

export const SidebarLogoImg = styled.img`
width: 5rem;
`;

export const LogoutButton = styled.button`
display: flex;
flex-direction: column;
margin-bottom: 0.3rem;
`;

export const LogoutImg = styled.img`
width: 2rem;
filter: invert(70%);
`;

export const LogoutSpan = styled.span`
font-size: 0.5rem;
color: ${({ theme }) => theme.color.deepGrey};
margin-left: -7px;
`;

export const MovedListContainerAll = styled.nav`
margin-top: 1.5rem;
display: grid;
gap: 1.5rem;
`;
29 changes: 29 additions & 0 deletions src/components/common/admin/sidebar/AdminSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { SIDEBAR_LIST } from '../../../../constants/admin/sidebar';
import * as S from './AdminSidebar.styled';
import logo from '../../../../assets/mainlogo.svg';
import logoutIcon from '../../../../assets/logout.svg';
import AdminSidebarList from './sidebarList/AdminSidebarList';
import ContentBorder from '../../contentBorder/ContentBorder';
import useAuthStore from '../../../../store/authStore';

export default function AdminSidebar() {
const logout = useAuthStore((state) => state.logout);

return (
<S.SidebarContainer>
<S.SidebarLogoWrapper>
<S.SidebarLogoImg src={logo} alt='logo' />
<S.LogoutButton type='button' onClick={logout}>
<S.LogoutImg src={logoutIcon} alt='logout icon' />
<S.LogoutSpan>Logout</S.LogoutSpan>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

접근성 개선을 위한 속성 추가가 필요합니다.

로그아웃 버튼과 이미지에 적절한 접근성 속성이 누락되어 있습니다.

다음과 같이 접근성 속성을 추가하세요:

        <S.SidebarLogoImg src={logo} alt='logo' />
-       <S.LogoutButton type='button' onClick={logout}>
+       <S.LogoutButton 
+         type='button' 
+         onClick={logout}
+         aria-label='관리자 로그아웃'
+         title='로그아웃'
+       >
-         <S.LogoutImg src={logoutIcon} alt='logout icon' />
+         <S.LogoutImg src={logoutIcon} alt='' role='presentation' />
          <S.LogoutSpan>Logout</S.LogoutSpan>
        </S.LogoutButton>
📝 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
<S.SidebarLogoImg src={logo} alt='logo' />
<S.LogoutButton type='button' onClick={logout}>
<S.LogoutImg src={logoutIcon} alt='logout icon' />
<S.LogoutSpan>Logout</S.LogoutSpan>
<S.SidebarLogoImg src={logo} alt='logo' />
<S.LogoutButton
type='button'
onClick={logout}
aria-label='관리자 로그아웃'
title='로그아웃'
>
<S.LogoutImg src={logoutIcon} alt='' role='presentation' />
<S.LogoutSpan>Logout</S.LogoutSpan>
</S.LogoutButton>
🤖 Prompt for AI Agents
In src/components/common/admin/sidebar/AdminSidebar.tsx around lines 15 to 18,
the logout button and its image lack proper accessibility attributes. Add an
aria-label to the logout button describing its action, and ensure the logout
image has an empty alt attribute (alt="") if it is decorative, or a descriptive
alt text if it conveys information. This will improve screen reader support and
overall accessibility.

</S.LogoutButton>
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입니다.

확인 모달이나 확인 절차를 추가하는 것을 제안합니다:

+ import { useState } from 'react';

export default function AdminSidebar() {
  const logout = useAuthStore((state) => state.logout);
+ const [showLogoutModal, setShowLogoutModal] = useState(false);

+ const handleLogoutClick = () => {
+   setShowLogoutModal(true);
+ };

+ const handleConfirmLogout = () => {
+   logout();
+   setShowLogoutModal(false);
+ };

  return (
    <S.SidebarContainer>
      <S.SidebarLogoWrapper>
        <S.SidebarLogoImg src={logo} alt='logo' />
-       <S.LogoutButton type='button' onClick={logout}>
+       <S.LogoutButton type='button' onClick={handleLogoutClick}>
          <S.LogoutImg src={logoutIcon} alt='logout icon' />
          <S.LogoutSpan>Logout</S.LogoutSpan>
        </S.LogoutButton>
      </S.SidebarLogoWrapper>
+     {showLogoutModal && (
+       <LogoutConfirmModal
+         onConfirm={handleConfirmLogout}
+         onCancel={() => setShowLogoutModal(false)}
+       />
+     )}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/components/common/admin/sidebar/AdminSidebar.tsx around lines 16 to 19,
the logout button triggers immediate logout without user confirmation, which
harms UX. Modify the logout handler to first show a confirmation modal or dialog
asking the user to confirm the logout action. Only proceed with the actual
logout if the user confirms; otherwise, cancel the operation. Implement this
confirmation step to improve user experience and prevent accidental logouts.

</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>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Link } from 'react-router-dom';
import styled from 'styled-components';

export const MovedListContainer = styled.nav``;

export const MovedListLink = styled(Link)`
display: flex;
align-items: center;
gap: 1rem;
padding: 0.8rem;

&:hover {
color: ${({ theme }) => theme.color.deepGrey};
}
`;

export const MovedListIcon = styled.div`
display: flex;
align-items: center;

svg {
width: 1.5rem;
}
`;

export const MovedList = styled.div`
font-size: 1.2rem;
`;

export const MovedListTitleWrapper = styled.div``;

export const MovedListTitle = styled.h3`
padding: 0.5rem;
color: ${({ theme }) => theme.color.deepGrey};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as S from './AdminSidebarList.styled';
import {
ArrowRightStartOnRectangleIcon,
ChatBubbleBottomCenterTextIcon,
EnvelopeIcon,
ExclamationTriangleIcon,
HomeIcon,
MegaphoneIcon,
PhotoIcon,
TagIcon,
UserGroupIcon,
} from '@heroicons/react/24/outline';

const iconMap = {
mainPage: <HomeIcon />,
movedSite: <ArrowRightStartOnRectangleIcon />,
notice: <MegaphoneIcon />,
banner: <PhotoIcon />,
tags: <TagIcon />,
allUser: <UserGroupIcon />,
reports: <ExclamationTriangleIcon />,
inquiries: <EnvelopeIcon />,
manage: <ChatBubbleBottomCenterTextIcon />,
};

type IconKey = keyof typeof iconMap;

interface AdminSidebarListProps {
title: string;
list: readonly { name: IconKey; title: string; router: string }[];
}

export default function AdminSidebarList({
title,
list,
}: AdminSidebarListProps) {
return (
<S.MovedListContainer>
<S.MovedListTitleWrapper>
{title && <S.MovedListTitle>{title}</S.MovedListTitle>}
</S.MovedListTitleWrapper>
{list.map((item) => (
<S.MovedListLink
to={item.router}
target={item.name.includes('movedSite') ? '_blank' : '_self'}
key={item.name}
>
<S.MovedListIcon>{iconMap[item.name]}</S.MovedListIcon>
<S.MovedList>{item.title}</S.MovedList>
</S.MovedListLink>
))}
</S.MovedListContainer>
);
}
10 changes: 8 additions & 2 deletions src/components/common/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { formatImgPath } from '../../../util/formatImgPath';
// import { useEffect } from 'react';
// import { testLiveAlarm } from '../../../api/alarm.api';
import { useMyProfileInfo } from '../../../hooks/user/useMyInfo';
import { ROUTES } from '../../../constants/user/routes';
import { ROUTES } from '../../../constants/routes';

function Header() {
const location = useLocation();
Expand All @@ -26,6 +26,12 @@ function Header() {
const isLoggedIn = useAuthStore((state) => state.isLoggedIn);
const { myData, isLoading } = useMyProfileInfo();

const handleClickLogout = () => {
userLogout();
useAuthStore.persist.clearStorage();
localStorage.clear();
};

// const { signalData, setSignalData } = useNotification();

// useEffect(() => {
Expand Down Expand Up @@ -100,7 +106,7 @@ function Header() {
<Link to='#' onClick={(e) => e.preventDefault()}>
<S.Item
aria-label='클릭시 로그아웃 됩니다.'
onClick={userLogout}
onClick={handleClickLogout}
>
로그아웃
</S.Item>
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/header/Notification/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import LoadingSpinner from '../../loadingSpinner/LoadingSpinner';
import useAlarmList from '../../../../hooks/user/useAlarmList';
import arrow_right from '../../../../assets/ArrowRight.svg';
import { useNavigate } from 'react-router-dom';
import { ROUTES } from '../../../../constants/user/routes';
import { ROUTES } from '../../../../constants/routes';

const Notification = () => {
const navigate = useNavigate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import chat from '../../../../../assets/chat.svg';
import { Link } from 'react-router-dom';
import CommentInput from '../../commentInput/CommentInput';
import type { CommentType } from '../../../../../models/comment';
import { ROUTES } from '../../../../../constants/user/routes';
import { ROUTES } from '../../../../../constants/routes';
import Avatar from '../../../../common/avatar/Avatar';

interface CommentComponentProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import CommentInput from '../commentInput/CommentInput';
import useGetReply from '../../../../hooks/user/CommentHooks/useGetReply';
import LoadingSpinner from '../../../common/loadingSpinner/LoadingSpinner';
import { Link } from 'react-router-dom';
import { ROUTES } from '../../../../constants/user/routes';
import { ROUTES } from '../../../../constants/routes';
import dropdownButton from '../../../../assets/dropdownButton.svg';

interface ReplyComponentProps {
Expand Down
2 changes: 1 addition & 1 deletion src/components/user/customerService/MoveInquiredLink.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useLocation } from 'react-router-dom';
import { ROUTES } from '../../../constants/user/routes';
import { ROUTES } from '../../../constants/routes';
import * as S from './MoveInquiredLink.styled';

export default function MovedInquiredLink() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ROUTES } from '../../../../../../constants/user/routes';
import { ROUTES } from '../../../../../../constants/routes';
import ContentBorder from '../../../../../common/contentBorder/ContentBorder';
import * as S from './ListButton.styled';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ROUTES } from '../../../../../../constants/user/routes';
import { ROUTES } from '../../../../../../constants/routes';
import type { OtherNotice } from '../../../../../../models/customerService';
import { formatDate } from '../../../../../../util/format';
import * as S from './OtherNoticeButton.styled';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useProjectCardListData } from '../../../../hooks/user/useProjectCardLis
import CardList from './cardList/CardList';
import * as S from './ProjectCardLists.styled';
import { Link } from 'react-router-dom';
import { ROUTES } from '../../../../constants/user/routes';
import { ROUTES } from '../../../../constants/routes';
import EmptyLoading from '../../../common/emptyLoading/EmptyLoading';
import NoResult from '../../../common/noResult/NoResult';
import { useSaveSearchFiltering } from '../../../../hooks/user/useSaveSearchFiltering';
Expand Down
2 changes: 1 addition & 1 deletion src/components/user/manageProjects/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as S from './Card.styled';
import type { ManagedProject } from '../../../models/manageMyProject';
import AvatarList from '../../common/avatar/AvatarList';
import { formatDate } from '../../../util/formatDate';
import { ROUTES } from '../../../constants/user/routes';
import { ROUTES } from '../../../constants/routes';
interface CardProps {
project: ManagedProject;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/user/manageProjects/CardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as S from './CardList.styled';
import type { ManagedProject } from '../../../models/manageMyProject';
import Card from './Card';
import CreateButton from '../../../assets/createProjectButton.svg';
import { ROUTES } from '../../../constants/user/routes';
import { ROUTES } from '../../../constants/routes';

interface CardListProps {
projects: ManagedProject[];
Expand Down
2 changes: 1 addition & 1 deletion src/components/user/mypage/ContentTab.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import * as S from './ContentTab.styled';
import { Link, Outlet, useLocation } from 'react-router-dom';
import { ROUTES } from '../../../constants/user/routes';
import { ROUTES } from '../../../constants/routes';
import ScrollWrapper from './ScrollWrapper';
import MovedInquiredLink from '../customerService/MoveInquiredLink';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Project from './Project';
import Spinner from '../Spinner';
import ScrollWrapper from '../ScrollWrapper';
import { useMyJoinedProjectList } from '../../../../hooks/user/useMyInfo';
import { ROUTES } from '../../../../constants/user/routes';
import { ROUTES } from '../../../../constants/routes';
import NoContent from '../../../common/noContent/NoContent';

const MyJoinProjects = () => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/user/mypage/joinedProject/Project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as S from './Project.styled';
import { EllipsisHorizontalIcon } from '@heroicons/react/24/outline';
import type { JoinedProject } from '../../../../models/userProject';
import beginner from '../../../../assets/beginner.svg';
import { ROUTES } from '../../../../constants/user/routes';
import { ROUTES } from '../../../../constants/routes';

interface ProjectProps {
project: JoinedProject;
Expand Down
2 changes: 1 addition & 1 deletion src/components/user/mypage/myProfile/MyProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useRef } from 'react';
import ScrollWrapper from '../ScrollWrapper';
import { useModal } from '../../../../hooks/useModal';
import { useMyProfileInfo } from '../../../../hooks/user/useMyInfo';
import { ROUTES } from '../../../../constants/user/routes';
import { ROUTES } from '../../../../constants/routes';
import Modal from '../../../common/modal/Modal';

const MyProfile = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { UserInfo } from '../../../../../models/userInfo';
import { useSearchFilteringSkillTag } from '../../../../../hooks/user/useSearchFilteringSkillTag';
import { useEditMyProfileInfo } from '../../../../../hooks/user/useMyInfo';
import useNickNameVerification from '../../../../../hooks/user/useNicknameVerification';
import { ROUTES } from '../../../../../constants/user/routes';
import { ROUTES } from '../../../../../constants/routes';
import Button from '../../../../common/Button/Button';
import {
ERROR_MESSAGES,
Expand Down
2 changes: 1 addition & 1 deletion src/components/user/mypage/myProfile/profile/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useEffect } from 'react';
import MyProfileWrapper from '../MyProfileWrapper';
import type { UserInfo } from '../../../../../models/userInfo';
import { PROFILE_DEFAULT_MESSAGE } from '../../../../../constants/user/myPageProfile';
import { ROUTES } from '../../../../../constants/user/routes';
import { ROUTES } from '../../../../../constants/routes';
import 'chart.js/auto';
import { chartOptions } from '../../../../../constants/evaluationChartData';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ 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/user/routes';
import { ROUTES } from '../../../../../constants/routes';

export default function AppliedProjects() {
const { myAppliedStatusListData, isLoading } = useMyAppliedStatusList();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Link } from 'react-router-dom';
import * as S from '../../mypage/joinedProject/MyJoinProjects.styled';
import { ROUTES } from '../../../../constants/user/routes';
import { ROUTES } from '../../../../constants/routes';
import NoContent from '../../../common/noContent/NoContent';
import ScrollWrapper from '../../mypage/ScrollWrapper';
import Spinner from '../../mypage/Spinner';
Expand Down
Loading