summaryrefslogtreecommitdiff
path: root/lib/basic-contract/agreement-comments/agreement-comment-list.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/basic-contract/agreement-comments/agreement-comment-list.tsx')
-rw-r--r--lib/basic-contract/agreement-comments/agreement-comment-list.tsx104
1 files changed, 86 insertions, 18 deletions
diff --git a/lib/basic-contract/agreement-comments/agreement-comment-list.tsx b/lib/basic-contract/agreement-comments/agreement-comment-list.tsx
index bad5aee5..fc64eab3 100644
--- a/lib/basic-contract/agreement-comments/agreement-comment-list.tsx
+++ b/lib/basic-contract/agreement-comments/agreement-comment-list.tsx
@@ -30,6 +30,7 @@ import {
getAgreementComments,
addAgreementComment,
deleteAgreementComment,
+ submitAgreementComment,
uploadCommentAttachment,
deleteCommentAttachment,
completeNegotiation,
@@ -65,6 +66,7 @@ export function AgreementCommentList({
const [isSaving, setIsSaving] = useState(false);
const [pendingFiles, setPendingFiles] = useState<File[]>([]); // 첨부 대기 중인 파일들
const [isCompletingNegotiation, setIsCompletingNegotiation] = useState(false);
+ const [submittingComments, setSubmittingComments] = useState<Set<number>>(new Set()); // 제출 중인 코멘트 ID
// 코멘트 로드
const loadComments = useCallback(async () => {
@@ -205,6 +207,33 @@ export function AgreementCommentList({
}
}, []); // loadComments 제거
+ // 코멘트 제출 핸들러
+ const handleSubmitComment = useCallback(async (commentId: number) => {
+ if (!confirm("이 코멘트를 제출하시겠습니까?\n제출 시 상대방에게 이메일이 발송됩니다.")) {
+ return;
+ }
+
+ setSubmittingComments(prev => new Set(prev).add(commentId));
+ try {
+ const result = await submitAgreementComment(commentId);
+ if (result.success) {
+ toast.success("코멘트가 제출되었으며 상대방에게 이메일이 발송되었습니다.");
+ await loadComments(); // 목록 새로고침
+ } else {
+ toast.error(result.error || "코멘트 제출에 실패했습니다.");
+ }
+ } catch (error) {
+ console.error('코멘트 제출 실패:', error);
+ toast.error("코멘트 제출에 실패했습니다.");
+ } finally {
+ setSubmittingComments(prev => {
+ const next = new Set(prev);
+ next.delete(commentId);
+ return next;
+ });
+ }
+ }, []); // loadComments 제거
+
// 협의 완료 핸들러
const handleCompleteNegotiation = useCallback(async () => {
if (!confirm("협의를 완료하시겠습니까?\n협의 완료 후에는 법무검토 요청이 가능합니다.")) {
@@ -525,7 +554,7 @@ export function AgreementCommentList({
<div className="space-y-3">
{/* 헤더: 작성자 정보 */}
<div className="flex items-start justify-between">
- <div className="flex items-center space-x-2">
+ <div className="flex items-center space-x-2 flex-1">
<Badge
variant="outline"
className={cn(
@@ -552,18 +581,50 @@ export function AgreementCommentList({
{comment.authorName}
</span>
)}
+ {comment.isSubmitted && (
+ <Badge
+ variant="outline"
+ className="bg-green-100 text-green-700 border-green-300 text-xs"
+ >
+ <Send className="h-3 w-3 mr-1" />
+ 제출됨
+ </Badge>
+ )}
</div>
- {!readOnly && isCommentOwner && (
- <Button
- variant="ghost"
- size="sm"
- onClick={() => handleDeleteComment(comment.id)}
- className="h-7 w-7 p-0 text-red-500 hover:text-red-700 hover:bg-red-50"
- >
- <Trash2 className="h-4 w-4" />
- </Button>
- )}
+ <div className="flex items-center space-x-1">
+ {!readOnly && isCommentOwner && !comment.isSubmitted && (
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={() => handleSubmitComment(comment.id)}
+ disabled={submittingComments.has(comment.id)}
+ className="h-7 text-xs bg-blue-50 text-blue-700 border-blue-300 hover:bg-blue-100"
+ >
+ {submittingComments.has(comment.id) ? (
+ <>
+ <Loader2 className="h-3 w-3 mr-1 animate-spin" />
+ 제출 중...
+ </>
+ ) : (
+ <>
+ <Send className="h-3 w-3 mr-1" />
+ 제출
+ </>
+ )}
+ </Button>
+ )}
+ {!readOnly && isCommentOwner && (
+ <Button
+ variant="ghost"
+ size="sm"
+ onClick={() => handleDeleteComment(comment.id)}
+ className="h-7 w-7 p-0 text-red-500 hover:text-red-700 hover:bg-red-50"
+ >
+ <Trash2 className="h-4 w-4" />
+ </Button>
+ )}
+ </div>
</div>
{/* 코멘트 내용 */}
@@ -667,16 +728,23 @@ export function AgreementCommentList({
</div>
)}
- {/* 푸터: 작성일시 */}
+ {/* 푸터: 작성일시 및 제출일시 */}
<div className="flex items-center justify-between text-xs text-gray-500 pt-2 border-t border-gray-200">
- <span>
- 작성일: {formatDateTime(comment.createdAt, "KR")}
- </span>
- {comment.updatedAt && comment.updatedAt.getTime() !== comment.createdAt.getTime() && (
+ <div className="flex items-center space-x-3">
<span>
- 수정일: {formatDateTime(comment.updatedAt, "KR")}
+ 작성일: {formatDateTime(comment.createdAt, "KR")}
</span>
- )}
+ {comment.updatedAt && comment.updatedAt.getTime() !== comment.createdAt.getTime() && (
+ <span>
+ 수정일: {formatDateTime(comment.updatedAt, "KR")}
+ </span>
+ )}
+ {comment.isSubmitted && comment.submittedAt && (
+ <span className="text-green-600 font-medium">
+ 제출일: {formatDateTime(comment.submittedAt, "KR")}
+ </span>
+ )}
+ </div>
</div>
</div>
</CardContent>