Merge branch 'Document_Manag' of https://git.marcoaiot.com/admin/marco.pms.web into Document_Manag

# Conflicts:
#	src/components/Employee/EmpOverview.jsx
This commit is contained in:
Vikas Nale 2025-09-10 10:38:13 +05:30
commit bac62e1fa7
12 changed files with 347 additions and 203 deletions

View File

@ -96,8 +96,9 @@ const DocumentFilterPanel = ({ entityTypeId, onApply }) => {
placeholder="DD-MM-YYYY To DD-MM-YYYY" placeholder="DD-MM-YYYY To DD-MM-YYYY"
startField="startDate" startField="startDate"
endField="endDate" endField="endDate"
defaultRange={false} defaultRange={true}
resetSignal={resetKey} resetSignal={resetKey}
maxDate={new Date()}
/> />
</div> </div>

View File

@ -13,6 +13,9 @@ const DocumentVersionList = ({
isPending, isPending,
setOpenDocument, setOpenDocument,
VerifyDocument, VerifyDocument,
RejectDocument,
showVersions,
latestDoc,
}) => { }) => {
const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT); const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT);
const canDownloadDocument = useHasUserPermission(DOWNLOAD_DOCUMENT); const canDownloadDocument = useHasUserPermission(DOWNLOAD_DOCUMENT);
@ -23,147 +26,262 @@ const DocumentVersionList = ({
} }
}; };
const sortedVersions = versionList?.data
? [...versionList.data].sort((a, b) => b.version - a.version)
: [];
if (versionLoding) { if (versionLoding) {
return <VersionListSkeleton items={2} />; return <VersionListSkeleton items={2} />;
} }
const sortedVersions = versionList?.data
? [...versionList.data].sort((a, b) => b.version - a.version)
: [];
const currentDoc = sortedVersions.length ? sortedVersions[0] : latestDoc;
if (!showVersions) {
if (!currentDoc) {
return <p className="text-muted">No documents available.</p>;
}
return (
<>
<div className="list-group list-group-flush" style={{ marginTop: "-4px", marginLeft: "10px" }}>
<div className="list-group-item list-group-item-action cursor-pointer" style={{ marginLeft: "-30px" }}>
<div className="d-flex justify-content-between">
{/* Left Side: Document Details */}
<div className="d-flex align-items-start" onClick={handleOpenDocument}>
<FileIcon
type={currentDoc.contentType}
size="fs-2"
className="me-2"
/>
<div>
<div className="d-flex align-items-center mb-1">
<span className="fw-semibold" style={{ marginTop: "-6px" }}>
{currentDoc.name}
</span>
</div>
<div className="d-flex align-items-center mb-1">
{getDocuementsStatus(currentDoc.isVerified)}
<span className="text-secondary text-tiny ms-7 ">
File Size: {currentDoc.fileSize} Kb
</span>
</div>
<div className="d-flex align-items-center">
<small className="text-secondary fw-semibold me-2">
Uploaded by
</small>
<Avatar
size="xs"
classAvatar="m-0"
firstName={currentDoc.uploadedBy?.firstName}
lastName={currentDoc.uploadedBy?.lastName}
/>
<span className="ms-1">
<small className="fw-normal" style={{ marginLeft: "-10px" }}>
{`${currentDoc.uploadedBy?.firstName ?? ""} ${currentDoc.uploadedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
</div>
<small className="ms-2" style={{ marginRight: "-113px" }}>
{formatUTCToLocalTime(currentDoc?.uploadedAt)}
</small>
</div>
</div>
<div className="d-flex flex-column align-items-end" style={{ marginTop: "-8px", marginRight: "-540px" }}>
<span className="badge bg-success-subtle text-success">
latest
</span>
</div>
{/* Right Side: Status and Info */}
<div className="d-flex flex-column align-items-end" style={{ marginTop: "31px", marginRight: "21px" }}>
{/* <span className="badge bg-success-subtle text-success">
latest
</span> */}
<div className="d-flex align-items-center mt-1">
{currentDoc?.updatedBy && (
<>
<small className="text-secondary me-2 fw-semibold">Updated by</small>
<Avatar
size="xs"
classAvatar="m-0"
firstName={currentDoc.updatedBy?.firstName}
lastName={currentDoc.updatedBy?.lastName}
/>
<span className="ms-1" style={{ marginRight: "-37px" }}>
<small className="fw-normal" style={{ marginLeft: "-10px" }}>
{`${currentDoc.updatedBy?.firstName ?? ""} ${currentDoc.updatedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
</>
)}
</div>
{/* Conditionally render updated date */}
{currentDoc?.updatedAt && (
<small className="ms-2" style={{ marginRight: "-75px" }}>
{formatUTCToLocalTime(currentDoc?.updatedAt)}
</small>
)}
</div>
</div>
</div>
</div>
{/* Buttons Div - only for the latest pending document when showVersions is false */}
{currentDoc.isVerified === null && canVerifyDocument && (
<div className="d-flex justify-content-end mb-3 me-4">
{isPending ? (
<span className="text-muted">Please Wait...</span>
) : (
<>
<button
type="button"
onClick={RejectDocument}
className="btn btn-sm btn-danger me-2"
>
Reject
</button>
<button
type="button"
onClick={VerifyDocument}
className="btn btn-sm btn-primary"
>
Verify
</button>
</>
)}
</div>
)}
</>
);
}
// If showVersions is true, display all versions
if (!sortedVersions.length) { if (!sortedVersions.length) {
return <p className="text-muted">No documents available.</p>; return <p className="text-muted">No documents available.</p>;
} }
return ( return (
<> <div className="list-group list-group-flush">
<div className="d-flex justify-content-between align-items-center mb-3"> {sortedVersions.map((document, index) => (
<h5 className="mb-0">Documents</h5> <div
<div className="form-check form-switch"> key={document.id}
<input className="list-group-item list-group-item-action cursor-pointer" style={{ marginLeft: "-30px",marginTop:"5px" }}
className="form-check-input" >
type="checkbox" <div className="d-flex justify-content-between">
id="showVersionsSwitch"
/> <div className="d-flex align-items-start" onClick={handleOpenDocument}>
<label className="form-check-label" htmlFor="showVersionsSwitch"> <FileIcon
Show Versions type={document.contentType}
</label> size="fs-2"
</div> className="me-2"
</div> />
<div className="accordion" id="docAccordion"> <div>
<div className="accordion-item shadow-none"> <div className="d-flex align-items-center mb-1">
<div className="accordion-body p-2"> <span className="fw-semibold" style={{ marginTop: "-6px" }}>
<div className="list-group list-group-flush"> {document.name}
{sortedVersions.map((document, index) => ( </span>
<div </div>
key={document.id} <div className="d-flex align-items-center mb-1">
className="list-group-item list-group-item-action" style={{ marginLeft: "-30px" }} {getDocuementsStatus(document.isVerified)}
> <span className="ms-7 ">
<div className="d-flex justify-content-between"> File Size: {document.fileSize} Kb
{/* Left Side: Document Details */} </span>
<div className="d-flex align-items-start"> </div>
<FileIcon <div className="d-flex align-items-center">
type={document.contentType} <small className="text-secondary fw-semibold me-2">
size="fs-2" Uploaded by
className="me-2" </small>
/> <Avatar
<div> size="xs"
<div className="d-flex align-items-center mb-1"> classAvatar="m-0"
<span className="fw-normal"> firstName={document.uploadedBy?.firstName}
{document.name} lastName={document.uploadedBy?.lastName}
</span> />
</div> <span className="ms-1">
<div className="d-flex align-items-center mb-1"> <small className="fw-normal" style={{ marginLeft: "-10px" }}>
{getDocuementsStatus(document.isVerified)} {`${document.uploadedBy?.firstName ?? ""} ${document.uploadedBy?.lastName ?? ""}`.trim() || "N/A"}
<span className="text-secondary ms-7"> </small>
File Size: {document.fileSize} Kb </span>
</span> </div>
</div> <small className="ms-2" style={{ marginRight: "-113px" }}>
<div className="d-flex align-items-center"> {formatUTCToLocalTime(document?.uploadedAt)}
<small className="text-secondary me-2"> </small>
Uploaded by {document?.verifiedAt && (
<div className="d-flex align-items-center mt-1">
<small className="text-secondary me-2 fw-semibold">
{document.isVerified ? "Approved by" : "Rejected by"}
</small> </small>
<Avatar <Avatar
size="xs" size="xs"
classAvatar="m-0" classAvatar="m-0"
firstName={document.uploadedBy?.firstName} firstName={document.verifiedBy?.firstName}
lastName={document.uploadedBy?.lastName} lastName={document.verifiedBy?.lastName}
/> />
<span className="ms-1"> <span className="ms-1">
<small className="fw-normal"> <small className="fw-normal" style={{ marginLeft: "-10px" }}>
{`${document.uploadedBy?.firstName ?? ""} ${document.uploadedBy?.lastName ?? ""}`.trim() || "N/A"} {`${document.verifiedBy?.firstName ?? ""} ${document.verifiedBy?.lastName ?? ""}`.trim() || "N/A"}
</small> </small>
</span> </span>
<small className="ms-2">
{formatUTCToLocalTime(document?.uploadedAt)}
</small>
</div> </div>
{document?.verifiedAt && (
<div className="d-flex align-items-center mt-1">
<small className="text-secondary me-2">
{document.isVerified ? "Approved by" : "Rejected by"}
</small>
<Avatar
size="xs"
classAvatar="m-0"
firstName={document.verifiedBy?.firstName}
lastName={document.verifiedBy?.lastName}
/>
<span className="ms-1">
<small className="fw-normal">
{`${document.verifiedBy?.firstName ?? ""} ${document.verifiedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
<small className="ms-2">
{formatUTCToLocalTime(document?.verifiedAt)}
</small>
</div>
)}
</div>
</div>
{/* Right Side: Status and Actions */}
<div className="d-flex flex-column align-items-end" style={{ marginTop: "42px", marginRight: "-52px" }}>
{document.isLatest && (
<span className="badge bg-success-subtle text-success">
latest
</span>
)} )}
{/* Conditionally render verified date */}
<div className="d-flex align-items-center mt-1"> {document?.verifiedAt && (
{document?.updatedBy && ( <small className="ms-2" style={{ marginRight: "-103px" }}>
<> {formatUTCToLocalTime(document?.verifiedAt)}
<small className="text-secondary me-2">Updated by</small> </small>
<Avatar )}
size="xs"
classAvatar="m-0"
firstName={document.updatedBy?.firstName}
lastName={document.updatedBy?.lastName}
/>
<span className="ms-1">
<small className="fw-normal">
{`${document.updatedBy?.firstName ?? ""} ${document.updatedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
<small className="ms-2">
{formatUTCToLocalTime(document?.updatedAt)}
</small>
</>
)}
</div>
<small className="text-secondary mt-1">
version {document.version}
</small>
</div> </div>
</div> </div>
<div className="d-flex flex-column align-items-end" style={{ marginTop: "-13px", marginRight: "46px" }}>
<small className="badge rounded-pill bg-label-secondary mt-1" style={{ marginRight: "-336px" }}>
version {document.version}
</small>
{document.isLatest && (
<span className="badge bg-success-subtle text-success">
latest
</span>
)}
</div>
{/* Right Side: Status and Actions */}
<div className="d-flex flex-column align-items-end" style={{ marginTop: "16px", marginRight: "46px" }}>
{/* <small className="badge rounded-pill bg-label-secondary mt-1" style={{ marginRight: "-105px" }}>
version {document.version}
</small> */}
{document.isLatest && (
<span className="badge bg-success-subtle text-success">
latest
</span>
)}
<div className="d-flex align-items-center mt-1">
{document?.updatedBy && (
<>
<small className="text-secondary me-2 fw-semibold">Updated by</small>
<Avatar
size="xs"
classAvatar="m-0"
firstName={document.updatedBy?.firstName}
lastName={document.updatedBy?.lastName}
/>
<span className="ms-1" style={{ marginRight: "-37px" }}>
<small className="fw-normal" style={{ marginLeft: "-10px" }}>
{`${document.updatedBy?.firstName ?? ""} ${document.updatedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
</>
)}
</div>
{/* Conditionally render updated date */}
{document?.updatedAt && (
<small className="ms-2" style={{ marginRight: "-75px" }}>
{formatUTCToLocalTime(document?.updatedAt)}
</small>
)}
</div>
</div> </div>
))} </div>
</div> ))}
</div> </div>
</div>
</div>
</>
); );
}; };
export default DocumentVersionList; export default DocumentVersionList;

View File

@ -16,6 +16,7 @@ import ManageDocument from "./ManageDocument";
import ViewDocument from "./ViewDocument"; import ViewDocument from "./ViewDocument";
import DocumentViewerModal from "./DocumentViewerModal"; import DocumentViewerModal from "./DocumentViewerModal";
import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { useProfile } from "../../hooks/useProfile";
// Context // Context
export const DocumentContext = createContext(); export const DocumentContext = createContext();
@ -47,6 +48,7 @@ export const getDocuementsStatus = (status) => {
} }
}; };
const Documents = ({ Document_Entity, Entity }) => { const Documents = ({ Document_Entity, Entity }) => {
const [isSelf, setIsSelf] = useState(false);
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const [isActive, setIsActive] = useState(true); const [isActive, setIsActive] = useState(true);
const [filters, setFilter] = useState(); const [filters, setFilter] = useState();
@ -63,8 +65,14 @@ const Documents = ({ Document_Entity, Entity }) => {
document: null, document: null,
isOpen: false, isOpen: false,
}); });
const { profile } = useProfile();
const canUploadDocument = useHasUserPermission(UPLOAD_DOCUMENT) useEffect(() => {
if (profile?.employeeInfo?.id) {
setIsSelf(profile.employeeInfo.id === employeeId);
}
}, [profile?.employeeInfo?.id, employeeId]);
const canUploadDocument = useHasUserPermission(UPLOAD_DOCUMENT);
const { setOffcanvasContent, setShowTrigger } = useFab(); const { setOffcanvasContent, setShowTrigger } = useFab();
@ -114,13 +122,16 @@ const Documents = ({ Document_Entity, Entity }) => {
<div className="row align-items-center"> <div className="row align-items-center">
{/* Search */} {/* Search */}
<div className="d-flex col-8 col-md-8 col-lg-4 mb-md-0 align-items-center"> <div className="d-flex col-8 col-md-8 col-lg-4 mb-md-0 align-items-center">
<div className="d-flex"> <input <div className="d-flex">
type="search" {" "}
value={searchText} <input
onChange={(e) => setSearchText(e.target.value)} type="search"
className="form-control form-control-sm" value={searchText}
placeholder="Search Document" onChange={(e) => setSearchText(e.target.value)}
/></div> className="form-control form-control-sm"
placeholder="Search Document"
/>
</div>
<label className="switch switch-sm mx-2"> <label className="switch switch-sm mx-2">
<input <input
type="checkbox" type="checkbox"
@ -137,7 +148,6 @@ const Documents = ({ Document_Entity, Entity }) => {
</span> </span>
</label> </label>
</div> </div>
{/* Actions */} {/* Actions */}
<div className="col-6 col-md-6 col-lg-8 text-end"> <div className="col-6 col-md-6 col-lg-8 text-end">
@ -157,21 +167,22 @@ const Documents = ({ Document_Entity, Entity }) => {
}`} }`}
></i> ></i>
</span> */} </span> */}
{canUploadDocument && (<button {(isSelf || canUploadDocument) && (
type="button" <button
title="Add New Document" type="button"
className="p-1 bg-primary rounded-circle cursor-pointer" title="Add New Document"
onClick={() => className="p-1 bg-primary rounded-circle cursor-pointer"
setManageDoc({ onClick={() =>
document: null, setManageDoc({
isOpen: true, document: null,
}) isOpen: true,
} })
> }
<i className="bx bx-plus fs-4 text-white"></i> >
</button>)} <i className="bx bx-plus fs-4 text-white"></i>
</button>
)}
</div> </div>
</div> </div>
<DocumentsList <DocumentsList

View File

@ -17,6 +17,9 @@ import Pagination from "../common/Pagination";
import ConfirmModal from "../common/ConfirmModal"; import ConfirmModal from "../common/ConfirmModal";
import { isPending } from "@reduxjs/toolkit"; import { isPending } from "@reduxjs/toolkit";
import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { useProfile } from "../../hooks/useProfile";
import { useParams } from "react-router-dom";
import showToast from "../../services/toastService";
const DocumentsList = ({ const DocumentsList = ({
Document_Entity, Document_Entity,
@ -27,13 +30,22 @@ const DocumentsList = ({
setRefetchFn, setRefetchFn,
isActive, isActive,
}) => { }) => {
const { employeeId } = useParams();
const [isSelf, setIsSelf] = useState(false);
const { profile } = useProfile();
const canDeleteDocument = useHasUserPermission(DELETE_DOCUMENT);
const canModifyDocument = useHasUserPermission(MODIFY_DOCUMENT);
useEffect(() => {
if (profile?.employeeInfo?.id && employeeId) {
setIsSelf(String(profile.employeeInfo.id) === String(employeeId));
}
}, [profile?.employeeInfo?.id, employeeId]);
const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [deletingId, setDeletingId] = useState(null); const [deletingId, setDeletingId] = useState(null);
const [restoringIds, setRestoringIds] = useState([]); const [restoringIds, setRestoringIds] = useState([]);
const debouncedSearch = useDebounce(searchText, 500); const debouncedSearch = useDebounce(searchText, 500);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const canDeleteDocument = useHasUserPermission(DELETE_DOCUMENT);
const canModifyDocument = useHasUserPermission(MODIFY_DOCUMENT);
const { data, isError, isLoading, error, refetch, isFetching } = const { data, isError, isLoading, error, refetch, isFetching } =
useDocumentListByEntityId( useDocumentListByEntityId(
Document_Entity, Document_Entity,
@ -205,7 +217,7 @@ const DocumentsList = ({
} }
></i> ></i>
{canModifyDocument && ( {(isSelf || canModifyDocument) && (
<i <i
className="bx bx-edit text-secondary cursor-pointer" className="bx bx-edit text-secondary cursor-pointer"
onClick={() => onClick={() =>
@ -214,7 +226,7 @@ const DocumentsList = ({
></i> ></i>
)} )}
{canDeleteDocument && ( {(isSelf || canDeleteDocument) && (
<i <i
className="bx bx-trash text-danger cursor-pointer" className="bx bx-trash text-danger cursor-pointer"
onClick={() => { onClick={() => {

View File

@ -12,9 +12,6 @@ import {
ITEMS_PER_PAGE, ITEMS_PER_PAGE,
VERIFY_DOCUMENT, VERIFY_DOCUMENT,
} from "../../utils/constants"; } from "../../utils/constants";
import Pagination from "../common/Pagination";
import VersionListSkeleton from "./VersionListSkeleton";
// import DocumentDetailsSkeleton from "./DocumentDetailsSkeleton";
import DocumentDetailsSkeleton from "./DocumentDetailsSkeleton "; import DocumentDetailsSkeleton from "./DocumentDetailsSkeleton ";
import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import DocumentVersionList from "./DocumentVersionList"; import DocumentVersionList from "./DocumentVersionList";
@ -22,15 +19,20 @@ import DocumentVersionList from "./DocumentVersionList";
const ViewDocument = () => { const ViewDocument = () => {
const { viewDoc, setOpenDocument } = useDocumentContext(); const { viewDoc, setOpenDocument } = useDocumentContext();
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [showVersions, setShowVersions] = useState(false);
const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT); const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT);
// Document Details
const { data, isLoading, isError, error } = useDocumentDetails( const { data, isLoading, isError, error } = useDocumentDetails(
viewDoc?.document viewDoc?.document
); );
// Document Versions (fetch only if toggle is ON)
const { const {
data: versionList, data: versionList,
isLoading: versionLoding, isLoading: versionLoading,
} = useDocumentVersionList( } = useDocumentVersionList(
data?.parentAttachmentId, showVersions ? data?.parentAttachmentId : null,
ITEMS_PER_PAGE - 10, ITEMS_PER_PAGE - 10,
currentPage currentPage
); );
@ -41,6 +43,7 @@ const ViewDocument = () => {
} }
}; };
// Verify / Reject
const { mutate: VerifyDoc, isPending } = useVerifyDocument(); const { mutate: VerifyDoc, isPending } = useVerifyDocument();
const VerifyDocument = () => { const VerifyDocument = () => {
VerifyDoc({ documentId: viewDoc?.document, isVerify: true }); VerifyDoc({ documentId: viewDoc?.document, isVerify: true });
@ -57,11 +60,12 @@ const ViewDocument = () => {
<p className="danger-text">{error?.response?.status}</p> <p className="danger-text">{error?.response?.status}</p>
</div> </div>
); );
console.log("kartik", data)
return ( return (
<div className="p-3"> <div className="p-3">
<p className="fw-bold fs-5 mb-3 border-bottom pb-2">Document Details</p> <p className="fw-bold fs-5 mb-3 border-bottom pb-2">Document Details</p>
{/* Document Info Rows */}
<div className="row mb-2 text-start"> <div className="row mb-2 text-start">
<div className="col-12 col-md-6 d-flex"> <div className="col-12 col-md-6 d-flex">
<span className="fw-semibold me-2" style={{ minWidth: "140px" }}> <span className="fw-semibold me-2" style={{ minWidth: "140px" }}>
@ -103,14 +107,7 @@ const ViewDocument = () => {
{formatUTCToLocalTime(data.uploadedAt)} {formatUTCToLocalTime(data.uploadedAt)}
</span> </span>
</div> </div>
<div className="col-12 col-md-6 d-flex">
<span className="fw-semibold me-2" style={{ minWidth: "140px" }}>
Updated At:
</span>
<span className="text-muted">
{formatUTCToLocalTime(data.updatedAt) || "-"}
</span>
</div>
</div> </div>
<div className="row mb-2 text-start"> <div className="row mb-2 text-start">
@ -144,42 +141,35 @@ const ViewDocument = () => {
</div> </div>
</div> </div>
{/* Verify / Reject */} {/* Toggle for Versions */}
{data.isVerified === null && canVerifyDocument && ( <div className="d-flex justify-content-between align-items-center mb-3">
<div className="d-flex justify-content-end mb-3"> <p className="m-0 fw-semibold fs-6">Documents:</p>
{isPending ? ( <div className="form-check form-switch">
<span className="text-muted">Please Wait...</span> <label className="form-check-label" htmlFor="showVersionsSwitch">
) : ( Show Versions
<> </label>
<button <input
type="button" className="form-check-input"
onClick={RejectDocument} type="checkbox"
className="btn btn-sm btn-danger me-2" id="showVersionsSwitch"
> checked={showVersions}
Reject onChange={(e) => setShowVersions(e.target.checked)}
</button> />
<button
type="button"
onClick={VerifyDocument}
className="btn btn-sm btn-primary"
>
Verify
</button>
</>
)}
</div> </div>
)} </div>
<DocumentVersionList <DocumentVersionList
versionLoding={versionLoding} versionLoding={versionLoading}
versionList={versionList} versionList={versionList}
isPending={isPending} isPending={isPending}
setOpenDocument={setOpenDocument} setOpenDocument={setOpenDocument}
VerifyDocument={VerifyDocument} VerifyDocument={VerifyDocument}
RejectDocument={RejectDocument}
showVersions={showVersions}
latestDoc={data}
/> />
</div> </div>
); );
}; };
export default ViewDocument; export default ViewDocument;

View File

@ -3,6 +3,7 @@ import React, { useState, useEffect } from "react";
import { useChangePassword } from "../../components/Context/ChangePasswordContext"; import { useChangePassword } from "../../components/Context/ChangePasswordContext";
import GlobalModel from "../common/GlobalModel"; import GlobalModel from "../common/GlobalModel";
import ManageEmployee from "./ManageEmployee"; import ManageEmployee from "./ManageEmployee";
import { formatUTCToLocalTime } from "../../utils/dateUtils";
const EmpBanner = ({ profile, loggedInUser }) => { const EmpBanner = ({ profile, loggedInUser }) => {
const { openChangePassword } = useChangePassword(); const { openChangePassword } = useChangePassword();
@ -77,7 +78,7 @@ const EmpBanner = ({ profile, loggedInUser }) => {
{" "} {" "}
Joined on{" "} Joined on{" "}
{profile?.joiningDate ? ( {profile?.joiningDate ? (
new Date(profile.joiningDate).toLocaleDateString() formatUTCToLocalTime(profile.joiningDate)
) : ( ) : (
<em>NA</em> <em>NA</em>
)} )}

View File

@ -1,19 +1,31 @@
import React from "react"; import React, { useEffect, useState } from "react";
import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { VIEW_DOCUMENT } from "../../utils/constants"; import { VIEW_DOCUMENT } from "../../utils/constants";
import { useProfile } from "../../hooks/useProfile";
import { useParams } from "react-router-dom";
const EmployeeNav = ({ onPillClick, activePill }) => { const EmployeeNav = ({ onPillClick, activePill }) => {
const canViewDocuments = useHasUserPermission(VIEW_DOCUMENT) const { employeeId } = useParams();
const tabs = [ const [isAbleToViewDocuments, setIsAbleToViewDocuments] = useState(false);
const canViewDocuments = useHasUserPermission(VIEW_DOCUMENT);
const { profile } = useProfile();
useEffect(() => {
if (profile?.employeeInfo?.id) {
setIsAbleToViewDocuments(profile.employeeInfo.id === employeeId);
}
}, [profile?.employeeInfo?.id, employeeId]);
const tabs = [
{ key: "profile", icon: "bx bx-user", label: "Profile" }, { key: "profile", icon: "bx bx-user", label: "Profile" },
{ key: "attendance", icon: "bx bx-group", label: "Attendances" }, { key: "attendance", icon: "bx bx-group", label: "Attendances" },
canViewDocuments && { (isAbleToViewDocuments || canViewDocuments) && {
key: "documents", key: "documents",
icon: "bx bx-file", icon: "bx bx-file",
label: "Documents", label: "Documents",
}, },
{ key: "activities", icon: "bx bx-grid-alt", label: "Activities" }, { key: "activities", icon: "bx bx-grid-alt", label: "Activities" },
].filter(Boolean); ].filter(Boolean);
return ( return (
<div className="col-md-12"> <div className="col-md-12">
<div className="nav-align-top"> <div className="nav-align-top">

View File

@ -105,7 +105,7 @@ const ProjectPermission = () => {
}; };
return ( return (
<div className="row"> <div className="row px-2 py-1">
<form className="row" onSubmit={handleSubmit(onSubmit)}> <form className="row" onSubmit={handleSubmit(onSubmit)}>
{/* Employee Dropdown */} {/* Employee Dropdown */}
<div className="d-flex align-items-end gap-2"> <div className="d-flex align-items-end gap-2">
@ -142,7 +142,7 @@ const ProjectPermission = () => {
{/* Permissions */} {/* Permissions */}
{ProjectModules.map((feature) => ( {ProjectModules.map((feature) => (
<div key={feature.id} className="row my-2"> <div key={feature.id} className="row my-2 px-3 ">
<div className="col-12 text-start fw-semibold mb-2"> <div className="col-12 text-start fw-semibold mb-2">
{feature.name} {feature.name}
</div> </div>

View File

@ -31,7 +31,7 @@ const ProjectSetting = () => {
return ( return (
<div className="w-100"> <div className="w-100">
<div className="card p-3"> <div className="card py-2 px-5">
<div className="col-4"> <div className="col-4">
<div className="dropdown text-start"> <div className="dropdown text-start">
<button <button

View File

@ -84,6 +84,7 @@ export const DateRangePicker1 = ({
allowText = false, allowText = false,
resetSignal, resetSignal,
defaultRange = true, defaultRange = true,
maxDate = null,
...rest ...rest
}) => { }) => {
const inputRef = useRef(null); const inputRef = useRef(null);
@ -117,6 +118,7 @@ export const DateRangePicker1 = ({
mode: "range", mode: "range",
dateFormat: "d-m-Y", dateFormat: "d-m-Y",
allowInput: allowText, allowInput: allowText,
maxDate ,
onChange: (selectedDates) => { onChange: (selectedDates) => {
if (selectedDates.length === 2) { if (selectedDates.length === 2) {
const [start, end] = selectedDates; const [start, end] = selectedDates;

View File

@ -110,7 +110,7 @@ const SelectMultiple = ({
onChange={() => handleCheckboxChange(valueVal)} onChange={() => handleCheckboxChange(valueVal)}
style={{ marginRight: 8 }} style={{ marginRight: 8 }}
/> />
<label className="text-secondary">{labelVal}</label> <label className="fw-semibold">{labelVal}</label>
</div> </div>
); );
})} })}

View File

@ -185,12 +185,9 @@ export const useActiveInActiveDocument = ()=>{
return useMutation({ return useMutation({
mutationFn:async({documentId,isActive}) => await DocumentRepository.deleteDocument(documentId,isActive), mutationFn:async({documentId,isActive}) => await DocumentRepository.deleteDocument(documentId,isActive),
onSuccess: (data, variables) => { onSuccess: (data, variables) => {
const {isActive} = variables;
queryClient.invalidateQueries({ queryKey: ["DocumentList"] }); queryClient.invalidateQueries({ queryKey: ["DocumentList"] });
showToast( showToast(`Document ${isActive ? "restored":"Deleted"} successfully`,"success")
data.response.data.message ||
"Document Successfully Verified !",
"success"
);
}, },
onError: (error) => { onError: (error) => {
showToast( showToast(