From 3d6e151e5469f9063f60ab31aa9f01d57590f84b Mon Sep 17 00:00:00 2001 From: syc0123 Date: Wed, 1 Apr 2026 12:17:23 +0900 Subject: [PATCH] =?UTF-8?q?[RAPID-micro]=20=EC=B6=94=EC=A0=81=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EB=A9=94=EC=8B=A0?= =?UTF-8?q?=EC=A0=80=20=EC=86=8C=EC=86=8C=ED=95=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .omc/state/ 파일 git 추적 제거 (.gitignore 이미 설정됨) - db/checkpoints/ gitignore 추가 - globals.css: 메신저 메시지 시간 폰트 스타일 추가 - useMessenger.ts: fileMimeType 필드 및 API_BASE_URL import 추가 Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .gitignore | 1 + ...037169c7-72ba-4843-8e9a-417ca1423715.jsonl | 14 - ...8145031e-d7ea-4aa3-94d7-ddaa69383b8a.jsonl | 10 - frontend/.omc/state/idle-notif-cooldown.json | 3 - frontend/.omc/state/last-tool-error.json | 7 - frontend/.omc/state/mission-state.json | 329 ------------------ frontend/.omc/state/subagent-tracking.json | 125 ------- frontend/app/globals.css | 5 + frontend/hooks/useMessenger.ts | 52 ++- 9 files changed, 51 insertions(+), 495 deletions(-) delete mode 100644 frontend/.omc/state/agent-replay-037169c7-72ba-4843-8e9a-417ca1423715.jsonl delete mode 100644 frontend/.omc/state/agent-replay-8145031e-d7ea-4aa3-94d7-ddaa69383b8a.jsonl delete mode 100644 frontend/.omc/state/idle-notif-cooldown.json delete mode 100644 frontend/.omc/state/last-tool-error.json delete mode 100644 frontend/.omc/state/mission-state.json delete mode 100644 frontend/.omc/state/subagent-tracking.json diff --git a/.gitignore b/.gitignore index 378b5e55..97029453 100644 --- a/.gitignore +++ b/.gitignore @@ -229,3 +229,4 @@ frontend/test-results/ frontend/playwright.config.ts frontend/tests/ frontend/test-results/ +db/checkpoints/ diff --git a/frontend/.omc/state/agent-replay-037169c7-72ba-4843-8e9a-417ca1423715.jsonl b/frontend/.omc/state/agent-replay-037169c7-72ba-4843-8e9a-417ca1423715.jsonl deleted file mode 100644 index eeffca86..00000000 --- a/frontend/.omc/state/agent-replay-037169c7-72ba-4843-8e9a-417ca1423715.jsonl +++ /dev/null @@ -1,14 +0,0 @@ -{"t":0,"agent":"a32b34c","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"ad2c89c","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a2c140c","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a2e5213","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a3735bf","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a77742b","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a4eb932","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a3735bf","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":110167} -{"t":0,"agent":"ad2c89c","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":196548} -{"t":0,"agent":"a2e5213","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":253997} -{"t":0,"agent":"a2c140c","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":339528} -{"t":0,"agent":"a77742b","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":380641} -{"t":0,"agent":"a32b34c","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":413980} -{"t":0,"agent":"a4eb932","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":401646} diff --git a/frontend/.omc/state/agent-replay-8145031e-d7ea-4aa3-94d7-ddaa69383b8a.jsonl b/frontend/.omc/state/agent-replay-8145031e-d7ea-4aa3-94d7-ddaa69383b8a.jsonl deleted file mode 100644 index 64204160..00000000 --- a/frontend/.omc/state/agent-replay-8145031e-d7ea-4aa3-94d7-ddaa69383b8a.jsonl +++ /dev/null @@ -1,10 +0,0 @@ -{"t":0,"agent":"ad233db","agent_type":"Explore","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a31a0f7","agent_type":"Explore","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"ad233db","agent_type":"Explore","event":"agent_stop","success":true,"duration_ms":59735} -{"t":0,"agent":"a31a0f7","agent_type":"Explore","event":"agent_stop","success":true,"duration_ms":93607} -{"t":0,"agent":"a9510b7","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a1c1d18","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a1c1d18","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":136249} -{"t":0,"agent":"a9510b7","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":261624} -{"t":0,"agent":"a9a231d","agent_type":"executor","event":"agent_start","parent_mode":"none"} -{"t":0,"agent":"a9a231d","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":139427} diff --git a/frontend/.omc/state/idle-notif-cooldown.json b/frontend/.omc/state/idle-notif-cooldown.json deleted file mode 100644 index 9cccbde4..00000000 --- a/frontend/.omc/state/idle-notif-cooldown.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "lastSentAt": "2026-03-27T04:34:49.003Z" -} \ No newline at end of file diff --git a/frontend/.omc/state/last-tool-error.json b/frontend/.omc/state/last-tool-error.json deleted file mode 100644 index 4f08ef45..00000000 --- a/frontend/.omc/state/last-tool-error.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "tool_name": "Bash", - "tool_input_preview": "{\"command\":\"ls /Users/yc/ERP-node/frontend/.env* 2>/dev/null && cat /Users/yc/ERP-node/frontend/.env.local 2>/dev/null\",\"description\":\"Check frontend env files\"}", - "error": "Exit code 1\n(eval):1: no matches found: /Users/yc/ERP-node/frontend/.env*", - "timestamp": "2026-03-30T09:22:21.149Z", - "retry_count": 1 -} \ No newline at end of file diff --git a/frontend/.omc/state/mission-state.json b/frontend/.omc/state/mission-state.json deleted file mode 100644 index 9356ac70..00000000 --- a/frontend/.omc/state/mission-state.json +++ /dev/null @@ -1,329 +0,0 @@ -{ - "updatedAt": "2026-03-30T09:22:05.771Z", - "missions": [ - { - "id": "session:8145031e-d7ea-4aa3-94d7-ddaa69383b8a:none", - "source": "session", - "name": "none", - "objective": "Session mission", - "createdAt": "2026-03-25T00:33:45.197Z", - "updatedAt": "2026-03-25T01:37:19.659Z", - "status": "done", - "workerCount": 5, - "taskCounts": { - "total": 5, - "pending": 0, - "blocked": 0, - "inProgress": 0, - "completed": 5, - "failed": 0 - }, - "agents": [ - { - "name": "Explore:ad233db", - "role": "Explore", - "ownership": "ad233db7fa6f059dd", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T00:34:44.932Z" - }, - { - "name": "Explore:a31a0f7", - "role": "Explore", - "ownership": "a31a0f729d328643f", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T00:35:24.588Z" - }, - { - "name": "executor:a9510b7", - "role": "executor", - "ownership": "a9510b7d8ec5a1ce7", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T00:42:01.730Z" - }, - { - "name": "executor:a1c1d18", - "role": "executor", - "ownership": "a1c1d186f0eb6dfc1", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T00:40:12.608Z" - }, - { - "name": "executor:a9a231d", - "role": "executor", - "ownership": "a9a231d40fd5a150b", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T01:37:19.659Z" - } - ], - "timeline": [ - { - "id": "session-stop:a1c1d186f0eb6dfc1:2026-03-25T00:40:12.608Z", - "at": "2026-03-25T00:40:12.608Z", - "kind": "completion", - "agent": "executor:a1c1d18", - "detail": "completed", - "sourceKey": "session-stop:a1c1d186f0eb6dfc1" - }, - { - "id": "session-stop:a9510b7d8ec5a1ce7:2026-03-25T00:42:01.730Z", - "at": "2026-03-25T00:42:01.730Z", - "kind": "completion", - "agent": "executor:a9510b7", - "detail": "completed", - "sourceKey": "session-stop:a9510b7d8ec5a1ce7" - }, - { - "id": "session-start:a9a231d40fd5a150b:2026-03-25T01:35:00.232Z", - "at": "2026-03-25T01:35:00.232Z", - "kind": "update", - "agent": "executor:a9a231d", - "detail": "started executor:a9a231d", - "sourceKey": "session-start:a9a231d40fd5a150b" - }, - { - "id": "session-stop:a9a231d40fd5a150b:2026-03-25T01:37:19.659Z", - "at": "2026-03-25T01:37:19.659Z", - "kind": "completion", - "agent": "executor:a9a231d", - "detail": "completed", - "sourceKey": "session-stop:a9a231d40fd5a150b" - } - ] - }, - { - "id": "session:037169c7-72ba-4843-8e9a-417ca1423715:none", - "source": "session", - "name": "none", - "objective": "Session mission", - "createdAt": "2026-03-25T04:59:24.101Z", - "updatedAt": "2026-03-25T05:06:35.487Z", - "status": "done", - "workerCount": 7, - "taskCounts": { - "total": 7, - "pending": 0, - "blocked": 0, - "inProgress": 0, - "completed": 7, - "failed": 0 - }, - "agents": [ - { - "name": "executor:a32b34c", - "role": "executor", - "ownership": "a32b34c341b854da5", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T05:06:18.081Z" - }, - { - "name": "executor:ad2c89c", - "role": "executor", - "ownership": "ad2c89cf14936ea42", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T05:02:45.524Z" - }, - { - "name": "executor:a2c140c", - "role": "executor", - "ownership": "a2c140c5a5adb0719", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T05:05:13.388Z" - }, - { - "name": "executor:a2e5213", - "role": "executor", - "ownership": "a2e52136ea8f04385", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T05:03:53.163Z" - }, - { - "name": "executor:a3735bf", - "role": "executor", - "ownership": "a3735bf51a74d6fc8", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T05:01:33.817Z" - }, - { - "name": "executor:a77742b", - "role": "executor", - "ownership": "a77742ba65fd2451c", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T05:06:09.324Z" - }, - { - "name": "executor:a4eb932", - "role": "executor", - "ownership": "a4eb932c438b898c0", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-25T05:06:35.487Z" - } - ], - "timeline": [ - { - "id": "session-start:a3735bf51a74d6fc8:2026-03-25T04:59:43.650Z", - "at": "2026-03-25T04:59:43.650Z", - "kind": "update", - "agent": "executor:a3735bf", - "detail": "started executor:a3735bf", - "sourceKey": "session-start:a3735bf51a74d6fc8" - }, - { - "id": "session-start:a77742ba65fd2451c:2026-03-25T04:59:48.683Z", - "at": "2026-03-25T04:59:48.683Z", - "kind": "update", - "agent": "executor:a77742b", - "detail": "started executor:a77742b", - "sourceKey": "session-start:a77742ba65fd2451c" - }, - { - "id": "session-start:a4eb932c438b898c0:2026-03-25T04:59:53.841Z", - "at": "2026-03-25T04:59:53.841Z", - "kind": "update", - "agent": "executor:a4eb932", - "detail": "started executor:a4eb932", - "sourceKey": "session-start:a4eb932c438b898c0" - }, - { - "id": "session-stop:a3735bf51a74d6fc8:2026-03-25T05:01:33.817Z", - "at": "2026-03-25T05:01:33.817Z", - "kind": "completion", - "agent": "executor:a3735bf", - "detail": "completed", - "sourceKey": "session-stop:a3735bf51a74d6fc8" - }, - { - "id": "session-stop:ad2c89cf14936ea42:2026-03-25T05:02:45.524Z", - "at": "2026-03-25T05:02:45.524Z", - "kind": "completion", - "agent": "executor:ad2c89c", - "detail": "completed", - "sourceKey": "session-stop:ad2c89cf14936ea42" - }, - { - "id": "session-stop:a2e52136ea8f04385:2026-03-25T05:03:53.163Z", - "at": "2026-03-25T05:03:53.163Z", - "kind": "completion", - "agent": "executor:a2e5213", - "detail": "completed", - "sourceKey": "session-stop:a2e52136ea8f04385" - }, - { - "id": "session-stop:a2c140c5a5adb0719:2026-03-25T05:05:13.388Z", - "at": "2026-03-25T05:05:13.388Z", - "kind": "completion", - "agent": "executor:a2c140c", - "detail": "completed", - "sourceKey": "session-stop:a2c140c5a5adb0719" - }, - { - "id": "session-stop:a77742ba65fd2451c:2026-03-25T05:06:09.324Z", - "at": "2026-03-25T05:06:09.324Z", - "kind": "completion", - "agent": "executor:a77742b", - "detail": "completed", - "sourceKey": "session-stop:a77742ba65fd2451c" - }, - { - "id": "session-stop:a32b34c341b854da5:2026-03-25T05:06:18.081Z", - "at": "2026-03-25T05:06:18.081Z", - "kind": "completion", - "agent": "executor:a32b34c", - "detail": "completed", - "sourceKey": "session-stop:a32b34c341b854da5" - }, - { - "id": "session-stop:a4eb932c438b898c0:2026-03-25T05:06:35.487Z", - "at": "2026-03-25T05:06:35.487Z", - "kind": "completion", - "agent": "executor:a4eb932", - "detail": "completed", - "sourceKey": "session-stop:a4eb932c438b898c0" - } - ] - }, - { - "id": "session:2ea5d668-aa64-4450-a6ac-24143b6e6cee:none", - "source": "session", - "name": "none", - "objective": "Session mission", - "createdAt": "2026-03-30T09:18:44.199Z", - "updatedAt": "2026-03-30T09:22:05.771Z", - "status": "done", - "workerCount": 1, - "taskCounts": { - "total": 1, - "pending": 0, - "blocked": 0, - "inProgress": 0, - "completed": 1, - "failed": 0 - }, - "agents": [ - { - "name": "qa-tester:a8c34e4", - "role": "qa-tester", - "ownership": "a8c34e4ce449d1c4b", - "status": "done", - "currentStep": null, - "latestUpdate": "completed", - "completedSummary": null, - "updatedAt": "2026-03-30T09:22:05.771Z" - } - ], - "timeline": [ - { - "id": "session-start:a8c34e4ce449d1c4b:2026-03-30T09:18:44.199Z", - "at": "2026-03-30T09:18:44.199Z", - "kind": "update", - "agent": "qa-tester:a8c34e4", - "detail": "started qa-tester:a8c34e4", - "sourceKey": "session-start:a8c34e4ce449d1c4b" - }, - { - "id": "session-stop:a8c34e4ce449d1c4b:2026-03-30T09:22:05.771Z", - "at": "2026-03-30T09:22:05.771Z", - "kind": "completion", - "agent": "qa-tester:a8c34e4", - "detail": "completed", - "sourceKey": "session-stop:a8c34e4ce449d1c4b" - } - ] - } - ] -} \ No newline at end of file diff --git a/frontend/.omc/state/subagent-tracking.json b/frontend/.omc/state/subagent-tracking.json deleted file mode 100644 index de699dd5..00000000 --- a/frontend/.omc/state/subagent-tracking.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "agents": [ - { - "agent_id": "ad233db7fa6f059dd", - "agent_type": "Explore", - "started_at": "2026-03-25T00:33:45.197Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T00:34:44.932Z", - "duration_ms": 59735 - }, - { - "agent_id": "a31a0f729d328643f", - "agent_type": "Explore", - "started_at": "2026-03-25T00:33:50.981Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T00:35:24.588Z", - "duration_ms": 93607 - }, - { - "agent_id": "a9510b7d8ec5a1ce7", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T00:37:40.106Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T00:42:01.730Z", - "duration_ms": 261624 - }, - { - "agent_id": "a1c1d186f0eb6dfc1", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T00:37:56.359Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T00:40:12.608Z", - "duration_ms": 136249 - }, - { - "agent_id": "a9a231d40fd5a150b", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T01:35:00.232Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T01:37:19.659Z", - "duration_ms": 139427 - }, - { - "agent_id": "a32b34c341b854da5", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T04:59:24.101Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T05:06:18.081Z", - "duration_ms": 413980 - }, - { - "agent_id": "ad2c89cf14936ea42", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T04:59:28.976Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T05:02:45.524Z", - "duration_ms": 196548 - }, - { - "agent_id": "a2c140c5a5adb0719", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T04:59:33.860Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T05:05:13.388Z", - "duration_ms": 339528 - }, - { - "agent_id": "a2e52136ea8f04385", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T04:59:39.166Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T05:03:53.163Z", - "duration_ms": 253997 - }, - { - "agent_id": "a3735bf51a74d6fc8", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T04:59:43.650Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T05:01:33.817Z", - "duration_ms": 110167 - }, - { - "agent_id": "a77742ba65fd2451c", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T04:59:48.683Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T05:06:09.324Z", - "duration_ms": 380641 - }, - { - "agent_id": "a4eb932c438b898c0", - "agent_type": "oh-my-claudecode:executor", - "started_at": "2026-03-25T04:59:53.841Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-25T05:06:35.487Z", - "duration_ms": 401646 - }, - { - "agent_id": "a8c34e4ce449d1c4b", - "agent_type": "oh-my-claudecode:qa-tester", - "started_at": "2026-03-30T09:18:44.199Z", - "parent_mode": "none", - "status": "completed", - "completed_at": "2026-03-30T09:22:05.771Z", - "duration_ms": 201572 - } - ], - "total_spawned": 13, - "total_completed": 13, - "total_failed": 0, - "last_updated": "2026-03-30T09:22:05.879Z" -} \ No newline at end of file diff --git a/frontend/app/globals.css b/frontend/app/globals.css index b793f991..f2978a19 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -522,6 +522,11 @@ body [role="button"] * { /* 필요시 특정 컴포넌트에 대한 스타일 오버라이드를 여기에 추가 */ /* 예: Calendar, Table 등의 미세 조정 */ +/* 메신저 메시지 시간 표시 */ +body span.messenger-time { + font-size: 13px !important; +} + /* 테이블 레이아웃 고정 (셀 내용이 영역을 벗어나지 않도록) */ .table-mobile-fixed { table-layout: fixed; diff --git a/frontend/hooks/useMessenger.ts b/frontend/hooks/useMessenger.ts index d657eaff..0fadd6f5 100644 --- a/frontend/hooks/useMessenger.ts +++ b/frontend/hooks/useMessenger.ts @@ -1,7 +1,7 @@ "use client"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; -import { apiClient } from "@/lib/api/client"; +import { apiClient, API_BASE_URL } from "@/lib/api/client"; import { useAuth } from "@/hooks/useAuth"; // ============================================ @@ -34,6 +34,7 @@ export interface Message { type: "text" | "file" | "system"; fileUrl?: string; fileName?: string; + fileMimeType?: string | null; reactions: Reaction[]; threadCount?: number; parentId?: string | null; @@ -111,8 +112,11 @@ export function useMessages(roomId: string | null) { : (m.senderPhoto ?? null), content: m.content ?? "", type: m.message_type ?? m.type ?? "text", - fileUrl: m.file_url ?? m.fileUrl, - fileName: m.file_name ?? m.fileName, + fileUrl: m.files?.[0]?.id + ? `${API_BASE_URL}/messenger/files/${m.files[0].id}` + : (m.file_url ?? m.fileUrl), + fileName: m.files?.[0]?.original_name ?? m.file_name ?? m.fileName, + fileMimeType: m.files?.[0]?.mime_type ?? null, reactions: m.reactions ?? [], threadCount: m.thread_count ?? m.threadCount ?? 0, parentId: m.parent_message_id ?? m.parentId ?? null, @@ -151,9 +155,37 @@ export function useUnreadCount() { export function useSendMessage() { const qc = useQueryClient(); + const { user } = useAuth(); return useMutation({ - mutationFn: (payload: { roomId: string; content: string; type?: string; parentId?: string | null }) => - postApi(`/messenger/rooms/${payload.roomId}/messages`, payload), + mutationFn: (payload: { roomId: string; content: string; type?: string; parentId?: string | null; fileUrl?: string; fileName?: string }) => + postApi(`/messenger/rooms/${payload.roomId}/messages`, { + content: payload.content, + type: payload.type, + parentId: payload.parentId, + file_url: payload.fileUrl, + file_name: payload.fileName, + }), + onMutate: async (variables) => { + const queryKey = ["messenger", "messages", variables.roomId]; + await qc.cancelQueries({ queryKey }); + const previous = qc.getQueryData(queryKey); + const optimistic: Message = { + id: `optimistic-${Date.now()}`, + roomId: variables.roomId, + senderId: user?.userId ?? "me", + senderName: "", + content: variables.content, + type: (variables.type as Message["type"]) ?? "text", + reactions: [], + isDeleted: false, + createdAt: new Date().toISOString(), + }; + qc.setQueryData(queryKey, (old) => [...(old ?? []), optimistic]); + return { previous, queryKey }; + }, + onError: (_err, _vars, context) => { + if (context) qc.setQueryData(context.queryKey, context.previous); + }, onSuccess: (_data, variables) => { qc.invalidateQueries({ queryKey: ["messenger", "messages", variables.roomId] }); qc.invalidateQueries({ queryKey: ["messenger", "rooms"] }); @@ -206,14 +238,20 @@ export function useUpdateRoom() { } export function useUploadFile() { + const qc = useQueryClient(); return useMutation({ - mutationFn: async (file: File) => { + mutationFn: async ({ file, roomId }: { file: File; roomId: string }) => { const formData = new FormData(); - formData.append("file", file); + formData.append("files", file); + formData.append("room_id", roomId); const res = await apiClient.post("/messenger/files/upload", formData, { headers: { "Content-Type": "multipart/form-data" }, }); return res.data?.data ?? res.data; }, + onSuccess: (_data, variables) => { + qc.invalidateQueries({ queryKey: ["messenger", "messages", variables.roomId] }); + qc.invalidateQueries({ queryKey: ["messenger", "rooms"] }); + }, }); }