summaryrefslogtreecommitdiff
path: root/lib/techsales-rfq/vendor-response/detail/communication-tab.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-05-28 19:03:21 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-05-28 19:03:21 +0000
commit5036cf2908792cef45f06256e71f10920f647f49 (patch)
tree3116e7419e872d45025d1d48e6ddaffe2ba2dd38 /lib/techsales-rfq/vendor-response/detail/communication-tab.tsx
parent7ae037e9c2fc0be1fe68cecb461c5e1e837cb0da (diff)
(김준회) 기술영업 조선 RFQ (SHI/벤더)
Diffstat (limited to 'lib/techsales-rfq/vendor-response/detail/communication-tab.tsx')
-rw-r--r--lib/techsales-rfq/vendor-response/detail/communication-tab.tsx215
1 files changed, 215 insertions, 0 deletions
diff --git a/lib/techsales-rfq/vendor-response/detail/communication-tab.tsx b/lib/techsales-rfq/vendor-response/detail/communication-tab.tsx
new file mode 100644
index 00000000..0332232c
--- /dev/null
+++ b/lib/techsales-rfq/vendor-response/detail/communication-tab.tsx
@@ -0,0 +1,215 @@
+"use client"
+
+import * as React from "react"
+import { useState } from "react"
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Textarea } from "@/components/ui/textarea"
+import { Badge } from "@/components/ui/badge"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { Separator } from "@/components/ui/separator"
+import { Avatar, AvatarFallback } from "@/components/ui/avatar"
+import { Send, MessageCircle } from "lucide-react"
+import { formatDateTime } from "@/lib/utils"
+import { toast } from "sonner"
+
+interface CommunicationTabProps {
+ quotation: {
+ id: number
+ rfq: {
+ id: number
+ rfqCode: string | null
+ createdByUser?: {
+ id: number
+ name: string | null
+ email: string | null
+ } | null
+ } | null
+ vendor: {
+ vendorName: string
+ } | null
+ }
+}
+
+// 임시 코멘트 데이터 (실제로는 API에서 가져와야 함)
+const MOCK_COMMENTS = [
+ {
+ id: 1,
+ content: "안녕하세요. 해당 자재에 대한 견적 요청 드립니다. 납기일은 언제까지 가능한지 문의드립니다.",
+ createdAt: new Date("2024-01-15T09:00:00"),
+ author: {
+ name: "김구매",
+ email: "buyer@company.com",
+ role: "구매담당자"
+ }
+ },
+ {
+ id: 2,
+ content: "안녕하세요. 견적 요청 확인했습니다. 해당 자재의 경우 약 2주 정도의 제작 기간이 필요합니다. 상세한 견적은 내일까지 제출하겠습니다.",
+ createdAt: new Date("2024-01-15T14:30:00"),
+ author: {
+ name: "이벤더",
+ email: "vendor@supplier.com",
+ role: "벤더"
+ }
+ },
+ {
+ id: 3,
+ content: "감사합니다. 추가로 품질 인증서도 함께 제출 가능한지 확인 부탁드립니다.",
+ createdAt: new Date("2024-01-16T10:15:00"),
+ author: {
+ name: "김구매",
+ email: "buyer@company.com",
+ role: "구매담당자"
+ }
+ }
+]
+
+export function CommunicationTab({ quotation }: CommunicationTabProps) {
+ const [newComment, setNewComment] = useState("")
+ const [isLoading, setIsLoading] = useState(false)
+ const [comments, setComments] = useState(MOCK_COMMENTS)
+
+ const handleSendComment = async () => {
+ if (!newComment.trim()) {
+ toast.error("메시지를 입력해주세요.")
+ return
+ }
+
+ setIsLoading(true)
+ try {
+ // TODO: API 호출로 코멘트 전송
+ const newCommentData = {
+ id: comments.length + 1,
+ content: newComment,
+ createdAt: new Date(),
+ author: {
+ name: "현재사용자", // 실제로는 세션에서 가져와야 함
+ email: "current@user.com",
+ role: "벤더"
+ }
+ }
+
+ setComments([...comments, newCommentData])
+ setNewComment("")
+ toast.success("메시지가 전송되었습니다.")
+ } catch {
+ toast.error("메시지 전송 중 오류가 발생했습니다.")
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ const getAuthorInitials = (name: string) => {
+ return name
+ .split(" ")
+ .map(word => word[0])
+ .join("")
+ .toUpperCase()
+ .slice(0, 2)
+ }
+
+ const getRoleBadgeVariant = (role: string) => {
+ return role === "구매담당자" ? "default" : "secondary"
+ }
+
+ return (
+ <div className="h-full flex flex-col">
+ {/* 헤더 */}
+ <Card className="mb-4">
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <MessageCircle className="h-5 w-5" />
+ 커뮤니케이션
+ </CardTitle>
+ <CardDescription>
+ RFQ {quotation.rfq?.rfqCode || "미할당"}에 대한 구매담당자와의 커뮤니케이션
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <div className="flex items-center gap-4 text-sm text-muted-foreground">
+ <span>구매담당자: {quotation.rfq?.createdByUser?.name || "N/A"}</span>
+ <span>•</span>
+ <span>벤더: {quotation.vendor?.vendorName}</span>
+ </div>
+ </CardContent>
+ </Card>
+
+ {/* 메시지 목록 */}
+ <Card className="flex-1 flex flex-col min-h-0">
+ <CardHeader>
+ <CardTitle className="text-lg">메시지 ({comments.length})</CardTitle>
+ </CardHeader>
+ <CardContent className="flex-1 flex flex-col min-h-0">
+ <ScrollArea className="flex-1 pr-4">
+ <div className="space-y-4">
+ {comments.length === 0 ? (
+ <div className="text-center py-8 text-muted-foreground">
+ <MessageCircle className="h-12 w-12 mx-auto mb-4 opacity-50" />
+ <p>아직 메시지가 없습니다.</p>
+ <p className="text-sm">첫 번째 메시지를 보내보세요.</p>
+ </div>
+ ) : (
+ comments.map((comment) => (
+ <div key={comment.id} className="flex gap-3">
+ <Avatar className="h-8 w-8 mt-1">
+ <AvatarFallback className="text-xs">
+ {getAuthorInitials(comment.author.name)}
+ </AvatarFallback>
+ </Avatar>
+ <div className="flex-1 space-y-2">
+ <div className="flex items-center gap-2">
+ <span className="font-medium text-sm">{comment.author.name}</span>
+ <Badge variant={getRoleBadgeVariant(comment.author.role)} className="text-xs">
+ {comment.author.role}
+ </Badge>
+ <span className="text-xs text-muted-foreground">
+ {formatDateTime(comment.createdAt)}
+ </span>
+ </div>
+ <div className="bg-muted p-3 rounded-lg text-sm">
+ {comment.content}
+ </div>
+ </div>
+ </div>
+ ))
+ )}
+ </div>
+ </ScrollArea>
+
+ <Separator className="my-4" />
+
+ {/* 새 메시지 입력 */}
+ <div className="space-y-3">
+ <Textarea
+ placeholder="메시지를 입력하세요..."
+ value={newComment}
+ onChange={(e) => setNewComment(e.target.value)}
+ rows={3}
+ className="resize-none"
+ onKeyDown={(e) => {
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
+ e.preventDefault()
+ handleSendComment()
+ }
+ }}
+ />
+ <div className="flex justify-between items-center">
+ <div className="text-xs text-muted-foreground">
+ Ctrl + Enter로 빠른 전송
+ </div>
+ <Button
+ onClick={handleSendComment}
+ disabled={isLoading || !newComment.trim()}
+ size="sm"
+ >
+ <Send className="h-4 w-4 mr-2" />
+ 전송
+ </Button>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ </div>
+ )
+} \ No newline at end of file