diff options
Diffstat (limited to 'lib/pq/pq-review-table-new/send-results-dialog.tsx')
| -rw-r--r-- | lib/pq/pq-review-table-new/send-results-dialog.tsx | 279 |
1 files changed, 211 insertions, 68 deletions
diff --git a/lib/pq/pq-review-table-new/send-results-dialog.tsx b/lib/pq/pq-review-table-new/send-results-dialog.tsx index 0a423f7f..3c8614cc 100644 --- a/lib/pq/pq-review-table-new/send-results-dialog.tsx +++ b/lib/pq/pq-review-table-new/send-results-dialog.tsx @@ -1,69 +1,212 @@ -"use client" - -import * as React from "react" - -import { Button } from "@/components/ui/button" -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog" - -interface SendResultsDialogProps { - isOpen: boolean - onClose: () => void - onConfirm: () => Promise<void> - selectedCount: number -} - -export function SendResultsDialog({ - isOpen, - onClose, - onConfirm, - selectedCount, -}: SendResultsDialogProps) { - const [isPending, setIsPending] = React.useState(false) - - async function handleConfirm() { - setIsPending(true) - try { - await onConfirm() - } finally { - setIsPending(false) - } - } - - return ( - <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}> - <DialogContent> - <DialogHeader> - <DialogTitle>실사 결과 발송</DialogTitle> - <DialogDescription> - 선택한 {selectedCount}개 협력업체의 실사 결과를 발송하시겠습니까? - 완료된 실사만 결과를 발송할 수 있습니다. - </DialogDescription> - </DialogHeader> - <DialogFooter> - <Button - type="button" - variant="outline" - onClick={onClose} - disabled={isPending} - > - 취소 - </Button> - <Button - type="button" - onClick={handleConfirm} - disabled={isPending} - > - {isPending ? "처리 중..." : "결과 발송"} - </Button> - </DialogFooter> - </DialogContent> - </Dialog> - ) +"use client"
+
+import * as React from "react"
+import { useForm } from "react-hook-form"
+import { zodResolver } from "@hookform/resolvers/zod"
+import * as z from "zod"
+
+
+import { Button } from "@/components/ui/button"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "@/components/ui/form"
+import { Textarea } from "@/components/ui/textarea"
+import { Badge } from "@/components/ui/badge"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Separator } from "@/components/ui/separator"
+
+// 실사 결과 발송을 위한 스키마
+const sendResultsSchema = z.object({
+ purchaseComment: z.string().optional(),
+})
+
+type SendResultsFormValues = z.infer<typeof sendResultsSchema>
+
+interface AuditResult {
+ id: number
+ vendorCode: string
+ vendorName: string
+ vendorEmail: string
+ vendorContactPerson: string
+ pqNumber: string
+ auditItem: string
+ auditFactoryAddress: string
+ auditMethod: string
+ auditResult: string
+ additionalNotes?: string
+ investigationNotes?: string
+}
+
+interface SendResultsDialogProps {
+ isOpen: boolean
+ onClose: () => void
+ onConfirm: (data: SendResultsFormValues) => Promise<void>
+ selectedCount: number
+ auditResults: AuditResult[]
+}
+
+export function SendResultsDialog({
+ isOpen,
+ onClose,
+ onConfirm,
+ selectedCount,
+ auditResults,
+}: SendResultsDialogProps) {
+ const [isPending, setIsPending] = React.useState(false)
+
+ const form = useForm<SendResultsFormValues>({
+ resolver: zodResolver(sendResultsSchema),
+ defaultValues: {
+ purchaseComment: "",
+ },
+ })
+
+ async function handleSubmit(data: SendResultsFormValues) {
+ setIsPending(true)
+ try {
+ await onConfirm(data)
+ } finally {
+ setIsPending(false)
+ }
+ }
+
+ const getResultBadgeVariant = (result: string) => {
+ if (result.includes("Pass")) return "default"
+ if (result.includes("Fail")) return "destructive"
+ return "secondary"
+ }
+
+ return (
+ <Dialog open={isOpen} onOpenChange={(open) => !open && onClose()}>
+ <DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
+ <DialogHeader>
+ <DialogTitle>실사 결과 발송</DialogTitle>
+ <DialogDescription>
+ 선택한 {selectedCount}개 협력업체의 실사 결과를 발송하시겠습니까?
+ 완료된 실사만 결과를 발송할 수 있습니다.
+ </DialogDescription>
+ </DialogHeader>
+
+ <div className="space-y-6">
+ {/* 실사 결과 미리보기 */}
+ <div>
+ <h3 className="text-lg font-semibold mb-4">실사 결과 미리보기</h3>
+ <div className="space-y-4">
+ {auditResults.map((result) => (
+ <Card key={result.id}>
+ <CardHeader>
+ <CardTitle className="flex items-center justify-between">
+ <span>{result.vendorName} ({result.vendorCode})</span>
+ <Badge variant={getResultBadgeVariant(result.auditResult)}>
+ {result.auditResult}
+ </Badge>
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-3 text-sm">
+ <div className="grid grid-cols-3 gap-4">
+ <div className="font-medium text-muted-foreground">PQ No.</div>
+ <div className="col-span-2">{result.pqNumber}</div>
+ </div>
+ <div className="grid grid-cols-3 gap-4">
+ <div className="font-medium text-muted-foreground">Vendor</div>
+ <div className="col-span-2">{result.vendorCode} | {result.vendorName}</div>
+ </div>
+ <div className="grid grid-cols-3 gap-4">
+ <div className="font-medium text-muted-foreground">수신자</div>
+ <div className="col-span-2">{result.vendorContactPerson} ({result.vendorEmail})</div>
+ </div>
+ <div className="grid grid-cols-3 gap-4">
+ <div className="font-medium text-muted-foreground">실사품목</div>
+ <div className="col-span-2">{result.auditItem}</div>
+ </div>
+ <div className="grid grid-cols-3 gap-4">
+ <div className="font-medium text-muted-foreground">실사공장주소</div>
+ <div className="col-span-2">{result.auditFactoryAddress}</div>
+ </div>
+ <div className="grid grid-cols-3 gap-4">
+ <div className="font-medium text-muted-foreground">QM 실사방법</div>
+ <div className="col-span-2">{result.auditMethod}</div>
+ </div>
+ <div className="grid grid-cols-3 gap-4">
+ <div className="font-medium text-muted-foreground">실사결과</div>
+ <div className="col-span-2">
+ <Badge variant={getResultBadgeVariant(result.auditResult)}>
+ {result.auditResult}
+ </Badge>
+ </div>
+ </div>
+ {result.investigationNotes && (
+ <div className="grid grid-cols-3 gap-4">
+ <div className="font-medium text-muted-foreground">실사합격조건</div>
+ <div className="col-span-2">{result.investigationNotes}</div>
+ </div>
+ )}
+ </div>
+ </CardContent>
+ </Card>
+ ))}
+ </div>
+ </div>
+
+ <Separator />
+
+ {/* 추가 Comment 입력 */}
+ <Form {...form}>
+ <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
+ <FormField
+ control={form.control}
+ name="purchaseComment"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel className="text-base font-medium">
+ 추가 Comment (선택사항)
+ </FormLabel>
+ <FormControl>
+ <Textarea
+ placeholder="구매 담당자가 협력업체에 추가 설명/Comment 하고자 할 때 활용합니다. 입력하지 않으면 메일 본문에서 생략됩니다."
+ className="min-h-[100px]"
+ {...field}
+ />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <DialogFooter>
+ <Button
+ type="button"
+ variant="outline"
+ onClick={onClose}
+ disabled={isPending}
+ >
+ 취소
+ </Button>
+ <Button
+ type="submit"
+ disabled={isPending}
+ >
+ {isPending ? "처리 중..." : "결과 발송"}
+ </Button>
+ </DialogFooter>
+ </form>
+ </Form>
+ </div>
+ </DialogContent>
+ </Dialog>
+ )
}
\ No newline at end of file |
