summaryrefslogtreecommitdiff
path: root/lib/site-visit/site-visit-detail-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/site-visit/site-visit-detail-dialog.tsx')
-rw-r--r--lib/site-visit/site-visit-detail-dialog.tsx520
1 files changed, 260 insertions, 260 deletions
diff --git a/lib/site-visit/site-visit-detail-dialog.tsx b/lib/site-visit/site-visit-detail-dialog.tsx
index 7788454a..634d2aef 100644
--- a/lib/site-visit/site-visit-detail-dialog.tsx
+++ b/lib/site-visit/site-visit-detail-dialog.tsx
@@ -1,261 +1,261 @@
-"use client"
-
-import * as React from "react"
-import { format } from "date-fns"
-import { ko } from "date-fns/locale"
-import { FileText, Download } from "lucide-react"
-import { toast } from "sonner"
-
-import { Button } from "@/components/ui/button"
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog"
-import { Separator } from "@/components/ui/separator"
-import { formatDate } from "../utils"
-
-interface SiteVisitRequest {
- id: number
- investigationId: number
- requesterId: number | null
- inspectionDuration: string | null
- requestedStartDate: Date | null
- requestedEndDate: Date | null
- shiAttendees: Record<string, unknown> | null
- shiAttendeeDetails?: string | null
- vendorRequests: Record<string, unknown> | null
- additionalRequests: string | null
- status: string
- sentAt: Date | null
- createdAt: Date
- updatedAt: Date
-
- // 실사정보
- investigationMethod: string | null // QM담당자가 작성한 실사방법
- investigationAddress: string | null
- investigationNotes: string | null
- forecastedAt: Date | null
- actualAt: Date | null
- result: string | null
- resultNotes: string | null
-
- // PQ 정보
- pqItems: string | null | Array<{itemCode: string, itemName: string}>
-
- // 요청자 정보
- requesterName: string | null
- requesterEmail: string | null
- requesterTitle: string | null
-
- // QM 매니저 정보
- qmManagerName: string | null
- qmManagerEmail: string | null
- qmManagerTitle: string | null
-
- // 협력업체 정보
- vendorInfo?: {
- id: number
- siteVisitRequestId: number
- factoryName: string
- factoryLocation: string
- factoryAddress: string
- factoryPicName: string
- factoryPicPhone: string
- factoryPicEmail: string
- factoryDirections: string | null
- accessProcedure: string | null
- hasAttachments: boolean
- otherInfo: string | null
- submittedAt: Date
- submittedBy: number
- createdAt: Date
- updatedAt: Date
- } | null
-
- // SHI 첨부파일
- shiAttachments?: Array<{
- id: number
- siteVisitRequestId: number
- vendorSiteVisitInfoId: number | null
- fileName: string
- originalFileName: string
- filePath: string
- fileSize: number
- mimeType: string
- createdAt: Date
- updatedAt: Date
- }> | null
-}
-
-interface SiteVisitDetailDialogProps {
- isOpen: boolean
- onOpenChange: (open: boolean) => void
- selectedRequest: SiteVisitRequest | null
-}
-
-export function SiteVisitDetailDialog({
- isOpen,
- onOpenChange,
- selectedRequest,
-}: SiteVisitDetailDialogProps) {
-
- return (
- <Dialog open={isOpen} onOpenChange={onOpenChange}>
- <DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
- <DialogHeader>
- <DialogTitle>방문실사 상세 정보</DialogTitle>
- <DialogDescription>
- 작성한 방문실사 정보의 상세 내용입니다.
- </DialogDescription>
- </DialogHeader>
-
- {selectedRequest && (
- <div className="space-y-6">
- {/* 기본 정보 */}
-
- {/* 협력업체 정보 */}
- {selectedRequest.vendorInfo && (
- <>
- <Separator />
- <div>
- <h3 className="font-semibold mb-2">작성한 협력업체 정보</h3>
- <div className="bg-muted p-4 rounded-md">
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
- <div className="space-y-4">
- <div>
- <h4 className="font-semibold mb-2">공장 기본 정보</h4>
- <div className="space-y-2 text-sm">
- <div><span className="font-medium">공장명:</span> {selectedRequest.vendorInfo.factoryName}</div>
- <div><span className="font-medium">공장위치:</span> {selectedRequest.vendorInfo.factoryLocation}</div>
- <div><span className="font-medium">공장주소:</span> {selectedRequest.vendorInfo.factoryAddress}</div>
- </div>
- </div>
-
- <div>
- <h4 className="font-semibold mb-2">공장 담당자 정보</h4>
- <div className="space-y-2 text-sm">
- <div><span className="font-medium">이름:</span> {selectedRequest.vendorInfo.factoryPicName}</div>
- <div><span className="font-medium">전화번호:</span> {selectedRequest.vendorInfo.factoryPicPhone}</div>
- <div><span className="font-medium">이메일:</span> {selectedRequest.vendorInfo.factoryPicEmail}</div>
- </div>
- </div>
- </div>
-
- <div className="space-y-4">
- {selectedRequest.vendorInfo.factoryDirections && (
- <div>
- <h4 className="font-semibold mb-2">공장 가는 법</h4>
- <div className="bg-background p-3 rounded-md">
- <p className="text-sm whitespace-pre-wrap">{selectedRequest.vendorInfo.factoryDirections}</p>
- </div>
- </div>
- )}
-
- {selectedRequest.vendorInfo.accessProcedure && (
- <div>
- <h4 className="font-semibold mb-2">공장 출입절차</h4>
- <div className="bg-background p-3 rounded-md">
- <p className="text-sm whitespace-pre-wrap">{selectedRequest.vendorInfo.accessProcedure}</p>
- </div>
- </div>
- )}
- </div>
- </div>
-
- {/* 기타 정보 */}
- {selectedRequest.vendorInfo.otherInfo && (
- <div className="mt-6">
- <h4 className="font-semibold mb-2">기타 정보</h4>
- <div className="bg-background p-3 rounded-md">
- <p className="text-sm whitespace-pre-wrap">{selectedRequest.vendorInfo.otherInfo}</p>
- </div>
- </div>
- )}
-
- {/* 제출 정보 */}
- <div className="mt-6">
- <h4 className="font-semibold mb-2">제출 정보</h4>
- <div className="space-y-2 text-sm">
- <div><span className="font-medium">제출일:</span> {formatDate(selectedRequest.vendorInfo.submittedAt, "kr")}</div>
- <div><span className="font-medium">첨부파일:</span> {selectedRequest.vendorInfo.hasAttachments ? "있음" : "없음"}</div>
- </div>
- </div>
- </div>
- </div>
- </>
- )}
-
- <Separator />
-
- {/* SHI 첨부파일 */}
- {selectedRequest.shiAttachments && selectedRequest.shiAttachments.length > 0 && (
- <>
- <div>
- <h3 className="font-semibold mb-2">SHI 첨부파일 ({selectedRequest.shiAttachments.length}개)</h3>
- <div className="bg-muted p-4 rounded-md">
- <div className="space-y-2">
- {selectedRequest.shiAttachments.map((attachment) => (
- <div key={attachment.id} className="flex items-center justify-between p-2 border rounded-md">
- <div className="flex items-center space-x-2 flex-1 min-w-0">
- <FileText className="h-4 w-4 text-muted-foreground" />
- <span className="text-sm truncate">{attachment.originalFileName}</span>
- <span className="text-xs text-muted-foreground">
- ({Math.round((attachment.fileSize || 0) / 1024)}KB)
- </span>
- </div>
- <Button
- type="button"
- variant="outline"
- size="sm"
- className="p-2"
- onClick={async () => {
- try {
- const { downloadFile } = await import('@/lib/file-download')
- await downloadFile(attachment.filePath, attachment.originalFileName || '', {
- showToast: true,
- onError: (error) => {
- console.error('다운로드 오류:', error)
- toast.error("다운로드 실패: " + error)
- },
- onSuccess: (fileName, fileSize) => {
- console.log(`다운로드 성공: ${fileName} (${fileSize} bytes)`)
- }
- })
- } catch (error) {
- console.error('다운로드 오류:', error)
- toast.error("파일 다운로드 중 오류가 발생했습니다.")
- }
- }}
- aria-label="파일 다운로드"
- >
- <Download className="h-4 w-4" />
- </Button>
- </div>
- ))}
- </div>
- </div>
- </div>
- </>
- )}
-
- {/* 추가 요청사항 */}
- {selectedRequest.additionalRequests && (
- <>
- <div>
- <h3 className="font-semibold mb-2">SHI 추가 요청사항</h3>
- <div className="bg-muted p-4 rounded-md">
- <p className="text-sm whitespace-pre-wrap">{selectedRequest.additionalRequests}</p>
- </div>
- </div>
- <Separator />
- </>
- )}
- </div>
- )}
- </DialogContent>
- </Dialog>
- )
+"use client"
+
+import * as React from "react"
+import { format } from "date-fns"
+import { ko } from "date-fns/locale"
+import { FileText, Download } from "lucide-react"
+import { toast } from "sonner"
+
+import { Button } from "@/components/ui/button"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Separator } from "@/components/ui/separator"
+import { formatDate } from "../utils"
+
+interface SiteVisitRequest {
+ id: number
+ investigationId: number
+ requesterId: number | null
+ inspectionDuration: string | null
+ requestedStartDate: Date | null
+ requestedEndDate: Date | null
+ shiAttendees: Record<string, unknown> | null
+ shiAttendeeDetails?: string | null
+ vendorRequests: Record<string, unknown> | null
+ additionalRequests: string | null
+ status: string
+ sentAt: Date | null
+ createdAt: Date
+ updatedAt: Date
+
+ // 실사정보
+ investigationMethod: string | null // QM담당자가 작성한 실사방법
+ investigationAddress: string | null
+ investigationNotes: string | null
+ forecastedAt: Date | null
+ actualAt: Date | null
+ result: string | null
+ resultNotes: string | null
+
+ // PQ 정보
+ pqItems: string | null | Array<{itemCode: string, itemName: string}>
+
+ // 요청자 정보
+ requesterName: string | null
+ requesterEmail: string | null
+ requesterTitle: string | null
+
+ // QM 매니저 정보
+ qmManagerName: string | null
+ qmManagerEmail: string | null
+ qmManagerTitle: string | null
+
+ // 협력업체 정보
+ vendorInfo?: {
+ id: number
+ siteVisitRequestId: number
+ factoryName: string
+ factoryLocation: string
+ factoryAddress: string
+ factoryPicName: string
+ factoryPicPhone: string
+ factoryPicEmail: string
+ factoryDirections: string | null
+ accessProcedure: string | null
+ hasAttachments: boolean
+ otherInfo: string | null
+ submittedAt: Date
+ submittedBy: number
+ createdAt: Date
+ updatedAt: Date
+ } | null
+
+ // SHI 첨부파일
+ shiAttachments?: Array<{
+ id: number
+ siteVisitRequestId: number
+ vendorSiteVisitInfoId: number | null
+ fileName: string
+ originalFileName: string
+ filePath: string
+ fileSize: number
+ mimeType: string
+ createdAt: Date
+ updatedAt: Date
+ }> | null
+}
+
+interface SiteVisitDetailDialogProps {
+ isOpen: boolean
+ onOpenChange: (open: boolean) => void
+ selectedRequest: SiteVisitRequest | null
+}
+
+export function SiteVisitDetailDialog({
+ isOpen,
+ onOpenChange,
+ selectedRequest,
+}: SiteVisitDetailDialogProps) {
+
+ return (
+ <Dialog open={isOpen} onOpenChange={onOpenChange}>
+ <DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
+ <DialogHeader>
+ <DialogTitle>방문실사 상세 정보</DialogTitle>
+ <DialogDescription>
+ 작성한 방문실사 정보의 상세 내용입니다.
+ </DialogDescription>
+ </DialogHeader>
+
+ {selectedRequest && (
+ <div className="space-y-6">
+ {/* 기본 정보 */}
+
+ {/* 협력업체 정보 */}
+ {selectedRequest.vendorInfo && (
+ <>
+ <Separator />
+ <div>
+ <h3 className="font-semibold mb-2">작성한 협력업체 정보</h3>
+ <div className="bg-muted p-4 rounded-md">
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
+ <div className="space-y-4">
+ <div>
+ <h4 className="font-semibold mb-2">공장 기본 정보</h4>
+ <div className="space-y-2 text-sm">
+ <div><span className="font-medium">공장명:</span> {selectedRequest.vendorInfo.factoryName}</div>
+ <div><span className="font-medium">공장위치:</span> {selectedRequest.vendorInfo.factoryLocation}</div>
+ <div><span className="font-medium">공장주소:</span> {selectedRequest.vendorInfo.factoryAddress}</div>
+ </div>
+ </div>
+
+ <div>
+ <h4 className="font-semibold mb-2">공장 담당자 정보</h4>
+ <div className="space-y-2 text-sm">
+ <div><span className="font-medium">이름:</span> {selectedRequest.vendorInfo.factoryPicName}</div>
+ <div><span className="font-medium">전화번호:</span> {selectedRequest.vendorInfo.factoryPicPhone}</div>
+ <div><span className="font-medium">이메일:</span> {selectedRequest.vendorInfo.factoryPicEmail}</div>
+ </div>
+ </div>
+ </div>
+
+ <div className="space-y-4">
+ {selectedRequest.vendorInfo.factoryDirections && (
+ <div>
+ <h4 className="font-semibold mb-2">공장 가는 법</h4>
+ <div className="bg-background p-3 rounded-md">
+ <p className="text-sm whitespace-pre-wrap">{selectedRequest.vendorInfo.factoryDirections}</p>
+ </div>
+ </div>
+ )}
+
+ {selectedRequest.vendorInfo.accessProcedure && (
+ <div>
+ <h4 className="font-semibold mb-2">공장 출입절차</h4>
+ <div className="bg-background p-3 rounded-md">
+ <p className="text-sm whitespace-pre-wrap">{selectedRequest.vendorInfo.accessProcedure}</p>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+
+ {/* 기타 정보 */}
+ {selectedRequest.vendorInfo.otherInfo && (
+ <div className="mt-6">
+ <h4 className="font-semibold mb-2">기타 정보</h4>
+ <div className="bg-background p-3 rounded-md">
+ <p className="text-sm whitespace-pre-wrap">{selectedRequest.vendorInfo.otherInfo}</p>
+ </div>
+ </div>
+ )}
+
+ {/* 제출 정보 */}
+ <div className="mt-6">
+ <h4 className="font-semibold mb-2">제출 정보</h4>
+ <div className="space-y-2 text-sm">
+ <div><span className="font-medium">제출일:</span> {formatDate(selectedRequest.vendorInfo.submittedAt, "kr")}</div>
+ <div><span className="font-medium">첨부파일:</span> {selectedRequest.vendorInfo.hasAttachments ? "있음" : "없음"}</div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </>
+ )}
+
+ <Separator />
+
+ {/* SHI 첨부파일 */}
+ {selectedRequest.shiAttachments && selectedRequest.shiAttachments.length > 0 && (
+ <>
+ <div>
+ <h3 className="font-semibold mb-2">SHI 첨부파일 ({selectedRequest.shiAttachments.length}개)</h3>
+ <div className="bg-muted p-4 rounded-md">
+ <div className="space-y-2">
+ {selectedRequest.shiAttachments.map((attachment) => (
+ <div key={attachment.id} className="flex items-center justify-between p-2 border rounded-md">
+ <div className="flex items-center space-x-2 flex-1 min-w-0">
+ <FileText className="h-4 w-4 text-muted-foreground" />
+ <span className="text-sm truncate">{attachment.originalFileName}</span>
+ <span className="text-xs text-muted-foreground">
+ ({Math.round((attachment.fileSize || 0) / 1024)}KB)
+ </span>
+ </div>
+ <Button
+ type="button"
+ variant="outline"
+ size="sm"
+ className="p-2"
+ onClick={async () => {
+ try {
+ const { downloadFile } = await import('@/lib/file-download')
+ await downloadFile(attachment.filePath, attachment.originalFileName || '', {
+ showToast: true,
+ onError: (error) => {
+ console.error('다운로드 오류:', error)
+ toast.error("다운로드 실패: " + error)
+ },
+ onSuccess: (fileName, fileSize) => {
+ console.log(`다운로드 성공: ${fileName} (${fileSize} bytes)`)
+ }
+ })
+ } catch (error) {
+ console.error('다운로드 오류:', error)
+ toast.error("파일 다운로드 중 오류가 발생했습니다.")
+ }
+ }}
+ aria-label="파일 다운로드"
+ >
+ <Download className="h-4 w-4" />
+ </Button>
+ </div>
+ ))}
+ </div>
+ </div>
+ </div>
+ </>
+ )}
+
+ {/* 추가 요청사항 */}
+ {selectedRequest.additionalRequests && (
+ <>
+ <div>
+ <h3 className="font-semibold mb-2">SHI 추가 요청사항</h3>
+ <div className="bg-muted p-4 rounded-md">
+ <p className="text-sm whitespace-pre-wrap">{selectedRequest.additionalRequests}</p>
+ </div>
+ </div>
+ <Separator />
+ </>
+ )}
+ </div>
+ )}
+ </DialogContent>
+ </Dialog>
+ )
} \ No newline at end of file