import { zodResolver } from "@hookform/resolvers/zod"; import React, { useEffect, useState } from "react"; import { useForm, FormProvider } from "react-hook-form"; import { defaultDocumentValues, DocumentPayloadSchema } from "./DocumentSchema"; import Label from "../common/Label"; import { useDocumentCategories, useDocumentTypes, } from "../../hooks/masterHook/useMaster"; import TagInput from "../common/TagInput"; import { useDocumentDetails, useDocumentTags, useUpdateDocument, useUploadDocument, } from "../../hooks/useDocument"; import showToast from "../../services/toastService"; import { useDocumentContext } from "./Documents"; import { isPending } from "@reduxjs/toolkit"; const toBase64 = (file) => new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result); reader.onerror = (err) => reject(err); }); const MergedTagsWithExistenStatus = (formTags = [], originalTags = []) => { const tagMap = new Map(); const safeFormTags = Array.isArray(formTags) ? formTags : []; const safeOriginalTags = Array.isArray(originalTags) ? originalTags : []; safeOriginalTags.forEach(tag => { if (tag?.name) { tagMap.set(tag.name, { ...tag, isActive: tag.isActive ?? true }); } }); safeFormTags.forEach(tag => { if (tag?.name) { tagMap.set(tag.name, { ...tag, isActive: true }); } }); safeOriginalTags.forEach(tag => { if (tag?.name && !safeFormTags.some(t => t.name === tag.name)) { tagMap.set(tag.name, { ...tag, isActive: false }); } }); return Array.from(tagMap.values()); }; const ManageDocument = ({ closeModal, Document_Entity, Entity }) => { const { ManageDoc } = useDocumentContext(); const isUpdateForm = Boolean(ManageDoc?.document); const [selectedType, setSelectedType] = useState(null); const [selectedCategory, setSelectedCategory] = useState(null); const [schema, setSchema] = useState(() => DocumentPayloadSchema({ isUpdateForm }) ); const methods = useForm({ resolver: zodResolver(schema), defaultValues: defaultDocumentValues, }); const { register, handleSubmit, watch, setValue, reset, formState: { errors }, } = methods; const { mutate: UploadDocument, isPending: isUploading } = useUploadDocument( () => { showToast("Document Uploaded Successfully", "success"); closeModal(); } ); const { mutate: UpdateDocument, isPending: isUpdating } = useUpdateDocument( () => { showToast("Document Updated Successfully", "success"); closeModal(); } ); const onSubmit = (data) => { const normalizeAttachment = (attachment) => { if (!attachment) return null; return { ...attachment, fileSize: Math.ceil(attachment.fileSize / 1024), }; }; const payload = { ...data, attachment: normalizeAttachment(data.attachment), }; if (ManageDoc?.document) { const DocumentPayload = { ...payload, id: DocData.id, tags: MergedTagsWithExistenStatus(data?.tags, DocData?.tags), }; UpdateDocument({ documentId: DocData?.id, DocumentPayload }); } else { const DocumentPayload = { ...payload, entityId: Entity }; UploadDocument(DocumentPayload); } }; const { data: DocData, isLoading: isDocLoading, isError: isDocError, DocError, } = useDocumentDetails(ManageDoc?.document); const file = watch("attachment"); const documentTypeId = watch("documentTypeId"); // This hooks calling api base Entity(Employee) and Category const { DocumentCategories, isLoading } = useDocumentCategories(Document_Entity); const categoryId = watch("documentCategoryId"); const { DocumentTypes, isLoading: isTypeLoading } = useDocumentTypes( categoryId || null ); const {data:DocumentTags} = useDocumentTags() // Update schema whenever document type changes useEffect(() => { if (!documentTypeId) return; const type = DocumentTypes?.find( (t) => String(t.id) === String(documentTypeId) ); if (!type) return; setSelectedType(type) const newSchema = DocumentPayloadSchema({ isMandatory: type.isMandatory ?? false, regexExpression: type.regexExpression ?? null, allowedContentType: type.allowedContentType ?? [ "application/pdf", "image/jpeg", "image/png", ], maxSizeAllowedInMB: type.maxSizeAllowedInMB ?? 25, isUpdateForm, }); setSchema(() => newSchema); methods.reset(methods.getValues(), { keepValues: true }); methods.formState.errors; // triggers revalidation }, [documentTypeId, DocumentTypes, isUpdateForm]); // File Upload const onFileChange = async (e) => { const uploaded = e.target.files[0]; if (!uploaded) return; const base64Data = await toBase64(uploaded); const parsedFile = { fileName: uploaded.name, base64Data, contentType: uploaded.type, fileSize: uploaded.size, description: "", isActive: true, }; setValue("attachment", parsedFile, { shouldDirty: true, shouldValidate: true, }); }; const removeFile = () => { setValue("attachment", null, { shouldDirty: true, shouldValidate: true, }); }; // build dynamic file accept string const fileAccept = selectedType?.allowedContentType ?.split(",") .map((t) => t === "application/pdf" ? ".pdf" : t === "image/jpeg" ? ".jpg,.jpeg" : t === "image/png" ? ".png" : "" ) .join(",") || ""; useEffect(() => { if (DocData) { reset({ ...defaultDocumentValues, name: DocData?.name ?? "", documentCategoryId: DocData?.documentType?.documentCategory?.id ? String(DocData.documentType.documentCategory.id) : "", documentTypeId: DocData?.documentType?.id ? String(DocData.documentType.id) : "", documentId: DocData?.documentId ?? "", description: DocData?.description ?? "", attachment: DocData?.attachment ?? null, tags: DocData?.tags ?? [], }); } }, [DocData, reset]); if (isDocLoading) return
Upload New Document