Adding Chips in Document.

This commit is contained in:
Kartik Sharma 2025-10-09 17:50:56 +05:30
parent cbb52087c3
commit c686b388f4
5 changed files with 133 additions and 92 deletions

View File

@ -124,7 +124,7 @@ const AttendLogs = ({ Id }) => {
return ( return (
<div className="table-responsive"> <div className="table-responsive">
<div className="mb-3"> <div className="mb-3">
<h5 className="fw-bold mb-2">Attendance Logs</h5> <h5 className="fw-bold mb-4">Attendance Logs</h5>
{logs && !loading && ( {logs && !loading && (
<p className="mb-0 text-start"> <p className="mb-0 text-start">
Showing logs for{" "} Showing logs for{" "}
@ -146,9 +146,9 @@ const AttendLogs = ({ Id }) => {
<table className="table table-sm mb-0"> <table className="table table-sm mb-0">
<thead> <thead>
<tr> <tr>
<th>Activity</th>
<th>Date</th> <th>Date</th>
<th>Time</th> <th>Time</th>
<th>Activity</th>
<th>Location</th> <th>Location</th>
<th>Recored By</th> <th>Recored By</th>
<th>Description</th> <th>Description</th>
@ -160,15 +160,16 @@ const AttendLogs = ({ Id }) => {
.sort((a, b) => b.id - a.id) .sort((a, b) => b.id - a.id)
.map((log, index) => ( .map((log, index) => (
<tr key={index}> <tr key={index}>
<td>
{whichActivityPerform(log.activity, log.activityTime)}
</td>
<td> <td>
<div className="py-2"> <div className="py-2">
{formatUTCToLocalTime(log.activityTime)} {formatUTCToLocalTime(log.activityTime)}
</div> </div>
</td> </td>
<td>{convertShortTime(log.activityTime)}</td> <td>{convertShortTime(log.activityTime)}</td>
<td>
{whichActivityPerform(log.activity, log.activityTime)}
</td>
<td> <td>
{log?.latitude != 0 ? ( {log?.latitude != 0 ? (
<i <i

View File

@ -2,80 +2,93 @@ import React, { useMemo } from "react";
import moment from "moment"; import moment from "moment";
const DocumentFilterChips = ({ filters, filterData, removeFilterChip }) => { const DocumentFilterChips = ({ filters, filterData, removeFilterChip }) => {
const filterChips = useMemo(() => { // Normalize structure: handle both "filterData.data" and plain "filterData"
const chips = []; const data = filterData?.data || filterData || {};
const buildGroup = (ids, list, label, key) => { const filterChips = useMemo(() => {
if (!ids?.length) return; const chips = [];
const items = ids.map((id) => ({
id,
name: list.find((item) => item.id === id)?.name || id,
}));
chips.push({ key, label, items });
};
// Build chips from document filters const buildGroup = (ids, list, label, key) => {
buildGroup(filters.uploadedByIds, filterData.data.uploadedBy || [], "Uploaded By", "uploadedByIds"); if (!ids?.length) return;
buildGroup(filters.documentCategoryIds, filterData.data.documentCategory || [], "Category", "documentCategoryIds"); const items = ids.map((id) => ({
buildGroup(filters.documentTypeIds, filterData.data.documentType || [], "Type", "documentTypeIds"); id,
buildGroup(filters.documentTagIds, filterData.data.documentTag || [], "Tags", "documentTagIds"); name: list?.find((item) => item.id === id)?.name || id,
}));
chips.push({ key, label, items });
};
if (filters.statusIds?.length) { // Build chips using normalized data
const items = filters.statusIds.map((status) => ({ buildGroup(filters.uploadedByIds, data.uploadedBy || [], "Uploaded By", "uploadedByIds");
id: status, buildGroup(filters.documentCategoryIds, data.documentCategory || [], "Category", "documentCategoryIds");
name: buildGroup(filters.documentTypeIds, data.documentType || [], "Type", "documentTypeIds");
status === true buildGroup(filters.documentTagIds, data.documentTag || [], "Tags", "documentTagIds");
? "Verified"
: status === false
? "Rejected"
: "Pending",
}));
chips.push({ key: "statusIds", label: "Status", items });
}
if (filters.startDate || filters.endDate) { if (filters.statusIds?.length) {
const start = filters.startDate ? moment(filters.startDate).format("DD-MM-YYYY") : ""; const items = filters.statusIds.map((status) => ({
const end = filters.endDate ? moment(filters.endDate).format("DD-MM-YYYY") : ""; id: status,
chips.push({ name:
key: "dateRange", status === true
label: "Date Range", ? "Verified"
items: [{ id: "dateRange", name: `${start} - ${end}` }], : status === false
}); ? "Rejected"
} : "Pending",
}));
chips.push({ key: "statusIds", label: "Status", items });
}
return chips; if (filters.startDate || filters.endDate) {
}, [filters, filterData]); const start = filters.startDate ? moment(filters.startDate).format("DD-MM-YYYY") : "";
const end = filters.endDate ? moment(filters.endDate).format("DD-MM-YYYY") : "";
chips.push({
key: "dateRange",
label: "Date Range",
items: [{ id: "dateRange", name: `${start} - ${end}` }],
});
}
if (!filterChips.length) return null; return chips;
}, [filters, filterData]);
console.log("Kartik", filterData.uploadedBy) if (!filterChips.length) return null;
return (
<div className="row my-2"> return (
<div className="col-12"> <div className="row my-2">
<div className="d-flex flex-wrap align-items-start gap-1"> <div className="col-12">
{filterChips.map((chip) => ( <div className="d-flex flex-wrap align-items-start gap-1">
<div key={chip.key} className="d-flex align-items-center flex-wrap px-2 py-1" style={{ fontSize: "0.9rem" }}> {filterChips.map((chip) => (
<span className="fw-semibold me-2">{chip.label}:</span> <div
<div className="d-flex flex-wrap align-items-center gap-1"> key={chip.key}
{chip.items.map((item) => ( className="d-flex align-items-center flex-wrap px-2 py-1"
<span key={item.id} className="d-flex align-items-center bg-light rounded px-2 py-1 text-xs"> style={{ fontSize: "0.9rem" }}
<span>{item.name}</span> >
<button <span className="fw-semibold me-2">{chip.label}:</span>
type="button" <div className="d-flex flex-wrap align-items-center gap-1">
className="btn-close btn-close-white btn-sm ms-2" {chip.items.map((item) => (
style={{ filter: "invert(1) grayscale(1)", opacity: 0.7, fontSize: "0.6rem" }} <span
onClick={() => removeFilterChip(chip.key, item.id)} key={item.id}
/> className="d-flex align-items-center bg-light rounded px-2 py-1 text-xs"
</span> >
))} <span>{item.name}</span>
</div> <button
</div> type="button"
))} className="btn-close btn-close-white btn-sm ms-2"
</div> style={{
filter: "invert(1) grayscale(1)",
opacity: 0.7,
fontSize: "0.6rem",
}}
onClick={() => removeFilterChip(chip.key, item.id)}
/>
</span>
))}
</div>
</div> </div>
))}
</div> </div>
); </div>
</div>
);
}; };
export default DocumentFilterChips; export default DocumentFilterChips;

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState,useMemo } from "react"; import React, { useEffect, useState, useMemo, useImperativeHandle, forwardRef } from "react";
import { useDocumentFilterEntities } from "../../hooks/useDocument"; import { useDocumentFilterEntities } from "../../hooks/useDocument";
import { FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
@ -11,16 +11,16 @@ import SelectMultiple from "../common/SelectMultiple";
import moment from "moment"; import moment from "moment";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
const DocumentFilterPanel = ({ entityTypeId, onApply,setFilterdata }) => { const DocumentFilterPanel = forwardRef(({ entityTypeId, onApply, setFilterdata }, ref) => {
const [resetKey, setResetKey] = useState(0); const [resetKey, setResetKey] = useState(0);
const { status } = useParams(); const { status } = useParams();
const { data, isError, isLoading, error } = const { data, isError, isLoading, error } =
useDocumentFilterEntities(entityTypeId); useDocumentFilterEntities(entityTypeId);
//changes //changes
const dynamicDocumentFilterDefaultValues = useMemo(() => { const dynamicDocumentFilterDefaultValues = useMemo(() => {
return { return {
...DocumentFilterDefaultValues, ...DocumentFilterDefaultValues,
uploadedByIds: DocumentFilterDefaultValues.uploadedByIds || [], uploadedByIds: DocumentFilterDefaultValues.uploadedByIds || [],
@ -49,13 +49,24 @@ const DocumentFilterPanel = ({ entityTypeId, onApply,setFilterdata }) => {
document.querySelector(".offcanvas.show .btn-close")?.click(); document.querySelector(".offcanvas.show .btn-close")?.click();
}; };
//changes useImperativeHandle(ref, () => ({
useEffect(() => { resetFieldValue: (name, value) => {
// Reset specific field
if (value !== undefined) {
setValue(name, value);
} else {
reset({ ...methods.getValues(), [name]: DocumentFilterDefaultValues[name] });
}
},
getValues: methods.getValues, // optional, to read current filter state
}));
//changes
useEffect(() => {
if (data && setFilterdata) { if (data && setFilterdata) {
setFilterdata(data); setFilterdata(data);
} }
}, [data, setFilterdata]); }, [data, setFilterdata]);
console.log("Veer",data)
const onSubmit = (values) => { const onSubmit = (values) => {
onApply({ onApply({
@ -88,7 +99,7 @@ const DocumentFilterPanel = ({ entityTypeId, onApply,setFilterdata }) => {
documentTag = [], documentTag = [],
} = data?.data || {}; } = data?.data || {};
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>
@ -100,18 +111,16 @@ const DocumentFilterPanel = ({ entityTypeId, onApply,setFilterdata }) => {
<div className="d-inline-flex border rounded-pill overflow-hidden shadow-none"> <div className="d-inline-flex border rounded-pill overflow-hidden shadow-none">
<button <button
type="button" type="button"
className={`btn px-2 py-1 rounded-0 text-tiny ${ className={`btn px-2 py-1 rounded-0 text-tiny ${isUploadedAt ? "active btn-secondary text-white" : ""
isUploadedAt ? "active btn-secondary text-white" : "" }`}
}`}
onClick={() => setValue("isUploadedAt", true)} onClick={() => setValue("isUploadedAt", true)}
> >
Uploaded On Uploaded On
</button> </button>
<button <button
type="button" type="button"
className={`btn px-2 py-1 rounded-0 text-tiny ${ className={`btn px-2 py-1 rounded-0 text-tiny ${!isUploadedAt ? "active btn-secondary text-white" : ""
!isUploadedAt ? "active btn-secondary text-white" : "" }`}
}`}
onClick={() => setValue("isUploadedAt", false)} onClick={() => setValue("isUploadedAt", false)}
> >
Updated On Updated On
@ -228,6 +237,6 @@ const DocumentFilterPanel = ({ entityTypeId, onApply,setFilterdata }) => {
</form> </form>
</FormProvider> </FormProvider>
); );
}; });
export default DocumentFilterPanel; export default DocumentFilterPanel;

View File

@ -1,4 +1,4 @@
import React, { createContext, useContext, useEffect, useState } from "react"; import React, { createContext, useContext, useEffect, useRef, useState } from "react";
import GlobalModel from "../common/GlobalModel"; import GlobalModel from "../common/GlobalModel";
import NewDocument from "./ManageDocument"; import NewDocument from "./ManageDocument";
import { DOCUMENTS_ENTITIES, UPLOAD_DOCUMENT } from "../../utils/constants"; import { DOCUMENTS_ENTITIES, UPLOAD_DOCUMENT } from "../../utils/constants";
@ -59,6 +59,7 @@ const Documents = ({ Document_Entity, Entity }) => {
const { employeeId } = useParams(); const { employeeId } = useParams();
const [OpenDocument, setOpenDocument] = useState(false); const [OpenDocument, setOpenDocument] = useState(false);
const [filterData, setFilterdata] = useState(DocumentFilterDefaultValues); const [filterData, setFilterdata] = useState(DocumentFilterDefaultValues);
const updatedFilters = useRef();
const [ManageDoc, setManageDoc] = useState({ const [ManageDoc, setManageDoc] = useState({
document: null, document: null,
isOpen: false, isOpen: false,
@ -94,7 +95,7 @@ const Documents = ({ Document_Entity, Entity }) => {
setShowTrigger(true); setShowTrigger(true);
setOffcanvasContent( setOffcanvasContent(
"Document Filters", "Document Filters",
<DocumentFilterPanel entityTypeId={DocumentEntity} onApply={setFilter} setFilterdata={setFilterdata} /> <DocumentFilterPanel entityTypeId={DocumentEntity} onApply={setFilter} setFilterdata={setFilterdata} ref={updatedFilters} />
); );
return () => { return () => {
@ -102,7 +103,7 @@ const Documents = ({ Document_Entity, Entity }) => {
setOffcanvasContent("", null); setOffcanvasContent("", null);
}; };
}, []); }, []);
console.log("Testing",filterData)
const contextValues = { const contextValues = {
ManageDoc, ManageDoc,
setManageDoc, setManageDoc,
@ -110,6 +111,7 @@ console.log("Testing",filterData)
setViewDoc, setViewDoc,
setOpenDocument, setOpenDocument,
OpenDocument, OpenDocument,
// removeFilterChip
}; };
useEffect(() => { useEffect(() => {
@ -118,22 +120,38 @@ console.log("Testing",filterData)
} }
}, [Document_Entity]); }, [Document_Entity]);
const removeFilterChip = (key, id) => { const removeFilterChip = (key, id) => {
const updatedFilters = { ...filters }; const updatedFilters = { ...filters };
if (Array.isArray(updatedFilters[key])) { if (Array.isArray(updatedFilters[key])) {
updatedFilters[key] = updatedFilters[key].filter((v) => v !== id); updatedFilters[key] = updatedFilters[key].filter((v) => v !== id);
} else { }
else if (key === "dateRange") {
updatedFilters.startDate = null;
updatedFilters.endDate = null;
}
else {
updatedFilters[key] = null; updatedFilters[key] = null;
} }
setFilter(updatedFilters); setFilter(updatedFilters);
methods.setValue(key, updatedFilters[key] ?? DocumentFilterDefaultValues[key]);
if (key === "dateRange") {
methods.setValue("startDate", null);
methods.setValue("endDate", null);
}
}; };
return ( return (
<DocumentContext.Provider value={contextValues}> <DocumentContext.Provider value={contextValues}>
<div className="mt-2"> <div className="mt-2">
<div className="card page-min-h d-flex p-2"> <div className="card page-min-h d-flex p-2">
<DocumentFilterChips filters={filters} filterData={filterData} removeFilterChip={removeFilterChip} /> <DocumentFilterChips filters={filters} filterData={filterData} removeFilterChip={removeFilterChip} />
<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">

View File

@ -65,7 +65,7 @@ const DocumentsList = ({
setIsRefetching(isFetching); setIsRefetching(isFetching);
}, [isFetching, setIsRefetching]); }, [isFetching, setIsRefetching]);
const { setManageDoc, setViewDoc } = useDocumentContext(); const { setManageDoc, setViewDoc,removeFilterChip } = useDocumentContext();
const { mutate: ActiveInActive, isPending } = useActiveInActiveDocument(); const { mutate: ActiveInActive, isPending } = useActiveInActiveDocument();
const paginate = (page) => { const paginate = (page) => {