From 34750be68b2f353997e3280dca168ca056457037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A4=80=EC=98=81?= Date: Wed, 15 Apr 2026 12:30:45 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=97=90=20=EA=B4=80=EB=A6=AC=20=EB=8F=99?= =?UTF-8?q?=EC=95=84=EB=A6=AC=20=EB=AA=A9=EB=A1=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 - src/components/common/Card.tsx | 7 +- src/pages/Manager/ManagedClubList/index.tsx | 42 ------ .../User/MyPage/components/MyPageRows.tsx | 56 ++++++++ .../User/MyPage/components/UserInfoCard.tsx | 2 +- src/pages/User/MyPage/index.tsx | 121 +++++++++++------- src/utils/hooks/useSmartBack.ts | 6 +- 7 files changed, 137 insertions(+), 99 deletions(-) delete mode 100644 src/pages/Manager/ManagedClubList/index.tsx create mode 100644 src/pages/User/MyPage/components/MyPageRows.tsx diff --git a/src/App.tsx b/src/App.tsx index cb66b19a..0bcfadb3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -36,7 +36,6 @@ const ManagedApplicationDetail = lazy(() => import('./pages/Manager/ManagedAppli const ManagedApplicationList = lazy(() => import('./pages/Manager/ManagedApplicationList')); const ManagedClubDetail = lazy(() => import('./pages/Manager/ManagedClubDetail')); const ManagedClubInfo = lazy(() => import('./pages/Manager/ManagedClubProfile')); -const ManagedClubList = lazy(() => import('./pages/Manager/ManagedClubList')); const ManagedMemberApplicationDetail = lazy(() => import('./pages/Manager/ManagedMemberApplicationDetail')); const ManagedMemberList = lazy(() => import('./pages/Manager/ManagedMemberList')); const ManagedRecruitment = lazy(() => import('./pages/Manager/ManagedRecruitment')); @@ -94,7 +93,6 @@ function App() { } /> - } /> } /> } /> } /> diff --git a/src/components/common/Card.tsx b/src/components/common/Card.tsx index 6003bc53..c2fd067d 100644 --- a/src/components/common/Card.tsx +++ b/src/components/common/Card.tsx @@ -7,10 +7,11 @@ interface CardProps extends HTMLAttributes { } function Card({ children, className, ...props }: CardProps) { - const base = 'border-indigo-5 flex w-full flex-col gap-3 rounded-lg border bg-white p-3'; - return ( -
+
{children}
); diff --git a/src/pages/Manager/ManagedClubList/index.tsx b/src/pages/Manager/ManagedClubList/index.tsx deleted file mode 100644 index 8f2fe5e5..00000000 --- a/src/pages/Manager/ManagedClubList/index.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useSuspenseQuery } from '@tanstack/react-query'; -import { Link } from 'react-router-dom'; -import { managedClubQueries } from '@/apis/club/managedQueries'; -import RightArrowIcon from '@/assets/svg/Chevron-left-dark.svg'; -import ManagerInfoCard from '@/pages/User/MyPage/components/ManagerInfoCard'; - -function ManagedClubList() { - const { data: managedClubList } = useSuspenseQuery(managedClubQueries.clubs()); - - return ( -
- -
-

동아리 목록

-
- {managedClubList.joinedClubs.map((club) => ( - -
- Club Avatar -
- {club.name} - {club.categoryName} -
-
- - - ))} -
-
-
- ); -} - -export default ManagedClubList; diff --git a/src/pages/User/MyPage/components/MyPageRows.tsx b/src/pages/User/MyPage/components/MyPageRows.tsx new file mode 100644 index 00000000..f5686f2e --- /dev/null +++ b/src/pages/User/MyPage/components/MyPageRows.tsx @@ -0,0 +1,56 @@ +import type { ReactNode } from 'react'; +import ChatIcon from '@/assets/svg/chat.svg'; +import RightArrowIcon from '@/assets/svg/Chevron-left-dark.svg'; + +type MyPageRowIcon = typeof ChatIcon; + +interface MyPageRowBaseProps { + icon: MyPageRowIcon; + label: string; +} + +interface MyPageRowLayoutProps extends MyPageRowBaseProps { + rightSlot: ReactNode; + labelClassName: string; +} + +type MyPageLinkRowProps = MyPageRowBaseProps; + +interface MyPageInfoRowProps extends MyPageRowBaseProps { + value: string; +} + +type MyPageActionRowProps = MyPageRowBaseProps; + +function MyPageRowLayout({ icon: Icon, label, rightSlot, labelClassName }: MyPageRowLayoutProps) { + return ( +
+
+ +
{label}
+
+ {rightSlot} +
+ ); +} + +export function MyPageLinkRow({ icon, label }: MyPageLinkRowProps) { + return } labelClassName="text-sub2" />; +} + +export function MyPageInfoRow({ icon, label, value }: MyPageInfoRowProps) { + return ( + {value}
} + labelClassName="text-sm leading-4 font-semibold" + /> + ); +} + +export function MyPageActionRow({ icon, label }: MyPageActionRowProps) { + return ( + + ); +} diff --git a/src/pages/User/MyPage/components/UserInfoCard.tsx b/src/pages/User/MyPage/components/UserInfoCard.tsx index 514b77e2..77dadf35 100644 --- a/src/pages/User/MyPage/components/UserInfoCard.tsx +++ b/src/pages/User/MyPage/components/UserInfoCard.tsx @@ -33,7 +33,7 @@ function UserInfoCard() { }; return ( - +
diff --git a/src/pages/User/MyPage/index.tsx b/src/pages/User/MyPage/index.tsx index 2a847c09..8616d2fd 100644 --- a/src/pages/User/MyPage/index.tsx +++ b/src/pages/User/MyPage/index.tsx @@ -1,86 +1,109 @@ import { useSuspenseQuery } from '@tanstack/react-query'; import { Link } from 'react-router-dom'; -import { authQueries } from '@/apis/auth/queries'; +import { managedClubQueries } from '@/apis/club/managedQueries'; import ChatIcon from '@/assets/svg/chat.svg'; -import RightArrowIcon from '@/assets/svg/chevron-right.svg'; +import RightArrowIcon from '@/assets/svg/Chevron-left-dark.svg'; import FileSearchIcon from '@/assets/svg/file-search.svg'; import FileIcon from '@/assets/svg/file.svg'; import LayersIcon from '@/assets/svg/layers.svg'; import LogoutIcon from '@/assets/svg/logout.svg'; -import UserIdCardIcon from '@/assets/svg/user-id-card.svg'; import UserSquareIcon from '@/assets/svg/user-square.svg'; import BottomModal from '@/components/common/BottomModal'; import useBooleanState from '@/utils/hooks/useBooleanState'; import { useAdminChatMutation } from '../hooks/useAdminChatMutation'; +import { MyPageActionRow, MyPageInfoRow, MyPageLinkRow } from './components/MyPageRows'; import UserInfoCard from './components/UserInfoCard'; import { useLogoutMutation } from './hooks/useLogout'; -const menuItems = [ - { to: 'manager', icon: UserIdCardIcon, label: '동아리 관리' }, - { to: '/legal/oss', icon: FileSearchIcon, label: '오픈소스 라이선스' }, - { to: '/legal/terms', icon: FileIcon, label: '코넥트 약관 확인' }, - { to: '/legal/privacy', icon: UserSquareIcon, label: '개인정보 처리 방침' }, +interface LegalMenuState { + backPath: string; +} + +interface MenuItem { + to: string; + icon: typeof ChatIcon; + label: string; + state?: LegalMenuState; +} + +interface ManagedClubSummary { + id: number; + name: string; + categoryName: string; + imageUrl: string; +} + +interface ManagedClubLinkProps { + club: ManagedClubSummary; +} + +const menuItems: MenuItem[] = [ + { to: '/legal/oss', icon: FileSearchIcon, label: '오픈소스 라이선스', state: { backPath: '/mypage' } }, + { to: '/legal/terms', icon: FileIcon, label: '코넥트 약관 확인', state: { backPath: '/mypage' } }, + { to: '/legal/privacy', icon: UserSquareIcon, label: '개인정보 처리 방침', state: { backPath: '/mypage' } }, ]; +function ManagedClubLink({ club }: ManagedClubLinkProps) { + return ( + +
+ Club Avatar +
+ {club.name} + {club.categoryName} +
+
+ + + ); +} + function MyPage() { - const { data: myInfo } = useSuspenseQuery(authQueries.myInfo()); + const { data: managedClubList } = useSuspenseQuery(managedClubQueries.clubs()); const { mutate: logout, isPending: isLoggingOut } = useLogoutMutation(); const { value: isOpen, setTrue: openModal, setFalse: closeModal } = useBooleanState(false); const { mutate: goToAdminChat, isPending: isCreatingAdminChat } = useAdminChatMutation(); return ( -
+
-
- {menuItems - .filter(({ to }) => to !== 'manager' || myInfo.isClubManager || myInfo.role === 'ADMIN') - .map(({ to, icon: Icon, label }) => ( - -
-
- -
{label}
-
- -
- + +
+ 관리중인 동아리 +
+ {managedClubList.joinedClubs.map((club) => ( + ))} +
+
+
+ {menuItems.map(({ to, icon, label, state }) => ( + + + + ))}
-
-
- -
버전관리
-
-
- {window.APP_VERSION ? `v${window.APP_VERSION}` : '-'} -
-
+
-
diff --git a/src/utils/hooks/useSmartBack.ts b/src/utils/hooks/useSmartBack.ts index 315e8fdf..052bb3f9 100644 --- a/src/utils/hooks/useSmartBack.ts +++ b/src/utils/hooks/useSmartBack.ts @@ -61,7 +61,9 @@ export function useSmartBack() { const parts = pathname.split('/'); const clubId = parts[3]; - if (parts[4] === 'info') { + if (parts.length === 4) { + targetPath = '/mypage'; + } else if (parts[4] === 'info') { targetPath = `/mypage/manager/${clubId}`; } else if (parts[4] === 'recruitment' && parts[5]) { targetPath = `/mypage/manager/${clubId}/recruitment`; @@ -76,7 +78,7 @@ export function useSmartBack() { } else if (parts[4] === 'members') { targetPath = `/mypage/manager/${clubId}`; } else { - targetPath = `/mypage/manager`; + targetPath = '/mypage/manager'; } } else if (pathname === '/mypage/manager') { targetPath = '/mypage'; From 67191a084812436e59546afe1f5c1233a0eb6bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A4=80=EC=98=81?= Date: Wed, 15 Apr 2026 12:30:55 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=ED=97=A4=EB=8D=94=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout/Header/components/ProfileHeader.tsx | 15 --------------- src/components/layout/Header/headerConfig.ts | 7 ++----- src/components/layout/Header/index.tsx | 2 -- src/components/layout/Header/types.ts | 1 - 4 files changed, 2 insertions(+), 23 deletions(-) delete mode 100644 src/components/layout/Header/components/ProfileHeader.tsx diff --git a/src/components/layout/Header/components/ProfileHeader.tsx b/src/components/layout/Header/components/ProfileHeader.tsx deleted file mode 100644 index 10cdbcf8..00000000 --- a/src/components/layout/Header/components/ProfileHeader.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import type { Ref } from 'react'; -import NotificationBell from './NotificationBell'; - -function ProfileHeader({ headerRef }: { headerRef?: Ref }) { - return ( -
- -
- ); -} - -export default ProfileHeader; diff --git a/src/components/layout/Header/headerConfig.ts b/src/components/layout/Header/headerConfig.ts index ad2b0f17..60acfd1e 100644 --- a/src/components/layout/Header/headerConfig.ts +++ b/src/components/layout/Header/headerConfig.ts @@ -17,13 +17,10 @@ export const HEADER_CONFIGS: HeaderConfig[] = [ type: 'default', match: (pathname) => /^\/clubs\/\d+$/.test(pathname), }, - { - type: 'profile', - match: (pathname) => pathname === '/mypage', - }, { type: 'info', - match: (pathname) => pathname === '/home' || pathname === '/timer' || pathname === '/council', + match: (pathname) => + pathname === '/home' || pathname === '/timer' || pathname === '/council' || pathname === '/mypage', }, { type: 'chatList', diff --git a/src/components/layout/Header/index.tsx b/src/components/layout/Header/index.tsx index 2e12ba54..4af26900 100644 --- a/src/components/layout/Header/index.tsx +++ b/src/components/layout/Header/index.tsx @@ -6,7 +6,6 @@ import DefaultHeader from './components/DefaultHeader'; import InfoHeader from './components/InfoHeader'; import ManagerHeader from './components/ManagerHeader'; import PlainSubpageHeader from './components/PlainSubpageHeader'; -import ProfileHeader from './components/ProfileHeader'; import ScheduleHeader from './components/ScheduleHeader'; import SubpageHeader from './components/SubpageHeader'; import { getHeaderPresentation } from './presentation'; @@ -22,7 +21,6 @@ function Header({ headerRef }: HeaderProps) { const { title, type: headerType } = getHeaderPresentation(pathname); const HEADER_RENDERERS: Record = { - profile: ({ headerRef }) => , info: ({ headerRef }) => , chatList: ({ title, headerRef }) => , chat: ({ headerRef }) => , diff --git a/src/components/layout/Header/types.ts b/src/components/layout/Header/types.ts index 9a4a4fd5..9d219d9a 100644 --- a/src/components/layout/Header/types.ts +++ b/src/components/layout/Header/types.ts @@ -2,7 +2,6 @@ import type { ReactNode, Ref } from 'react'; export type HeaderType = | 'info' - | 'profile' | 'chat' | 'none' | 'notification' From 1c6ce51bcb0b535f12005073874645ec1eaac458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A4=80=EC=98=81?= Date: Wed, 15 Apr 2026 12:44:07 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20=EC=BB=A8=EB=B2=A4=EC=85=98=20?= =?UTF-8?q?=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Card.tsx | 5 ++--- src/pages/User/MyPage/index.tsx | 2 +- src/utils/hooks/useSmartBack.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/common/Card.tsx b/src/components/common/Card.tsx index c2fd067d..6c9e96e8 100644 --- a/src/components/common/Card.tsx +++ b/src/components/common/Card.tsx @@ -1,6 +1,5 @@ import type { HTMLAttributes, ReactNode } from 'react'; -import clsx from 'clsx'; -import { twMerge } from 'tailwind-merge'; +import { cn } from '@/utils/ts/cn'; interface CardProps extends HTMLAttributes { children: ReactNode; @@ -9,7 +8,7 @@ interface CardProps extends HTMLAttributes { function Card({ children, className, ...props }: CardProps) { return (
{children} diff --git a/src/pages/User/MyPage/index.tsx b/src/pages/User/MyPage/index.tsx index 8616d2fd..3867b5d7 100644 --- a/src/pages/User/MyPage/index.tsx +++ b/src/pages/User/MyPage/index.tsx @@ -9,9 +9,9 @@ import LayersIcon from '@/assets/svg/layers.svg'; import LogoutIcon from '@/assets/svg/logout.svg'; import UserSquareIcon from '@/assets/svg/user-square.svg'; import BottomModal from '@/components/common/BottomModal'; +import { MyPageActionRow, MyPageInfoRow, MyPageLinkRow } from '@/pages/User/MyPage/components/MyPageRows'; import useBooleanState from '@/utils/hooks/useBooleanState'; import { useAdminChatMutation } from '../hooks/useAdminChatMutation'; -import { MyPageActionRow, MyPageInfoRow, MyPageLinkRow } from './components/MyPageRows'; import UserInfoCard from './components/UserInfoCard'; import { useLogoutMutation } from './hooks/useLogout'; diff --git a/src/utils/hooks/useSmartBack.ts b/src/utils/hooks/useSmartBack.ts index 052bb3f9..5f1ae1ed 100644 --- a/src/utils/hooks/useSmartBack.ts +++ b/src/utils/hooks/useSmartBack.ts @@ -78,7 +78,7 @@ export function useSmartBack() { } else if (parts[4] === 'members') { targetPath = `/mypage/manager/${clubId}`; } else { - targetPath = '/mypage/manager'; + targetPath = '/mypage'; } } else if (pathname === '/mypage/manager') { targetPath = '/mypage';