diff --git a/src/assets/icons/nav/calendar.svg b/src/assets/icons/nav/calendar.svg deleted file mode 100644 index c9cfcda9..00000000 --- a/src/assets/icons/nav/calendar.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/assets/icons/nav/menu.svg b/src/assets/icons/nav/menu.svg deleted file mode 100644 index caba79e6..00000000 --- a/src/assets/icons/nav/menu.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/assets/icons/nav/store.svg b/src/assets/icons/nav/store.svg deleted file mode 100644 index fcd177d5..00000000 --- a/src/assets/icons/nav/store.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/assets/icons/nav/swap.svg b/src/assets/icons/nav/swap.svg deleted file mode 100644 index e55c1cb6..00000000 --- a/src/assets/icons/nav/swap.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/assets/icons/nav/users.svg b/src/assets/icons/nav/users.svg deleted file mode 100644 index aca6ec88..00000000 --- a/src/assets/icons/nav/users.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/assets/icons/nav/wallet.svg b/src/assets/icons/nav/wallet.svg deleted file mode 100644 index aff4f0ab..00000000 --- a/src/assets/icons/nav/wallet.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/assets/icons/nav/x.svg b/src/assets/icons/nav/x.svg deleted file mode 100644 index 7497a770..00000000 --- a/src/assets/icons/nav/x.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/features/user/home/applied-stores/hooks/useAppliedStoresViewModel.ts b/src/features/user/home/applied-stores/hooks/useAppliedStoresViewModel.ts index 0825255b..64c533e8 100644 --- a/src/features/user/home/applied-stores/hooks/useAppliedStoresViewModel.ts +++ b/src/features/user/home/applied-stores/hooks/useAppliedStoresViewModel.ts @@ -16,24 +16,30 @@ import { queryKeys } from '@/shared/lib/queryKeys' const PAGE_SIZE = 20 const FILTER_OPTIONS: { key: FilterType; label: string }[] = [ - { key: 'completed', label: '지원 완료' }, - { key: 'viewed', label: '열람' }, - { key: 'not_viewed', label: '미열람' }, - { key: 'cancelled', label: '지원 취소' }, + { key: 'all', label: '전체' }, + { key: 'submitted', label: '제출됨' }, + { key: 'accepted', label: '수락됨' }, + { key: 'rejected', label: '불합격됨' }, + { key: 'cancelled', label: '취소됨' }, ] const STATUS_SECTIONS: { key: ApplicationStatus; label: string }[] = [ { key: 'submitted', label: '제출됨' }, { key: 'accepted', label: '수락됨' }, + { key: 'rejected', label: '불합격됨' }, { key: 'cancelled', label: '취소됨' }, ] -function getCardStatus(status: ApplicationStatus): 'applied' | 'rejected' { - return status === 'cancelled' ? 'rejected' : 'applied' +function getCardStatus( + status: ApplicationStatus +): 'applied' | 'accepted' | 'rejected' | 'cancelled' { + if (status === 'accepted') return 'accepted' + if (status === 'rejected') return 'rejected' + if (status === 'cancelled') return 'cancelled' + return 'applied' } function getFilterLabel(filter: FilterType): string { - if (filter === 'all') return '전체' return FILTER_OPTIONS.find(o => o.key === filter)?.label ?? '전체' } @@ -110,6 +116,7 @@ export function useAppliedStoresViewModel() { } return { + selectedFilter, filterLabel: getFilterLabel(selectedFilter), isDropdownOpen, dropdownRef, diff --git a/src/features/user/home/applied-stores/types/application.ts b/src/features/user/home/applied-stores/types/application.ts index 1817dddb..386fc126 100644 --- a/src/features/user/home/applied-stores/types/application.ts +++ b/src/features/user/home/applied-stores/types/application.ts @@ -59,13 +59,13 @@ export interface ApplicationListQueryParams { status?: ApplicationApiStatus[] } -// ---- FilterType → API Status 매핑 ---- +// ---- FilterType → API Status 매핑 (mapApiStatusToUiStatus와 동일 기준) ---- export const FILTER_TO_API_STATUS: Record = { all: [], - not_viewed: ['SUBMITTED'], - viewed: ['SHORTLISTED', 'ACCEPTED', 'REJECTED'], - completed: ['ACCEPTED'], + submitted: ['SUBMITTED', 'SHORTLISTED'], + accepted: ['ACCEPTED'], + rejected: ['REJECTED'], cancelled: ['CANCELLED', 'EXPIRED', 'DELETED'], } @@ -121,9 +121,9 @@ function mapApiStatusToUiStatus( apiStatus: ApplicationApiStatus ): ApplicationStatus { if (apiStatus === 'ACCEPTED') return 'accepted' + if (apiStatus === 'REJECTED') return 'rejected' if ( apiStatus === 'CANCELLED' || - apiStatus === 'REJECTED' || apiStatus === 'EXPIRED' || apiStatus === 'DELETED' ) @@ -131,14 +131,6 @@ function mapApiStatusToUiStatus( return 'submitted' } -function mapApiStatusToFilterType(apiStatus: ApplicationApiStatus): FilterType { - if (apiStatus === 'SUBMITTED') return 'not_viewed' - if (apiStatus === 'SHORTLISTED') return 'viewed' - if (apiStatus === 'ACCEPTED') return 'completed' - if (apiStatus === 'REJECTED') return 'viewed' - return 'cancelled' -} - // ---- DTO → UI Model ---- export function adaptApplicationDto(dto: ApplicationDto): AppliedStoreData { const { postingSchedule, posting, description, status } = dto @@ -146,7 +138,6 @@ export function adaptApplicationDto(dto: ApplicationDto): AppliedStoreData { id: dto.id, storeName: posting.title, status: mapApiStatusToUiStatus(status.value), - filterType: mapApiStatusToFilterType(status.value), applicationDetail: { selectedWeekdays: parseWorkingDays(postingSchedule.workingDays), timeRangeLabel: formatTimeRange( diff --git a/src/features/user/home/applied-stores/types/appliedStore.ts b/src/features/user/home/applied-stores/types/appliedStore.ts index 6f979645..3c75643e 100644 --- a/src/features/user/home/applied-stores/types/appliedStore.ts +++ b/src/features/user/home/applied-stores/types/appliedStore.ts @@ -1,12 +1,11 @@ -export type ApplicationStatus = 'submitted' | 'accepted' | 'cancelled' - -export type FilterType = - | 'all' - | 'completed' - | 'viewed' - | 'not_viewed' +export type ApplicationStatus = + | 'submitted' + | 'accepted' + | 'rejected' | 'cancelled' +export type FilterType = 'all' | ApplicationStatus + export const WEEKDAY_LABELS = [ '월', '화', @@ -30,7 +29,6 @@ export interface AppliedStoreData { id: number storeName: string status: ApplicationStatus - filterType: FilterType thumbnailUrl?: string applicationDetail?: AppliedApplicationDetail } diff --git a/src/features/user/home/applied-stores/ui/AppliedStoreCard.tsx b/src/features/user/home/applied-stores/ui/AppliedStoreCard.tsx index 56648e4d..1683c2ae 100644 --- a/src/features/user/home/applied-stores/ui/AppliedStoreCard.tsx +++ b/src/features/user/home/applied-stores/ui/AppliedStoreCard.tsx @@ -1,8 +1,11 @@ -import { ApplicationStatusBadge } from '@/shared/ui/home/ApplicationStatusBadge' +import { + ApplicationStatusBadge, + type ApplicationStatusBadgeProps, +} from '@/shared/ui/home/ApplicationStatusBadge' interface AppliedStoreCardProps { storeName: string - status?: 'applied' | 'rejected' + status?: ApplicationStatusBadgeProps['status'] } export function AppliedStoreCard({ diff --git a/src/features/user/home/applied-stores/ui/AppliedStoreList.tsx b/src/features/user/home/applied-stores/ui/AppliedStoreList.tsx index a06f8ac3..b0610c84 100644 --- a/src/features/user/home/applied-stores/ui/AppliedStoreList.tsx +++ b/src/features/user/home/applied-stores/ui/AppliedStoreList.tsx @@ -1,10 +1,11 @@ import { MoreButton } from '@/shared/ui/common/MoreButton' import { AppliedStoreCard } from '@/features/user/home/applied-stores/ui/AppliedStoreCard' +import type { ApplicationStatusBadgeProps } from '@/shared/ui/home/ApplicationStatusBadge' interface AppliedStoreItem { id: number | string storeName: string - status: 'applied' | 'rejected' + status: ApplicationStatusBadgeProps['status'] } interface AppliedStoreListProps { diff --git a/src/features/user/home/applied-stores/ui/AppliedStoreListItem.tsx b/src/features/user/home/applied-stores/ui/AppliedStoreListItem.tsx index 133ffe66..8b1810d0 100644 --- a/src/features/user/home/applied-stores/ui/AppliedStoreListItem.tsx +++ b/src/features/user/home/applied-stores/ui/AppliedStoreListItem.tsx @@ -1,8 +1,11 @@ -import { ApplicationStatusBadge } from '@/shared/ui/home/ApplicationStatusBadge' +import { + ApplicationStatusBadge, + type ApplicationStatusBadgeProps, +} from '@/shared/ui/home/ApplicationStatusBadge' interface AppliedStoreListItemProps { storeName: string - status: 'applied' | 'rejected' + status: ApplicationStatusBadgeProps['status'] thumbnailUrl?: string onClick?: () => void } diff --git a/src/pages/manager/home/index.tsx b/src/pages/manager/home/index.tsx index 308bfc75..dd2f7b2f 100644 --- a/src/pages/manager/home/index.tsx +++ b/src/pages/manager/home/index.tsx @@ -61,7 +61,9 @@ export function ManagerHomePage() { return ( <>
- +
+ +
{isDropdownOpen && ( -
- {filterOptions.map((option, index) => ( - +
    + {filterOptions.map(option => ( +
  • + +
  • ))} -
+ )}
{isLoading ? ( -
-

로딩 중...

+
+
) : isError ? ( -
-

+

+

데이터를 불러오는 데 실패했습니다.

) : grouped.length === 0 ? ( -
-

+

+

지원 내역이 없습니다.

@@ -114,14 +124,12 @@ export function AppliedStoresPage() {
{shouldShowInfiniteListLoadMore(hasNextPage, totalCount) && ( - + /> )} )} diff --git a/src/pages/user/home/index.tsx b/src/pages/user/home/index.tsx index dc563d0d..dad19dd7 100644 --- a/src/pages/user/home/index.tsx +++ b/src/pages/user/home/index.tsx @@ -21,7 +21,7 @@ export function UserHomePage() { const { workspaces } = useWorkspacesViewModel() - const { grouped } = useAppliedStoresViewModel() + const { grouped, getCardStatus } = useAppliedStoresViewModel() const appliedStores = useMemo( () => @@ -31,9 +31,9 @@ export function UserHomePage() { .map(s => ({ id: s.id, storeName: s.storeName, - status: s.status === 'cancelled' ? 'rejected' : 'applied', + status: getCardStatus(s.status), })), - [grouped] + [grouped, getCardStatus] ) return ( diff --git a/src/shared/ui/common/HamburgerMenuDrawer.tsx b/src/shared/ui/common/HamburgerMenuDrawer.tsx deleted file mode 100644 index f84be070..00000000 --- a/src/shared/ui/common/HamburgerMenuDrawer.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { useEffect } from 'react' -import { createPortal } from 'react-dom' -import { useNavigate } from 'react-router-dom' -import StoreIcon from '@/assets/icons/nav/store.svg' -import UsersIcon from '@/assets/icons/nav/users.svg' -import CalendarIcon from '@/assets/icons/nav/calendar.svg' -import WalletIcon from '@/assets/icons/nav/wallet.svg' -import SwapIcon from '@/assets/icons/nav/swap.svg' -import CloseXIcon from '@/assets/icons/nav/x.svg' -import { cn } from '@/shared/lib/utils' -import { ROUTES } from '@/shared/constants/routes' -import useAuthStore from '@/shared/stores/useAuthStore' - -export interface HamburgerMenuDrawerProps { - open: boolean - onClose: () => void -} - -type MenuRow = { - label: string - icon: string - path: string -} - -const MANAGER_ITEMS: MenuRow[] = [ - { label: '업장 관리', icon: StoreIcon, path: ROUTES.USER.WORKSPACE }, - { label: '직원 관리', icon: UsersIcon, path: ROUTES.MANAGER.HOME }, - { - label: '근무 일정 관리', - icon: CalendarIcon, - path: ROUTES.MANAGER.WORKER_SCHEDULE, - }, - { label: '급여 관리', icon: WalletIcon, path: ROUTES.MY.ROOT }, -] - -const USER_ITEMS: MenuRow[] = [ - { label: '내 근무 일정', icon: CalendarIcon, path: ROUTES.USER.SCHEDULE }, - { label: '급여 확인', icon: WalletIcon, path: ROUTES.MY.ROOT }, - { label: '대타 요청', icon: SwapIcon, path: ROUTES.USER.SUBSTITUTE_REQUEST }, -] - -function MenuList({ - items, - accentClass, - onNavigate, -}: { - items: MenuRow[] - accentClass: string - onNavigate: (path: string) => void -}) { - return ( -
    - {items.map(row => ( -
  • - -
  • - ))} -
- ) -} - -export function HamburgerMenuDrawer({ - open, - onClose, -}: HamburgerMenuDrawerProps) { - const navigate = useNavigate() - const scope = useAuthStore(s => s.scope) - - useEffect(() => { - if (!open) { - return - } - const onKeyDown = (e: KeyboardEvent) => { - if (e.key === 'Escape') { - onClose() - } - } - const prevOverflow = document.body.style.overflow - document.body.style.overflow = 'hidden' - document.addEventListener('keydown', onKeyDown) - return () => { - document.body.style.overflow = prevOverflow - document.removeEventListener('keydown', onKeyDown) - } - }, [open, onClose]) - - if (!open || typeof document === 'undefined') { - return null - } - - const handleNavigate = (path: string) => { - navigate(path) - onClose() - } - - const isManager = scope === 'MANAGER' - const isUser = scope === 'USER' || scope === null - - return createPortal( -
- -
- -
- {isManager && ( -
-

- 사장님 -

- -
- )} - - {isUser && !isManager && ( -
-

- 알바생 -

- -
- )} -
- -
, - document.body - ) -} diff --git a/src/shared/ui/common/Navbar.tsx b/src/shared/ui/common/Navbar.tsx index c4d18bce..b3f67974 100644 --- a/src/shared/ui/common/Navbar.tsx +++ b/src/shared/ui/common/Navbar.tsx @@ -1,10 +1,8 @@ -import { useState, type ReactNode } from 'react' +import type { ReactNode } from 'react' import { AlterLogo } from '@/shared/ui/common/AlterLogo' import BellIcon from '@/assets/icons/nav/bell.svg' -import MenuIcon from '@/assets/icons/nav/menu.svg' import ChevronLeftIcon from '@/assets/icons/nav/chevron-left.svg' import { useNavigate } from 'react-router-dom' -import { HamburgerMenuDrawer } from '@/shared/ui/common/HamburgerMenuDrawer' import { cn } from '@/shared/lib/utils' type NavbarVariant = 'main' | 'detail' @@ -33,7 +31,6 @@ export function Navbar({ onNotificationClick, }: NavbarProps) { const navigate = useNavigate() - const [menuOpen, setMenuOpen] = useState(false) const isMain = variant === 'main' const handleBackClick = () => { @@ -45,70 +42,55 @@ export function Navbar({ } return ( - <> -
+
+ {isMain ? ( +
+ + 알터 +
+ ) : ( + )} - > -
- {isMain ? ( -
- - 알터 -
- ) : ( - - )} -
+
-
- {!isMain && ( - - {title} - - )} -
+
+ {!isMain && ( + + {title} + + )} +
-
- {isMain ? ( - <> - - - - ) : ( - rightAction - )} -
-
- setMenuOpen(false)} /> - +
+ {isMain ? ( + + ) : ( + rightAction + )} +
+ ) } diff --git a/src/shared/ui/home/ApplicationStatusBadge.tsx b/src/shared/ui/home/ApplicationStatusBadge.tsx index 665bfef5..363fe310 100644 --- a/src/shared/ui/home/ApplicationStatusBadge.tsx +++ b/src/shared/ui/home/ApplicationStatusBadge.tsx @@ -1,5 +1,5 @@ interface ApplicationStatusBadgeProps { - status: 'applied' | 'rejected' + status: 'applied' | 'accepted' | 'rejected' | 'cancelled' className?: string } @@ -9,11 +9,21 @@ const BADGE_STYLE_MAP = { containerClassName: 'bg-white border border-line-1', textClassName: 'text-text-50', }, + accepted: { + label: '합격', + containerClassName: 'bg-main border border-main', + textClassName: 'text-white', + }, rejected: { label: '불합격', containerClassName: 'bg-error border border-error', textClassName: 'text-white', }, + cancelled: { + label: '취소됨', + containerClassName: 'bg-white border border-line-2', + textClassName: 'text-text-50', + }, } as const export function ApplicationStatusBadge({