diff options
Diffstat (limited to 'lib/vendor-rfq-response/vendor-cbe-table/respond-cbe-sheet.tsx')
| -rw-r--r-- | lib/vendor-rfq-response/vendor-cbe-table/respond-cbe-sheet.tsx | 427 |
1 files changed, 0 insertions, 427 deletions
diff --git a/lib/vendor-rfq-response/vendor-cbe-table/respond-cbe-sheet.tsx b/lib/vendor-rfq-response/vendor-cbe-table/respond-cbe-sheet.tsx deleted file mode 100644 index 8cc4fa6f..00000000 --- a/lib/vendor-rfq-response/vendor-cbe-table/respond-cbe-sheet.tsx +++ /dev/null @@ -1,427 +0,0 @@ -"use client" - -import * as React from "react" -import { zodResolver } from "@hookform/resolvers/zod" -import { Loader } from "lucide-react" -import { useForm } from "react-hook-form" -import { toast } from "sonner" -import { z } from "zod" - -import { Button } from "@/components/ui/button" -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form" -import { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { Input } from "@/components/ui/input" -import { - Sheet, - SheetClose, - SheetContent, - SheetDescription, - SheetFooter, - SheetHeader, - SheetTitle, -} from "@/components/ui/sheet" -import { Textarea } from "@/components/ui/textarea" -import { VendorWithCbeFields } from "@/config/vendorCbeColumnsConfig" -import { getCommercialResponseByResponseId, updateCommercialResponse } from "../service" - -// Define schema for form validation (client-side) -const commercialResponseFormSchema = z.object({ - responseStatus: z.enum(["PENDING", "IN_PROGRESS", "SUBMITTED", "REJECTED", "ACCEPTED"]), - totalPrice: z.coerce.number().optional(), - currency: z.string().default("USD"), - paymentTerms: z.string().optional(), - incoterms: z.string().optional(), - deliveryPeriod: z.string().optional(), - warrantyPeriod: z.string().optional(), - validityPeriod: z.string().optional(), - priceBreakdown: z.string().optional(), - commercialNotes: z.string().optional(), -}) - -type CommercialResponseFormInput = z.infer<typeof commercialResponseFormSchema> - -interface CommercialResponseSheetProps - extends React.ComponentPropsWithRef<typeof Sheet> { - rfq: VendorWithCbeFields | null - responseId: number | null // This is the vendor_responses.id - onSuccess?: () => void -} - -export function CommercialResponseSheet({ - rfq, - responseId, - onSuccess, - ...props -}: CommercialResponseSheetProps) { - const [isSubmitting, startSubmitTransition] = React.useTransition() - const [isLoading, setIsLoading] = React.useState(true) - - const form = useForm<CommercialResponseFormInput>({ - resolver: zodResolver(commercialResponseFormSchema), - defaultValues: { - responseStatus: "PENDING", - totalPrice: undefined, - currency: "USD", - paymentTerms: "", - incoterms: "", - deliveryPeriod: "", - warrantyPeriod: "", - validityPeriod: "", - priceBreakdown: "", - commercialNotes: "", - }, - }) - - // Load existing commercial response data when sheet opens - React.useEffect(() => { - async function loadCommercialResponse() { - if (!responseId) return - - setIsLoading(true) - try { - // Use the helper function to get existing data - const existingResponse = await getCommercialResponseByResponseId(responseId) - - if (existingResponse) { - // If we found existing data, populate the form - form.reset({ - responseStatus: existingResponse.responseStatus, - totalPrice: existingResponse.totalPrice, - currency: existingResponse.currency || "USD", - paymentTerms: existingResponse.paymentTerms || "", - incoterms: existingResponse.incoterms || "", - deliveryPeriod: existingResponse.deliveryPeriod || "", - warrantyPeriod: existingResponse.warrantyPeriod || "", - validityPeriod: existingResponse.validityPeriod || "", - priceBreakdown: existingResponse.priceBreakdown || "", - commercialNotes: existingResponse.commercialNotes || "", - }) - } else if (rfq) { - // If no existing data but we have rfq data with some values already - form.reset({ - responseStatus: rfq.commercialResponseStatus as any || "PENDING", - totalPrice: rfq.totalPrice || undefined, - currency: rfq.currency || "USD", - paymentTerms: rfq.paymentTerms || "", - incoterms: rfq.incoterms || "", - deliveryPeriod: rfq.deliveryPeriod || "", - warrantyPeriod: rfq.warrantyPeriod || "", - validityPeriod: rfq.validityPeriod || "", - priceBreakdown: "", - commercialNotes: "", - }) - } - } catch (error) { - console.error("Failed to load commercial response data:", error) - toast.error("상업 응답 데이터를 불러오는데 실패했습니다") - } finally { - setIsLoading(false) - } - } - - loadCommercialResponse() - }, [responseId, rfq, form]) - - function onSubmit(formData: CommercialResponseFormInput) { - if (!responseId) { - toast.error("응답 ID를 찾을 수 없습니다") - return - } - - if (!rfq?.vendorId) { - toast.error("협력업체 ID를 찾을 수 없습니다") - return - } - - startSubmitTransition(async () => { - try { - // Pass both responseId and vendorId to the server action - const result = await updateCommercialResponse({ - responseId, - vendorId: rfq.vendorId, // Include vendorId for revalidateTag - ...formData, - }) - - if (!result.success) { - toast.error(result.error || "응답 제출 중 오류가 발생했습니다") - return - } - - toast.success("Commercial response successfully submitted") - props.onOpenChange?.(false) - - if (onSuccess) { - onSuccess() - } - } catch (error) { - console.error("Error submitting response:", error) - toast.error("응답 제출 중 오류가 발생했습니다") - } - }) - } - - return ( - <Sheet {...props}> - <SheetContent className="flex flex-col gap-6 sm:max-w-md"> - <SheetHeader className="text-left"> - <SheetTitle>Commercial Response</SheetTitle> - <SheetDescription> - {rfq?.rfqCode && <span className="font-medium">{rfq.rfqCode}</span>} - <div className="mt-1">Please provide your commercial response for this RFQ</div> - </SheetDescription> - </SheetHeader> - - {isLoading ? ( - <div className="flex items-center justify-center py-8"> - <Loader className="h-8 w-8 animate-spin text-muted-foreground" /> - </div> - ) : ( - <Form {...form}> - <form - onSubmit={form.handleSubmit(onSubmit)} - className="flex flex-col gap-4 overflow-y-auto max-h-[calc(100vh-200px)] pr-2" - > - <FormField - control={form.control} - name="responseStatus" - render={({ field }) => ( - <FormItem> - <FormLabel>Response Status</FormLabel> - <Select - onValueChange={field.onChange} - defaultValue={field.value} - > - <FormControl> - <SelectTrigger className="capitalize"> - <SelectValue placeholder="Select response status" /> - </SelectTrigger> - </FormControl> - <SelectContent> - <SelectGroup> - <SelectItem value="PENDING">Pending</SelectItem> - <SelectItem value="IN_PROGRESS">In Progress</SelectItem> - <SelectItem value="SUBMITTED">Submitted</SelectItem> - </SelectGroup> - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - - <div className="grid grid-cols-2 gap-4"> - <FormField - control={form.control} - name="totalPrice" - render={({ field }) => ( - <FormItem> - <FormLabel>Total Price</FormLabel> - <FormControl> - <Input - type="number" - placeholder="0.00" - {...field} - value={field.value || ''} - onChange={(e) => { - const value = e.target.value === '' ? undefined : parseFloat(e.target.value); - field.onChange(value); - }} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="currency" - render={({ field }) => ( - <FormItem> - <FormLabel>Currency</FormLabel> - <Select - onValueChange={field.onChange} - defaultValue={field.value} - > - <FormControl> - <SelectTrigger> - <SelectValue placeholder="Select currency" /> - </SelectTrigger> - </FormControl> - <SelectContent> - <SelectGroup> - <SelectItem value="USD">USD</SelectItem> - <SelectItem value="EUR">EUR</SelectItem> - <SelectItem value="GBP">GBP</SelectItem> - <SelectItem value="KRW">KRW</SelectItem> - <SelectItem value="JPY">JPY</SelectItem> - </SelectGroup> - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - </div> - - {/* Other form fields remain the same */} - <FormField - control={form.control} - name="paymentTerms" - render={({ field }) => ( - <FormItem> - <FormLabel>Payment Terms</FormLabel> - <FormControl> - <Input placeholder="e.g. Net 30" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="incoterms" - render={({ field }) => ( - <FormItem> - <FormLabel>Incoterms</FormLabel> - <Select - onValueChange={field.onChange} - defaultValue={field.value || ''} - > - <FormControl> - <SelectTrigger> - <SelectValue placeholder="Select incoterms" /> - </SelectTrigger> - </FormControl> - <SelectContent> - <SelectGroup> - <SelectItem value="EXW">EXW (Ex Works)</SelectItem> - <SelectItem value="FCA">FCA (Free Carrier)</SelectItem> - <SelectItem value="FOB">FOB (Free On Board)</SelectItem> - <SelectItem value="CIF">CIF (Cost, Insurance & Freight)</SelectItem> - <SelectItem value="DAP">DAP (Delivered At Place)</SelectItem> - <SelectItem value="DDP">DDP (Delivered Duty Paid)</SelectItem> - </SelectGroup> - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="deliveryPeriod" - render={({ field }) => ( - <FormItem> - <FormLabel>Delivery Period</FormLabel> - <FormControl> - <Input placeholder="e.g. 4-6 weeks" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="warrantyPeriod" - render={({ field }) => ( - <FormItem> - <FormLabel>Warranty Period</FormLabel> - <FormControl> - <Input placeholder="e.g. 12 months" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="validityPeriod" - render={({ field }) => ( - <FormItem> - <FormLabel>Validity Period</FormLabel> - <FormControl> - <Input placeholder="e.g. 30 days" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="priceBreakdown" - render={({ field }) => ( - <FormItem> - <FormLabel>Price Breakdown (Optional)</FormLabel> - <FormControl> - <Textarea - placeholder="Enter price breakdown details here" - className="min-h-[100px]" - {...field} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="commercialNotes" - render={({ field }) => ( - <FormItem> - <FormLabel>Additional Notes (Optional)</FormLabel> - <FormControl> - <Textarea - placeholder="Any additional comments or notes" - className="min-h-[100px]" - {...field} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - <SheetFooter className="gap-2 pt-4 sm:space-x-0"> - <SheetClose asChild> - <Button type="button" variant="outline"> - Cancel - </Button> - </SheetClose> - <Button disabled={isSubmitting} type="submit"> - {isSubmitting && ( - <Loader - className="mr-2 size-4 animate-spin" - aria-hidden="true" - /> - )} - Submit Response - </Button> - </SheetFooter> - </form> - </Form> - )} - </SheetContent> - </Sheet> - ) -}
\ No newline at end of file |
