summaryrefslogtreecommitdiff
path: root/lib/rfqs/table/add-rfq-dialog.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-12-01 19:52:06 +0900
committerjoonhoekim <26rote@gmail.com>2025-12-01 19:52:06 +0900
commit44b74ff4170090673b6eeacd8c528e0abf47b7aa (patch)
tree3f3824b4e2cb24536c1677188b4cae5b8909d3da /lib/rfqs/table/add-rfq-dialog.tsx
parent4953e770929b82ef77da074f77071ebd0f428529 (diff)
(김준회) deprecated code 정리
Diffstat (limited to 'lib/rfqs/table/add-rfq-dialog.tsx')
-rw-r--r--lib/rfqs/table/add-rfq-dialog.tsx468
1 files changed, 0 insertions, 468 deletions
diff --git a/lib/rfqs/table/add-rfq-dialog.tsx b/lib/rfqs/table/add-rfq-dialog.tsx
deleted file mode 100644
index 67561b4f..00000000
--- a/lib/rfqs/table/add-rfq-dialog.tsx
+++ /dev/null
@@ -1,468 +0,0 @@
-"use client"
-
-import * as React from "react"
-import { useForm } from "react-hook-form"
-import { zodResolver } from "@hookform/resolvers/zod"
-import { toast } from "sonner"
-
-import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
-
-import { useSession } from "next-auth/react"
-import { createRfqSchema, type CreateRfqSchema, RfqType } from "../validations"
-import { createRfq, generateNextRfqCode, getBudgetaryRfqs } from "../service"
-import { ProjectSelector } from "@/components/ProjectSelector"
-import { type Project } from "../service"
-import { ParentRfqSelector } from "./ParentRfqSelector"
-import { EstimateProjectSelector } from "@/components/BidProjectSelector"
-
-// 부모 RFQ 정보 타입 정의
-interface ParentRfq {
- id: number;
- rfqCode: string;
- description: string | null;
- rfqType: RfqType;
- projectId: number | null;
- projectCode: string | null;
- projectName: string | null;
-}
-
-interface AddRfqDialogProps {
- rfqType?: RfqType;
-}
-
-export function AddRfqDialog({ rfqType = RfqType.PURCHASE }: AddRfqDialogProps) {
- const [open, setOpen] = React.useState(false)
- const { data: session, status } = useSession()
- const [parentRfqs, setParentRfqs] = React.useState<ParentRfq[]>([])
- const [isLoadingParents, setIsLoadingParents] = React.useState(false)
- const [selectedParentRfq, setSelectedParentRfq] = React.useState<ParentRfq | null>(null)
- const [isLoadingRfqCode, setIsLoadingRfqCode] = React.useState(false)
-
- // Get the user ID safely, ensuring it's a valid number
- const userId = React.useMemo(() => {
- const id = session?.user?.id ? Number(session.user.id) : null;
-
- return id;
- }, [session, status]);
-
- // RfqType에 따른 타이틀 생성
- const getTitle = () => {
- switch (rfqType) {
- case RfqType.PURCHASE:
- return "Purchase RFQ";
- case RfqType.BUDGETARY:
- return "Budgetary RFQ";
- case RfqType.PURCHASE_BUDGETARY:
- return "Purchase Budgetary RFQ";
- default:
- return "RFQ";
- }
- };
-
- // RfqType 설명 가져오기
- const getTypeDescription = () => {
- switch (rfqType) {
- case RfqType.PURCHASE:
- return "실제 구매 발주 전에 가격을 요청";
- case RfqType.BUDGETARY:
- return "기술영업 단계에서 입찰가 산정을 위한 견적 요청";
- case RfqType.PURCHASE_BUDGETARY:
- return "프로젝트 수주 후, 공식 입찰 전 예산 책정을 위한 가격 요청";
- default:
- return "";
- }
- };
-
- // RHF + Zod
- const form = useForm<CreateRfqSchema>({
- resolver: zodResolver(createRfqSchema),
- defaultValues: {
- rfqCode: "",
- description: "",
- projectId: undefined,
- parentRfqId: undefined,
- dueDate: new Date(),
- status: "DRAFT",
- rfqType: rfqType,
- // Don't set createdBy yet - we'll set it when the form is submitted
- createdBy: undefined,
- },
- });
-
- // Update form values when session loads
- React.useEffect(() => {
- if (status === "authenticated" && userId) {
- form.setValue("createdBy", userId);
- }
- }, [status, userId, form]);
-
- // 다이얼로그가 열릴 때 자동으로 RFQ 코드 생성
- React.useEffect(() => {
- if (open) {
- const generateRfqCode = async () => {
- setIsLoadingRfqCode(true);
- try {
- // 서버 액션 호출
- const result = await generateNextRfqCode(rfqType);
-
- if (result.error) {
- toast.error(`RFQ 코드 생성 실패: ${result.error}`);
- return;
- }
-
- // 생성된 코드를 폼에 설정
- form.setValue("rfqCode", result.code);
- } catch (error) {
- console.error("RFQ 코드 생성 오류:", error);
- toast.error("RFQ 코드 생성에 실패했습니다");
- } finally {
- setIsLoadingRfqCode(false);
- }
- };
-
- generateRfqCode();
- }
- }, [open, rfqType, form]);
-
- // 현재 RFQ 타입에 따라 선택 가능한 부모 RFQ 타입들 결정
- const getParentRfqTypes = (): RfqType[] => {
- switch (rfqType) {
- case RfqType.PURCHASE:
- // PURCHASE는 BUDGETARY와 PURCHASE_BUDGETARY를 부모로 가질 수 있음
- return [RfqType.BUDGETARY, RfqType.PURCHASE_BUDGETARY];
- case RfqType.PURCHASE_BUDGETARY:
- // PURCHASE_BUDGETARY는 BUDGETARY만 부모로 가질 수 있음
- return [RfqType.BUDGETARY];
- default:
- return [];
- }
- };
-
- // 선택 가능한 부모 RFQ 목록 로드
- React.useEffect(() => {
- if ((rfqType === RfqType.PURCHASE || rfqType === RfqType.PURCHASE_BUDGETARY) && open) {
- const loadParentRfqs = async () => {
- setIsLoadingParents(true);
- try {
- // 현재 RFQ 타입에 따라 선택 가능한, 부모가 될 수 있는 RFQ 타입들 가져오기
- const parentTypes = getParentRfqTypes();
-
- // 부모 RFQ 타입이 있을 때만 API 호출
- if (parentTypes.length > 0) {
- const result = await getBudgetaryRfqs({
- rfqTypes: parentTypes // 서비스에 rfqTypes 파라미터 추가 필요
- });
-
- if ('rfqs' in result) {
- setParentRfqs(result.rfqs as unknown as ParentRfq[]);
- } else if ('error' in result) {
- console.error("부모 RFQ 로드 오류:", result.error);
- }
- }
- } catch (error) {
- console.error("부모 RFQ 로드 오류:", error);
- } finally {
- setIsLoadingParents(false);
- }
- };
-
- loadParentRfqs();
- }
- }, [rfqType, open]);
-
- // 프로젝트 선택 처리
- const handleProjectSelect = (project: Project | null) => {
- if (project === null) {
- return;
- }
-
- form.setValue("projectId", project.id);
- };
-
- const handleBidProjectSelect = (project: Project | null) => {
- if (project === null) {
- return;
- }
-
- form.setValue("bidProjectId", project.id);
- };
-
- // 부모 RFQ 선택 처리
- const handleParentRfqSelect = (rfq: ParentRfq | null) => {
- setSelectedParentRfq(rfq);
- form.setValue("parentRfqId", rfq?.id);
- };
-
- async function onSubmit(data: CreateRfqSchema) {
- // Check if user is authenticated before submitting
- if (status !== "authenticated" || !userId) {
- toast.error("사용자 인증이 필요합니다. 다시 로그인해주세요.");
- return;
- }
-
- // Make sure createdBy is set with the current user ID
- const submitData = {
- ...data,
- createdBy: userId
- };
-
- console.log("Submitting form data:", submitData);
-
- const result = await createRfq(submitData);
- if (result.error) {
- toast.error(`에러: ${result.error}`);
- return;
- }
-
- toast.success("RFQ가 성공적으로 생성되었습니다.");
- form.reset();
- setSelectedParentRfq(null);
- setOpen(false);
- }
-
- function handleDialogOpenChange(nextOpen: boolean) {
- if (!nextOpen) {
- form.reset();
- setSelectedParentRfq(null);
- }
- setOpen(nextOpen);
- }
-
- // Return a message or disabled state if user is not authenticated
- if (status === "loading") {
- return <Button variant="outline" size="sm" disabled>Loading...</Button>;
- }
-
- // 타입에 따라 부모 RFQ 선택 필드를 보여줄지 결정
- const shouldShowParentRfqSelector = rfqType === RfqType.PURCHASE || rfqType === RfqType.PURCHASE_BUDGETARY;
- const shouldShowEstimateSelector = rfqType === RfqType.BUDGETARY;
-
- // 부모 RFQ 선택기 레이블 및 설명 가져오기
- const getParentRfqSelectorLabel = () => {
- if (rfqType === RfqType.PURCHASE) {
- return "부모 RFQ (BUDGETARY/PURCHASE_BUDGETARY)";
- } else if (rfqType === RfqType.PURCHASE_BUDGETARY) {
- return "부모 RFQ (BUDGETARY)";
- }
- return "부모 RFQ";
- };
-
- const getParentRfqDescription = () => {
- if (rfqType === RfqType.PURCHASE) {
- return "BUDGETARY 또는 PURCHASE_BUDGETARY 타입의 RFQ를 부모로 선택할 수 있습니다.";
- } else if (rfqType === RfqType.PURCHASE_BUDGETARY) {
- return "BUDGETARY 타입의 RFQ만 부모로 선택할 수 있습니다.";
- }
- return "";
- };
-
- return (
- <Dialog open={open} onOpenChange={handleDialogOpenChange}>
- {/* 모달을 열기 위한 버튼 */}
- <DialogTrigger asChild>
- <Button variant="default" size="sm">
- Add {getTitle()}
- </Button>
- </DialogTrigger>
-
- <DialogContent>
- <DialogHeader>
- <DialogTitle>Create New {getTitle()}</DialogTitle>
- <DialogDescription>
- 새 {getTitle()} 정보를 입력하고 <b>Create</b> 버튼을 누르세요.
- <div className="mt-1 text-xs text-muted-foreground">
- {getTypeDescription()}
- </div>
- </DialogDescription>
- </DialogHeader>
-
- <Form {...form}>
- <form onSubmit={form.handleSubmit(onSubmit)}>
- <div className="space-y-4 py-4">
- {/* rfqType - hidden field */}
- <FormField
- control={form.control}
- name="rfqType"
- render={({ field }) => (
- <input type="hidden" {...field} />
- )}
- />
-
- {/* Project Selector */}
- <FormField
- control={form.control}
- name="projectId"
- render={({ field }) => (
- <FormItem>
- <FormLabel>Project</FormLabel>
- <FormControl>
-
- {shouldShowEstimateSelector ?
- <EstimateProjectSelector
- selectedProjectId={field.value}
- onProjectSelect={handleBidProjectSelect}
- placeholder="견적 프로젝트 선택..."
- /> :
- <ProjectSelector
- selectedProjectId={field.value}
- onProjectSelect={handleProjectSelect}
- placeholder="프로젝트 선택..."
- />}
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* Parent RFQ Selector - PURCHASE 또는 PURCHASE_BUDGETARY 타입일 때만 표시 */}
- {shouldShowParentRfqSelector && (
- <FormField
- control={form.control}
- name="parentRfqId"
- render={({ field }) => (
- <FormItem>
- <FormLabel>{getParentRfqSelectorLabel()}</FormLabel>
- <FormControl>
- <ParentRfqSelector
- selectedRfqId={field.value as number | undefined}
- onRfqSelect={handleParentRfqSelect}
- rfqType={rfqType}
- parentRfqTypes={getParentRfqTypes()}
- placeholder={
- rfqType === RfqType.PURCHASE
- ? "BUDGETARY 또는 PURCHASE_BUDGETARY RFQ 선택..."
- : "BUDGETARY RFQ 선택..."
- }
- />
- </FormControl>
- <div className="text-xs text-muted-foreground mt-1">
- {getParentRfqDescription()}
- </div>
- <FormMessage />
- </FormItem>
- )}
- />
- )}
-
- {/* rfqCode - 자동 생성되고 읽기 전용 */}
- <FormField
- control={form.control}
- name="rfqCode"
- render={({ field }) => (
- <FormItem>
- <FormLabel>RFQ Code</FormLabel>
- <FormControl>
- <div className="flex">
- <Input
- placeholder="자동으로 생성 중..."
- {...field}
- disabled={true}
- className="bg-muted"
- />
- {isLoadingRfqCode && (
- <div className="ml-2 flex items-center">
- <div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
- </div>
- )}
- </div>
- </FormControl>
- <div className="text-xs text-muted-foreground mt-1">
- RFQ 타입과 현재 날짜를 기준으로 자동 생성됩니다
- </div>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* description */}
- <FormField
- control={form.control}
- name="description"
- render={({ field }) => (
- <FormItem>
- <FormLabel>RFQ Description</FormLabel>
- <FormControl>
- <Input placeholder="e.g. 설명을 입력하세요" {...field} />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* dueDate */}
- <FormField
- control={form.control}
- name="dueDate"
- render={({ field }) => (
- <FormItem>
- <FormLabel>Due Date</FormLabel>
- <FormControl>
- <Input
- type="date"
- value={field.value ? field.value.toISOString().slice(0, 10) : ""}
- onChange={(e) => {
- const val = e.target.value
- if (val) {
- const date = new Date(val);
- // 날짜 1일씩 밀리는 문제로 우선 KTC로 입력
- // 추후 아래와 같이 수정
- // 1. 해당 유저 타임존 값으로 입력
- // 2. DB에는 UTC 타임존 값으로 저장
- // 3. 출력시 유저별 타임존 값으로 변환해 출력
- // 4. 어떤 타임존으로 나오는지도 함께 렌더링
- // field.onChange(new Date(val + "T00:00:00"))
- field.onChange(date);
- }
- }}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
-
- {/* status (Read-only) */}
- <FormField
- control={form.control}
- name="status"
- render={({ field }) => (
- <FormItem>
- <FormLabel>Status</FormLabel>
- <FormControl>
- <Input
- disabled
- className="capitalize"
- {...field}
- onChange={() => { }} // Prevent changes
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
- </div>
-
- <DialogFooter>
- <Button
- type="button"
- variant="outline"
- onClick={() => setOpen(false)}
- >
- Cancel
- </Button>
- <Button
- type="submit"
- disabled={form.formState.isSubmitting || status !== "authenticated"}
- >
- Create
- </Button>
- </DialogFooter>
- </form>
- </Form>
- </DialogContent>
- </Dialog>
- )
-} \ No newline at end of file