From 406a1a7fe7afdd18feaa256459cdb946cb5de8a7 Mon Sep 17 00:00:00 2001 From: mini Date: Tue, 11 Aug 2026 13:30:29 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=97=85=EB=AC=B4=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=EC=9D=98=20=EA=B0=80=EC=A7=9C=20=EB=AF=B8?= =?UTF-8?q?=EB=A6=AC=EB=B3=B4=EA=B8=B0=20=EB=8D=B0=EC=9D=B4=ED=84=B0=C2=B7?= =?UTF-8?q?=EB=AF=B8=EA=B5=AC=ED=98=84=20=EC=9B=90=EB=AC=B8=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B2=84=ED=8A=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 원본 요청을 실제 편집 가능한 textarea로 변경 (프리필 없으면 빈 값) - Agent가 이해한 요청/업무 건 지금 할 일/대상 근로자/필수정보 등 하드코딩된 가짜 레일 카드 전부 제거 — 실제 입력과 무관하게 항상 같은 값을 보여주고 있었음 - 원문 수정 스텁 버튼 제거 (텍스트영역이 항상 편집 가능하므로 불필요) - createWorkData.ts에서 안 쓰이게 된 가짜 데이터 export 정리 closes #313 --- .../CreateWorkPage/CreateWorkPage.test.tsx | 38 ++--- src/pages/CreateWorkPage/CreateWorkPage.tsx | 141 +++++------------- src/pages/CreateWorkPage/createWorkData.ts | 77 +--------- .../ReviewWorkPage/ReviewWorkPage.module.css | 19 +++ 4 files changed, 70 insertions(+), 205 deletions(-) diff --git a/src/pages/CreateWorkPage/CreateWorkPage.test.tsx b/src/pages/CreateWorkPage/CreateWorkPage.test.tsx index b5d806c..02a52bf 100644 --- a/src/pages/CreateWorkPage/CreateWorkPage.test.tsx +++ b/src/pages/CreateWorkPage/CreateWorkPage.test.tsx @@ -5,7 +5,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { ToastViewport } from '../../components/ui/ToastViewport/ToastViewport' import { useToastStore } from '../../store/toastStore' import { CreateWorkPage } from './CreateWorkPage' -import { DEFAULT_ORIGINAL_REQUEST, WORKFLOW_TASKS } from './createWorkData' function jsonResponse(body: unknown, init: ResponseInit = {}) { return new Response(JSON.stringify(body), { @@ -67,36 +66,34 @@ function renderPage(initialEntry: string | { pathname: string; state?: unknown } } describe('CreateWorkPage', () => { - it('shows the request forwarded from the dashboard as the original request', () => { + it('prefills the request forwarded from the dashboard as editable text', () => { renderPage({ pathname: '/tasks/new', state: { prefill: '응웬반A 체류기간 연장 준비' } }) - expect(screen.getByText('응웬반A 체류기간 연장 준비')).toBeInTheDocument() + expect(screen.getByRole('textbox', { name: '원본 요청' })).toHaveValue( + '응웬반A 체류기간 연장 준비', + ) }) - it('falls back to a default original request when nothing was forwarded', () => { + it('starts with an empty, editable request when nothing was forwarded', () => { renderPage() - expect(screen.getByText(DEFAULT_ORIGINAL_REQUEST.split('\n')[0])).toBeInTheDocument() + expect(screen.getByRole('textbox', { name: '원본 요청' })).toHaveValue('') + expect(screen.getByRole('button', { name: '정보 보완' })).toBeDisabled() }) - it('renders every candidate task in the work item', () => { - renderPage() - - for (const task of WORKFLOW_TASKS) { - expect(screen.getByText(task.title)).toBeInTheDocument() - } - }) - - it('navigates to the review flow when moving to information review', async () => { + it('navigates to the review flow with the text the user typed', async () => { const user = userEvent.setup() renderPage() + await user.type(screen.getByRole('textbox', { name: '원본 요청' }), '직접 입력한 요청') await user.click(screen.getByRole('button', { name: '정보 보완' })) expect(await screen.findByText(/검토 화면\?aiRunId=A-1/)).toBeInTheDocument() - const analyzeCall = vi.mocked(fetch).mock.calls.find(([url]) => String(url).endsWith('/ai-runs')) + const analyzeCall = vi + .mocked(fetch) + .mock.calls.find(([url]) => String(url).endsWith('/ai-runs')) expect(JSON.parse((analyzeCall?.[1] as RequestInit).body as string)).toEqual({ - instruction: DEFAULT_ORIGINAL_REQUEST, + instruction: '직접 입력한 요청', }) }) @@ -117,13 +114,4 @@ describe('CreateWorkPage', () => { expect(screen.getByRole('dialog', { name: '파일 가져오기 · 파일 확인' })).toBeInTheDocument() }) - - it('shows a toast when editing the original request', async () => { - const user = userEvent.setup() - renderPage() - - await user.click(screen.getByRole('button', { name: '원문 수정' })) - - expect(screen.getByText('원문 수정은 준비 중입니다.')).toBeInTheDocument() - }) }) diff --git a/src/pages/CreateWorkPage/CreateWorkPage.tsx b/src/pages/CreateWorkPage/CreateWorkPage.tsx index cfdd39d..446c34e 100644 --- a/src/pages/CreateWorkPage/CreateWorkPage.tsx +++ b/src/pages/CreateWorkPage/CreateWorkPage.tsx @@ -4,22 +4,9 @@ import { ApiError, getErrorMessage } from '../../api/errors' import { createAiRun } from '../../api/aiRuns' import { Button } from '../../components/ui/Button/Button' import { WorkflowStepIndicator } from '../../components/ui/WorkflowStepIndicator/WorkflowStepIndicator' -import { useToastStore } from '../../store/toastStore' import { REVIEW_STEPS } from '../ReviewWorkPage/reviewWorkData' import styles from '../ReviewWorkPage/ReviewWorkPage.module.css' -import { - ACTION_DOCK, - AGENT_SCOPE_NOTE, - COMPOUND_REQUEST_NOTE, - DEFAULT_ORIGINAL_REQUEST, - REQUIRED_INFO_COUNT, - REQUIRED_INFO_ROWS, - SCENARIO_STATUS_LABEL, - TARGET_CASE, - UNDERSTOOD_WORK, - WORKFLOW_TASKS, - type InfoSourceTone, -} from './createWorkData' +import { AGENT_SCOPE_NOTE } from './createWorkData' import { ImportWizardModal } from './importWizard/ImportWizardModal' import { saveActiveWorkRequestDraft, @@ -27,31 +14,23 @@ import { type WorkRequestDraft, } from './workRequestDraft' -const TASK_STATUS_TONE: Record = { - current: 'pillBrand', - pending: 'pillAmber', - blocked: 'pillNeutral', -} - -const INFO_SOURCE_TONE: Record = { - neutral: 'pillNeutral', - brand: 'pillBrand', - amber: 'pillAmber', -} - export function CreateWorkPage() { const navigate = useNavigate() const location = useLocation() - // HOME-001 대시보드의 AI 요청 프롬프트 칩에서 넘어온 경우 선택한 문구를 원본 요청으로 보여준다. - const routeState = location.state as { prefill?: string; request?: string } | null - const originalRequest = routeState?.request ?? routeState?.prefill ?? DEFAULT_ORIGINAL_REQUEST + // HOME-001 대시보드의 AI 요청 프롬프트 칩·업무함의 "업무 준비" 액션에서 넘어온 경우 + // 선택한 문구를 원본 요청 초안으로 미리 채운다. 없으면 빈 값으로 시작해서 직접 입력한다. + const routeState = location.state as { + prefill?: string + request?: string + workerId?: string + } | null + const [requestText, setRequestText] = useState(routeState?.request ?? routeState?.prefill ?? '') const [importWizardOpen, setImportWizardOpen] = useState(false) const [analyzing, setAnalyzing] = useState(false) const [analysisError, setAnalysisError] = useState(null) - const showToast = useToastStore((state) => state.showToast) async function handleAnalyze() { - const instruction = originalRequest.trim() + const instruction = requestText.trim() if (instruction === '' || analyzing) return setAnalyzing(true) @@ -60,9 +39,9 @@ export function CreateWorkPage() { // UI 분류값이나 Intent 코드를 붙이지 않고 사용자가 입력한 원문만 전달한다. const aiRun = await createAiRun(instruction, globalThis.crypto.randomUUID()) const draft: WorkRequestDraft = { - request: originalRequest, + request: requestText, mode: 'nl', - workerId: '', + workerId: routeState?.workerId ?? '', attachments: [], } saveActiveWorkRequestDraft(draft) @@ -79,11 +58,6 @@ export function CreateWorkPage() { } } - function handleEditRequest() { - // TODO(backend): PATCH /api/work-items/draft -> 원문 수정 반영 - showToast('원문 수정은 준비 중입니다.') - } - function handleStepClick(index: number) { if (index === 0) return navigate(`/tasks/new/review?step=${index}`) @@ -101,12 +75,11 @@ export function CreateWorkPage() {
-

요청을 업무 단위로 확인해 주세요

+

요청을 자연어로 입력해 주세요

- 원문과 기존 데이터를 바탕으로 상위 업무 건의 지금 할 일을 정리했습니다. + 입력한 원문을 그대로 분석해서 처리할 업무 후보를 준비합니다.

- {SCENARIO_STATUS_LABEL}
@@ -116,71 +89,27 @@ export function CreateWorkPage() {

원본 요청

HR 입력
- {originalRequest.split('\n').map((line) => ( -

- {line} -

- ))} - - -
-
-
-

Agent가 이해한 요청

-

{UNDERSTOOD_WORK.title}

-
- {UNDERSTOOD_WORK.note} -
+