summaryrefslogtreecommitdiff
path: root/lib/legal-review/status/create-legal-work-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/legal-review/status/create-legal-work-dialog.tsx')
-rw-r--r--lib/legal-review/status/create-legal-work-dialog.tsx506
1 files changed, 0 insertions, 506 deletions
diff --git a/lib/legal-review/status/create-legal-work-dialog.tsx b/lib/legal-review/status/create-legal-work-dialog.tsx
deleted file mode 100644
index 0ee1c430..00000000
--- a/lib/legal-review/status/create-legal-work-dialog.tsx
+++ /dev/null
@@ -1,506 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { useRouter } from "next/navigation"
-import { useForm } from "react-hook-form"
-import { zodResolver } from "@hookform/resolvers/zod"
-import * as z from "zod"
-import { Loader2, Check, ChevronsUpDown, Calendar, User } from "lucide-react"
-import { toast } from "sonner"
-
-import { Button } from "@/components/ui/button"
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog"
-import {
- Form,
- FormControl,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form"
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select"
-import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
-} from "@/components/ui/command"
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover"
-import { Input } from "@/components/ui/input"
-import { Badge } from "@/components/ui/badge"
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
-import { Switch } from "@/components/ui/switch"
-import { cn } from "@/lib/utils"
-import { getVendorsForSelection } from "@/lib/b-rfq/service"
-import { createLegalWork } from "../service"
-import { useSession } from "next-auth/react"
-
-interface CreateLegalWorkDialogProps {
- open: boolean
- onOpenChange: (open: boolean) => void
- onSuccess?: () => void
- onDataChange?: () => void
-}
-
-// legalWorks 테이블에 맞춘 단순화된 폼 스키마
-const createLegalWorkSchema = z.object({
- category: z.enum(["CP", "GTC", "기타"]),
- vendorId: z.number().min(1, "벤더를 선택해주세요"),
- isUrgent: z.boolean().default(false),
- requestDate: z.string().min(1, "답변요청일을 선택해주세요"),
- expectedAnswerDate: z.string().optional(),
- reviewer: z.string().min(1, "검토요청자를 입력해주세요"),
-})
-
-type CreateLegalWorkFormValues = z.infer<typeof createLegalWorkSchema>
-
-interface Vendor {
- id: number
- vendorName: string
- vendorCode: string
- country: string
- taxId: string
- status: string
-}
-
-export function CreateLegalWorkDialog({
- open,
- onOpenChange,
- onSuccess,
- onDataChange
-}: CreateLegalWorkDialogProps) {
- const router = useRouter()
- const [isSubmitting, setIsSubmitting] = React.useState(false)
- const [vendors, setVendors] = React.useState<Vendor[]>([])
- const [vendorsLoading, setVendorsLoading] = React.useState(false)
- const [vendorOpen, setVendorOpen] = React.useState(false)
- const { data: session } = useSession()
-
- const userName = React.useMemo(() => {
- return session?.user?.name || "";
- }, [session]);
-
- const userEmail = React.useMemo(() => {
- return session?.user?.email || "";
- }, [session]);
-
- const defaultReviewer = React.useMemo(() => {
- if (userName && userEmail) {
- return `${userName} (${userEmail})`;
- } else if (userName) {
- return userName;
- } else if (userEmail) {
- return userEmail;
- }
- return "";
- }, [userName, userEmail]);
-
- const loadVendors = React.useCallback(async () => {
- setVendorsLoading(true)
- try {
- const vendorList = await getVendorsForSelection()
- setVendors(vendorList)
- } catch (error) {
- console.error("Failed to load vendors:", error)
- toast.error("벤더 목록을 불러오는데 실패했습니다.")
- } finally {
- setVendorsLoading(false)
- }
- }, [])
-
- // 오늘 날짜 + 7일 후를 기본 답변요청일로 설정
- const getDefaultRequestDate = () => {
- const date = new Date()
- date.setDate(date.getDate() + 7)
- return date.toISOString().split('T')[0]
- }
-
- // 답변요청일 + 3일 후를 기본 답변예정일로 설정
- const getDefaultExpectedDate = (requestDate: string) => {
- if (!requestDate) return ""
- const date = new Date(requestDate)
- date.setDate(date.getDate() + 3)
- return date.toISOString().split('T')[0]
- }
-
- const form = useForm<CreateLegalWorkFormValues>({
- resolver: zodResolver(createLegalWorkSchema),
- defaultValues: {
- category: "CP",
- vendorId: 0,
- isUrgent: false,
- requestDate: getDefaultRequestDate(),
- expectedAnswerDate: "",
- reviewer: defaultReviewer,
- },
- })
-
- React.useEffect(() => {
- if (open) {
- loadVendors()
- }
- }, [open, loadVendors])
-
- // 세션 정보가 로드되면 검토요청자 필드 업데이트
- React.useEffect(() => {
- if (defaultReviewer) {
- form.setValue("reviewer", defaultReviewer)
- }
- }, [defaultReviewer, form])
-
- // 답변요청일 변경시 답변예정일 자동 설정
- const requestDate = form.watch("requestDate")
- React.useEffect(() => {
- if (requestDate) {
- const expectedDate = getDefaultExpectedDate(requestDate)
- form.setValue("expectedAnswerDate", expectedDate)
- }
- }, [requestDate, form])
-
- // 폼 제출 - 서버 액션 적용
- async function onSubmit(data: CreateLegalWorkFormValues) {
- console.log("Form submitted with data:", data)
- setIsSubmitting(true)
-
- try {
- // legalWorks 테이블에 맞춘 데이터 구조
- const legalWorkData = {
- ...data,
- // status는 서버에서 "검토요청"으로 설정
- // consultationDate는 서버에서 오늘 날짜로 설정
- // hasAttachment는 서버에서 false로 설정
- }
-
- const result = await createLegalWork(legalWorkData)
-
- if (result.success) {
- toast.success(result.data?.message || "법무업무가 성공적으로 등록되었습니다.")
- onOpenChange(false)
- form.reset({
- category: "CP",
- vendorId: 0,
- isUrgent: false,
- requestDate: getDefaultRequestDate(),
- expectedAnswerDate: "",
- reviewer: defaultReviewer,
- })
- onSuccess?.()
- onDataChange?.()
- router.refresh()
- } else {
- toast.error(result.error || "등록 중 오류가 발생했습니다.")
- }
- } catch (error) {
- console.error("Error creating legal work:", error)
- toast.error("등록 중 오류가 발생했습니다.")
- } finally {
- setIsSubmitting(false)
- }
- }
-
- // 다이얼로그 닫기 핸들러
- const handleOpenChange = (open: boolean) => {
- onOpenChange(open)
- if (!open) {
- form.reset({
- category: "CP",
- vendorId: 0,
- isUrgent: false,
- requestDate: getDefaultRequestDate(),
- expectedAnswerDate: "",
- reviewer: defaultReviewer,
- })
- }
- }
-
- // 선택된 벤더 정보
- const selectedVendor = vendors.find(v => v.id === form.watch("vendorId"))
-
- return (
- <Dialog open={open} onOpenChange={handleOpenChange}>
- <DialogContent className="max-w-2xl h-[80vh] p-0 flex flex-col">
- {/* 고정 헤더 */}
- <div className="flex-shrink-0 p-6 border-b">
- <DialogHeader>
- <DialogTitle>법무업무 신규 등록</DialogTitle>
- <DialogDescription>
- 새로운 법무업무를 등록합니다. 상세한 검토 요청은 등록 후 별도로 진행할 수 있습니다.
- </DialogDescription>
- </DialogHeader>
- </div>
-
- <Form {...form}>
- <form
- onSubmit={form.handleSubmit(onSubmit)}
- className="flex flex-col flex-1 min-h-0"
- >
- {/* 스크롤 가능한 콘텐츠 영역 */}
- <div className="flex-1 overflow-y-auto p-6">
- <div className="space-y-6">
- {/* 기본 정보 */}
- <Card>
- <CardHeader>
- <CardTitle className="text-lg">기본 정보</CardTitle>
- </CardHeader>
- <CardContent className="space-y-4">
- <div className="grid grid-cols-2 gap-4">
- {/* 구분 */}
- <FormField
- control={form.control}
- name="category"
- render={({ field }) => (
- <FormItem>
- <FormLabel>구분</FormLabel>
- <Select onValueChange={field.onChange} defaultValue={field.value}>
- <FormControl>
- <SelectTrigger>
- <SelectValue placeholder="구분 선택" />
- </SelectTrigger>
- </FormControl>
- <SelectContent>
- <SelectItem value="CP">CP</SelectItem>
- <SelectItem value="GTC">GTC</SelectItem>
- <SelectItem value="기타">기타</SelectItem>
- </SelectContent>
- </Select>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* 긴급여부 */}
- <FormField
- control={form.control}
- name="isUrgent"
- render={({ field }) => (
- <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
- <div className="space-y-0.5">
- <FormLabel className="text-base">긴급 요청</FormLabel>
- <div className="text-sm text-muted-foreground">
- 긴급 처리가 필요한 경우 체크
- </div>
- </div>
- <FormControl>
- <Switch
- checked={field.value}
- onCheckedChange={field.onChange}
- />
- </FormControl>
- </FormItem>
- )}
- />
- </div>
-
- {/* 벤더 선택 */}
- <FormField
- control={form.control}
- name="vendorId"
- render={({ field }) => (
- <FormItem>
- <FormLabel>벤더</FormLabel>
- <Popover open={vendorOpen} onOpenChange={setVendorOpen}>
- <PopoverTrigger asChild>
- <FormControl>
- <Button
- variant="outline"
- role="combobox"
- aria-expanded={vendorOpen}
- className="w-full justify-between"
- >
- {selectedVendor ? (
- <span className="flex items-center gap-2">
- <Badge variant="outline">{selectedVendor.vendorCode}</Badge>
- {selectedVendor.vendorName}
- </span>
- ) : (
- "벤더 선택..."
- )}
- <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
- </Button>
- </FormControl>
- </PopoverTrigger>
- <PopoverContent className="w-full p-0" align="start">
- <Command>
- <CommandInput placeholder="벤더 검색..." />
- <CommandList
- onWheel={(e) => {
- e.stopPropagation(); // 이벤트 전파 차단
- const target = e.currentTarget;
- target.scrollTop += e.deltaY; // 직접 스크롤 처리
- }}>
- <CommandEmpty>검색 결과가 없습니다.</CommandEmpty>
- <CommandGroup>
- {vendors.map((vendor) => (
- <CommandItem
- key={vendor.id}
- value={`${vendor.vendorCode} ${vendor.vendorName}`}
- onSelect={() => {
- field.onChange(vendor.id)
- setVendorOpen(false)
- }}
- >
- <Check
- className={cn(
- "mr-2 h-4 w-4",
- vendor.id === field.value ? "opacity-100" : "opacity-0"
- )}
- />
- <div className="flex items-center gap-2">
- <Badge variant="outline">{vendor.vendorCode}</Badge>
- <span>{vendor.vendorName}</span>
- </div>
- </CommandItem>
- ))}
- </CommandGroup>
- </CommandList>
- </Command>
- </PopoverContent>
- </Popover>
- <FormMessage />
- </FormItem>
- )}
- />
- </CardContent>
- </Card>
-
- {/* 담당자 및 일정 정보 */}
- <Card>
- <CardHeader>
- <CardTitle className="text-lg flex items-center gap-2">
- <Calendar className="h-5 w-5" />
- 담당자 및 일정
- </CardTitle>
- </CardHeader>
- <CardContent className="space-y-4">
- {/* 검토요청자 */}
- <FormField
- control={form.control}
- name="reviewer"
- render={({ field }) => (
- <FormItem>
- <FormLabel className="flex items-center gap-2">
- <User className="h-4 w-4" />
- 검토요청자
- </FormLabel>
- <FormControl>
- <Input
- placeholder={defaultReviewer || "검토요청자 이름을 입력하세요"}
- {...field}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- <div className="grid grid-cols-2 gap-4">
- {/* 답변요청일 */}
- <FormField
- control={form.control}
- name="requestDate"
- render={({ field }) => (
- <FormItem>
- <FormLabel>답변요청일</FormLabel>
- <FormControl>
- <Input
- type="date"
- {...field}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* 답변예정일 */}
- <FormField
- control={form.control}
- name="expectedAnswerDate"
- render={({ field }) => (
- <FormItem>
- <FormLabel>답변예정일 (선택사항)</FormLabel>
- <FormControl>
- <Input
- type="date"
- {...field}
- />
- </FormControl>
- <div className="text-xs text-muted-foreground">
- 답변요청일 기준으로 자동 설정됩니다
- </div>
- <FormMessage />
- </FormItem>
- )}
- />
- </div>
- </CardContent>
- </Card>
-
- {/* 안내 메시지 */}
- <Card className="bg-blue-50 border-blue-200">
- <CardContent className="pt-6">
- <div className="flex items-start gap-3">
- <div className="h-2 w-2 rounded-full bg-blue-500 mt-2"></div>
- <div className="space-y-1">
- <p className="text-sm font-medium text-blue-900">
- 법무업무 등록 안내
- </p>
- <p className="text-sm text-blue-700">
- 기본 정보 등록 후, 목록에서 해당 업무를 선택하여 상세한 검토 요청을 진행할 수 있습니다.
- </p>
- <p className="text-xs text-blue-600">
- • 상태: "검토요청"으로 자동 설정<br/>
- • 의뢰일: 오늘 날짜로 자동 설정<br/>
- • 법무답변자: 나중에 배정
- </p>
- </div>
- </div>
- </CardContent>
- </Card>
- </div>
- </div>
-
- {/* 고정 버튼 영역 */}
- <div className="flex-shrink-0 border-t bg-background p-6">
- <div className="flex justify-end gap-3">
- <Button
- type="button"
- variant="outline"
- onClick={() => handleOpenChange(false)}
- disabled={isSubmitting}
- >
- 취소
- </Button>
- <Button
- type="submit"
- disabled={isSubmitting}
- >
- {isSubmitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
- 등록
- </Button>
- </div>
- </div>
- </form>
- </Form>
- </DialogContent>
- </Dialog>
- )
-} \ No newline at end of file