From 0257350f55c00735cadbd5b507ef5cc9cd3adb10 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 29 May 2025 08:17:25 +0000 Subject: (김준회) 기술영업 조선 RFQ - 캐시 문제 대응, 코멘트 기능 UX 향상 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vendor-response/buyer-communication-drawer.tsx | 140 +++++++++++++++++---- 1 file changed, 119 insertions(+), 21 deletions(-) (limited to 'lib/techsales-rfq/vendor-response') diff --git a/lib/techsales-rfq/vendor-response/buyer-communication-drawer.tsx b/lib/techsales-rfq/vendor-response/buyer-communication-drawer.tsx index c8a0efc2..4422a32c 100644 --- a/lib/techsales-rfq/vendor-response/buyer-communication-drawer.tsx +++ b/lib/techsales-rfq/vendor-response/buyer-communication-drawer.tsx @@ -28,7 +28,6 @@ import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" import { Avatar, AvatarFallback } from "@/components/ui/avatar" import { Badge } from "@/components/ui/badge" -import { ScrollArea } from "@/components/ui/scroll-area" import { Dialog, DialogContent, @@ -237,6 +236,11 @@ export function BuyerCommunicationDrawer({ const fileInputRef = useRef(null); const messagesEndRef = useRef(null); + // 자동 새로고침 관련 상태 + const [autoRefresh, setAutoRefresh] = useState(true); + const [lastMessageCount, setLastMessageCount] = useState(0); + const intervalRef = useRef(null); + // 첨부파일 관련 상태 const [previewDialogOpen, setPreviewDialogOpen] = useState(false); const [selectedAttachment, setSelectedAttachment] = useState(null); @@ -245,8 +249,20 @@ export function BuyerCommunicationDrawer({ useEffect(() => { if (open && quotation) { loadComments(); + // 자동 새로고침 시작 + if (autoRefresh) { + startAutoRefresh(); + } + } else { + // 드로어가 닫히면 자동 새로고침 중지 + stopAutoRefresh(); } - }, [open, quotation]); + + // 컴포넌트 언마운트 시 정리 + return () => { + stopAutoRefresh(); + }; + }, [open, quotation, autoRefresh]); // 스크롤 최하단으로 이동 useEffect(() => { @@ -255,23 +271,77 @@ export function BuyerCommunicationDrawer({ } }, [comments]); - // 코멘트 로드 함수 - const loadComments = async () => { + // 자동 새로고침 시작 + const startAutoRefresh = () => { + stopAutoRefresh(); // 기존 interval 정리 + intervalRef.current = setInterval(() => { + if (open && quotation && !isSubmitting) { + loadComments(true); // 자동 새로고침임을 표시 + } + }, 60000); // 60초마다 새로고침 + }; + + // 자동 새로고침 중지 + const stopAutoRefresh = () => { + if (intervalRef.current) { + clearInterval(intervalRef.current); + intervalRef.current = null; + } + }; + + // 자동 새로고침 토글 + const toggleAutoRefresh = () => { + setAutoRefresh(prev => { + const newValue = !prev; + if (newValue && open) { + startAutoRefresh(); + } else { + stopAutoRefresh(); + } + return newValue; + }); + }; + + // 코멘트 로드 함수 (자동 새로고침 여부 파라미터 추가) + const loadComments = async (isAutoRefresh = false) => { if (!quotation) return; try { - setIsLoading(true); + // 자동 새로고침일 때는 로딩 표시하지 않음 + if (!isAutoRefresh) { + setIsLoading(true); + } // API를 사용하여 코멘트 데이터 가져오기 const commentsData = await fetchTechSalesVendorCommentsClient(quotation.rfqId, quotation.vendorId); + + // 새 메시지가 있는지 확인 (자동 새로고침일 때만) + if (isAutoRefresh) { + const newMessageCount = commentsData.length; + if (newMessageCount > lastMessageCount && lastMessageCount > 0) { + // 새 메시지 알림 + toast.success(`새 메시지 ${newMessageCount - lastMessageCount}개가 도착했습니다`); + } + setLastMessageCount(newMessageCount); + } else { + setLastMessageCount(commentsData.length); + } + setComments(commentsData); // 읽음 상태 처리는 API 측에서 처리되는 것으로 가정 } catch (error) { console.error("코멘트 로드 오류:", error); - toast.error("메시지를 불러오는 중 오류가 발생했습니다"); + if (!isAutoRefresh) { // 자동 새로고침일 때는 에러 토스트 표시하지 않음 + toast.error("메시지를 불러오는 중 오류가 발생했습니다"); + } } finally { - setIsLoading(false); + // 항상 로딩 상태를 해제하되, 최소 200ms는 유지하여 깜빡거림 방지 + if (!isAutoRefresh) { + setTimeout(() => { + setIsLoading(false); + }, 200); + } } }; @@ -413,8 +483,8 @@ export function BuyerCommunicationDrawer({ return ( - - + + @@ -431,10 +501,10 @@ export function BuyerCommunicationDrawer({ -
+
{/* 메시지 목록 */} - - {isLoading ? ( +
+ {isLoading && comments.length === 0 ? (

메시지 로딩 중...

@@ -446,7 +516,15 @@ export function BuyerCommunicationDrawer({
) : ( -
+
+ {isLoading && ( +
+
+
+ 새로고침 중... +
+
+ )} {comments.map(comment => (
)} - +
{/* 선택된 첨부파일 표시 */} {attachments.length > 0 && ( -
+
첨부파일
{attachments.map((file, index) => ( @@ -558,7 +636,7 @@ export function BuyerCommunicationDrawer({ )} {/* 메시지 입력 영역 */} -
+