diff --git a/src/components/layout/AppLayout.module.css b/src/components/layout/AppLayout.module.css
index 52d2021..5d1a894 100644
--- a/src/components/layout/AppLayout.module.css
+++ b/src/components/layout/AppLayout.module.css
@@ -178,6 +178,22 @@
overflow-y: auto;
}
+.contentDashboard {
+ padding-top: 18px;
+}
+
+.contentWorkInbox {
+ padding-bottom: 0;
+ overflow: hidden;
+}
+
+@media (max-width: 1180px) {
+ .contentWorkInbox {
+ padding-bottom: 32px;
+ overflow-y: auto;
+ }
+}
+
@media (max-width: 768px) {
.topBar {
padding: 12px 16px;
@@ -189,4 +205,12 @@
padding: 16px;
overflow-y: visible;
}
+
+ .contentWorkInbox {
+ padding-bottom: 16px;
+ }
+
+ .contentDashboard {
+ padding-top: 16px;
+ }
}
diff --git a/src/components/layout/AppLayout.test.tsx b/src/components/layout/AppLayout.test.tsx
index 502fcea..d17708d 100644
--- a/src/components/layout/AppLayout.test.tsx
+++ b/src/components/layout/AppLayout.test.tsx
@@ -35,7 +35,7 @@ afterEach(() => {
})
describe('AppLayout', () => {
- it('renders the FOWOCO logo and every nav item', () => {
+ it('renders the current global navigation without a workers tab', () => {
localStorage.setItem('fowoco.onboarding.completed', 'true')
renderLayout()
@@ -43,6 +43,7 @@ describe('AppLayout', () => {
for (const item of NAV_ITEMS) {
expect(screen.getByRole('link', { name: item.label })).toBeInTheDocument()
}
+ expect(screen.queryByRole('link', { name: '근로자' })).not.toBeInTheDocument()
})
it('opens and closes the help modal', async () => {
diff --git a/src/components/layout/AppLayout.tsx b/src/components/layout/AppLayout.tsx
index 3fd9957..9e9dabc 100644
--- a/src/components/layout/AppLayout.tsx
+++ b/src/components/layout/AppLayout.tsx
@@ -18,6 +18,8 @@ export function AppLayout() {
const [helpOpen, setHelpOpen] = useState(false)
const [tourOpen, setTourOpen] = useState(false)
const isTaskDetail = /^\/tasks\/[^/]+$/.test(location.pathname)
+ const isWorkInbox = location.pathname === '/tasks'
+ const isDashboard = location.pathname === '/dashboard'
useEffect(() => {
if (!hasCompletedOnboarding()) setTourOpen(true)
@@ -78,7 +80,11 @@ export function AppLayout() {
-
+
diff --git a/src/components/layout/navItems.ts b/src/components/layout/navItems.ts
index c48ece5..c6c56fa 100644
--- a/src/components/layout/navItems.ts
+++ b/src/components/layout/navItems.ts
@@ -2,7 +2,6 @@ import documentsIcon from './nav-icons/documents.svg'
import settingsIcon from './nav-icons/settings.svg'
import todayIcon from './nav-icons/today.svg'
import workIcon from './nav-icons/work.svg'
-import workersIcon from './nav-icons/workers.svg'
export interface NavItem {
label: string
@@ -10,13 +9,12 @@ export interface NavItem {
iconSrc: string
}
-// Figma PWF v3 사이드바(Aside - SideNavBar, 05_Desktop Core Product 전 화면 공통)는 5개 메뉴만
-// 정의한다. Agent/티켓 메뉴는 Figma에 없는 화면이라(#206) 링크만 제거하고 라우트는 유지한다.
+// 공용 사이드바에는 주요 운영 진입점만 노출한다. 근로자 기능은 업무·문서 흐름에서
+// 컨텍스트로 진입하므로 전역 탭에서는 제외하고, 딥링크와 관련 라우트는 유지한다.
// SettingsPage는 제거되어 "설정" 메뉴는 내 프로필 페이지로 연결된다.
export const NAV_ITEMS: NavItem[] = [
{ label: 'Today', to: '/dashboard', iconSrc: todayIcon },
{ label: '업무함', to: '/tasks', iconSrc: workIcon },
- { label: '근로자', to: '/workers', iconSrc: workersIcon },
{ label: '문서함', to: '/documents', iconSrc: documentsIcon },
{ label: '설정', to: '/profile', iconSrc: settingsIcon },
]
diff --git a/src/components/ui/SearchInput/SearchInput.module.css b/src/components/ui/SearchInput/SearchInput.module.css
index 434632f..7104eb1 100644
--- a/src/components/ui/SearchInput/SearchInput.module.css
+++ b/src/components/ui/SearchInput/SearchInput.module.css
@@ -1,15 +1,42 @@
-.search {
+.field {
+ display: flex;
+ align-items: center;
+ gap: 7px;
flex: 1 1 240px;
max-width: 520px;
height: 48px;
padding: 0 var(--fowoco-spacing-16);
- font-size: 14px;
- font-family: inherit;
+ overflow: hidden;
+ background: var(--surface-default);
border: 1px solid var(--border-default);
border-radius: var(--fowoco-radius-6);
}
-.search:focus-visible {
+.field:focus-within {
outline: 2px solid var(--brand-primary);
outline-offset: 2px;
}
+
+.icon {
+ flex: 0 0 16px;
+ width: 16px;
+ height: 16px;
+}
+
+.search {
+ min-width: 0;
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ background: transparent;
+ border: 0;
+ outline: 0;
+ font-family: inherit;
+ font-size: 14px;
+ color: var(--text-primary);
+}
+
+.search::placeholder {
+ color: var(--text-secondary);
+ opacity: 1;
+}
diff --git a/src/components/ui/SearchInput/SearchInput.tsx b/src/components/ui/SearchInput/SearchInput.tsx
index e7162aa..d619e42 100644
--- a/src/components/ui/SearchInput/SearchInput.tsx
+++ b/src/components/ui/SearchInput/SearchInput.tsx
@@ -1,4 +1,5 @@
import type { ChangeEvent } from 'react'
+import searchIcon from './search.svg'
import styles from './SearchInput.module.css'
export interface SearchInputProps {
@@ -21,12 +22,15 @@ export function SearchInput({
}
return (
-
+
)
}
diff --git a/src/components/ui/SearchInput/search.svg b/src/components/ui/SearchInput/search.svg
new file mode 100644
index 0000000..5cdb1c6
--- /dev/null
+++ b/src/components/ui/SearchInput/search.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/ui/WorkItemRow/WorkItemRow.module.css b/src/components/ui/WorkItemRow/WorkItemRow.module.css
index 0a54620..38ba993 100644
--- a/src/components/ui/WorkItemRow/WorkItemRow.module.css
+++ b/src/components/ui/WorkItemRow/WorkItemRow.module.css
@@ -2,7 +2,9 @@
display: flex;
align-items: center;
gap: var(--fowoco-spacing-16);
- padding: var(--fowoco-spacing-16) var(--fowoco-spacing-20);
+ width: 100%;
+ min-height: 56px;
+ padding: 8px var(--fowoco-spacing-20);
background: var(--surface-default);
border: 1px solid var(--border-default);
border-radius: var(--fowoco-radius-8);
@@ -36,7 +38,7 @@
.rail {
flex-shrink: 0;
width: 4px;
- height: 44px;
+ height: 40px;
border-radius: var(--fowoco-radius-4);
background: var(--status-warning);
}
@@ -45,6 +47,10 @@
background: var(--status-critical);
}
+.railInfo {
+ background: #3976d3;
+}
+
.railNeutral {
background: var(--border-default);
}
@@ -53,8 +59,8 @@
flex: 1;
min-width: 0;
display: flex;
- flex-direction: column;
- gap: var(--fowoco-spacing-4);
+ align-items: center;
+ gap: 12px;
}
.title {
@@ -62,6 +68,48 @@
font-size: 14px;
font-weight: 500;
color: var(--text-primary);
+ white-space: nowrap;
+}
+
+.inlineMeta {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+}
+
+.status {
+ display: inline-flex;
+ align-items: center;
+ min-height: 26px;
+ padding: 4px 8px;
+ border-radius: var(--fowoco-radius-999);
+ font-size: 12px;
+ font-weight: 500;
+ line-height: 18px;
+ white-space: nowrap;
+}
+
+.statusWarning {
+ color: var(--status-warning);
+ background: var(--fowoco-amber-50);
+}
+
+.statusPrimary {
+ color: var(--brand-primary);
+ background: var(--fowoco-teal-50);
+}
+
+.statusNeutral {
+ color: var(--text-secondary);
+ background: var(--surface-subtle);
+}
+
+.detailItem {
+ font-size: 12px;
+ line-height: 18px;
+ color: var(--text-secondary);
+ white-space: nowrap;
}
.meta {
@@ -72,8 +120,35 @@
.next {
flex-shrink: 0;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 120px;
+ height: 40px;
+ padding: 8px 16px;
+ border: 1px solid var(--border-default);
+ border-radius: var(--fowoco-radius-6);
font-family: var(--font-sans);
- font-size: 13px;
+ font-size: 14px;
font-weight: 500;
- color: var(--brand-primary);
+ color: var(--text-primary);
+ background: var(--surface-default);
+}
+
+@media (max-width: 720px) {
+ .content {
+ flex: 1 1 calc(100% - 20px);
+ align-items: flex-start;
+ flex-direction: column;
+ gap: 4px;
+ }
+
+ .inlineMeta {
+ flex-wrap: wrap;
+ }
+
+ .next {
+ flex-basis: auto;
+ width: 100%;
+ }
}
diff --git a/src/components/ui/WorkItemRow/WorkItemRow.tsx b/src/components/ui/WorkItemRow/WorkItemRow.tsx
index ba56a8e..1505b31 100644
--- a/src/components/ui/WorkItemRow/WorkItemRow.tsx
+++ b/src/components/ui/WorkItemRow/WorkItemRow.tsx
@@ -1,16 +1,28 @@
import styles from './WorkItemRow.module.css'
-export type WorkItemUrgency = 'warning' | 'critical' | 'neutral'
+export type WorkItemUrgency = 'warning' | 'critical' | 'info' | 'neutral'
const RAIL_CLASS: Record = {
warning: '',
critical: styles.railCritical,
+ info: styles.railInfo,
neutral: styles.railNeutral,
}
+export type WorkItemStatusTone = 'warning' | 'primary' | 'neutral'
+
+const STATUS_CLASS: Record = {
+ warning: styles.statusWarning,
+ primary: styles.statusPrimary,
+ neutral: styles.statusNeutral,
+}
+
export interface WorkItemRowProps {
title: string
- meta: string
+ meta?: string
+ statusLabel?: string
+ statusTone?: WorkItemStatusTone
+ detailItems?: string[]
nextAction: string
urgency?: WorkItemUrgency
onClick?: () => void
@@ -19,6 +31,9 @@ export interface WorkItemRowProps {
export function WorkItemRow({
title,
meta,
+ statusLabel,
+ statusTone = 'neutral',
+ detailItems = [],
nextAction,
urgency = 'warning',
onClick,
@@ -28,7 +43,22 @@ export function WorkItemRow({
{title}
- {meta}
+ {statusLabel || detailItems.length > 0 ? (
+
+ {statusLabel && (
+
+ {statusLabel}
+
+ )}
+ {detailItems.map((item) => (
+
+ {item}
+
+ ))}
+
+ ) : (
+ {meta}
+ )}
{nextAction}
diff --git a/src/pages/DashboardPage/DashboardPage.module.css b/src/pages/DashboardPage/DashboardPage.module.css
index cd61077..cddaebd 100644
--- a/src/pages/DashboardPage/DashboardPage.module.css
+++ b/src/pages/DashboardPage/DashboardPage.module.css
@@ -1,339 +1,574 @@
-.stateWrap {
- margin-top: 24px;
+.page {
+ width: 100%;
+ min-width: 0;
+ font-family: var(--font-sans);
+}
+
+.pageHeader {
+ margin-left: 5px;
}
.headline {
margin: 0;
font-size: 28px;
font-weight: 700;
+ line-height: 36px;
color: var(--text-primary);
}
.description {
- margin: 8px 0 0;
+ margin: 0;
font-size: 14px;
+ line-height: 22px;
color: var(--text-secondary);
}
-.commandBox {
- margin-top: 24px;
- padding: 19px;
- background: var(--fowoco-teal-50);
- border: 1px solid var(--border-default);
+.agentRequest {
+ height: 144px;
+ margin-top: 19px;
+ padding: 13px 13px 12px;
+ overflow: hidden;
+ background: #f4faf9;
+ border: 1px solid #95cecb;
border-radius: var(--fowoco-radius-8);
}
-.commandBoxHeader {
+.agentRequestTitle {
display: flex;
align-items: center;
- justify-content: space-between;
- margin-bottom: 12px;
+ gap: 5px;
+ height: 22px;
}
-.commandBoxTitle {
- font-size: 13px;
- font-weight: 700;
- color: var(--brand-primary);
+.agentRequestTitle img,
+.agentPreparedTitle img {
+ flex: 0 0 auto;
+ width: 20px;
+ height: 20px;
}
-.commandBoxChevron {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 24px;
- height: 24px;
+.agentRequestTitle h2 {
+ margin: 0;
+ font-size: 12px;
+ font-weight: 700;
+ line-height: 21px;
color: var(--brand-primary);
}
.commandInput {
display: flex;
align-items: center;
- width: 100%;
- padding: 15px 19px;
- background: var(--surface-default);
- border: 1px solid var(--border-default);
- border-radius: var(--fowoco-radius-8);
+ justify-content: space-between;
+ width: calc(100% - 37px);
+ height: 40px;
+ margin: 6px 18px 0;
+ padding: 3px 13px;
+ overflow: hidden;
+ background: rgba(207, 227, 227, 0.7);
+ border: 0;
+ border-radius: 21px;
font-family: inherit;
+ font-size: 13px;
+ font-weight: 500;
+ line-height: 22px;
+ color: #465b5d;
+ text-align: left;
cursor: pointer;
}
-.commandPlaceholder {
- font-size: 14px;
- color: var(--text-secondary);
+.commandInput span {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.commandInput img {
+ flex: 0 0 auto;
+ width: 18px;
+ height: 18px;
}
.promptChips {
display: flex;
- flex-wrap: wrap;
- gap: 8px;
- margin-top: 12px;
+ align-items: center;
+ gap: 10px;
+ margin: 6px 25px 0;
}
.promptChip {
- padding: 7px 14px;
- background: var(--surface-default);
- border: none;
- border-radius: var(--fowoco-radius-999);
- font-size: 12px;
- font-weight: 500;
- color: var(--brand-primary);
+ height: 24px;
+ padding: 2px 5px;
+ background: var(--surface-subtle);
+ border: 0;
+ border-radius: var(--fowoco-radius-8);
+ font-family: inherit;
+ font-size: 11px;
+ font-weight: 400;
+ line-height: 20px;
+ color: var(--text-secondary);
+ white-space: nowrap;
cursor: pointer;
}
-.metricStrip {
+.dashboardGrid {
display: grid;
- grid-template-columns: repeat(4, 1fr);
- gap: 16px;
+ grid-template-columns: minmax(0, 767px) minmax(0, 359px);
+ gap: 26px;
margin-top: 16px;
}
-@media (max-width: 720px) {
- .metricStrip {
- grid-template-columns: repeat(2, 1fr);
- }
+.primaryColumn {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ min-width: 0;
+}
+
+.metricStrip {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 30px;
+ height: 72px;
}
.metricCard {
display: flex;
- flex-direction: column;
- gap: 8px;
- padding: 16px 19px;
+ align-items: center;
+ justify-content: space-between;
+ min-width: 0;
+ height: 72px;
+ padding: 16px;
background: var(--surface-default);
border: 1px solid var(--border-default);
border-radius: var(--fowoco-radius-8);
+ font-family: inherit;
text-align: left;
cursor: pointer;
}
+.metricText {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ height: 40px;
+ white-space: nowrap;
+}
+
.metricLabel {
font-size: 12px;
+ font-weight: 500;
+ line-height: 18px;
color: var(--text-secondary);
}
-.metricValueRow {
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
-
.metricValue {
- font-size: 20px;
+ font-size: 16px;
font-weight: 700;
+ line-height: 22px;
color: var(--text-primary);
}
.metricIcon {
- width: 20px;
- height: 20px;
- color: var(--brand-primary);
+ display: flex;
+ flex: 0 0 32px;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ border-radius: var(--fowoco-radius-8);
}
-.mainGrid {
- display: grid;
- grid-template-columns: 1fr 340px;
- gap: 16px;
- margin-top: 40px;
- align-items: start;
+.metricIcon img {
+ width: 18px;
+ height: 18px;
}
-@media (max-width: 960px) {
- .mainGrid {
- grid-template-columns: 1fr;
- }
+.metricIcon_warning {
+ background: var(--fowoco-amber-50);
+}
- .commandInput {
- flex-direction: column;
- align-items: flex-start;
- gap: 8px;
- }
+.metricIcon_info {
+ background: var(--surface-subtle);
}
-.mainColumn {
- display: flex;
- flex-direction: column;
- gap: 0;
+.metricIcon_critical {
+ background: var(--fowoco-red-50);
}
-.topApprovalCard {
- padding: 19px;
+.metricIcon_success {
+ background: var(--fowoco-green-50);
+}
+
+.priorityApproval {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 183px;
+ padding: 15px 24px;
background: var(--surface-default);
- border: 1px solid var(--border-default);
+ border: 1px solid var(--status-warning);
border-radius: var(--fowoco-radius-8);
+ box-shadow: 0 2px 8px rgba(23, 43, 46, 0.08);
}
-.topApprovalHeader {
+.priorityHeader {
display: flex;
- align-items: baseline;
+ align-items: center;
justify-content: space-between;
+ height: 26px;
+ padding: 0 10px;
}
-.topApprovalItem {
+.priorityHeader h2 {
+ margin: 0;
+ font-size: 18px;
+ font-weight: 700;
+ line-height: 26px;
+ color: var(--text-primary);
+}
+
+.priorityHeader span {
+ font-size: 11px;
+ line-height: 18px;
+ color: #bbc3c4;
+ white-space: nowrap;
+}
+
+.priorityBody {
display: flex;
align-items: center;
- justify-content: space-between;
- gap: 16px;
- width: 100%;
- margin-top: 16px;
- padding: 15px 19px;
- background: var(--surface-subtle);
- border: none;
- border-radius: var(--fowoco-radius-8);
- text-align: left;
- cursor: pointer;
+ gap: 25px;
+ margin-top: 15px;
}
-.topApprovalContent {
+.priorityContent {
display: flex;
+ flex: 1;
+ min-width: 0;
flex-direction: column;
- gap: 4px;
+ gap: 5px;
}
-.topApprovalTitle {
- font-size: 14px;
- font-weight: 700;
- color: var(--text-primary);
+.priorityCopy {
+ display: flex;
+ min-height: 70px;
+ flex-direction: column;
+ justify-content: center;
+ padding: 8px 15px;
+ background: var(--surface-default);
+ border: 1px solid var(--border-default);
+ border-radius: var(--fowoco-radius-6);
+ white-space: nowrap;
}
-.topApprovalMeta {
+.priorityCopy strong {
+ margin-bottom: -3px;
+ overflow: hidden;
font-size: 12px;
+ font-weight: 500;
+ line-height: 22px;
+ color: var(--text-primary);
+ text-overflow: ellipsis;
+}
+
+.priorityCopy span {
+ overflow: hidden;
+ font-size: 8px;
+ font-weight: 400;
+ line-height: 20px;
color: var(--text-secondary);
+ text-overflow: ellipsis;
}
-.topApprovalNote {
+.priorityContent > button {
+ width: 100%;
+ height: 32px;
+ padding: 5px 16px;
+ background: var(--surface-default);
+ border: 1px solid var(--border-default);
+ border-radius: var(--fowoco-radius-6);
+ font-family: inherit;
font-size: 12px;
- color: var(--text-secondary);
+ font-weight: 500;
+ line-height: 20px;
+ color: var(--text-primary);
+ cursor: pointer;
}
-.topApprovalChevron {
- flex-shrink: 0;
- font-size: 20px;
+.priorityNext {
+ display: flex;
+ flex: 0 0 40px;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ padding: 0 0 3px;
+ background: var(--surface-default);
+ border: 1px solid var(--border-default);
+ border-radius: var(--fowoco-radius-6);
+ font-family: inherit;
+ font-size: 28px;
+ font-weight: 400;
+ line-height: 1;
color: var(--text-secondary);
+ cursor: pointer;
}
-.topApprovalAction {
- width: 100%;
- margin-top: 12px;
- height: 44px;
- background: var(--text-primary);
- border: none;
- border-radius: var(--fowoco-radius-8);
- font-size: 14px;
- font-weight: 500;
- color: var(--fowoco-white);
- cursor: pointer;
+.todayTasks {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ min-width: 0;
}
.sectionHeader {
display: flex;
- align-items: baseline;
+ align-items: center;
justify-content: space-between;
- margin-top: 32px;
+ width: calc(100% - 13px);
+ min-height: 26px;
+ margin: 0 auto;
}
-.sectionTitle {
+.sectionHeader h2 {
margin: 0;
font-size: 18px;
font-weight: 700;
+ line-height: 26px;
color: var(--text-primary);
}
-.sectionNote {
+.sectionHeader p {
margin: 0;
font-size: 12px;
+ line-height: 20px;
color: var(--text-secondary);
}
.workItemList {
display: flex;
flex-direction: column;
- gap: 16px;
- margin-top: 16px;
- max-height: 480px;
- overflow-y: auto;
+ gap: 8px;
}
-.agentPanel {
- padding: 19px;
+.agentPrepared {
+ display: flex;
+ height: 539px;
+ min-width: 0;
+ flex-direction: column;
+ gap: 15px;
+ padding: 16px;
+ overflow: hidden;
background: var(--fowoco-teal-50);
- border: 1px solid var(--border-default);
+ border: 1px solid rgba(7, 132, 127, 0.7);
border-radius: var(--fowoco-radius-8);
}
-.agentPanelTitle {
+.agentPreparedTitle {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ height: 26px;
+}
+
+.agentPreparedTitle h2 {
margin: 0;
- font-size: 13px;
+ font-size: 16px;
font-weight: 700;
+ line-height: 24px;
color: var(--brand-primary);
+ white-space: nowrap;
}
-.agentPanelSummary {
- margin: 12px 0 0;
- font-size: 13px;
- font-weight: 700;
- color: var(--text-primary);
+.preparedIntro {
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+ line-height: 18px;
}
-.agentPanelNote {
- margin: 6px 0 0;
+.preparedIntro strong {
font-size: 12px;
- line-height: 18px;
- color: var(--text-secondary);
+ font-weight: 500;
+ color: var(--text-primary);
}
-.agentGroupLabel {
- margin: 20px 0 0;
- font-size: 12px;
- font-weight: 700;
+.preparedIntro p {
+ margin: 0;
+ font-size: 11px;
color: var(--text-secondary);
}
-.agentGroupLabelWarning {
- margin: 0 0 8px;
+.preparedSections {
+ display: flex;
+ min-height: 0;
+ flex: 1;
+ flex-direction: column;
+ gap: 18px;
+ overflow-y: auto;
+ scrollbar-width: thin;
+}
+
+.preparedSection {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.preparedSection h3 {
+ margin: 0;
font-size: 12px;
- font-weight: 700;
- color: var(--fowoco-amber-600);
+ font-weight: 500;
+ line-height: normal;
+ color: var(--text-primary);
}
-.agentReadyList {
+.preparedSection ul {
display: flex;
flex-direction: column;
gap: 8px;
- margin: 10px 0 0;
+ margin: 0;
padding: 0;
- max-height: 220px;
- overflow-y: auto;
list-style: none;
}
-.agentReadyItem {
- font-size: 12px;
+.preparedSection li {
+ display: grid;
+ grid-template-columns: 16px minmax(0, 1fr);
+ column-gap: 8px;
+ align-items: center;
+ min-height: 20px;
+ font-size: 13px;
+ line-height: 20px;
color: var(--text-primary);
}
-.agentNeedsInfoBox {
- margin-top: 16px;
- padding: 15px;
- background: var(--fowoco-amber-50);
- border-radius: var(--fowoco-radius-8);
+.preparedSection li strong {
+ font-weight: 500;
}
-.agentPendingItem {
- margin-top: 12px;
+.doneMark,
+.reviewMark,
+.nextMark {
+ align-self: start;
+ width: 16px;
+ font-size: 13px;
+ font-weight: 700;
+ line-height: 20px;
}
-.agentNeedsInfoBox .agentPendingItem:first-of-type {
- margin-top: 0;
+.doneMark {
+ color: var(--fowoco-green-600);
}
-.agentPendingLabel {
- margin: 0;
- font-size: 12px;
- font-weight: 700;
- color: var(--text-primary);
+.reviewMark {
+ color: var(--status-warning);
}
-.agentPendingNote {
- margin: 4px 0 0;
+.nextMark {
+ color: #3976d3;
+}
+
+.reviewSection {
+ padding: 12px;
+ background: var(--fowoco-amber-50);
+ border: 1px solid var(--status-warning);
+ border-radius: var(--fowoco-radius-6);
+}
+
+.reviewSection h3 {
+ color: var(--status-warning);
+}
+
+.describedItem p {
+ grid-column: 1 / -1;
+ margin: 0;
font-size: 11px;
+ font-weight: 400;
+ line-height: normal;
color: var(--text-secondary);
}
+
+.stateWrap {
+ margin-top: 16px;
+}
+
+@media (max-width: 1260px) {
+ .dashboardGrid {
+ grid-template-columns: minmax(0, 2fr) minmax(290px, 1fr);
+ }
+
+ .metricStrip {
+ gap: 12px;
+ }
+
+ .priorityBody {
+ gap: 12px;
+ }
+}
+
+@media (max-width: 1080px) {
+ .dashboardGrid {
+ grid-template-columns: 1fr;
+ }
+
+ .agentPrepared {
+ height: auto;
+ max-height: 539px;
+ }
+}
+
+@media (max-width: 760px) {
+ .headline {
+ font-size: 22px;
+ line-height: 30px;
+ }
+
+ .description {
+ margin-top: 4px;
+ }
+
+ .agentRequest {
+ height: auto;
+ min-height: 144px;
+ }
+
+ .commandInput {
+ width: 100%;
+ margin-right: 0;
+ margin-left: 0;
+ }
+
+ .promptChips {
+ flex-wrap: wrap;
+ margin-right: 0;
+ margin-left: 0;
+ }
+
+ .metricStrip {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ height: auto;
+ }
+
+ .priorityApproval {
+ height: auto;
+ }
+
+ .priorityHeader {
+ height: auto;
+ padding: 0;
+ }
+
+ .priorityHeader h2 {
+ font-size: 16px;
+ }
+
+ .priorityBody {
+ align-items: stretch;
+ flex-direction: column;
+ }
+
+ .priorityNext {
+ width: 100%;
+ }
+}
diff --git a/src/pages/DashboardPage/DashboardPage.test.tsx b/src/pages/DashboardPage/DashboardPage.test.tsx
index 3d386c8..d1b8638 100644
--- a/src/pages/DashboardPage/DashboardPage.test.tsx
+++ b/src/pages/DashboardPage/DashboardPage.test.tsx
@@ -3,50 +3,48 @@ import userEvent from '@testing-library/user-event'
import { MemoryRouter, Route, Routes } from 'react-router-dom'
import { describe, expect, it } from 'vitest'
import { DashboardPage } from './DashboardPage'
+import styles from './DashboardPage.module.css'
import {
AGENT_PREPARED,
AI_REQUEST_PROMPT_CHIPS,
+ APPROVAL_QUEUE,
METRIC_STRIP,
TODAY_WORK_ITEMS,
- TOP_APPROVAL,
} from './dashboardData'
function renderPage(demoState = 'success') {
- render(
+ return render(
} />
업무 생성 페이지
} />
- 업무함} />
- 업무 상세} />
,
)
}
describe('DashboardPage', () => {
- it('renders the pending-approval headline', () => {
+ it('renders the blocking approval headline from the HOME-001 structure', () => {
renderPage()
- const pendingApproval = METRIC_STRIP.find((metric) => metric.id === 'pending-approval')
expect(
- screen.getByText(`지금 확인이 필요한 승인 ${pendingApproval?.value}건이 있습니다.`),
+ screen.getByRole('heading', {
+ name: `지금 확인이 필요한 승인 ${APPROVAL_QUEUE.blockingCount}건이 있습니다.`,
+ }),
).toBeInTheDocument()
})
- it('renders the top approval card and navigates to its task on click', async () => {
- const user = userEvent.setup()
+ it('renders every work item row', () => {
renderPage()
-
- expect(screen.getByText(TOP_APPROVAL.title)).toBeInTheDocument()
- await user.click(screen.getByRole('button', { name: TOP_APPROVAL.actionLabel }))
-
- expect(await screen.findByText('업무 상세')).toBeInTheDocument()
+ for (const item of TODAY_WORK_ITEMS) {
+ expect(screen.getByText(item.title)).toBeInTheDocument()
+ }
})
- it('renders every work item row', () => {
+ it('renders the Figma status label and next action for every priority work item', () => {
renderPage()
for (const item of TODAY_WORK_ITEMS) {
- expect(screen.getByText(item.title)).toBeInTheDocument()
+ expect(screen.getByText(item.status)).toBeInTheDocument()
+ expect(screen.getAllByText(item.nextAction).length).toBeGreaterThan(0)
}
})
@@ -74,26 +72,21 @@ describe('DashboardPage', () => {
}
})
- it('renders the agent-prepared panel with ready, needs-info, and after-approval groups', () => {
+ it('renders every Agent prepared group', () => {
renderPage()
- for (const item of AGENT_PREPARED.ready) {
- expect(screen.getByText(item.label, { exact: false })).toBeInTheDocument()
- }
- for (const item of AGENT_PREPARED.needsInfo) {
- expect(screen.getByText(item.label, { exact: false })).toBeInTheDocument()
- }
- for (const item of AGENT_PREPARED.afterApproval) {
- expect(screen.getByText(item.label, { exact: false })).toBeInTheDocument()
+ const items = [
+ ...AGENT_PREPARED.prepared,
+ ...AGENT_PREPARED.review,
+ ...AGENT_PREPARED.afterApproval,
+ ]
+ for (const item of items) {
+ expect(screen.getByText(item.label)).toBeInTheDocument()
}
})
- it('navigates to work creation when the command box is clicked', async () => {
- const user = userEvent.setup()
- renderPage()
-
- await user.click(screen.getByText(/처리할 업무를 자연어로 입력해 주세요/))
-
- expect(await screen.findByText('업무 생성 페이지')).toBeInTheDocument()
+ it('uses the Figma desktop grid class for the success view', () => {
+ const { container } = renderPage()
+ expect(container.querySelector(`.${styles.dashboardGrid}`)).toBeInTheDocument()
})
it('navigates to work creation with the chosen prompt chip prefilled', async () => {
diff --git a/src/pages/DashboardPage/DashboardPage.tsx b/src/pages/DashboardPage/DashboardPage.tsx
index 9edf706..d33274e 100644
--- a/src/pages/DashboardPage/DashboardPage.tsx
+++ b/src/pages/DashboardPage/DashboardPage.tsx
@@ -1,51 +1,52 @@
import { useNavigate } from 'react-router-dom'
import { EmptyState } from '../../components/ui/EmptyState/EmptyState'
-import { WorkItemRow } from '../../components/ui/WorkItemRow/WorkItemRow'
+import { WorkItemRow, type WorkItemStatusTone } from '../../components/ui/WorkItemRow/WorkItemRow'
import { useAsyncDemoData } from '../../hooks/useAsyncDemoData'
-import { CalendarIcon, CheckCircleIcon, WarningTriangleIcon } from './DashboardIcons'
+import agentSparkIcon from './assets/agent-spark.svg'
+import commandSubmitIcon from './assets/command-submit.svg'
import styles from './DashboardPage.module.css'
import {
AGENT_PREPARED,
AI_REQUEST_PROMPT_CHIPS,
- COMMAND_BAR,
+ APPROVAL_QUEUE,
METRIC_STRIP,
TODAY_WORK_ITEMS,
- TOP_APPROVAL,
- type MetricIconKey,
+ type DashboardWorkStatus,
} from './dashboardData'
-const METRIC_ICON: Record = {
- check: CheckCircleIcon,
- calendar: CalendarIcon,
- warning: WarningTriangleIcon,
- response: CheckCircleIcon,
+const STATUS_TONE: Record = {
+ 승인대기: 'warning',
+ 요청전송: 'primary',
+ 서류대기: 'neutral',
}
export function DashboardPage() {
const navigate = useNavigate()
const status = useAsyncDemoData(TODAY_WORK_ITEMS.length === 0)
- const pendingApprovalCount = METRIC_STRIP.find((metric) => metric.id === 'pending-approval')?.value ?? 0
return (
-
- {status === 'success' && (
- <>
-
지금 확인이 필요한 승인 {pendingApprovalCount}건이 있습니다.
-
- Agent가 필요한 자료와 다음 행동을 먼저 준비했습니다. 검토와 최종 결정은 담당자가 수행합니다.
-
- >
- )}
+
+
-
-
-
✦ {COMMAND_BAR.title}
-
- ⌃
-
+
+
+

+
Agent 업무 요청
-
-
-
- {METRIC_STRIP.map((metric) => {
- const Icon = METRIC_ICON[metric.icon]
- return (
- navigate('/tasks')}>
- {metric.label}
-
- {metric.value}건 ›
-
-
-
- )
- })}
-
+
{status === 'loading' && (
@@ -112,90 +98,125 @@ export function DashboardPage() {
)}
{status === 'success' && (
-
-
-
-
-
먼저 검토할 승인 업무
-
{TOP_APPROVAL.requestedLabel}
+
+
+
+ {METRIC_STRIP.map((metric) => (
+
navigate(`/tasks?view=${metric.id}`)}
+ >
+
+ {metric.label}
+ {metric.value}건 ›
+
+
+
+
+
+ ))}
+
+
+
+
+
먼저 검토할 승인 업무
+ 요청 · {APPROVAL_QUEUE.oldestValue}
- navigate(`/tasks/${TODAY_WORK_ITEMS[0].id}`)}
- >
-
- {TOP_APPROVAL.title}
- {TOP_APPROVAL.meta}
- {TOP_APPROVAL.note}
-
-
+
+
+
+ {APPROVAL_QUEUE.title}
+ {APPROVAL_QUEUE.meta}
+ {APPROVAL_QUEUE.note}
+
+
navigate('/tasks')}>
+ 승인 검토
+
+
+
navigate('/tasks')}
+ >
›
-
-
-
navigate(`/tasks/${TODAY_WORK_ITEMS[0].id}`)}
- >
- {TOP_APPROVAL.actionLabel}
-
-
+
+
+
-
-
오늘의 우선 업무
-
지금 할 일 · {TODAY_WORK_ITEMS.length}건
-
+
+
+
오늘의 우선 업무
+
지금 할 일 · {TODAY_WORK_ITEMS.length}건
+
+
+ {TODAY_WORK_ITEMS.map((item) => (
+ navigate(`/tasks/${item.id}`)}
+ />
+ ))}
+
+
+
-
- {TODAY_WORK_ITEMS.map((item) => (
-
navigate(`/tasks/${item.id}`)}
- />
- ))}
+
-
-
{headerStatus.label}
+
+ ···
+
-
- Agent 제안 · {due.label}, {getWorkflowLabel(activeTask)} 확인 필요
-
+
+
+ Agent 제안 · {due.label}, {getWorkflowLabel(activeTask)} 확인 필요
+
-
-
-
- 우선 Case {Math.max(activeCaseIndex, 0) + 1}/{group.cases.length}
-
-
onOpenTask(activeTask.task.task_id)}
- >
- Case 열기 →
-
-
-
- {activeCase.caseId &&
Case {activeCase.caseId}
}
-
{activeTask.task.title}
-
- {getWorkflowLabel(activeTask)} · {due.label} · {activeStatus.label}
-
-
-
- 진행 {progress.completed}/{progress.total}
-
-
-
- {group.cases.length > 1 && (
-
- 다른 Case 열기 →
+
+
+
+ 우선 업무 건 · {Math.max(activeCaseIndex, 0) + 1}/{group.cases.length}
+
+
onOpenTask(activeTask.task.task_id)}
+ >
+ 업무 건 열기
+
+ ›
+
- )}
-
-
-
-
-
-
- 검토할 업무
-
- {reviewTasks.length}건
+
+
+ {activeCase.caseId &&
Case {activeCase.caseId}}
+
{activeTask.task.title}
+
+ {getWorkflowLabel(activeTask)} · {due.label} · {activeStatus.label}
+
+
+
+ {progress.completed}/{progress.total}
+
+
+
+ {group.cases.length > 1 && (
+
+ 다른 Case 열기 →
+
+ )}
+
- {reviewTasks.length === 0 ? (
-
현재 검토할 업무가 없습니다.
- ) : (
-
- {reviewTasks.map((item, index) => {
- const taskDue = getDuePresentation(item.task.due_date)
- const taskStatus = getTaskStatusPresentation(item.task.status)
- return (
-
-
-
{item.task.title}
-
- {getWorkflowLabel(item)} · {taskStatus.label}
-
-
- {taskDue.label}
- onOpenTask(item.task.task_id)}
- >
- {getReviewActionLabel(item.task.status)}
-
-
- )
- })}
+
+
+
+ 검토할 업무
+
+ {reviewTasks.length}건
- )}
-
-
-
-
- 현재 결정
-
-
- 근거 보기 →
-
-
-
-
+ {reviewTasks.length === 0 ? (
+
현재 검토할 업무가 없습니다.
+ ) : (
+
+ {reviewTasks.map((item, index) => {
+ const taskDue = getDuePresentation(item.task.due_date)
+ const taskStatus = getTaskStatusPresentation(item.task.status)
+ return (
+
+
+
{item.task.title}
+
+ {getWorkflowLabel(item)} · {taskStatus.label}
+
+
+ {taskDue.label}
+ onOpenTask(item.task.task_id)}
+ >
+ {getReviewActionLabel(item.task.status)}
+
+
+ )
+ })}
+
+ )}
+
+
+
+
+
+ 현재 결정
+
+
+ 근거 보기
+
+ ›
+
+
+
+
{getDecisionSummary(activeTask.task.status)}
-
{activeStatus.label}
+
+ 진행 업무 건 {group.cases.length}개 · 확인할 업무 {reviewTasks.length}개 · 자동
+ 확정되지 않음
+
-
- 진행 업무 건 {group.cases.length}개 · 확인할 업무 {reviewTasks.length}개 · 자동 확정되지
- 않음
-
-
-
+
+
)
}
diff --git a/src/pages/WorkListPage/WorkInboxTargetList.tsx b/src/pages/WorkListPage/WorkInboxTargetList.tsx
index 5460abf..a6ce70f 100644
--- a/src/pages/WorkListPage/WorkInboxTargetList.tsx
+++ b/src/pages/WorkListPage/WorkInboxTargetList.tsx
@@ -46,7 +46,6 @@ export function WorkInboxTargetList({
근로자 {totalCount}명
-
업무 연결 기준
{capNotice &&
{capNotice}
}
diff --git a/src/pages/WorkListPage/WorkListPage.module.css b/src/pages/WorkListPage/WorkListPage.module.css
index 297dd57..1487792 100644
--- a/src/pages/WorkListPage/WorkListPage.module.css
+++ b/src/pages/WorkListPage/WorkListPage.module.css
@@ -1,6 +1,6 @@
.page {
width: 100%;
- margin: -20px 0 0;
+ margin: -21px 0 0;
}
.headline {
@@ -14,7 +14,7 @@
.description {
margin: 5px 0 0;
font-size: 14px;
- line-height: 1.5;
+ line-height: 20px;
color: var(--text-secondary);
}
@@ -31,6 +31,9 @@
height: 40px;
max-width: none;
padding: 0 14px;
+}
+
+.searchInput input {
font-size: 13px;
}
@@ -74,17 +77,21 @@
.workspace {
display: grid;
grid-template-columns: clamp(280px, 28.82%, 332px) minmax(0, 1fr);
- min-height: 520px;
+ min-height: 0;
height: calc(100svh - 208px);
- max-height: 712px;
+ max-height: none;
margin-top: 0;
overflow: hidden;
background: var(--surface-default);
- border: 1px solid var(--border-default);
border-radius: var(--fowoco-radius-8);
+ box-shadow: inset 0 0 0 1px var(--border-default);
}
.noticeStack + .workspace {
+ margin-top: 0;
+}
+
+.noticeStack:not(:empty) + .workspace {
margin-top: var(--fowoco-spacing-12);
}
@@ -116,12 +123,6 @@
color: var(--text-primary);
}
-.listCountNote {
- font-size: 11px;
- white-space: nowrap;
- color: var(--text-secondary);
-}
-
.capNotice {
flex-shrink: 0;
margin: var(--fowoco-spacing-8) 0 0;
@@ -143,6 +144,12 @@
margin-top: var(--fowoco-spacing-12);
padding: 0;
overflow-y: auto;
+ scrollbar-width: none;
+}
+
+.targetList::-webkit-scrollbar,
+.detailPanel::-webkit-scrollbar {
+ display: none;
}
.targetOption {
@@ -224,8 +231,11 @@
.detailPanel {
min-width: 0;
min-height: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
padding: var(--fowoco-spacing-16) var(--fowoco-spacing-24);
- overflow-y: auto;
+ overflow: hidden;
background: var(--surface-default);
}
@@ -237,6 +247,49 @@
min-height: 72px;
}
+.moreButton {
+ display: inline-flex;
+ flex: 0 0 40px;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ padding: 0;
+ background: var(--surface-default);
+ border: 1px solid var(--border-default);
+ border-radius: var(--fowoco-radius-6);
+ font-family: inherit;
+ font-size: 16px;
+ line-height: 20px;
+ color: var(--text-secondary);
+ cursor: pointer;
+}
+
+.caseSummaryScroll {
+ min-height: 0;
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: var(--fowoco-spacing-16);
+ overflow-x: hidden;
+ overflow-y: auto;
+ scrollbar-width: none;
+}
+
+.caseSummaryScroll::-webkit-scrollbar {
+ display: none;
+}
+
+.moreButton:hover {
+ border-color: var(--brand-primary);
+ color: var(--brand-primary);
+}
+
+.moreButton:focus-visible {
+ outline: 2px solid var(--brand-primary);
+ outline-offset: 2px;
+}
+
.detailName {
margin: 0;
font-size: 18px;
@@ -253,6 +306,7 @@
}
.agentSuggestion {
+ flex-shrink: 0;
min-height: 40px;
margin: 0;
padding: 9px 16px;
@@ -264,7 +318,8 @@
}
.priorityCase {
- margin-top: var(--fowoco-spacing-16);
+ flex-shrink: 0;
+ margin: 0;
padding: 0;
overflow: hidden;
border: 1px solid var(--border-default);
@@ -287,6 +342,11 @@
padding: 12px 16px;
}
+.decisionHeader {
+ padding-right: 21px;
+ padding-left: 21px;
+}
+
.sectionHeadingRow {
display: flex;
align-items: center;
@@ -294,32 +354,45 @@
gap: var(--fowoco-spacing-12);
}
-.caseEyebrow,
-.caseIdentifier {
+.caseEyebrow {
margin: 0;
font-size: 16px;
font-weight: 700;
- color: var(--text-primary);
-}
-
-.caseIdentifier {
- margin: 0 0 var(--fowoco-spacing-4);
- font-size: 12px;
- font-weight: 500;
- color: var(--brand-primary);
+ line-height: 20px;
+ color: var(--brand-dark);
}
.textLink {
- padding: 4px;
+ display: inline-flex;
+ align-items: center;
+ gap: var(--fowoco-spacing-8);
+ min-height: 40px;
+ padding: 0;
background: none;
border: none;
font-family: inherit;
- font-size: 12px;
- font-weight: 700;
+ font-size: 14px;
+ font-weight: 500;
color: var(--brand-primary);
cursor: pointer;
}
+.linkChevron {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 28px;
+ height: 28px;
+ margin: 0;
+ border: 1px solid var(--border-default);
+ border-radius: var(--fowoco-radius-6);
+ background: var(--surface-default);
+ font-size: 22px;
+ font-weight: 400;
+ line-height: 1;
+ color: var(--text-secondary);
+}
+
.textLink:hover {
text-decoration: underline;
}
@@ -333,14 +406,14 @@
margin: 0;
font-size: 16px;
font-weight: 500;
- line-height: 1.45;
+ line-height: 24px;
color: var(--text-primary);
}
.caseMeta {
- margin: 6px 0 0;
- font-size: 12px;
- line-height: 1.5;
+ margin: var(--fowoco-spacing-4) 0 0;
+ font-size: 13px;
+ line-height: 20px;
color: var(--text-secondary);
}
@@ -350,7 +423,9 @@
align-items: center;
gap: var(--fowoco-spacing-12);
margin-top: var(--fowoco-spacing-4);
+ min-height: 20px;
font-size: 13px;
+ line-height: 20px;
color: var(--text-secondary);
}
@@ -381,7 +456,8 @@
.detailSection,
.decisionSection {
- margin-top: var(--fowoco-spacing-16);
+ flex-shrink: 0;
+ margin: 0;
}
.sectionTitle {
@@ -409,7 +485,7 @@
display: flex;
flex-direction: column;
gap: var(--fowoco-spacing-8);
- margin-top: var(--fowoco-spacing-12);
+ margin-top: var(--fowoco-spacing-8);
}
.reviewTaskRow {
@@ -462,21 +538,19 @@
}
.decisionBody {
- padding: 8px 16px 12px;
-}
-
-.decisionStatusRow {
- display: flex;
- align-items: flex-start;
- justify-content: space-between;
- gap: var(--fowoco-spacing-12);
+ min-height: 64px;
+ padding: 8px 7px 12px;
}
.decisionSummary {
margin: 0;
font-size: 14px;
line-height: 1.6;
- color: var(--text-primary);
+ color: var(--text-secondary);
+}
+
+.decisionHeader .sectionTitle {
+ color: var(--brand-dark);
}
.decisionMeta {
diff --git a/src/pages/WorkListPage/WorkListPage.test.tsx b/src/pages/WorkListPage/WorkListPage.test.tsx
index 9d46ab6..ad32baf 100644
--- a/src/pages/WorkListPage/WorkListPage.test.tsx
+++ b/src/pages/WorkListPage/WorkListPage.test.tsx
@@ -244,7 +244,7 @@ describe('WorkListPage', () => {
expect(
screen.getByRole('heading', { name: '체류연장 업무 초안', level: 3 }),
).toBeInTheDocument()
- expect(screen.getByText('진행 1/2')).toBeInTheDocument()
+ expect(screen.getByText('1/2')).toBeInTheDocument()
expect(
screen.getByRole('progressbar', { name: /체류연장 업무 초안 Case 진행률/ }),
).toHaveAttribute('value', '1')
@@ -288,7 +288,7 @@ describe('WorkListPage', () => {
const user = userEvent.setup()
renderPage()
- const search = await screen.findByLabelText('근로자·Case·업무 검색')
+ const search = await screen.findByLabelText('근로자·업무 건·지금 할 일 검색')
await user.type(search, 'Contract Review')
await waitFor(() => {
@@ -326,7 +326,7 @@ describe('WorkListPage', () => {
const user = userEvent.setup()
renderPage()
- await user.click(await screen.findByRole('button', { name: 'Case 열기 →' }))
+ await user.click(await screen.findByRole('button', { name: '업무 건 열기' }))
expect(await screen.findByText('업무 상세 T-1')).toBeInTheDocument()
expect(screen.queryByText('업무 상세 CASE-1')).not.toBeInTheDocument()
@@ -406,7 +406,10 @@ describe('WorkListPage', () => {
const user = userEvent.setup()
renderPage()
- await user.type(await screen.findByLabelText('근로자·Case·업무 검색'), '존재하지 않는 검색어')
+ await user.type(
+ await screen.findByLabelText('근로자·업무 건·지금 할 일 검색'),
+ '존재하지 않는 검색어',
+ )
expect(await screen.findByText('검색 결과가 없습니다')).toBeInTheDocument()
})
@@ -428,13 +431,17 @@ describe('WorkListPage', () => {
await user.click(await screen.findByRole('option', { name: /응우옌 안/ }))
- expect(screen.getByText('우선 Case 1/2')).toBeInTheDocument()
- expect(screen.getByRole('heading', { level: 3, name: '체류연장 업무 초안' })).toBeInTheDocument()
+ expect(screen.getByText('우선 업무 건 · 1/2')).toBeInTheDocument()
+ expect(
+ screen.getByRole('heading', { level: 3, name: '체류연장 업무 초안' }),
+ ).toBeInTheDocument()
await user.click(screen.getByRole('button', { name: '다른 Case 열기 →' }))
- expect(screen.getByText('우선 Case 2/2')).toBeInTheDocument()
- expect(screen.getByRole('heading', { level: 3, name: '근로자 안내문 초안' })).toBeInTheDocument()
+ expect(screen.getByText('우선 업무 건 · 2/2')).toBeInTheDocument()
+ expect(
+ screen.getByRole('heading', { level: 3, name: '근로자 안내문 초안' }),
+ ).toBeInTheDocument()
})
it('shows a placeholder toast for "근거 보기"', async () => {
@@ -442,7 +449,7 @@ describe('WorkListPage', () => {
const user = userEvent.setup()
renderPage('/tasks', { withToasts: true })
- await user.click(await screen.findByRole('button', { name: '근거 보기 →' }))
+ await user.click(await screen.findByRole('button', { name: '근거 보기' }))
expect(screen.getByText('판단 근거 보기는 준비 중입니다.')).toBeInTheDocument()
})
diff --git a/src/pages/WorkListPage/WorkListPage.tsx b/src/pages/WorkListPage/WorkListPage.tsx
index b23ee6c..47b32fb 100644
--- a/src/pages/WorkListPage/WorkListPage.tsx
+++ b/src/pages/WorkListPage/WorkListPage.tsx
@@ -67,7 +67,6 @@ function TaskStateWorkspace({
근로자 {workers.length}명
-
업무 상태 미확인
{visibleWorkers.map((worker) => {
@@ -185,15 +184,15 @@ export function WorkListPage() {
= {
DRAFT: '초안 검토',
NEEDS_INFO: '정보 확인',
- READY_FOR_REVIEW: '검토하기',
+ READY_FOR_REVIEW: '초안 검토',
APPROVED: '실행 확인',
WAITING_WORKER: '대기 확인',
WAITING_EXTERNAL: '진행 확인',
@@ -40,8 +40,15 @@ export function getTaskStatusPresentation(status: TaskStatus): {
label: string
tone: StatusTone
} {
+ const workInboxLabel: Partial> = {
+ DRAFT: '서류 대기',
+ NEEDS_INFO: '처리 필요',
+ READY_FOR_REVIEW: '승인 대기',
+ WAITING_WORKER: '요청 전송',
+ }
+
return {
- label: TASK_STATUS_LABEL[status],
+ label: workInboxLabel[status] ?? TASK_STATUS_LABEL[status],
tone: TASK_STATUS_TONE[status],
}
}