initially setup update document
This commit is contained in:
parent
518928e439
commit
2f24d4a7ff
@ -34,13 +34,13 @@ export const TagSchema = z.object({
|
||||
isActive: z.boolean().default(true),
|
||||
});
|
||||
|
||||
|
||||
export const DocumentPayloadSchema = (docConfig = {}) => {
|
||||
const {
|
||||
isMandatory,
|
||||
regexExpression,
|
||||
allowedContentType,
|
||||
maxSizeAllowedInMB,
|
||||
isUpdateForm,
|
||||
} = docConfig;
|
||||
|
||||
let documentIdSchema = z.string();
|
||||
@ -58,20 +58,31 @@ export const DocumentPayloadSchema = (docConfig = {}) => {
|
||||
);
|
||||
}
|
||||
|
||||
// Base attachment schema
|
||||
let attachmentSchema = AttachmentSchema(
|
||||
allowedContentType,
|
||||
maxSizeAllowedInMB
|
||||
).nullable();
|
||||
|
||||
// If not update form, require attachment
|
||||
if (!isUpdateForm) {
|
||||
attachmentSchema = attachmentSchema.refine((val) => val !== null, {
|
||||
message: "Attachment is required",
|
||||
});
|
||||
}
|
||||
|
||||
return z.object({
|
||||
name: z.string().min(1, "Name is required"),
|
||||
documentId: documentIdSchema,
|
||||
description: z.string().min(1, { message: "Description is required" }),
|
||||
// entityId: z.string().min(1, { message: "Please Select Document Entity" }),
|
||||
documentTypeId: z.string().min(1, { message: "Please Select Document Type" }),
|
||||
documentTypeId: z
|
||||
.string()
|
||||
.min(1, { message: "Please Select Document Type" }),
|
||||
documentCategoryId: z
|
||||
.string()
|
||||
.min(1, { message: "Please Select Document Category" }),
|
||||
attachment: AttachmentSchema(allowedContentType, maxSizeAllowedInMB).nullable().refine(
|
||||
(val) => val !== null,
|
||||
{ message: "Attachment is required" }
|
||||
),
|
||||
tags: z.array(TagSchema).optional().default([]),
|
||||
attachment: attachmentSchema,
|
||||
tags: z.array(TagSchema).optional().default([]),
|
||||
});
|
||||
};
|
||||
|
||||
@ -83,14 +94,15 @@ export const defaultDocumentValues = {
|
||||
// entityId: "",
|
||||
documentTypeId: "",
|
||||
documentCategoryId: "",
|
||||
attachment: {
|
||||
fileName: "",
|
||||
base64Data: "",
|
||||
contentType: "",
|
||||
fileSize: 0,
|
||||
description: "",
|
||||
isActive: true,
|
||||
},
|
||||
// attachment: {
|
||||
// fileName: "",
|
||||
// base64Data: "",
|
||||
// contentType: "",
|
||||
// fileSize: 0,
|
||||
// description: "",
|
||||
// isActive: true,
|
||||
// },
|
||||
attachment:null,
|
||||
tags: [],
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { createContext, useContext, useEffect, useState } from "react";
|
||||
import GlobalModel from "../common/GlobalModel";
|
||||
import NewDocument from "./ManageDocument";
|
||||
import { DOCUMENTS_ENTITIES } from "../../utils/constants";
|
||||
@ -14,13 +14,28 @@ import {
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import ManageDocument from "./ManageDocument";
|
||||
|
||||
// Context
|
||||
export const DocumentContext = createContext();
|
||||
export const useDocumentContext = () => {
|
||||
const context = useContext(DocumentContext);
|
||||
if (!context) {
|
||||
throw new Error("useExpenseContext must be used within an ExpenseProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
const Documents = ({ Document_Entity, Entity }) => {
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [filters, setFilter] = useState();
|
||||
const [isRefetching, setIsRefetching] = useState(false);
|
||||
const [refetchFn, setRefetchFn] = useState(null);
|
||||
const { employeeId } = useParams();
|
||||
const [isUpload, setUpload] = useState(false);
|
||||
const [ManageDoc, setManageDoc] = useState({
|
||||
document: null,
|
||||
isOpen: false,
|
||||
});
|
||||
|
||||
|
||||
const { setOffcanvasContent, setShowTrigger } = useFab();
|
||||
|
||||
const methods = useForm({
|
||||
@ -47,9 +62,16 @@ const Documents = ({ Document_Entity, Entity }) => {
|
||||
setOffcanvasContent("", null);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
const contextValues = {
|
||||
ManageDoc,
|
||||
setManageDoc,
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-5">
|
||||
<DocumentContext.Provider value={contextValues}>
|
||||
|
||||
<div className="mt-5">
|
||||
<div className="card d-flex p-2">
|
||||
<div className="row align-items-center">
|
||||
{/* Search */}
|
||||
@ -86,7 +108,10 @@ const Documents = ({ Document_Entity, Entity }) => {
|
||||
type="button"
|
||||
title="Add New Document"
|
||||
className="p-1 bg-primary rounded-circle cursor-pointer"
|
||||
onClick={() => setUpload(true)}
|
||||
onClick={() => setManageDoc({
|
||||
document: null,
|
||||
isOpen: true,
|
||||
})}
|
||||
>
|
||||
<i className="bx bx-plus fs-4 text-white"></i>
|
||||
</button>
|
||||
@ -102,16 +127,31 @@ const Documents = ({ Document_Entity, Entity }) => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isUpload && (
|
||||
<GlobalModel isOpen={isUpload} closeModal={() => setUpload(false)}>
|
||||
{ManageDoc.isOpen && (
|
||||
<GlobalModel
|
||||
isOpen={ManageDoc.isOpen}
|
||||
closeModal={() =>
|
||||
setManageDoc({
|
||||
document: null,
|
||||
isOpen: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<ManageDocument
|
||||
closeModal={() => setUpload(false)}
|
||||
closeModal={() =>
|
||||
setManageDoc({
|
||||
document: null,
|
||||
isOpen: false,
|
||||
})
|
||||
}
|
||||
Document_Entity={Document_Entity}
|
||||
Entity={Entity}
|
||||
/>
|
||||
</GlobalModel>
|
||||
)}
|
||||
</div>
|
||||
</DocumentContext.Provider>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
import Loader from "../common/Loader";
|
||||
import { useDebounce } from "../../utils/appUtils";
|
||||
import { DocumentTableSkeleton } from "./DocumentSkeleton";
|
||||
import { useDocumentContext } from "./Documents";
|
||||
|
||||
export const getDocuementsStatus = (status) => {
|
||||
switch (status) {
|
||||
@ -53,6 +54,8 @@ const DocumentsList = ({
|
||||
setIsRefetching(isFetching);
|
||||
}, [isFetching, setIsRefetching]);
|
||||
|
||||
const {setManageDoc} = useDocumentContext()
|
||||
|
||||
// check no data scenarios
|
||||
const noData = !isLoading && !isError && data?.length === 0;
|
||||
const isSearchEmpty = noData && !!debouncedSearch;
|
||||
@ -146,7 +149,7 @@ const DocumentsList = ({
|
||||
<div className="d-flex justify-content-center gap-2">
|
||||
<i className="bx bx-show text-primary cursor-pointer"></i>
|
||||
|
||||
<i className="bx bx-edit text-secondary cursor-pointer"></i>
|
||||
<i className="bx bx-edit text-secondary cursor-pointer" onClick={()=>setManageDoc({document:doc?.id,isOpen:true})}></i>
|
||||
|
||||
<i className="bx bx-trash text-danger cursor-pointer"></i>
|
||||
</div>
|
||||
|
@ -8,8 +8,13 @@ import {
|
||||
useDocumentTypes,
|
||||
} from "../../hooks/masterHook/useMaster";
|
||||
import TagInput from "../common/TagInput";
|
||||
import { useUploadDocument } from "../../hooks/useDocument";
|
||||
import {
|
||||
useDocumentDetails,
|
||||
useUpdateDocument,
|
||||
useUploadDocument,
|
||||
} from "../../hooks/useDocument";
|
||||
import showToast from "../../services/toastService";
|
||||
import { useDocumentContext } from "./Documents";
|
||||
|
||||
const toBase64 = (file) =>
|
||||
new Promise((resolve, reject) => {
|
||||
@ -19,11 +24,14 @@ const toBase64 = (file) =>
|
||||
reader.onerror = (err) => reject(err);
|
||||
});
|
||||
|
||||
const ManageDocument = ({closeModal,Document_Entity,Entity}) => {
|
||||
|
||||
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({}));
|
||||
const [schema, setSchema] = useState(() =>
|
||||
DocumentPayloadSchema({ isUpdateForm })
|
||||
);
|
||||
const methods = useForm({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: defaultDocumentValues,
|
||||
@ -41,19 +49,35 @@ const ManageDocument = ({closeModal,Document_Entity,Entity}) => {
|
||||
showToast("Document Uploaded Successfully", "success");
|
||||
closeModal();
|
||||
});
|
||||
const { mutate: UpdateDocument, isPending: isUpdatinDoc } = useUpdateDocument(
|
||||
() => {
|
||||
showToast("Document Updated Successfully", "success");
|
||||
closeModal();
|
||||
}
|
||||
);
|
||||
const onSubmit = (data) => {
|
||||
const DocumentPayload = { ...data, entityId: Entity };
|
||||
UploadDocument(DocumentPayload);
|
||||
if (ManageDoc?.document) {
|
||||
const DocumentPayload = { ...DocData, ...data };
|
||||
UpdateDocument({ documentId: DocData?.id, DocumentPayload });
|
||||
} else {
|
||||
const DocumentPayload = { ...data, 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 { DocumentCategories, isLoading } =
|
||||
useDocumentCategories(Document_Entity);
|
||||
|
||||
const categoryId = watch("documentCategoryId");
|
||||
const { DocumentTypes, isLoading: isTypeLoading } = useDocumentTypes(
|
||||
@ -63,26 +87,29 @@ const ManageDocument = ({closeModal,Document_Entity,Entity}) => {
|
||||
// Update schema whenever document type changes
|
||||
useEffect(() => {
|
||||
if (!documentTypeId) return;
|
||||
const type = DocumentTypes?.find((t) => t.id === documentTypeId);
|
||||
setSelectedType(type || null);
|
||||
|
||||
if (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,
|
||||
});
|
||||
const type = DocumentTypes?.find(
|
||||
(t) => String(t.id) === String(documentTypeId)
|
||||
);
|
||||
if (!type) return;
|
||||
|
||||
setSchema(() => newSchema);
|
||||
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,
|
||||
});
|
||||
|
||||
reset({ ...methods.getValues() }, { keepValues: true });
|
||||
}
|
||||
}, [documentTypeId, DocumentTypes, reset]);
|
||||
setSchema(() => newSchema);
|
||||
|
||||
methods.reset(methods.getValues(), { keepValues: true });
|
||||
methods.formState.errors; // triggers revalidation
|
||||
}, [documentTypeId, DocumentTypes, isUpdateForm]);
|
||||
|
||||
// File Upload
|
||||
const onFileChange = async (e) => {
|
||||
@ -127,11 +154,33 @@ const ManageDocument = ({closeModal,Document_Entity,Entity}) => {
|
||||
: ""
|
||||
)
|
||||
.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 <div>Loading...</div>;
|
||||
if (isDocError) return <div>{DocError.message}</div>;
|
||||
return (
|
||||
<div className="p-2">
|
||||
<p className="fw-bold fs-6">Upload New Document</p>
|
||||
<FormProvider key={documentTypeId} {...methods}>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="text-start">
|
||||
{/* Document Name */}
|
||||
<div className="mb-2">
|
||||
<Label htmlFor="name" required>
|
||||
@ -174,28 +223,31 @@ const ManageDocument = ({closeModal,Document_Entity,Entity}) => {
|
||||
</div>
|
||||
|
||||
{/* Type */}
|
||||
{categoryId && (<div className="mb-2">
|
||||
<Label htmlFor="documentTypeId">Document Type</Label>
|
||||
<select
|
||||
{...register("documentTypeId")}
|
||||
className="form-select form-select-sm"
|
||||
>
|
||||
{isTypeLoading && (
|
||||
<option disabled value="">
|
||||
Loading...
|
||||
</option>
|
||||
{categoryId && (
|
||||
<div className="mb-2">
|
||||
<Label htmlFor="documentTypeId">Document Type</Label>
|
||||
<select
|
||||
{...register("documentTypeId")}
|
||||
className="form-select form-select-sm"
|
||||
>
|
||||
{isTypeLoading && (
|
||||
<option disabled value="">
|
||||
Loading...
|
||||
</option>
|
||||
)}
|
||||
{DocumentTypes?.map((type) => (
|
||||
<option key={type.id} value={type.id}>
|
||||
{type.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{errors.documentTypeId && (
|
||||
<div className="danger-text">
|
||||
{errors.documentTypeId.message}
|
||||
</div>
|
||||
)}
|
||||
{DocumentTypes?.map((type) => (
|
||||
<option key={type.id} value={type.id}>
|
||||
{type.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{errors.documentTypeId && (
|
||||
<div className="danger-text">{errors.documentTypeId.message}</div>
|
||||
)}
|
||||
</div>)}
|
||||
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Document ID */}
|
||||
<div className="mb-2">
|
||||
@ -308,7 +360,7 @@ const ManageDocument = ({closeModal,Document_Entity,Entity}) => {
|
||||
type="reset"
|
||||
className="btn btn-secondary btn-sm"
|
||||
disabled={isPending}
|
||||
onClick={()=>closeModal()}
|
||||
onClick={closeModal}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
@ -42,8 +42,13 @@ export const useDocumentFilterEntities =(entityTypeId)=>{
|
||||
export const useDocumentDetails =(documentId)=>{
|
||||
return useQuery({
|
||||
queryKey:["Document",documentId],
|
||||
queryFn:async()=> await DocumentRepository.getDocumentById(documentId)
|
||||
queryFn:async()=> {
|
||||
const resp = await DocumentRepository.getDocumentById(documentId);
|
||||
return resp.data;
|
||||
},
|
||||
enabled:!!documentId
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
//----------------------- MUTATION -------------------------
|
||||
@ -68,7 +73,7 @@ export const useUploadDocument =(onSuccessCallBack)=>{
|
||||
export const useUpdateDocument =(onSuccessCallBack)=>{
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation(({
|
||||
mutationFn:async(documentId,DocumentPayload)=>DocumentRepository.UpdateDocument(documentId,DocumentPayload),
|
||||
mutationFn:async({documentId,DocumentPayload})=>DocumentRepository.UpdateDocument(documentId,DocumentPayload),
|
||||
onSuccess:(data,variables)=>{
|
||||
queryClient.invalidateQueries({queryKey:["DocumentList"]});
|
||||
if(onSuccessCallBack) onSuccessCallBack()
|
||||
|
@ -6,10 +6,9 @@ export const DocumentRepository = {
|
||||
const payloadJsonString = JSON.stringify(filter);
|
||||
return api.get(`/api/Document/list/${entityTypeId}/entity/${entityId}/?pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&searchString=${searchString}`)
|
||||
},
|
||||
getDocumentById:(id)=>api.get(`/api/Document/${id}`),
|
||||
getDocumentById:(id)=>api.get(`/api/Document/get/details/${id}`),
|
||||
|
||||
getFilterEntities:(entityTypeId)=>api.get(`/api/Document/get/filter/${entityTypeId}`),
|
||||
|
||||
UpdateDocument:(documentId,data)=>api.get(`/api/Expense/edit/${documentId}`,data)
|
||||
|
||||
}
|
||||
UpdateDocument:(documentId,data)=>api.put(`/api/Document/edit/${documentId}`,data)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user