"use client"; import React, { useState, useEffect } from "react"; import { useSession } from "next-auth/react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from "@/components/ui/dialog"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; import { Loader2, Check, ChevronsUpDown } from "lucide-react"; import { toast } from "sonner"; import { cn } from "@/lib/utils"; import { createRevisionAction, fetchDocumentsByPackageId, fetchStagesByDocumentId, fetchRevisionsByStageParams, Document, IssueStage, Revision } from "@/lib/vendor-document/service"; interface PublishDialogProps { open: boolean; onOpenChange: (open: boolean) => void; packageId: number; formCode: string; fileBlob?: Blob; } export const PublishDialog: React.FC = ({ open, onOpenChange, packageId, formCode, fileBlob, }) => { // Get current user session from next-auth const { data: session } = useSession(); // State for form data const [documents, setDocuments] = useState([]); const [stages, setStages] = useState([]); const [latestRevision, setLatestRevision] = useState(""); // State for document search const [openDocumentCombobox, setOpenDocumentCombobox] = useState(false); const [documentSearchValue, setDocumentSearchValue] = useState(""); // Selected values const [selectedDocId, setSelectedDocId] = useState(""); const [selectedDocumentDisplay, setSelectedDocumentDisplay] = useState(""); const [selectedStage, setSelectedStage] = useState(""); const [revisionInput, setRevisionInput] = useState(""); const [uploaderName, setUploaderName] = useState(""); const [comment, setComment] = useState(""); const [customFileName, setCustomFileName] = useState(`${formCode}_document.docx`); // Loading states const [isLoading, setIsLoading] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); // Filter documents by search const filteredDocuments = documentSearchValue ? documents.filter(doc => doc.docNumber.toLowerCase().includes(documentSearchValue.toLowerCase()) || doc.title.toLowerCase().includes(documentSearchValue.toLowerCase()) ) : documents; // Set uploader name from session when dialog opens useEffect(() => { if (open && session?.user?.name) { setUploaderName(session.user.name); } }, [open, session]); // Reset all fields when dialog opens/closes useEffect(() => { if (open) { setSelectedDocId(""); setSelectedDocumentDisplay(""); setSelectedStage(""); setRevisionInput(""); // Only set uploaderName if not already set from session if (!session?.user?.name) setUploaderName(""); setComment(""); setLatestRevision(""); setCustomFileName(`${formCode}_document.docx`); setDocumentSearchValue(""); } }, [open, formCode, session]); // Fetch documents based on packageId useEffect(() => { async function loadDocuments() { if (packageId && open) { setIsLoading(true); try { const docs = await fetchDocumentsByPackageId(packageId); setDocuments(docs); } catch (error) { console.error("Error fetching documents:", error); toast.error("Failed to load documents"); } finally { setIsLoading(false); } } } loadDocuments(); }, [packageId, open]); // Fetch stages when document is selected useEffect(() => { async function loadStages() { if (selectedDocId) { setIsLoading(true); // Reset dependent fields setSelectedStage(""); setRevisionInput(""); setLatestRevision(""); try { const stagesList = await fetchStagesByDocumentId(parseInt(selectedDocId, 10)); setStages(stagesList); } catch (error) { console.error("Error fetching stages:", error); toast.error("Failed to load stages"); } finally { setIsLoading(false); } } else { setStages([]); } } loadStages(); }, [selectedDocId]); // Fetch latest revision when stage is selected (for reference) useEffect(() => { async function loadLatestRevision() { if (selectedDocId && selectedStage) { setIsLoading(true); try { const revsList = await fetchRevisionsByStageParams( parseInt(selectedDocId, 10), selectedStage ); // Find the latest revision (assuming revisions are sorted by revision number) if (revsList.length > 0) { // Sort revisions if needed const sortedRevisions = [...revsList].sort((a, b) => { return b.revision.localeCompare(a.revision, undefined, { numeric: true }); }); setLatestRevision(sortedRevisions[0].revision); // Pre-fill the revision input with an incremented value if possible if (sortedRevisions[0].revision.match(/^\d+$/)) { // If it's a number, increment it const nextRevision = String(parseInt(sortedRevisions[0].revision, 10) + 1); setRevisionInput(nextRevision); } else if (sortedRevisions[0].revision.match(/^[A-Za-z]$/)) { // If it's a single letter, get the next letter const currentChar = sortedRevisions[0].revision.charCodeAt(0); const nextChar = String.fromCharCode(currentChar + 1); setRevisionInput(nextChar); } else { // For other formats, just show the latest as reference setRevisionInput(""); } } else { // If no revisions exist, set default values setLatestRevision(""); setRevisionInput("0"); } } catch (error) { console.error("Error fetching revisions:", error); toast.error("Failed to load revision information"); } finally { setIsLoading(false); } } else { setLatestRevision(""); setRevisionInput(""); } } loadLatestRevision(); }, [selectedDocId, selectedStage]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!selectedDocId || !selectedStage || !revisionInput || !fileBlob) { toast.error("Please fill in all required fields"); return; } setIsSubmitting(true); try { // Create FormData const formData = new FormData(); formData.append("documentId", selectedDocId); formData.append("stage", selectedStage); formData.append("revision", revisionInput); formData.append("customFileName", customFileName); formData.append("uploaderType", "vendor"); // Default value if (uploaderName) { formData.append("uploaderName", uploaderName); } if (comment) { formData.append("comment", comment); } // Append file as attachment if (fileBlob) { const file = new File([fileBlob], customFileName, { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }); formData.append("attachment", file); } // Call server action directly const result = await createRevisionAction(formData); if (result) { toast.success("Document published successfully!"); onOpenChange(false); } } catch (error) { console.error("Error publishing document:", error); toast.error("Failed to publish document"); } finally { setIsSubmitting(false); } }; return ( Publish Document Select document, stage, and revision to publish the vendor document.
{/* Document Selection with Search */}
No document found. {filteredDocuments.map((doc) => ( { setSelectedDocId(String(doc.id)); setSelectedDocumentDisplay(`${doc.docNumber} - ${doc.title}`); setOpenDocumentCombobox(false); }} className="flex items-center" > {/* Add text-overflow handling for document items */} {doc.docNumber} - {doc.title} ))}
{/* Stage Selection */}
{/* Revision Input */}
setRevisionInput(e.target.value)} placeholder="Enter revision" disabled={isLoading || !selectedStage} /> {latestRevision && (

Latest revision: {latestRevision}

)}
setCustomFileName(e.target.value)} placeholder="Custom file name" />
setUploaderName(e.target.value)} placeholder="Your name" // Disable input but show a filled style className={session?.user?.name ? "opacity-70" : ""} readOnly={!!session?.user?.name} /> {session?.user?.name && (

Using your account name from login

)}