Compare commits
29 Commits
HotChanges
...
main
Author | SHA1 | Date | |
---|---|---|---|
12b632f087 | |||
6ee4fb6d04 | |||
67bb685d4b | |||
8fd4e7f3f1 | |||
aca2decb00 | |||
f7f4b68997 | |||
f839613066 | |||
b58bd33774 | |||
136bc94c5b | |||
281a956ac8 | |||
31882c3d12 | |||
a64635cd37 | |||
9b8c8c34ab | |||
704ba79289 | |||
3440467107 | |||
f4edcfd2f3 | |||
62e5c6899a | |||
00a23b3de9 | |||
79161a8ede | |||
860779d096 | |||
a2067e150d | |||
edce5ef614 | |||
dd944b3414 | |||
13d3572cf6 | |||
0dd7c19457 | |||
3cc4f0b416 | |||
f8095ac9bf | |||
6280abf95e | |||
1200937097 |
@ -9,4 +9,274 @@
|
|||||||
}
|
}
|
||||||
.table_header_border {
|
.table_header_border {
|
||||||
border-bottom:2px solid var(--bs-table-border-color) ;
|
border-bottom:2px solid var(--bs-table-border-color) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.text-xxs { font-size: 0.55rem; } /* 8px */
|
||||||
|
.text-xs { font-size: 0.75rem; } /* 12px */
|
||||||
|
.text-sm { font-size: 0.875rem; } /* 14px */
|
||||||
|
.text-base { font-size: 1rem; } /* 16px */
|
||||||
|
.text-lg { font-size: 1.125rem; } /* 18px */
|
||||||
|
.text-xl { font-size: 1.25rem; } /* 20px */
|
||||||
|
.text-2xl { font-size: 1.5rem; } /* 24px */
|
||||||
|
.text-3xl { font-size: 1.875rem; } /* 30px */
|
||||||
|
.text-4xl { font-size: 2.25rem; } /* 36px */
|
||||||
|
.text-5xl { font-size: 3rem; } /* 48px */
|
||||||
|
.text-6xl { font-size: 3.75rem; } /* 60px */
|
||||||
|
.text-7xl { font-size: 4.5rem; } /* 72px */
|
||||||
|
.text-8xl { font-size: 6rem; } /* 96px */
|
||||||
|
.text-9xl { font-size: 8rem; } /* 128px */
|
||||||
|
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
.w-0 { width: 0px; }
|
||||||
|
.w-px { width: 1px; }
|
||||||
|
.w-1 { width: 0.25rem; } /* 4px */
|
||||||
|
.w-2 { width: 0.5rem; } /* 8px */
|
||||||
|
.w-3 { width: 0.75rem; } /* 12px */
|
||||||
|
.w-4 { width: 1rem; } /* 16px */
|
||||||
|
.w-5 { width: 1.25rem; } /* 20px */
|
||||||
|
.w-6 { width: 1.5rem; } /* 24px */
|
||||||
|
.w-8 { width: 2rem; } /* 32px */
|
||||||
|
.w-10 { width: 2.5rem; } /* 40px */
|
||||||
|
.w-12 { width: 3rem; } /* 48px */
|
||||||
|
.w-16 { width: 4rem; } /* 64px */
|
||||||
|
.w-20 { width: 5rem; } /* 80px */
|
||||||
|
.w-24 { width: 6rem; } /* 96px */
|
||||||
|
.w-32 { width: 8rem; } /* 128px */
|
||||||
|
.w-40 { width: 10rem; } /* 160px */
|
||||||
|
.w-48 { width: 12rem; } /* 192px */
|
||||||
|
.w-56 { width: 14rem; } /* 224px */
|
||||||
|
.w-64 { width: 16rem; } /* 256px */
|
||||||
|
.w-auto { width: auto; }
|
||||||
|
.w-full { width: 100%; }
|
||||||
|
.w-screen{ width: 100vw; }
|
||||||
|
.w-min { width: min-content; }
|
||||||
|
.w-max { width: max-content; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.h-0 { height: 0px; }
|
||||||
|
.h-px { height: 1px; }
|
||||||
|
.h-1 { height: 0.25rem; } /* 4px */
|
||||||
|
.h-2 { height: 0.5rem; } /* 8px */
|
||||||
|
.h-3 { height: 0.75rem; } /* 12px */
|
||||||
|
.h-4 { height: 1rem; } /* 16px */
|
||||||
|
.h-5 { height: 1.25rem; } /* 20px */
|
||||||
|
.h-6 { height: 1.5rem; } /* 24px */
|
||||||
|
.h-8 { height: 2rem; } /* 32px */
|
||||||
|
.h-10 { height: 2.5rem; } /* 40px */
|
||||||
|
.h-12 { height: 3rem; } /* 48px */
|
||||||
|
.h-16 { height: 4rem; } /* 64px */
|
||||||
|
.h-20 { height: 5rem; } /* 80px */
|
||||||
|
.h-24 { height: 6rem; } /* 96px */
|
||||||
|
.h-32 { height: 8rem; } /* 128px */
|
||||||
|
.h-40 { height: 10rem; } /* 160px */
|
||||||
|
.h-48 { height: 12rem; } /* 192px */
|
||||||
|
.h-56 { height: 14rem; } /* 224px */
|
||||||
|
.h-64 { height: 16rem; } /* 256px */
|
||||||
|
.h-auto { height: auto; }
|
||||||
|
.h-full { height: 100%; }
|
||||||
|
.h-screen{ height: 100vh; }
|
||||||
|
.h-min { height: min-content; }
|
||||||
|
.h-max { height: max-content; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ==========================
|
||||||
|
Base Font Sizes (mobile first)
|
||||||
|
========================== */
|
||||||
|
.text-xxs { font-size: 0.55rem; } /* 8px */
|
||||||
|
.text-xs { font-size: 0.75rem; } /* 12px */
|
||||||
|
.text-sm { font-size: 0.875rem; } /* 14px */
|
||||||
|
.text-base{ font-size: 1rem; } /* 16px */
|
||||||
|
.text-lg { font-size: 1.125rem; } /* 18px */
|
||||||
|
.text-xl { font-size: 1.25rem; } /* 20px */
|
||||||
|
.text-2xl { font-size: 1.5rem; } /* 24px */
|
||||||
|
.text-3xl { font-size: 1.875rem; } /* 30px */
|
||||||
|
.text-4xl { font-size: 2.25rem; } /* 36px */
|
||||||
|
.text-5xl { font-size: 3rem; } /* 48px */
|
||||||
|
.text-6xl { font-size: 3.75rem; } /* 60px */
|
||||||
|
.text-7xl { font-size: 4.5rem; } /* 72px */
|
||||||
|
.text-8xl { font-size: 6rem; } /* 96px */
|
||||||
|
.text-9xl { font-size: 8rem; } /* 128px */
|
||||||
|
|
||||||
|
/* ==========================
|
||||||
|
Base Heights
|
||||||
|
========================== */
|
||||||
|
.h-0 { height: 0; }
|
||||||
|
.h-px { height: 1px; }
|
||||||
|
.h-1 { height: 0.25rem; } /* 4px */
|
||||||
|
.h-2 { height: 0.5rem; } /* 8px */
|
||||||
|
.h-3 { height: 0.75rem; } /* 12px */
|
||||||
|
.h-4 { height: 1rem; } /* 16px */
|
||||||
|
.h-5 { height: 1.25rem; } /* 20px */
|
||||||
|
.h-6 { height: 1.5rem; } /* 24px */
|
||||||
|
.h-8 { height: 2rem; } /* 32px */
|
||||||
|
.h-10 { height: 2.5rem; } /* 40px */
|
||||||
|
.h-12 { height: 3rem; } /* 48px */
|
||||||
|
.h-16 { height: 4rem; } /* 64px */
|
||||||
|
.h-20 { height: 5rem; } /* 80px */
|
||||||
|
.h-24 { height: 6rem; } /* 96px */
|
||||||
|
.h-32 { height: 8rem; } /* 128px */
|
||||||
|
.h-40 { height: 10rem; } /* 160px */
|
||||||
|
.h-48 { height: 12rem; } /* 192px */
|
||||||
|
.h-56 { height: 14rem; } /* 224px */
|
||||||
|
.h-64 { height: 16rem; } /* 256px */
|
||||||
|
.h-full { height: 100%; }
|
||||||
|
.h-screen{ height: 100vh; }
|
||||||
|
|
||||||
|
/* ==========================
|
||||||
|
Base Widths
|
||||||
|
========================== */
|
||||||
|
.w-0 { width: 0; }
|
||||||
|
.w-px { width: 1px; }
|
||||||
|
.w-1 { width: 0.25rem; }
|
||||||
|
.w-2 { width: 0.5rem; }
|
||||||
|
.w-3 { width: 0.75rem; }
|
||||||
|
.w-4 { width: 1rem; }
|
||||||
|
.w-5 { width: 1.25rem; }
|
||||||
|
.w-6 { width: 1.5rem; }
|
||||||
|
.w-8 { width: 2rem; }
|
||||||
|
.w-10 { width: 2.5rem; }
|
||||||
|
.w-12 { width: 3rem; }
|
||||||
|
.w-16 { width: 4rem; }
|
||||||
|
.w-20 { width: 5rem; }
|
||||||
|
.w-24 { width: 6rem; }
|
||||||
|
.w-32 { width: 8rem; }
|
||||||
|
.w-40 { width: 10rem; }
|
||||||
|
.w-48 { width: 12rem; }
|
||||||
|
.w-56 { width: 14rem; }
|
||||||
|
.w-64 { width: 16rem; }
|
||||||
|
.w-full { width: 100%; }
|
||||||
|
.w-screen{ width: 100vw; }
|
||||||
|
|
||||||
|
/* ==========================
|
||||||
|
Responsive Variants
|
||||||
|
========================== */
|
||||||
|
@media (min-width: 576px) { /* sm */
|
||||||
|
/* Font */
|
||||||
|
.text-xxs-sm { font-size: 0.55rem; }
|
||||||
|
.text-xs-sm { font-size: 0.75rem; }
|
||||||
|
.text-sm-sm { font-size: 0.875rem; }
|
||||||
|
.text-base-sm{ font-size: 1rem; }
|
||||||
|
.text-lg-sm { font-size: 1.125rem; }
|
||||||
|
.text-xl-sm { font-size: 1.25rem; }
|
||||||
|
.text-2xl-sm{ font-size: 1.5rem; }
|
||||||
|
|
||||||
|
/* Height */
|
||||||
|
.h-1-sm{ height: 0.25rem; }
|
||||||
|
.h-2-sm{ height: 0.5rem; }
|
||||||
|
.h-3-sm{ height: 0.75rem; }
|
||||||
|
.h-4-sm{ height: 1rem; }
|
||||||
|
.h-5-sm{ height: 1.25rem; }
|
||||||
|
.h-6-sm{ height: 1.5rem; }
|
||||||
|
.h-8-sm{ height: 2rem; }
|
||||||
|
.h-10-sm{ height: 2.5rem; }
|
||||||
|
|
||||||
|
/* Width */
|
||||||
|
.w-1-sm{ width: 0.25rem; }
|
||||||
|
.w-2-sm{ width: 0.5rem; }
|
||||||
|
.w-3-sm{ width: 0.75rem; }
|
||||||
|
.w-4-sm{ width: 1rem; }
|
||||||
|
.w-5-sm{ width: 1.25rem; }
|
||||||
|
.w-6-sm{ width: 1.5rem; }
|
||||||
|
.w-8-sm{ width: 2rem; }
|
||||||
|
.w-10-sm{ width: 2.5rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) { /* md */
|
||||||
|
/* Font */
|
||||||
|
.text-xxs-md { font-size: 0.55rem; }
|
||||||
|
.text-xs-md { font-size: 0.75rem; }
|
||||||
|
.text-sm-md { font-size: 0.875rem; }
|
||||||
|
.text-base-md{ font-size: 1rem; }
|
||||||
|
.text-lg-md { font-size: 1.125rem; }
|
||||||
|
.text-xl-md { font-size: 1.25rem; }
|
||||||
|
.text-2xl-md{ font-size: 1.5rem; }
|
||||||
|
|
||||||
|
/* Height */
|
||||||
|
.h-1-md{ height: 0.25rem; }
|
||||||
|
.h-2-md{ height: 0.5rem; }
|
||||||
|
.h-3-md{ height: 0.75rem; }
|
||||||
|
.h-4-md{ height: 1rem; }
|
||||||
|
.h-5-md{ height: 1.25rem; }
|
||||||
|
.h-6-md{ height: 1.5rem; }
|
||||||
|
.h-8-md{ height: 2rem; }
|
||||||
|
.h-10-md{ height: 2.5rem; }
|
||||||
|
|
||||||
|
/* Width */
|
||||||
|
.w-1-md{ width: 0.25rem; }
|
||||||
|
.w-2-md{ width: 0.5rem; }
|
||||||
|
.w-3-md{ width: 0.75rem; }
|
||||||
|
.w-4-md{ width: 1rem; }
|
||||||
|
.w-5-md{ width: 1.25rem; }
|
||||||
|
.w-6-md{ width: 1.5rem; }
|
||||||
|
.w-8-md{ width: 2rem; }
|
||||||
|
.w-10-md{ width: 2.5rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px) { /* lg */
|
||||||
|
/* Font */
|
||||||
|
.text-xxs-lg { font-size: 0.55rem; }
|
||||||
|
.text-xs-lg { font-size: 0.75rem; }
|
||||||
|
.text-sm-lg { font-size: 0.875rem; }
|
||||||
|
.text-base-lg{ font-size: 1rem; }
|
||||||
|
.text-lg-lg { font-size: 1.125rem; }
|
||||||
|
.text-xl-lg { font-size: 1.25rem; }
|
||||||
|
.text-2xl-lg{ font-size: 1.5rem; }
|
||||||
|
|
||||||
|
/* Height */
|
||||||
|
.h-1-lg{ height: 0.25rem; }
|
||||||
|
.h-2-lg{ height: 0.5rem; }
|
||||||
|
.h-3-lg{ height: 0.75rem; }
|
||||||
|
.h-4-lg{ height: 1rem; }
|
||||||
|
.h-5-lg{ height: 1.25rem; }
|
||||||
|
.h-6-lg{ height: 1.5rem; }
|
||||||
|
.h-8-lg{ height: 2rem; }
|
||||||
|
.h-10-lg{ height: 2.5rem; }
|
||||||
|
|
||||||
|
/* Width */
|
||||||
|
.w-1-lg{ width: 0.25rem; }
|
||||||
|
.w-2-lg{ width: 0.5rem; }
|
||||||
|
.w-3-lg{ width: 0.75rem; }
|
||||||
|
.w-4-lg{ width: 1rem; }
|
||||||
|
.w-5-lg{ width: 1.25rem; }
|
||||||
|
.w-6-lg{ width: 1.5rem; }
|
||||||
|
.w-8-lg{ width: 2rem; }
|
||||||
|
.w-10-lg{ width: 2.5rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px) { /* xl */
|
||||||
|
/* Font */
|
||||||
|
.text-xxs-xl { font-size: 0.55rem; }
|
||||||
|
.text-xs-xl { font-size: 0.75rem; }
|
||||||
|
.text-sm-xl { font-size: 0.875rem; }
|
||||||
|
.text-base-xl{ font-size: 1rem; }
|
||||||
|
.text-lg-xl { font-size: 1.125rem; }
|
||||||
|
.text-xl-xl { font-size: 1.25rem; }
|
||||||
|
.text-2xl-xl{ font-size: 1.5rem; }
|
||||||
|
|
||||||
|
/* Height */
|
||||||
|
.h-1-xl{ height: 0.25rem; }
|
||||||
|
.h-2-xl{ height: 0.5rem; }
|
||||||
|
.h-3-xl{ height: 0.75rem; }
|
||||||
|
.h-4-xl{ height: 1rem; }
|
||||||
|
.h-5-xl{ height: 1.25rem; }
|
||||||
|
.h-6-xl{ height: 1.5rem; }
|
||||||
|
.h-8-xl{ height: 2rem; }
|
||||||
|
.h-10-xl{ height: 2.5rem; }
|
||||||
|
|
||||||
|
/* Width */
|
||||||
|
.w-1-xl{ width: 0.25rem; }
|
||||||
|
.w-2-xl{ width: 0.5rem; }
|
||||||
|
.w-3-xl{ width: 0.75rem; }
|
||||||
|
.w-4-xl{ width: 1rem; }
|
||||||
|
.w-5-xl{ width: 1.25rem; }
|
||||||
|
.w-6-xl{ width: 1.5rem; }
|
||||||
|
.w-8-xl{ width: 2rem; }
|
||||||
|
.w-10-xl{ width: 2.5rem; }
|
||||||
|
}
|
||||||
|
@ -38,195 +38,141 @@ const usePagination = (data, itemsPerPage) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
||||||
// const selectedProject = useSelector(
|
const selectedProject = useSelectedProject();
|
||||||
// (store) => store.localVariables.projectId
|
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
||||||
// );
|
const dispatch = useDispatch();
|
||||||
const selectedProject = useSelectedProject();
|
const [loading, setLoading] = useState(false);
|
||||||
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
const [showPending, setShowPending] = useState(false);
|
||||||
const dispatch = useDispatch();
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [showPending, setShowPending] = useState(false);
|
|
||||||
|
|
||||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
const today = new Date();
|
||||||
const [processedData, setProcessedData] = useState([]);
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
const today = new Date();
|
const yesterday = new Date();
|
||||||
today.setHours(0, 0, 0, 0);
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
|
|
||||||
const yesterday = new Date();
|
const isSameDay = (dateStr) => {
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
if (!dateStr) return false;
|
||||||
|
const d = new Date(dateStr);
|
||||||
|
d.setHours(0, 0, 0, 0);
|
||||||
|
return d.getTime() === today.getTime();
|
||||||
|
};
|
||||||
|
|
||||||
const isSameDay = (dateStr) => {
|
const isBeforeToday = (dateStr) => {
|
||||||
if (!dateStr) return false;
|
if (!dateStr) return false;
|
||||||
const d = new Date(dateStr);
|
const d = new Date(dateStr);
|
||||||
d.setHours(0, 0, 0, 0);
|
d.setHours(0, 0, 0, 0);
|
||||||
return d.getTime() === today.getTime();
|
return d.getTime() < today.getTime();
|
||||||
};
|
};
|
||||||
|
|
||||||
const isBeforeToday = (dateStr) => {
|
const sortByName = (a, b) => {
|
||||||
if (!dateStr) return false;
|
const nameA = (a.firstName + a.lastName).toLowerCase();
|
||||||
const d = new Date(dateStr);
|
const nameB = (b.firstName + b.lastName).toLowerCase();
|
||||||
d.setHours(0, 0, 0, 0);
|
return nameA.localeCompare(nameB);
|
||||||
return d.getTime() < today.getTime();
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const sortByName = (a, b) => {
|
const { data = [], isLoading, error, refetch, isFetching } = useAttendancesLogs(
|
||||||
const nameA = a.firstName.toLowerCase() + a.lastName.toLowerCase();
|
selectedProject,
|
||||||
const nameB = b.firstName.toLowerCase() + b.lastName.toLowerCase();
|
dateRange.startDate,
|
||||||
return nameA?.localeCompare(nameB);
|
dateRange.endDate,
|
||||||
};
|
organizationId
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const processedData = useMemo(() => {
|
||||||
data = [],
|
const filteredData = showPending
|
||||||
isLoading,
|
? data.filter((item) => item.checkOutTime === null)
|
||||||
error,
|
: data;
|
||||||
refetch,
|
|
||||||
isFetching,
|
|
||||||
} = useAttendancesLogs(
|
|
||||||
selectedProject,
|
|
||||||
dateRange.startDate,
|
|
||||||
dateRange.endDate,
|
|
||||||
organizationId
|
|
||||||
);
|
|
||||||
const filtering = (data) => {
|
|
||||||
const filteredData = showPending
|
|
||||||
? data.filter((item) => item.checkOutTime === null)
|
|
||||||
: data;
|
|
||||||
|
|
||||||
const group1 = filteredData
|
const group1 = filteredData.filter((d) => d.activity === 1 && isSameDay(d.checkInTime)).sort(sortByName);
|
||||||
.filter((d) => d.activity === 1 && isSameDay(d.checkInTime))
|
const group2 = filteredData.filter((d) => d.activity === 4 && isSameDay(d.checkOutTime)).sort(sortByName);
|
||||||
.sort(sortByName);
|
const group3 = filteredData.filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime)).sort(sortByName);
|
||||||
const group2 = filteredData
|
const group4 = filteredData.filter((d) => d.activity === 4 && isBeforeToday(d.checkOutTime));
|
||||||
.filter((d) => d.activity === 4 && isSameDay(d.checkOutTime))
|
const group5 = filteredData.filter((d) => d.activity === 2 && isBeforeToday(d.checkOutTime)).sort(sortByName);
|
||||||
.sort(sortByName);
|
const group6 = filteredData.filter((d) => d.activity === 5).sort(sortByName);
|
||||||
const group3 = filteredData
|
|
||||||
.filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime))
|
|
||||||
.sort(sortByName);
|
|
||||||
const group4 = filteredData.filter(
|
|
||||||
(d) => d.activity === 4 && isBeforeToday(d.checkOutTime)
|
|
||||||
);
|
|
||||||
const group5 = filteredData
|
|
||||||
.filter((d) => d.activity === 2 && isBeforeToday(d.checkOutTime))
|
|
||||||
.sort(sortByName);
|
|
||||||
const group6 = filteredData
|
|
||||||
.filter((d) => d.activity === 5)
|
|
||||||
.sort(sortByName);
|
|
||||||
|
|
||||||
const sortedList = [
|
const sortedList = [...group1, ...group2, ...group3, ...group4, ...group5, ...group6];
|
||||||
...group1,
|
|
||||||
...group2,
|
|
||||||
...group3,
|
|
||||||
...group4,
|
|
||||||
...group5,
|
|
||||||
...group6,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Group by date
|
const groupedByDate = sortedList.reduce((acc, item) => {
|
||||||
const groupedByDate = sortedList.reduce((acc, item) => {
|
const date = (item.checkInTime || item.checkOutTime)?.split("T")[0];
|
||||||
const date = (item.checkInTime || item.checkOutTime)?.split("T")[0];
|
if (date) {
|
||||||
if (date) {
|
acc[date] = acc[date] || [];
|
||||||
acc[date] = acc[date] || [];
|
acc[date].push(item);
|
||||||
acc[date].push(item);
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const sortedDates = Object.keys(groupedByDate).sort(
|
|
||||||
(a, b) => new Date(b) - new Date(a)
|
|
||||||
);
|
|
||||||
|
|
||||||
const finalData = sortedDates.flatMap((date) => groupedByDate[date]);
|
|
||||||
setProcessedData(finalData);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
filtering(data);
|
|
||||||
}, [data, showPending]);
|
|
||||||
|
|
||||||
// New useEffect to handle search filtering
|
|
||||||
const filteredSearchData = useMemo(() => {
|
|
||||||
if (!searchTerm) {
|
|
||||||
return processedData;
|
|
||||||
}
|
}
|
||||||
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
return acc;
|
||||||
return processedData.filter((item) => {
|
}, {});
|
||||||
const fullName = `${item.firstName} ${item.lastName}`.toLowerCase();
|
|
||||||
return fullName.includes(lowercasedSearchTerm);
|
|
||||||
});
|
|
||||||
}, [processedData, searchTerm]);
|
|
||||||
|
|
||||||
const {
|
const sortedDates = Object.keys(groupedByDate).sort((a, b) => new Date(b) - new Date(a));
|
||||||
currentPage,
|
return sortedDates.flatMap((date) => groupedByDate[date]);
|
||||||
totalPages,
|
}, [data, showPending]);
|
||||||
currentItems: paginatedAttendances,
|
|
||||||
paginate,
|
|
||||||
resetPage,
|
|
||||||
} = usePagination(filteredSearchData, 20);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const filteredSearchData = useMemo(() => {
|
||||||
resetPage();
|
if (!searchTerm) return processedData;
|
||||||
}, [filteredSearchData, resetPage]);
|
|
||||||
|
|
||||||
const handler = useCallback(
|
const lowercased = searchTerm.toLowerCase();
|
||||||
(msg) => {
|
return processedData.filter((item) =>
|
||||||
const { startDate, endDate } = dateRange;
|
`${item.firstName} ${item.lastName}`.toLowerCase().includes(lowercased)
|
||||||
const checkIn = msg.response.checkInTime.substring(0, 10);
|
|
||||||
if (
|
|
||||||
selectedProject === msg.projectId &&
|
|
||||||
startDate <= checkIn &&
|
|
||||||
checkIn <= endDate
|
|
||||||
) {
|
|
||||||
queryClient.setQueriesData(["attendanceLogs"], (oldData) => {
|
|
||||||
if (!oldData) {
|
|
||||||
queryClient.invalidateQueries({ queryKey: ["attendanceLogs"] });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const updatedAttendance = oldData.map((record) =>
|
|
||||||
record.id === msg.response.id
|
|
||||||
? { ...record, ...msg.response }
|
|
||||||
: record
|
|
||||||
);
|
|
||||||
filtering(updatedAttendance);
|
|
||||||
return updatedAttendance;
|
|
||||||
});
|
|
||||||
resetPage();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[selectedProject, dateRange, filtering, resetPage]
|
|
||||||
);
|
);
|
||||||
|
}, [processedData, searchTerm]);
|
||||||
|
|
||||||
useEffect(() => {
|
const {
|
||||||
eventBus.on("attendance_log", handler);
|
currentPage,
|
||||||
return () => eventBus.off("attendance_log", handler);
|
totalPages,
|
||||||
}, [handler]);
|
currentItems: paginatedAttendances,
|
||||||
|
paginate,
|
||||||
|
resetPage,
|
||||||
|
} = usePagination(filteredSearchData, 20);
|
||||||
|
|
||||||
const employeeHandler = useCallback(
|
useEffect(() => {
|
||||||
(msg) => {
|
resetPage();
|
||||||
const { startDate, endDate } = dateRange;
|
}, [filteredSearchData]);
|
||||||
if (data.some((item) => item.employeeId == msg.employeeId)) {
|
|
||||||
// dispatch(
|
const handler = useCallback(
|
||||||
// fetchAttendanceData({
|
(msg) => {
|
||||||
// ,
|
const { startDate, endDate } = dateRange;
|
||||||
// fromDate: startDate,
|
const checkIn = msg.response.checkInTime.substring(0, 10);
|
||||||
// toDate: endDate,
|
|
||||||
// })
|
if (selectedProject === msg.projectId && startDate <= checkIn && checkIn <= endDate) {
|
||||||
// );
|
queryClient.setQueriesData(["attendanceLogs"], (oldData) => {
|
||||||
|
if (!oldData) {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["attendanceLogs"] });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return oldData.map((record) =>
|
||||||
|
record.id === msg.response.id ? { ...record, ...msg.response } : record
|
||||||
|
);
|
||||||
|
});
|
||||||
|
resetPage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[selectedProject, dateRange, resetPage]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
eventBus.on("attendance_log", handler);
|
||||||
|
return () => eventBus.off("attendance_log", handler);
|
||||||
|
}, [handler]);
|
||||||
|
|
||||||
|
const employeeHandler = useCallback(
|
||||||
|
(msg) => {
|
||||||
|
const { startDate, endDate } = dateRange;
|
||||||
|
if (data.some((item) => item.employeeId == msg.employeeId)) {
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[data, refetch]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
eventBus.on("employee", employeeHandler);
|
||||||
|
return () => eventBus.off("employee", employeeHandler);
|
||||||
|
}, [employeeHandler]);
|
||||||
|
|
||||||
refetch();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[selectedProject, dateRange, data, refetch]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
eventBus.on("employee", employeeHandler);
|
|
||||||
return () => eventBus.off("employee", employeeHandler);
|
|
||||||
}, [employeeHandler]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className="dataTables_length text-start py-2 d-flex justify-content-between"
|
className="dataTables_length text-start py-2 d-flex justify-content-between "
|
||||||
id="DataTables_Table_0_length"
|
id="DataTables_Table_0_length"
|
||||||
>
|
>
|
||||||
<div className="d-flex align-items-center my-0 ">
|
<div className="d-flex align-items-center my-0 ">
|
||||||
@ -234,7 +180,7 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
onRangeChange={setDateRange}
|
onRangeChange={setDateRange}
|
||||||
defaultStartDate={yesterday}
|
defaultStartDate={yesterday}
|
||||||
/>
|
/>
|
||||||
<div className="form-check form-switch text-start m-0 ms-5">
|
<div className="form-check form-switch text-start ms-1 ms-md-2 align-items-center mb-0">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="form-check-input"
|
className="form-check-input"
|
||||||
|
@ -1,25 +1,43 @@
|
|||||||
import React, { useCallback, useEffect, useState, useMemo } from "react";
|
import React, { useCallback, useEffect, useState, useMemo } from "react";
|
||||||
import Avatar from "../common/Avatar";
|
import Avatar from "../common/Avatar";
|
||||||
import { convertShortTime } from "../../utils/dateUtils";
|
import { convertShortTime, formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||||
import RegularizationActions from "./RegularizationActions";
|
import RegularizationActions from "./RegularizationActions";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { useRegularizationRequests } from "../../hooks/useAttendance";
|
import { useRegularizationRequests } from "../../hooks/useAttendance";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import usePagination from "../../hooks/usePagination";
|
import usePagination from "../../hooks/usePagination";
|
||||||
import eventBus from "../../services/eventBus";
|
import eventBus from "../../services/eventBus";
|
||||||
import { cacheData, clearCacheKey, useSelectedProject } from "../../slices/apiDataManager";
|
import {
|
||||||
|
cacheData,
|
||||||
|
clearCacheKey,
|
||||||
|
useSelectedProject,
|
||||||
|
} from "../../slices/apiDataManager";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
import Pagination from "../../components/common/Pagination";
|
||||||
|
|
||||||
const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, IncludeInActive }) => {
|
const Regularization = ({
|
||||||
|
handleRequest,
|
||||||
|
searchTerm,
|
||||||
|
projectId,
|
||||||
|
organizationId,
|
||||||
|
IncludeInActive,
|
||||||
|
}) => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
// var selectedProject = useSelector((store) => store.localVariables.projectId);
|
// var selectedProject = useSelector((store) => store.localVariables.projectId);
|
||||||
const selectedProject = useSelectedProject();
|
const selectedProject = useSelectedProject();
|
||||||
const [regularizesList, setregularizedList] = useState([]);
|
const [regularizesList, setregularizedList] = useState([]);
|
||||||
const { regularizes, loading, error, refetch } =
|
const { regularizes, loading, error, refetch } = useRegularizationRequests(
|
||||||
useRegularizationRequests(selectedProject, organizationId, IncludeInActive);
|
selectedProject,
|
||||||
|
organizationId,
|
||||||
|
IncludeInActive
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if(!regularizes) return
|
||||||
|
if(regularizes?.length) {
|
||||||
setregularizedList(regularizes);
|
setregularizedList(regularizes);
|
||||||
|
|
||||||
|
}
|
||||||
}, [regularizes]);
|
}, [regularizes]);
|
||||||
|
|
||||||
const sortByName = (a, b) => {
|
const sortByName = (a, b) => {
|
||||||
@ -54,48 +72,15 @@ const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, I
|
|||||||
}
|
}
|
||||||
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
const lowercasedSearchTerm = searchTerm.toLowerCase();
|
||||||
return sortedList.filter((item) => {
|
return sortedList.filter((item) => {
|
||||||
const fullName = `${item.firstName} ${item.lastName}`.toLowerCase();
|
const fullName = `${item?.firstName} ${item?.lastName}`.toLowerCase();
|
||||||
return fullName.includes(lowercasedSearchTerm);
|
return fullName.includes(lowercasedSearchTerm);
|
||||||
});
|
});
|
||||||
}, [regularizesList, searchTerm]);
|
}, [regularizesList, searchTerm]);
|
||||||
|
|
||||||
// const filteredSearchData = useMemo(() => {
|
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||||
// let sortedList = [...regularizesList].sort(sortByName);
|
filteredSearchData,
|
||||||
|
20
|
||||||
// // Search filter
|
);
|
||||||
// if (searchTerm) {
|
|
||||||
// const lowercasedSearchTerm = searchTerm.toLowerCase();
|
|
||||||
// sortedList = sortedList.filter((item) => {
|
|
||||||
// const fullName = `${item.firstName} ${item.lastName}`.toLowerCase();
|
|
||||||
// return fullName.includes(lowercasedSearchTerm);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Organization filter
|
|
||||||
// if (filters?.selectedOrganization) {
|
|
||||||
// sortedList = sortedList.filter(
|
|
||||||
// (item) => item.organization?.name === filters.selectedOrganization
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Services filter
|
|
||||||
// if (filters?.selectedServices?.length > 0) {
|
|
||||||
// sortedList = sortedList.filter((item) =>
|
|
||||||
// filters.selectedServices.includes(item.service?.name)
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return sortedList;
|
|
||||||
// }, [regularizesList, searchTerm, filters]);
|
|
||||||
|
|
||||||
|
|
||||||
const { currentPage, totalPages, currentItems, paginate } =
|
|
||||||
usePagination(filteredSearchData, 20);
|
|
||||||
|
|
||||||
// Reset pagination when the search term or data changes
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
}, [filteredSearchData]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
eventBus.on("regularization", handler);
|
eventBus.on("regularization", handler);
|
||||||
@ -117,9 +102,15 @@ const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, I
|
|||||||
}, [employeeHandler]);
|
}, [employeeHandler]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="table-responsive text-nowrap pb-4" style={{ minHeight: "200px" }}>
|
<div
|
||||||
|
className="table-responsive text-nowrap pb-4"
|
||||||
|
style={{ minHeight: "200px" }}
|
||||||
|
>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="d-flex justify-content-center align-items-center" style={{ height: "200px" }}>
|
<div
|
||||||
|
className="d-flex justify-content-center align-items-center"
|
||||||
|
style={{ height: "200px" }}
|
||||||
|
>
|
||||||
<p className="text-secondary">Loading...</p>
|
<p className="text-secondary">Loading...</p>
|
||||||
</div>
|
</div>
|
||||||
) : currentItems?.length > 0 ? (
|
) : currentItems?.length > 0 ? (
|
||||||
@ -135,18 +126,21 @@ const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, I
|
|||||||
<th>
|
<th>
|
||||||
<i className="bx bxs-up-arrow-alt text-danger"></i>Check-Out
|
<i className="bx bxs-up-arrow-alt text-danger"></i>Check-Out
|
||||||
</th>
|
</th>
|
||||||
|
<th colSpan={2}>
|
||||||
|
Requested By
|
||||||
|
</th>
|
||||||
|
<th >
|
||||||
|
Requested At
|
||||||
|
</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{currentItems?.map((att, index) => (
|
{currentItems?.map((att, index) => (
|
||||||
<tr key={index}>
|
<tr key={index}>
|
||||||
<td colSpan={2}>
|
<td colSpan={2}>
|
||||||
<div className="d-flex justify-content-start align-items-center">
|
<div className="d-flex justify-content-start align-items-center">
|
||||||
<Avatar
|
<Avatar firstName={att.firstName} lastName={att.lastName} />
|
||||||
firstName={att.firstName}
|
|
||||||
lastName={att.lastName}
|
|
||||||
/>
|
|
||||||
<div className="d-flex flex-column">
|
<div className="d-flex flex-column">
|
||||||
<a href="#" className="text-heading text-truncate">
|
<a href="#" className="text-heading text-truncate">
|
||||||
<span className="fw-normal">
|
<span className="fw-normal">
|
||||||
@ -162,7 +156,23 @@ const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, I
|
|||||||
|
|
||||||
<td>{convertShortTime(att.checkInTime)}</td>
|
<td>{convertShortTime(att.checkInTime)}</td>
|
||||||
<td>
|
<td>
|
||||||
{att.checkOutTime ? convertShortTime(att.checkOutTime) : "--"}
|
{att.requestedAt ? convertShortTime(att.checkOutTime) : "--"}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td colSpan={2}>
|
||||||
|
{att.requestedBy ? ( <div className="d-flex justify-content-start align-items-center">
|
||||||
|
<Avatar firstName={att?.requestedBy?.firstName} lastName={att?.requestedBy?.lastName} />
|
||||||
|
<div className="d-flex flex-column">
|
||||||
|
<a href="#" className="text-heading text-truncate">
|
||||||
|
<span className="fw-normal">
|
||||||
|
{att?.requestedBy?.firstName} {att?.requestedBy?.lastName}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>):(<small>--</small>)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{att?.requestedAt ? formatUTCToLocalTime(att.requestedAt,true) : "--"}
|
||||||
</td>
|
</td>
|
||||||
<td className="text-center ">
|
<td className="text-center ">
|
||||||
<RegularizationActions
|
<RegularizationActions
|
||||||
@ -175,7 +185,6 @@ const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, I
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="d-flex justify-content-center align-items-center"
|
className="d-flex justify-content-center align-items-center"
|
||||||
@ -188,7 +197,7 @@ const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, I
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!loading && totalPages > 1 && (
|
{/* {!loading && totalPages > 1 && (
|
||||||
<nav aria-label="Page ">
|
<nav aria-label="Page ">
|
||||||
<ul className="pagination pagination-sm justify-content-end py-1 mt-3">
|
<ul className="pagination pagination-sm justify-content-end py-1 mt-3">
|
||||||
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
||||||
@ -226,6 +235,14 @@ const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, I
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
)} */}
|
||||||
|
|
||||||
|
{totalPages > 0 && (
|
||||||
|
<Pagination
|
||||||
|
currentPage={currentPage}
|
||||||
|
totalPages={totalPages}
|
||||||
|
onPageChange={paginate}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -55,10 +55,11 @@ const TaskReportFilterPanel = ({ handleFilter }) => {
|
|||||||
endField="dateTo"
|
endField="dateTo"
|
||||||
resetSignal={resetKey}
|
resetSignal={resetKey}
|
||||||
defaultRange={false}
|
defaultRange={false}
|
||||||
|
maxDate={new Date()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="row g-2">
|
<div className="row mb-2">
|
||||||
<SelectMultiple
|
<SelectMultiple
|
||||||
name="buildingIds"
|
name="buildingIds"
|
||||||
label="Building"
|
label="Building"
|
||||||
@ -67,7 +68,7 @@ const TaskReportFilterPanel = ({ handleFilter }) => {
|
|||||||
valueKey="id"
|
valueKey="id"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="row g-2">
|
<div className="row mb-2">
|
||||||
<SelectMultiple
|
<SelectMultiple
|
||||||
name="floorIds"
|
name="floorIds"
|
||||||
label="Floor"
|
label="Floor"
|
||||||
@ -76,7 +77,7 @@ const TaskReportFilterPanel = ({ handleFilter }) => {
|
|||||||
valueKey="id"
|
valueKey="id"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="row g-2">
|
<div className="row mb-2">
|
||||||
<SelectMultiple
|
<SelectMultiple
|
||||||
name="activityIds"
|
name="activityIds"
|
||||||
label="Activities"
|
label="Activities"
|
||||||
|
@ -192,7 +192,7 @@ const TaskReportList = () => {
|
|||||||
if (isLoading) return <TaskReportListSkeleton />;
|
if (isLoading) return <TaskReportListSkeleton />;
|
||||||
if (isError) return <div>Loading....</div>;
|
if (isError) return <div>Loading....</div>;
|
||||||
return (
|
return (
|
||||||
<div className="mt-2">
|
<div className="mt-2 table-responsive text-nowrap">
|
||||||
<table className="table">
|
<table className="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -179,7 +179,7 @@ const ListViewContact = ({ data, Pagination }) => {
|
|||||||
<tr style={{ height: "200px" }}>
|
<tr style={{ height: "200px" }}>
|
||||||
<td
|
<td
|
||||||
colSpan={contactList.length + 1}
|
colSpan={contactList.length + 1}
|
||||||
className="text-center align-middle"
|
className="text-center border-0 align-middle"
|
||||||
>
|
>
|
||||||
No contacts found
|
No contacts found
|
||||||
</td>
|
</td>
|
||||||
|
@ -18,7 +18,7 @@ import { defatEmployeeObj, employeeSchema } from "./EmployeeSchema";
|
|||||||
import { useOrganizationsList } from "../../hooks/useOrganization";
|
import { useOrganizationsList } from "../../hooks/useOrganization";
|
||||||
import { ITEMS_PER_PAGE } from "../../utils/constants";
|
import { ITEMS_PER_PAGE } from "../../utils/constants";
|
||||||
|
|
||||||
const ManageEmployee = ({ employeeId, onClosed, IsAllEmployee }) => {
|
const ManageEmployee = ({ employeeId, onClosed }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { mutate: updateEmployee, isPending } = useUpdateEmployee();
|
const { mutate: updateEmployee, isPending } = useUpdateEmployee();
|
||||||
const {
|
const {
|
||||||
@ -72,7 +72,7 @@ const ManageEmployee = ({ employeeId, onClosed, IsAllEmployee }) => {
|
|||||||
data.email = null;
|
data.email = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = { ...data, IsAllEmployee };
|
const payload = { ...data };
|
||||||
|
|
||||||
if (employeeId) {
|
if (employeeId) {
|
||||||
payload.id = employeeId;
|
payload.id = employeeId;
|
||||||
|
@ -117,6 +117,7 @@ const ExpenseFilterPanel = ({ onApply, handleGroupBy }) => {
|
|||||||
endField="endDate"
|
endField="endDate"
|
||||||
resetSignal={resetKey}
|
resetSignal={resetKey}
|
||||||
defaultRange={false}
|
defaultRange={false}
|
||||||
|
maxDate={new Date()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
|||||||
<DatePicker
|
<DatePicker
|
||||||
name="reimburseDate"
|
name="reimburseDate"
|
||||||
control={control}
|
control={control}
|
||||||
minDate={data?.createdAt}
|
minDate={data?.transactionDate}
|
||||||
maxDate={new Date()}
|
maxDate={new Date()}
|
||||||
/>
|
/>
|
||||||
{errors.reimburseDate && (
|
{errors.reimburseDate && (
|
||||||
|
@ -189,7 +189,8 @@ const Header = () => {
|
|||||||
className="navbar-nav-right d-flex align-items-center justify-content-between"
|
className="navbar-nav-right d-flex align-items-center justify-content-between"
|
||||||
id="navbar-collapse"
|
id="navbar-collapse"
|
||||||
>
|
>
|
||||||
{showProjectDropdown(location.pathname) && (
|
<div className="d-flex align-items-center">
|
||||||
|
{showProjectDropdown(location.pathname) && (
|
||||||
<div className="align-items-center">
|
<div className="align-items-center">
|
||||||
<i className="rounded-circle bx bx-building-house bx-sm-lg bx-md me-2"></i>
|
<i className="rounded-circle bx bx-building-house bx-sm-lg bx-md me-2"></i>
|
||||||
<div className="btn-group">
|
<div className="btn-group">
|
||||||
@ -247,6 +248,7 @@ const Header = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<ul className="navbar-nav flex-row align-items-center ms-md-auto">
|
<ul className="navbar-nav flex-row align-items-center ms-md-auto">
|
||||||
<li className="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
|
<li className="nav-item dropdown-shortcuts navbar-dropdown dropdown me-2 me-xl-0">
|
||||||
|
@ -10,13 +10,15 @@ import { useForm } from "react-hook-form";
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { spridSchema } from "./OrganizationSchema";
|
import { spridSchema } from "./OrganizationSchema";
|
||||||
import { OrgCardSkeleton } from "./OrganizationSkeleton";
|
import { OrgCardSkeleton } from "./OrganizationSkeleton";
|
||||||
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
|
||||||
// Zod schema: only allow exactly 4 digits
|
// Zod schema: only allow exactly 4 digits
|
||||||
|
|
||||||
const OrgPickerFromSPId = ({ title, placeholder }) => {
|
const OrgPickerFromSPId = ({ title, placeholder }) => {
|
||||||
const { onClose, startStep, flowType, onOpen, prevStep } =
|
const { onClose, startStep, flowType, onOpen, prevStep,orgData } =
|
||||||
useOrganizationModal();
|
useOrganizationModal();
|
||||||
|
const clientQuery = useQueryClient()
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -35,8 +37,11 @@ const OrgPickerFromSPId = ({ title, placeholder }) => {
|
|||||||
const onSubmit = (formdata) => {
|
const onSubmit = (formdata) => {
|
||||||
setSPRID(formdata.spridSearchText);
|
setSPRID(formdata.spridSearchText);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOrg = (orgId) => {};
|
const handleCrateOrg = () => {
|
||||||
|
clientQuery.removeQueries({queryKey:["organization"]})
|
||||||
|
onOpen({ startStep: 4,orgData:null })
|
||||||
|
};
|
||||||
const SP = watch("spridSearchText");
|
const SP = watch("spridSearchText");
|
||||||
return (
|
return (
|
||||||
<div className="d-block">
|
<div className="d-block">
|
||||||
@ -126,7 +131,7 @@ const OrgPickerFromSPId = ({ title, placeholder }) => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-sm btn-primary mt-3"
|
className="btn btn-sm btn-primary mt-3"
|
||||||
onClick={() => onOpen({ startStep: 4 })}
|
onClick={handleCrateOrg}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
Create New Organization
|
Create New Organization
|
||||||
|
@ -142,7 +142,7 @@ const OrganizationsList = ({searchText}) => {
|
|||||||
colSpan={organizationsColumns.length + 1}
|
colSpan={organizationsColumns.length + 1}
|
||||||
className="text-center"
|
className="text-center"
|
||||||
>
|
>
|
||||||
<p className="fw-semibold">Not Found</p>
|
<p className="fw-semibold">{isLoading ? "Loading....":"Not Found Organization"}</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
|
@ -11,7 +11,8 @@ import { TasksRepository } from "../../repositories/ProjectRepository";
|
|||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
import {
|
import {
|
||||||
useEmployeeForTaskAssign,
|
useEmployeeForTaskAssign,
|
||||||
useProjectAssignedOrganizations,
|
useProjectAssignedOrganizationsName,
|
||||||
|
useProjectAssignedServices,
|
||||||
useProjectDetails,
|
useProjectDetails,
|
||||||
} from "../../hooks/useProjects";
|
} from "../../hooks/useProjects";
|
||||||
import eventBus from "../../services/eventBus";
|
import eventBus from "../../services/eventBus";
|
||||||
@ -95,9 +96,9 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const selectedProject = useSelectedProject();
|
const selectedProject = useSelectedProject();
|
||||||
const { data: serviceList, isLoading: isServiceLoading } = useServices();
|
const { data: serviceList, isLoading: isServiceLoading } = useProjectAssignedServices(selectedProject);
|
||||||
const { data: organizationList, isLoading: isOrgLoading } =
|
const { data: organizationList, isLoading: isOrgLoading } =
|
||||||
useProjectAssignedOrganizations(selectedProject);
|
useProjectAssignedOrganizationsName(selectedProject);
|
||||||
const { data: employees, isLoading: isEmployeeLoading } =
|
const { data: employees, isLoading: isEmployeeLoading } =
|
||||||
useEmployeeForTaskAssign(
|
useEmployeeForTaskAssign(
|
||||||
selectedProject,
|
selectedProject,
|
||||||
@ -274,7 +275,7 @@ const AssignTask = ({ assignData, onClose, setAssigned }) => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<option value="">--Select Service--</option>
|
<option value="">--Select Service--</option>
|
||||||
{serviceList?.data?.map((service,index) => (
|
{serviceList?.map((service,index) => (
|
||||||
<option key={`${service.id}-${index}`} value={service.id}>
|
<option key={`${service.id}-${index}`} value={service.id}>
|
||||||
{service.name}
|
{service.name}
|
||||||
</option>
|
</option>
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
useGroups,
|
useGroups,
|
||||||
useWorkCategoriesMaster,
|
useWorkCategoriesMaster,
|
||||||
} from "../../../hooks/masterHook/useMaster";
|
} from "../../../hooks/masterHook/useMaster";
|
||||||
import { useManageTask, useProjectAssignedOrganizations, useProjectAssignedServices } from "../../../hooks/useProjects";
|
import { useManageTask, useProjectAssignedOrganizationsName, useProjectAssignedServices } from "../../../hooks/useProjects";
|
||||||
import showToast from "../../../services/toastService";
|
import showToast from "../../../services/toastService";
|
||||||
import Label from "../../common/Label";
|
import Label from "../../common/Label";
|
||||||
import { useSelectedProject } from "../../../slices/apiDataManager";
|
import { useSelectedProject } from "../../../slices/apiDataManager";
|
||||||
@ -47,7 +47,7 @@ const TaskModel = ({ project, onSubmit, onClose }) => {
|
|||||||
const projectId = useSelectedProject();
|
const projectId = useSelectedProject();
|
||||||
|
|
||||||
const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(projectId);
|
const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(projectId);
|
||||||
const { data: assignedOrganizations, isLoading: orgLoading } = useProjectAssignedOrganizations(projectId);
|
const { data: assignedOrganizations, isLoading: orgLoading } = useProjectAssignedOrganizationsName(projectId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ const WorkArea = ({ workArea, floor, forBuilding }) => {
|
|||||||
<ProgressBar
|
<ProgressBar
|
||||||
completedWork={formatNumber(workArea?.completedWork)}
|
completedWork={formatNumber(workArea?.completedWork)}
|
||||||
plannedWork={formatNumber(workArea?.plannedWork)}
|
plannedWork={formatNumber(workArea?.plannedWork)}
|
||||||
className="m-0 my-2 me-6 text-info"
|
className="m-0 my-2 " height="6px"rounded showLabel={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -327,7 +327,7 @@ const ManageProjectInfo = ({ project, onClose }) => {
|
|||||||
<i className="bx bx-sm bx-info-circle"></i> Not found PMC and
|
<i className="bx bx-sm bx-info-circle"></i> Not found PMC and
|
||||||
Pomoter, find through SPRID or create new
|
Pomoter, find through SPRID or create new
|
||||||
</span>
|
</span>
|
||||||
<small className="cursor-pointer" onClick={handleOrganizaioFinder}>
|
<small className="cursor-pointer" onClick={handleOrganizaioFinder} >
|
||||||
<i className="bx bx-plus-circle text-primary"></i>
|
<i className="bx bx-plus-circle text-primary"></i>
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
@ -367,14 +367,14 @@ const ManageProjectInfo = ({ project, onClose }) => {
|
|||||||
className="btn btn-label-secondary btn-sm me-2"
|
className="btn btn-label-secondary btn-sm me-2"
|
||||||
onClick={handleCancel}
|
onClick={handleCancel}
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
disabled={isPending || isCreating}
|
disabled={isPending || isCreating || loading}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="btn btn-primary btn-sm"
|
className="btn btn-primary btn-sm"
|
||||||
disabled={isPending || isCreating}
|
disabled={isPending || isCreating || loading}
|
||||||
>
|
>
|
||||||
{isPending||isCreating ? "Please Wait..." : project ? "Update" : "Submit"}
|
{isPending||isCreating ? "Please Wait..." : project ? "Update" : "Submit"}
|
||||||
</button>
|
</button>
|
||||||
|
@ -132,11 +132,15 @@ const ProjectListView = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card page-min-h py-4 px-6 shadow-sm">
|
<div className="card page-min-h py-4 px-6 shadow-sm">
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="table-responsive text-nowrap page-min-h"
|
||||||
|
>
|
||||||
<table className="table table-hover align-middle m-0">
|
<table className="table table-hover align-middle m-0">
|
||||||
<thead className="border-bottom">
|
<thead className="border-bottom ">
|
||||||
<tr>
|
<tr>
|
||||||
{projectColumns.map((col) => (
|
{projectColumns.map((col) => (
|
||||||
<th key={col.key} colSpan={col.colSpan} className={col.className}>
|
<th key={col.key} colSpan={col.colSpan} className={`${col.className} table_header_border`}>
|
||||||
{col.label}
|
{col.label}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
@ -217,6 +221,7 @@ const ProjectListView = ({
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
|
@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|||||||
import TeamEmployeeList from "./TeamEmployeeList";
|
import TeamEmployeeList from "./TeamEmployeeList";
|
||||||
import { useOrganization } from "../../../hooks/useDirectory";
|
import { useOrganization } from "../../../hooks/useDirectory";
|
||||||
import { useOrganizationsList } from "../../../hooks/useOrganization";
|
import { useOrganizationsList } from "../../../hooks/useOrganization";
|
||||||
import { useProjectAssignedOrganizations } from "../../../hooks/useProjects";
|
import { useProjectAssignedOrganizationsName } from "../../../hooks/useProjects";
|
||||||
import { useSelectedProject } from "../../../slices/apiDataManager";
|
import { useSelectedProject } from "../../../slices/apiDataManager";
|
||||||
|
|
||||||
const TeamAssignToProject = ({ closeModal }) => {
|
const TeamAssignToProject = ({ closeModal }) => {
|
||||||
@ -10,13 +10,13 @@ const TeamAssignToProject = ({ closeModal }) => {
|
|||||||
const [selectedOrg, setSelectedOrg] = useState(null);
|
const [selectedOrg, setSelectedOrg] = useState(null);
|
||||||
const project = useSelectedProject();
|
const project = useSelectedProject();
|
||||||
const { data, isLoading, isError, error } =
|
const { data, isLoading, isError, error } =
|
||||||
useProjectAssignedOrganizations(project);
|
useProjectAssignedOrganizationsName(project);
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<p className="fs-5 fs-seminbod ">Assign Employee To Project </p>
|
<p className="fs-5 fs-seminbod ">Assign Employee To Project </p>
|
||||||
|
|
||||||
<div class="row align-items-center gx-5">
|
<div className="row align-items-center gx-5">
|
||||||
<div class="col">
|
<div className="col">
|
||||||
<div className="d-flex flex-grow-1 align-items-center gap-2">
|
<div className="d-flex flex-grow-1 align-items-center gap-2">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<select className="form-select form-select-sm w-100" disabled>
|
<select className="form-select form-select-sm w-100" disabled>
|
||||||
@ -49,7 +49,7 @@ const TeamAssignToProject = ({ closeModal }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div className="col">
|
||||||
<div className="d-flex flex-grow-1 align-items-center gap-2">
|
<div className="d-flex flex-grow-1 align-items-center gap-2">
|
||||||
<label htmlFor="search" className="form-label mb-0 text-nowrap">
|
<label htmlFor="search" className="form-label mb-0 text-nowrap">
|
||||||
Search Employee
|
Search Employee
|
||||||
|
@ -2,13 +2,14 @@ import React, { useState, useEffect } from "react";
|
|||||||
import Avatar from "../../common/Avatar";
|
import Avatar from "../../common/Avatar";
|
||||||
import { useDebounce } from "../../../utils/appUtils";
|
import { useDebounce } from "../../../utils/appUtils";
|
||||||
import { useSelectedProject } from "../../../slices/apiDataManager";
|
import { useSelectedProject } from "../../../slices/apiDataManager";
|
||||||
import { useOrganizationEmployees } from "../../../hooks/useOrganization";
|
|
||||||
import {
|
import {
|
||||||
useEmployeesByProjectAllocated,
|
useEmployeesByProjectAllocated,
|
||||||
useManageProjectAllocation,
|
useManageProjectAllocation,
|
||||||
|
useProjectAssignedServices,
|
||||||
} from "../../../hooks/useProjects";
|
} from "../../../hooks/useProjects";
|
||||||
import useMaster, { useServices } from "../../../hooks/masterHook/useMaster";
|
import useMaster, { useServices } from "../../../hooks/masterHook/useMaster";
|
||||||
import showToast from "../../../services/toastService";
|
import showToast from "../../../services/toastService";
|
||||||
|
import { useOrganizationEmployees } from "../../../hooks/useOrganization";
|
||||||
|
|
||||||
const TeamEmployeeList = ({ organizationId, searchTerm, closeModal }) => {
|
const TeamEmployeeList = ({ organizationId, searchTerm, closeModal }) => {
|
||||||
const selectedProject = useSelectedProject();
|
const selectedProject = useSelectedProject();
|
||||||
@ -29,7 +30,7 @@ const TeamEmployeeList = ({ organizationId, searchTerm, closeModal }) => {
|
|||||||
useEmployeesByProjectAllocated(selectedProject, null);
|
useEmployeesByProjectAllocated(selectedProject, null);
|
||||||
|
|
||||||
const { data: jobRoles } = useMaster();
|
const { data: jobRoles } = useMaster();
|
||||||
const { data: services } = useServices();
|
const { data: services } = useProjectAssignedServices(selectedProject);
|
||||||
|
|
||||||
const [employees, setEmployees] = useState([]);
|
const [employees, setEmployees] = useState([]);
|
||||||
|
|
||||||
@ -187,7 +188,7 @@ if (employees.length === 0) {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<option value="">Select Service</option>
|
<option value="">Select Service</option>
|
||||||
{services?.data?.map((s) => (
|
{services?.map((s) => (
|
||||||
<option key={s.id} value={s.id}>
|
<option key={s.id} value={s.id}>
|
||||||
{s.name}
|
{s.name}
|
||||||
</option>
|
</option>
|
||||||
|
@ -272,7 +272,7 @@ const Teams = () => {
|
|||||||
className="text-heading text-truncate cursor-pointer"
|
className="text-heading text-truncate cursor-pointer"
|
||||||
>
|
>
|
||||||
<span className="fw-normal">
|
<span className="fw-normal">
|
||||||
{emp.firstName}
|
{emp.firstName}{" "}
|
||||||
{emp.lastName}
|
{emp.lastName}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -14,7 +14,7 @@ const SkeletonCell = ({ width = "100%", height = 20, style = {} }) => (
|
|||||||
|
|
||||||
export const TenantTableSkeleton = ({ columns, rows = 5 }) => {
|
export const TenantTableSkeleton = ({ columns, rows = 5 }) => {
|
||||||
return (
|
return (
|
||||||
<div className="card p-2 mt-3">
|
<div className="p-2 mt-3">
|
||||||
<div className="card-datatable text-nowrap table-responsive">
|
<div className="card-datatable text-nowrap table-responsive">
|
||||||
<table className="table border-top dataTable text-nowrap">
|
<table className="table border-top dataTable text-nowrap">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -137,7 +137,7 @@ const TenantsList = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="p-2 mt-3">
|
<div className="p-2 mt-3">
|
||||||
<div className="card-datatable text-nowrap table-responsive">
|
<div className=" text-nowrap table-responsive">
|
||||||
<table className="table border-top dataTable text-nowrap">
|
<table className="table border-top dataTable text-nowrap">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="shadow-sm">
|
<tr className="shadow-sm">
|
||||||
|
@ -3,8 +3,8 @@ import { useController, useFormContext, useWatch } from "react-hook-form";
|
|||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
const DateRangePicker = ({
|
const DateRangePicker = ({
|
||||||
md,
|
md=12,
|
||||||
sm,
|
sm=6,
|
||||||
onRangeChange,
|
onRangeChange,
|
||||||
DateDifference = 7,
|
DateDifference = 7,
|
||||||
endDateMode = "yesterday",
|
endDateMode = "yesterday",
|
||||||
@ -63,21 +63,22 @@ const DateRangePicker = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`col-${sm} col-sm-${md} px-1`}>
|
<div className={`position-relative w-auto justify-content-center`}>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control form-control-sm ps-2 pe-5 me-4"
|
className="form-control form-control-sm w-100 pe-8 "
|
||||||
placeholder="From to End"
|
placeholder="From to End"
|
||||||
id="flatpickr-range"
|
id="flatpickr-range"
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<i
|
||||||
|
className="bx bx-calendar calendar-icon cursor-pointer position-absolute top-50 end-0 translate-middle-y me-2 "
|
||||||
|
onClick={handleIconClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<i
|
|
||||||
className="bx bx-calendar calendar-icon cursor-pointer position-relative top-50 translate-middle-y"
|
|
||||||
onClick={handleIconClick}
|
|
||||||
style={{ right: "22px", bottom: "-8px" }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,35 +3,65 @@ import React from "react";
|
|||||||
const ProgressBar = ({
|
const ProgressBar = ({
|
||||||
plannedWork = 100,
|
plannedWork = 100,
|
||||||
completedWork = 0,
|
completedWork = 0,
|
||||||
height = "8px",
|
height = "6px",
|
||||||
className = "mb-4",
|
className = "mb-4",
|
||||||
rounded = true,
|
rounded = true,
|
||||||
|
showLabel = true,
|
||||||
}) => {
|
}) => {
|
||||||
const getProgress = (planned, completed) => {
|
const getProgress = (planned, completed) => {
|
||||||
if (!planned || planned === 0) return "0%";
|
if (!planned || planned === 0) return 0;
|
||||||
return `${Math.min((completed / planned) * 100, 100).toFixed(2)}%`;
|
return Math.min((completed / planned) * 100, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
const progressStyle = {
|
const percentage = getProgress(plannedWork, completedWork);
|
||||||
width: getProgress(plannedWork, completedWork),
|
|
||||||
|
const progressBarStyle = {
|
||||||
|
width: ` ${percentage.toFixed(2)}%`,
|
||||||
|
transition: "width 0.4s ease",
|
||||||
|
};
|
||||||
|
|
||||||
|
const containerStyle = {
|
||||||
|
height,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "8px",
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`progress ${className} ${rounded ? "rounded" : ""}`}
|
className={`d-flex align-items-center ${className}`}
|
||||||
style={{ height }}
|
style={containerStyle}
|
||||||
>
|
>
|
||||||
<div
|
<div className="flex-grow-1">
|
||||||
className={`progress-bar ${rounded ? "rounded" : ""}`}
|
<div
|
||||||
role="progressbar"
|
className={`progress ${rounded ? "rounded" : ""}`}
|
||||||
style={progressStyle}
|
style={{ height, backgroundColor: "#f0f0f0" }}
|
||||||
aria-valuenow={completedWork}
|
>
|
||||||
aria-valuemin="0"
|
<div
|
||||||
aria-valuemax={plannedWork}
|
className={`progress-bar ${rounded ? "rounded" : ""}`}
|
||||||
></div>
|
role="progressbar"
|
||||||
|
style={progressBarStyle}
|
||||||
|
aria-valuenow={completedWork}
|
||||||
|
aria-valuemin="0"
|
||||||
|
aria-valuemax={plannedWork}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showLabel && (
|
||||||
|
<span
|
||||||
|
className="fw-semibold text-secondary"
|
||||||
|
style={{
|
||||||
|
minWidth: "45px",
|
||||||
|
textAlign: "right",
|
||||||
|
fontSize: "0.8rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{percentage.toFixed(2)}%
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ProgressBar;
|
export default ProgressBar;
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ const GalleryFilterPanel = ({ onApply }) => {
|
|||||||
endField="endDate"
|
endField="endDate"
|
||||||
resetSignal={resetKey}
|
resetSignal={resetKey}
|
||||||
defaultRange={false}
|
defaultRange={false}
|
||||||
|
maxDate={new Date()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
|
@ -41,7 +41,6 @@ const EditContactTag = ({ data, onClose }) => {
|
|||||||
name: formData.name,
|
name: formData.name,
|
||||||
description: formData.description,
|
description: formData.description,
|
||||||
};
|
};
|
||||||
debugger
|
|
||||||
updateContactTag({ id: data?.id, payload });
|
updateContactTag({ id: data?.id, payload });
|
||||||
}
|
}
|
||||||
// const onSubmit = (formdata) => {
|
// const onSubmit = (formdata) => {
|
||||||
|
@ -70,12 +70,12 @@ const MasterModal = ({ modaldata, closeModal }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="p-2 p-md-1">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="fs-5 fw-semibold" >{`${masterType, " ", modalType}`}</p>
|
<p className="fs-5 fw-semibold" >{`${masterType, " ", modalType}`}</p>
|
||||||
</div>
|
</div>
|
||||||
{ modalComponents[modalType] || null}
|
{ modalComponents[modalType] || null}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,8 +81,8 @@ const ServiceGroups = ({ service }) => {
|
|||||||
) : (
|
) : (
|
||||||
<div className="accordion-body text-start m-0 p-0">
|
<div className="accordion-body text-start m-0 p-0">
|
||||||
<div className="dropdown-divider border"></div>
|
<div className="dropdown-divider border"></div>
|
||||||
|
{!isLoading && groups?.data?.length === 0 && (<div className="text-center py-2"><p>No Group available.</p></div>)}
|
||||||
{groups?.data?.map((group) => {
|
{groups && groups?.data?.map((group) => {
|
||||||
const isOpen = activeGroupId === group.id;
|
const isOpen = activeGroupId === group.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -570,7 +570,6 @@ export const useUpdateContactTag = (onSuccessCallback) => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async ({ id, payload }) => {
|
mutationFn: async ({ id, payload }) => {
|
||||||
debugger;
|
|
||||||
const response = await MasterRespository.updateContactTag(id, payload);
|
const response = await MasterRespository.updateContactTag(id, payload);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
@ -704,13 +703,13 @@ export const useCreateService = (onSuccessCallback) => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (payload) => {
|
mutationFn: async (payload) => {
|
||||||
debugger;
|
|
||||||
const resp = await MasterRespository.createService(payload);
|
const resp = await MasterRespository.createService(payload);
|
||||||
debugger;
|
|
||||||
return resp.data;
|
return resp.data;
|
||||||
},
|
},
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
debugger;
|
|
||||||
queryClient.invalidateQueries({ queryKey: ["masterData", "Services"] });
|
queryClient.invalidateQueries({ queryKey: ["masterData", "Services"] });
|
||||||
|
|
||||||
showToast(data?.message || "Service added successfully", "success");
|
showToast(data?.message || "Service added successfully", "success");
|
||||||
@ -718,7 +717,7 @@ export const useCreateService = (onSuccessCallback) => {
|
|||||||
if (onSuccessCallback) onSuccessCallback(data?.data);
|
if (onSuccessCallback) onSuccessCallback(data?.data);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
debugger;
|
|
||||||
showToast( error?.response?.data?.message || error?.message || "Something went wrong", "error");
|
showToast( error?.response?.data?.message || error?.message || "Something went wrong", "error");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -759,7 +758,7 @@ export const useCreateActivityGroup = (onSuccessCallback) => {
|
|||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: ["groups"],
|
queryKey: ["groups"],
|
||||||
});
|
});
|
||||||
debugger
|
|
||||||
showToast( data?.message ||
|
showToast( data?.message ||
|
||||||
data?.response?.data?.message || "Activity Group created successfully.",
|
data?.response?.data?.message || "Activity Group created successfully.",
|
||||||
"success"
|
"success"
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
toggleModal,
|
toggleModal,
|
||||||
} from "../slices/localVariablesSlice.jsx";
|
} from "../slices/localVariablesSlice.jsx";
|
||||||
import { removeSession } from "../utils/authUtils.js";
|
import { removeSession } from "../utils/authUtils.js";
|
||||||
|
import { cacheProfileData } from "../slices/apiDataManager.jsx";
|
||||||
|
|
||||||
// ----------------------------Modal--------------------------
|
// ----------------------------Modal--------------------------
|
||||||
|
|
||||||
@ -84,6 +85,8 @@ export const useAuthModal = () => {
|
|||||||
|
|
||||||
export const useLogout = () => {
|
export const useLogout = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const naviget = useNavigate()
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@ -96,9 +99,12 @@ export const useLogout = () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
|
queryClient.clear()
|
||||||
removeSession();
|
removeSession();
|
||||||
|
dispatch(cacheProfileData(null))
|
||||||
|
|
||||||
window.location.href = "/auth/login";
|
// window.location.href = "/auth/login";
|
||||||
|
naviget("/auth/login",{replace:true})
|
||||||
if (onSuccessCallBack) onSuccessCallBack();
|
if (onSuccessCallBack) onSuccessCallBack();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -12,14 +12,14 @@ import { queryClient } from "../layouts/AuthLayout";
|
|||||||
// Query ---------------------------------------------------------------------------
|
// Query ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export const useEmployee = (employeeId) => {
|
export const useEmployee = (employeeId) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["employeeProfile", employeeId],
|
queryKey: ["employeeProfile", employeeId],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await EmployeeRepository.getEmployeeProfile(employeeId)
|
const res = await EmployeeRepository.getEmployeeProfile(employeeId);
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
enabled:!!employeeId
|
enabled: !!employeeId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useAllEmployees = (showInactive) => {
|
export const useAllEmployees = (showInactive) => {
|
||||||
@ -137,7 +137,6 @@ export const useEmployeesAllOrByProjectId = (
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: employees = [],
|
data: employees = [],
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -158,6 +157,18 @@ export const useEmployeesAllOrByProjectId = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// New Employee get list by CureentOrganization
|
||||||
|
|
||||||
|
export const useEmployeesByOrganization = (showInactive) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["employeesByOrganization", showInactive],
|
||||||
|
queryFn: async () => {
|
||||||
|
const res = await EmployeeRepository.getAllEmployeeList(showInactive);
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// ManageEmployee.jsx
|
// ManageEmployee.jsx
|
||||||
export const useEmployeeProfile = (employeeId) => {
|
export const useEmployeeProfile = (employeeId) => {
|
||||||
const isEnabled = !!employeeId;
|
const isEnabled = !!employeeId;
|
||||||
@ -184,11 +195,11 @@ export const useEmployeeProfile = (employeeId) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useEmployeesName = (projectId, search,allEmployee) => {
|
export const useEmployeesName = (projectId, search, allEmployee) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["employees", projectId, search,allEmployee],
|
queryKey: ["employees", projectId, search, allEmployee],
|
||||||
queryFn: async () =>
|
queryFn: async () =>
|
||||||
await EmployeeRepository.getEmployeeName(projectId, search,allEmployee),
|
await EmployeeRepository.getEmployeeName(projectId, search, allEmployee),
|
||||||
|
|
||||||
staleTime: 5 * 60 * 1000, // Optional: cache for 5 minutes
|
staleTime: 5 * 60 * 1000, // Optional: cache for 5 minutes
|
||||||
});
|
});
|
||||||
@ -208,9 +219,6 @@ export const useEmployeesNameByProject = (projectId) => {
|
|||||||
|
|
||||||
// Mutation------------------------------------------------------------------
|
// Mutation------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const useUpdateEmployee = () => {
|
export const useUpdateEmployee = () => {
|
||||||
const selectedProject = useSelector(
|
const selectedProject = useSelector(
|
||||||
(store) => store.localVariables.projectId
|
(store) => store.localVariables.projectId
|
||||||
@ -225,7 +233,7 @@ export const useUpdateEmployee = () => {
|
|||||||
const isAllEmployee = variables.IsAllEmployee;
|
const isAllEmployee = variables.IsAllEmployee;
|
||||||
|
|
||||||
// Cache invalidation
|
// Cache invalidation
|
||||||
queryClient.invalidateQueries({ queryKey: ["employeeProfile",id] });
|
queryClient.invalidateQueries({ queryKey: ["employeeProfile", id] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["allEmployees"] });
|
queryClient.invalidateQueries({ queryKey: ["allEmployees"] });
|
||||||
// queryClient.invalidateQueries(['employeeProfile', id]);
|
// queryClient.invalidateQueries(['employeeProfile', id]);
|
||||||
queryClient.invalidateQueries({ queryKey: ["projectEmployees"] });
|
queryClient.invalidateQueries({ queryKey: ["projectEmployees"] });
|
||||||
@ -247,7 +255,6 @@ export const useUpdateEmployee = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const useSuspendEmployee = ({
|
export const useSuspendEmployee = ({
|
||||||
setIsDeleteModalOpen,
|
setIsDeleteModalOpen,
|
||||||
setemployeeLodaing,
|
setemployeeLodaing,
|
||||||
@ -300,7 +307,6 @@ export const useSuspendEmployee = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const useUpdateEmployeeRoles = ({
|
export const useUpdateEmployeeRoles = ({
|
||||||
onClose,
|
onClose,
|
||||||
resetForm,
|
resetForm,
|
||||||
@ -334,4 +340,4 @@ export const useUpdateEmployeeRoles = ({
|
|||||||
isError: mutation.isError,
|
isError: mutation.isError,
|
||||||
error: mutation.error,
|
error: mutation.error,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,7 @@ export const useOrganizationModal = () => {
|
|||||||
dispatch(
|
dispatch(
|
||||||
openOrgModal({
|
openOrgModal({
|
||||||
isOpen: true,
|
isOpen: true,
|
||||||
orgData: options.orgData ?? orgData ?? null,
|
orgData: options.hasOwnProperty("orgData") ? options.orgData : orgData,
|
||||||
startStep: options.startStep ?? startStep ?? 1,
|
startStep: options.startStep ?? startStep ?? 1,
|
||||||
prevStep: options.prevStep ?? prevStep ?? 1,
|
prevStep: options.prevStep ?? prevStep ?? 1,
|
||||||
flowType: options.flowType ?? flowType ?? "default",
|
flowType: options.flowType ?? flowType ?? "default",
|
||||||
@ -138,8 +138,12 @@ export const useAssignOrgToProject = (onSuccessCallback) => {
|
|||||||
useClient.invalidateQueries({
|
useClient.invalidateQueries({
|
||||||
queryKey: ["projectAssignedOrganiztions"],
|
queryKey: ["projectAssignedOrganiztions"],
|
||||||
});
|
});
|
||||||
|
useClient.invalidateQueries({
|
||||||
|
queryKey: ["projectAssignedOrganiztionsName"],
|
||||||
|
});
|
||||||
|
|
||||||
useClient.invalidateQueries({
|
useClient.invalidateQueries({
|
||||||
queryKey: ["projectAssignedOrganization", projectId],
|
queryKey: ["projectAssignedServices", projectId],
|
||||||
});
|
});
|
||||||
showToast("Organization successfully", "success");
|
showToast("Organization successfully", "success");
|
||||||
if (onSuccessCallback) onSuccessCallback();
|
if (onSuccessCallback) onSuccessCallback();
|
||||||
@ -181,6 +185,8 @@ export const useUpdateOrganization = (onSuccessCallback) => {
|
|||||||
await OrganizationRepository.updateOrganizaion(orgId,payload),
|
await OrganizationRepository.updateOrganizaion(orgId,payload),
|
||||||
onSuccess: (_, variables) => {
|
onSuccess: (_, variables) => {
|
||||||
useClient.invalidateQueries({ queryKey: ["organizationList"] });
|
useClient.invalidateQueries({ queryKey: ["organizationList"] });
|
||||||
|
useClient.invalidateQueries({ queryKey: ["projectAssignedOrganiztionsName"] });
|
||||||
|
|
||||||
showToast("Organization Updated successfully", "success");
|
showToast("Organization Updated successfully", "success");
|
||||||
if (onSuccessCallback) onSuccessCallback();
|
if (onSuccessCallback) onSuccessCallback();
|
||||||
},
|
},
|
||||||
|
@ -294,9 +294,21 @@ export const useProjectAssignedOrganizations = (projectId) => {
|
|||||||
enabled: !!projectId,
|
enabled: !!projectId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
export const useProjectAssignedOrganizationsName = (projectId) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["projectAssignedOrganiztionsName", projectId],
|
||||||
|
queryFn: async () => {
|
||||||
|
const resp = await ProjectRepository.getProjectAssignedOrganizationsName(
|
||||||
|
projectId
|
||||||
|
);
|
||||||
|
return resp.data;
|
||||||
|
},
|
||||||
|
enabled: !!projectId,
|
||||||
|
});
|
||||||
|
};
|
||||||
export const useProjectAssignedServices = (projectId) => {
|
export const useProjectAssignedServices = (projectId) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["projectAssignedOrganization", projectId],
|
queryKey: ["projectAssignedServices", projectId],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const resp = await ProjectRepository.getProjectAssignedServices(
|
const resp = await ProjectRepository.getProjectAssignedServices(
|
||||||
projectId
|
projectId
|
||||||
|
@ -17,7 +17,7 @@ import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
|||||||
import { REGULARIZE_ATTENDANCE } from "../../utils/constants";
|
import { REGULARIZE_ATTENDANCE } from "../../utils/constants";
|
||||||
import eventBus from "../../services/eventBus";
|
import eventBus from "../../services/eventBus";
|
||||||
import {
|
import {
|
||||||
useProjectAssignedOrganizations,
|
useProjectAssignedOrganizationsName,
|
||||||
useProjectName,
|
useProjectName,
|
||||||
} from "../../hooks/useProjects";
|
} from "../../hooks/useProjects";
|
||||||
import GlobalModel from "../../components/common/GlobalModel";
|
import GlobalModel from "../../components/common/GlobalModel";
|
||||||
@ -47,7 +47,7 @@ const AttendancePage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { data: organizations = [], isLoading: orgLoading } =
|
const { data: organizations = [], isLoading: orgLoading } =
|
||||||
useProjectAssignedOrganizations(selectedProject);
|
useProjectAssignedOrganizationsName(selectedProject);
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
markTime: "",
|
markTime: "",
|
||||||
@ -131,7 +131,7 @@ const AttendancePage = () => {
|
|||||||
<div className="nav-align-top nav-tabs-shadow ">
|
<div className="nav-align-top nav-tabs-shadow ">
|
||||||
{/* Tabs */}
|
{/* Tabs */}
|
||||||
<div className="nav-align-top nav-tabs-shadow bg-white border-bottom pt-5">
|
<div className="nav-align-top nav-tabs-shadow bg-white border-bottom pt-5">
|
||||||
<div className="row align-items-center g-0 mb-3 mb-md-0 mx-5">
|
<div className="row align-items-center g-0 mb-3 mb-md-0 mx-1 mx-sm-5">
|
||||||
{/* Tabs */}
|
{/* Tabs */}
|
||||||
<div className="col-12 col-md">
|
<div className="col-12 col-md">
|
||||||
<ul className="nav nav-tabs" role="tablist">
|
<ul className="nav nav-tabs" role="tablist">
|
||||||
@ -181,9 +181,10 @@ const AttendancePage = () => {
|
|||||||
{/* Search + Organization filter */}
|
{/* Search + Organization filter */}
|
||||||
<div className="col-12 col-md-auto mt-2 mt-md-0 ms-md-auto d-flex gap-2 align-items-center">
|
<div className="col-12 col-md-auto mt-2 mt-md-0 ms-md-auto d-flex gap-2 align-items-center">
|
||||||
{/* Organization Dropdown */}
|
{/* Organization Dropdown */}
|
||||||
<select
|
<div className="row">
|
||||||
|
<div className="col-12 col-sm-6 mb-2 mb-sm-0">
|
||||||
|
<select
|
||||||
className="form-select form-select-sm"
|
className="form-select form-select-sm"
|
||||||
style={{ minWidth: "180px" }}
|
|
||||||
value={appliedFilters.selectedOrganization}
|
value={appliedFilters.selectedOrganization}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setAppliedFilters((prev) => ({
|
setAppliedFilters((prev) => ({
|
||||||
@ -200,16 +201,21 @@ const AttendancePage = () => {
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
{/* Search Input */}
|
<div className="col-12 col-sm-6">
|
||||||
|
{/* Search Input */}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control form-control-sm"
|
className="form-control form-control-sm"
|
||||||
placeholder="Search Employee..."
|
placeholder="Search Employee..."
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
style={{ minWidth: "200px" }}
|
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,8 @@ import ReportTask from "../../components/Activities/ReportTask";
|
|||||||
import TaskReportFilterPanel from "../../components/DailyProgressRport/TaskReportFilterPanel";
|
import TaskReportFilterPanel from "../../components/DailyProgressRport/TaskReportFilterPanel";
|
||||||
import { useFab } from "../../Context/FabContext";
|
import { useFab } from "../../Context/FabContext";
|
||||||
import SubTask from "../../components/Activities/SubTask";
|
import SubTask from "../../components/Activities/SubTask";
|
||||||
|
import { useProjectAssignedServices } from "../../hooks/useProjects";
|
||||||
|
import { useSelectedProject } from "../../slices/apiDataManager";
|
||||||
|
|
||||||
const DailyProgrssContext = createContext();
|
const DailyProgrssContext = createContext();
|
||||||
export const useDailyProgrssContext = () => {
|
export const useDailyProgrssContext = () => {
|
||||||
@ -21,10 +23,11 @@ export const useDailyProgrssContext = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DailyProgrssReport = () => {
|
const DailyProgrssReport = () => {
|
||||||
|
const selectedProject = useSelectedProject()
|
||||||
const [service, setService] = useState("");
|
const [service, setService] = useState("");
|
||||||
const [filter,setFilter] = useState('')
|
const [filter,setFilter] = useState('')
|
||||||
const { setOffcanvasContent, setShowTrigger } = useFab();
|
const { setOffcanvasContent, setShowTrigger } = useFab();
|
||||||
const { data, isLoading, isError, error } = useServices();
|
const { data, isLoading, isError, error } = useProjectAssignedServices(selectedProject);
|
||||||
|
|
||||||
const [modal, setModal] = useState({ type: null, data: null });
|
const [modal, setModal] = useState({ type: null, data: null });
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ const DailyProgrssReport = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="card card-fullscreen p-5">
|
<div className="card card-fullscreen p-5">
|
||||||
{data?.data?.length > 0 && (<div className="col-sm-4 col-md-3 col-12">
|
{data?.length > 0 && (<div className="col-sm-4 col-md-3 col-12">
|
||||||
<select
|
<select
|
||||||
className="form-select form-select-sm"
|
className="form-select form-select-sm"
|
||||||
value={service ?? ""}
|
value={service ?? ""}
|
||||||
@ -99,7 +102,7 @@ const DailyProgrssReport = () => {
|
|||||||
<option value="">
|
<option value="">
|
||||||
All Services
|
All Services
|
||||||
</option>
|
</option>
|
||||||
{data?.data?.map((service) => (
|
{data?.map((service) => (
|
||||||
<option key={service.id} value={service.id}>
|
<option key={service.id} value={service.id}>
|
||||||
{service.name}
|
{service.name}
|
||||||
</option>
|
</option>
|
||||||
|
@ -162,29 +162,33 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-1 px-2 py-3">
|
<div className="mb-1 px-md-2 px-0 py-3">
|
||||||
<div className="d-flex align-items-center justify-content-between">
|
<div className="row">
|
||||||
<div className="d-flex align-items-center gap-3">
|
<div className="col-12 col-md-10 mb-2">
|
||||||
{activeTab === "notes" && (
|
{activeTab === "notes" && (
|
||||||
<input
|
<div className="col-8 col-md-3">
|
||||||
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
className="form-control form-control-sm"
|
className="form-control form-control-sm"
|
||||||
placeholder="Search notes..."
|
placeholder="Search notes..."
|
||||||
value={searchNote}
|
value={searchNote}
|
||||||
onChange={(e) => setSearchNote(e.target.value)}
|
onChange={(e) => setSearchNote(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{activeTab === "contacts" && (
|
{activeTab === "contacts" && (
|
||||||
<div className="d-flex align-items-center gap-3">
|
<div className="d-flex align-items-center gap-3">
|
||||||
<div className="d-flex gap-2 align-items-center">
|
<div className="col-12 col-md-8 d-flex flex-row gap-2">
|
||||||
<input
|
<div className="col-7 col-md-4">
|
||||||
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
className="form-control form-control-sm"
|
className="form-control form-control-sm"
|
||||||
placeholder="Search contacts..."
|
placeholder="Search contacts..."
|
||||||
value={searchContact}
|
value={searchContact}
|
||||||
onChange={(e) => setsearchContact(e.target.value)}
|
onChange={(e) => setsearchContact(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
className={`btn btn-sm p-1 ${
|
className={`btn btn-sm p-1 ${
|
||||||
!gridView ? "btn-primary" : "btn-outline-primary"
|
!gridView ? "btn-primary" : "btn-outline-primary"
|
||||||
@ -202,9 +206,7 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
|
|||||||
>
|
>
|
||||||
<i className="bx bx-grid-alt"></i>
|
<i className="bx bx-grid-alt"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
<div className="form-check form-switch d-flex align-items-center d-none d-md-flex">
|
||||||
|
|
||||||
<div className="form-check form-switch d-flex align-items-center">
|
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="form-check-input"
|
className="form-check-input"
|
||||||
@ -220,11 +222,30 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
|
|||||||
{showActive ? "Active" : "Inactive"} Contacts
|
{showActive ? "Active" : "Inactive"} Contacts
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="col-12 col-md-2 d-flex justify-content-end align-items-center gap-2">
|
||||||
<div className="btn-group">
|
<div className={`form-check form-switch d-flex align-items-center ${activeTab === "contacts" ? " d-flex d-md-none m-0":"d-none" }`}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="form-check-input"
|
||||||
|
role="switch"
|
||||||
|
id="inactiveEmployeesCheckbox"
|
||||||
|
checked={showActive}
|
||||||
|
onChange={(e) => setShowActive(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
className="form-check-label ms-2"
|
||||||
|
htmlFor="inactiveEmployeesCheckbox"
|
||||||
|
>
|
||||||
|
{showActive ? "Active" : "Inactive"} Contacts
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className=" btn-group">
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm btn-label-secondary dropdown-toggle"
|
className="btn btn-sm btn-label-secondary dropdown-toggle"
|
||||||
type="button"
|
type="button"
|
||||||
@ -244,6 +265,8 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,6 +7,7 @@ import Breadcrumb from "../../components/common/Breadcrumb";
|
|||||||
import ManageEmp from "../../components/Employee/ManageRole";
|
import ManageEmp from "../../components/Employee/ManageRole";
|
||||||
import {
|
import {
|
||||||
useEmployeesAllOrByProjectId,
|
useEmployeesAllOrByProjectId,
|
||||||
|
useEmployeesByOrganization,
|
||||||
useSuspendEmployee,
|
useSuspendEmployee,
|
||||||
} from "../../hooks/useEmployees";
|
} from "../../hooks/useEmployees";
|
||||||
import { useProjectName, useProjects } from "../../hooks/useProjects";
|
import { useProjectName, useProjects } from "../../hooks/useProjects";
|
||||||
@ -36,6 +37,7 @@ import GlobalModel from "../../components/common/GlobalModel";
|
|||||||
import usePagination from "../../hooks/usePagination";
|
import usePagination from "../../hooks/usePagination";
|
||||||
import { setProjectId } from "../../slices/localVariablesSlice";
|
import { setProjectId } from "../../slices/localVariablesSlice";
|
||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
|
import Pagination from "../../components/common/Pagination";
|
||||||
|
|
||||||
const EmployeeList = () => {
|
const EmployeeList = () => {
|
||||||
const selectedProjectId = useSelector(
|
const selectedProjectId = useSelector(
|
||||||
@ -46,15 +48,14 @@ const EmployeeList = () => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [showInactive, setShowInactive] = useState(false);
|
const [showInactive, setShowInactive] = useState(false);
|
||||||
const [showAllEmployees, setShowAllEmployees] = useState(false);
|
|
||||||
const Manage_Employee = useHasUserPermission(MANAGE_EMPLOYEES);
|
const Manage_Employee = useHasUserPermission(MANAGE_EMPLOYEES);
|
||||||
|
|
||||||
const { employees, loading, setLoading, error, recallEmployeeData } =
|
const {
|
||||||
useEmployeesAllOrByProjectId(
|
data: employees,
|
||||||
showAllEmployees,
|
isLoading: loading,
|
||||||
selectedProjectId,
|
error,
|
||||||
showInactive
|
refetch: recallEmployeeData,
|
||||||
);
|
} = useEmployeesByOrganization(showInactive);
|
||||||
|
|
||||||
const [employeeList, setEmployeeList] = useState([]);
|
const [employeeList, setEmployeeList] = useState([]);
|
||||||
const [modelConfig, setModelConfig] = useState();
|
const [modelConfig, setModelConfig] = useState();
|
||||||
@ -70,7 +71,6 @@ const EmployeeList = () => {
|
|||||||
const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null);
|
const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null);
|
||||||
const [employeeLodaing, setemployeeLodaing] = useState(false);
|
const [employeeLodaing, setemployeeLodaing] = useState(false);
|
||||||
const ViewTeamMember = useHasUserPermission(VIEW_TEAM_MEMBERS);
|
const ViewTeamMember = useHasUserPermission(VIEW_TEAM_MEMBERS);
|
||||||
const ViewAllEmployee = useHasUserPermission(VIEW_ALL_EMPLOYEES);
|
|
||||||
const { mutate: suspendEmployee, isPending: empLodaing } = useSuspendEmployee(
|
const { mutate: suspendEmployee, isPending: empLodaing } = useSuspendEmployee(
|
||||||
{
|
{
|
||||||
setIsDeleteModalOpen,
|
setIsDeleteModalOpen,
|
||||||
@ -157,7 +157,7 @@ const EmployeeList = () => {
|
|||||||
const handleAllEmployeesToggle = (e) => {
|
const handleAllEmployeesToggle = (e) => {
|
||||||
const isChecked = e.target.checked;
|
const isChecked = e.target.checked;
|
||||||
setShowInactive(false);
|
setShowInactive(false);
|
||||||
setShowAllEmployees(isChecked);
|
// setShowAllEmployees(isChecked);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEmployeeModel = (id) => {
|
const handleEmployeeModel = (id) => {
|
||||||
@ -205,25 +205,16 @@ const EmployeeList = () => {
|
|||||||
|
|
||||||
setCurrentPage((prevPage) => (prevPage !== 1 ? 1 : prevPage));
|
setCurrentPage((prevPage) => (prevPage !== 1 ? 1 : prevPage));
|
||||||
}
|
}
|
||||||
}, [loading, employees, selectedProjectId, showAllEmployees]);
|
}, [loading, employees, selectedProjectId, showInactive]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!showAllEmployees) {
|
|
||||||
recallEmployeeData(showInactive, selectedProjectId);
|
|
||||||
}
|
|
||||||
}, [selectedProjectId, showInactive, showAllEmployees, recallEmployeeData]);
|
|
||||||
|
|
||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
(msg) => {
|
(msg) => {
|
||||||
if (employees.some((item) => item.id == msg.employeeId)) {
|
if (employees.some((item) => item.id == msg.employeeId)) {
|
||||||
setEmployeeList([]);
|
setEmployeeList([]);
|
||||||
recallEmployeeData(
|
recallEmployeeData(showInactive);
|
||||||
showInactive,
|
|
||||||
showAllEmployees ? null : selectedProjectId
|
|
||||||
); // Use selectedProjectId here
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[employees, showInactive, showAllEmployees, selectedProjectId] // Add all relevant dependencies
|
[employees, showInactive, showInactive, selectedProjectId] // Add all relevant dependencies
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -254,7 +245,6 @@ const EmployeeList = () => {
|
|||||||
<ManageEmployee
|
<ManageEmployee
|
||||||
employeeId={selectedEmployeeId}
|
employeeId={selectedEmployeeId}
|
||||||
onClosed={() => setShowModal(false)}
|
onClosed={() => setShowModal(false)}
|
||||||
IsAllEmployee={showAllEmployees}
|
|
||||||
/>
|
/>
|
||||||
</GlobalModel>
|
</GlobalModel>
|
||||||
)}
|
)}
|
||||||
@ -293,59 +283,39 @@ const EmployeeList = () => {
|
|||||||
|
|
||||||
{ViewTeamMember ? (
|
{ViewTeamMember ? (
|
||||||
// <div className="row">
|
// <div className="row">
|
||||||
<div className="card p-1">
|
<div className="card p-1 page-min-h">
|
||||||
<div className="card-datatable table-responsive pt-5 mx-5 py-10">
|
<div className="card-datatable table-responsive pt-5 mx-5 py-10">
|
||||||
<div
|
<div
|
||||||
id="DataTables_Table_0_wrapper"
|
id="DataTables_Table_0_wrapper"
|
||||||
className="dataTables_wrapper dt-bootstrap5 no-footer"
|
className="dataTables_wrapper dt-bootstrap5 no-footer"
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
>
|
||||||
<div className="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3">
|
<div className="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3">
|
||||||
{/* Switches: All Employees + Inactive */}
|
{/* Switches: All Employees + Inactive */}
|
||||||
<div className="d-flex flex-wrap align-items-center gap-3">
|
<div className="d-flex flex-wrap align-items-center gap-3">
|
||||||
{/* All Employees Switch */}
|
{/* All Employees Switch */}
|
||||||
{ViewAllEmployee && (
|
|
||||||
<div className="form-check form-switch text-start">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
className="form-check-input"
|
|
||||||
role="switch"
|
|
||||||
id="allEmployeesCheckbox"
|
|
||||||
checked={showAllEmployees}
|
|
||||||
onChange={handleAllEmployeesToggle}
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
className="form-check-label ms-0"
|
|
||||||
htmlFor="allEmployeesCheckbox"
|
|
||||||
>
|
|
||||||
Show All Employees
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Show Inactive Employees Switch */}
|
{/* Show Inactive Employees Switch */}
|
||||||
{showAllEmployees && (
|
|
||||||
<div className="form-check form-switch text-start">
|
<div className="form-check form-switch text-start">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="form-check-input"
|
className="form-check-input"
|
||||||
role="switch"
|
role="switch"
|
||||||
id="inactiveEmployeesCheckbox"
|
id="inactiveEmployeesCheckbox"
|
||||||
checked={showInactive}
|
checked={showInactive}
|
||||||
onChange={(e) => setShowInactive(e.target.checked)}
|
onChange={(e) => setShowInactive(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
className="form-check-label ms-0"
|
className="form-check-label ms-0"
|
||||||
htmlFor="inactiveEmployeesCheckbox"
|
htmlFor="inactiveEmployeesCheckbox"
|
||||||
>
|
>
|
||||||
Show Inactive Employees
|
Show Inactive Employees
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right side: Search + Export + Add Employee */}
|
{/* Right side: Search + Export + Add Employee */}
|
||||||
<div className="d-flex flex-wrap align-items-center justify-content-end gap-3 flex-grow-1">
|
<div className="d-flex flex-wrap align-items-center justify-content-start justify-content-md-end gap-3 flex-grow-1">
|
||||||
{/* Search Input - ALWAYS ENABLED */}
|
{/* Search Input - ALWAYS ENABLED */}
|
||||||
<div className="dataTables_filter">
|
<div className="dataTables_filter">
|
||||||
<label className="mb-0">
|
<label className="mb-0">
|
||||||
@ -431,7 +401,6 @@ const EmployeeList = () => {
|
|||||||
className="datatables-users table border-top dataTable no-footer dtr-column text-nowrap"
|
className="datatables-users table border-top dataTable no-footer dtr-column text-nowrap"
|
||||||
id="DataTables_Table_0"
|
id="DataTables_Table_0"
|
||||||
aria-describedby="DataTables_Table_0_info"
|
aria-describedby="DataTables_Table_0_info"
|
||||||
style={{ width: "100%" }}
|
|
||||||
ref={tableRef}
|
ref={tableRef}
|
||||||
>
|
>
|
||||||
<thead>
|
<thead>
|
||||||
@ -522,28 +491,27 @@ const EmployeeList = () => {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
{/* Conditional messages for no data or no search results */}
|
|
||||||
{!loading &&
|
{!loading &&
|
||||||
displayData?.length === 0 &&
|
displayData?.length === 0 &&
|
||||||
searchText &&
|
(!searchText ) ? (
|
||||||
!showAllEmployees ? (
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={8}>
|
<td colSpan={8} className="border-0 py-3">
|
||||||
<small className="muted">
|
<div className="py-4">
|
||||||
'{searchText}' employee not found
|
No Data Found
|
||||||
</small>{" "}
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
) : null}
|
) : null}
|
||||||
{!loading &&
|
|
||||||
|
{!loading &&
|
||||||
displayData?.length === 0 &&
|
displayData?.length === 0 &&
|
||||||
(!searchText || showAllEmployees) ? (
|
(searchText ) ? (
|
||||||
<tr>
|
<tr>
|
||||||
<td
|
<td colSpan={8} className="border-0 py-3">
|
||||||
colSpan={8}
|
<div className="py-4">
|
||||||
style={{ paddingTop: "20px", textAlign: "center" }}
|
{`No match record found ${searchText} `}
|
||||||
>
|
</div>
|
||||||
No Data Found
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
) : null}
|
) : null}
|
||||||
@ -697,55 +665,12 @@ const EmployeeList = () => {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div style={{ width: "1%" }}></div>
|
{displayData?.length > 0 && (
|
||||||
|
<Pagination
|
||||||
{/* Pagination */}
|
currentPage={currentPage}
|
||||||
{!loading && displayData.length > ITEMS_PER_PAGE && (
|
totalPages={totalPages}
|
||||||
<nav aria-label="Page">
|
onPageChange={paginate}
|
||||||
<ul className="pagination pagination-sm justify-content-end py-1">
|
/>
|
||||||
<li
|
|
||||||
className={`page-item ${
|
|
||||||
currentPage === 1 ? "disabled" : ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="page-link btn-xs"
|
|
||||||
onClick={() => paginate(currentPage - 1)}
|
|
||||||
>
|
|
||||||
«
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
{[...Array(totalPages)]?.map((_, index) => (
|
|
||||||
<li
|
|
||||||
key={index}
|
|
||||||
className={`page-item ${
|
|
||||||
currentPage === index + 1 ? "active" : ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="page-link"
|
|
||||||
onClick={() => paginate(index + 1)}
|
|
||||||
>
|
|
||||||
{index + 1}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<li
|
|
||||||
className={`page-item ${
|
|
||||||
currentPage === totalPages ? "disabled" : ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="page-link"
|
|
||||||
onClick={() => paginate(currentPage + 1)}
|
|
||||||
>
|
|
||||||
»
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -103,7 +103,7 @@ const MasterPage = () => {
|
|||||||
|
|
||||||
if (menuErrorFlag || isMasterError)
|
if (menuErrorFlag || isMasterError)
|
||||||
return (
|
return (
|
||||||
<div className="d-flex flex-column align-items-center justify-content-center py-5">
|
<div className="d-flex flex-column align-items-center justify-content-center py-1 py-md-5">
|
||||||
<h4 className="mb-3">
|
<h4 className="mb-3">
|
||||||
<i className="fa-solid fa-triangle-exclamation fs-5" /> Oops, an error
|
<i className="fa-solid fa-triangle-exclamation fs-5" /> Oops, an error
|
||||||
occurred
|
occurred
|
||||||
@ -161,21 +161,17 @@ const MasterPage = () => {
|
|||||||
data={[{ label: "Home", link: "/dashboard" }, { label: "Masters" }]}
|
data={[{ label: "Home", link: "/dashboard" }, { label: "Masters" }]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="row">
|
<div className="row page-min-h">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div
|
<div
|
||||||
className="card-datatable table-responsive py-10 mx-5 "
|
className="card-datatable table-responsive py-2 py-md-10 mx-1 mx-md-5 "
|
||||||
style={{ overflow: "hidden" }}
|
style={{ overflow: "hidden" }}
|
||||||
>
|
>
|
||||||
<div className="row mb-2">
|
<div className="row mb-2">
|
||||||
<div className="col-md-3 col-sm-6">
|
<div className="col-12 col-md-3">
|
||||||
<select
|
<select
|
||||||
className="form-select py-1 px-2"
|
className="form-select py-1 px-2"
|
||||||
style={{
|
|
||||||
fontSize: "0.875rem",
|
|
||||||
height: "32px",
|
|
||||||
width: "190px",
|
|
||||||
}}
|
|
||||||
value={selectedMaster}
|
value={selectedMaster}
|
||||||
onChange={(e) => dispatch(changeMaster(e.target.value))}
|
onChange={(e) => dispatch(changeMaster(e.target.value))}
|
||||||
>
|
>
|
||||||
@ -190,8 +186,8 @@ const MasterPage = () => {
|
|||||||
)}
|
)}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-9 col-sm-6 d-flex justify-content-end align-items-center gap-2">
|
<div className="col-12 col-md-9 d-flex justify-content-end align-items-center gap-2 mt-2 mt-md-0">
|
||||||
<div className="w-25">
|
<div className="col-6 col-md-3">
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
className="form-control form-control-sm"
|
className="form-control form-control-sm"
|
||||||
@ -207,8 +203,8 @@ const MasterPage = () => {
|
|||||||
handleModalData(selectedMaster, null, selectedMaster)
|
handleModalData(selectedMaster, null, selectedMaster)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>Add{" "}
|
<i className="bx bx-plus-circle me-2"></i> <span className="d-none d-md-inline-block">Add{" "}
|
||||||
{selectedMaster}
|
{selectedMaster}</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -92,7 +92,8 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => {
|
|||||||
{" "}
|
{" "}
|
||||||
{selectedMaster === "Activity" ? "Activity" : "Name"}
|
{selectedMaster === "Activity" ? "Activity" : "Name"}
|
||||||
</th>
|
</th>
|
||||||
<th className="text-start">
|
<th className="text-start d-none d-md-table-cell">
|
||||||
|
|
||||||
{" "}
|
{" "}
|
||||||
{selectedMaster === "Activity"
|
{selectedMaster === "Activity"
|
||||||
? "Unit"
|
? "Unit"
|
||||||
@ -108,12 +109,12 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{currentItems.length > 0 ? (
|
{currentItems.length > 0 ? (
|
||||||
currentItems.map((item, index) => (
|
currentItems.map((item, index) => (
|
||||||
<tr key={index}>
|
<tr key={index} >
|
||||||
<td style={{ width: "20px" }}>
|
<td style={{ width: "20px" }} className="py-3">
|
||||||
<i className="bx bx-right-arrow-alt"></i>
|
<i className="bx bx-right-arrow-alt"></i>
|
||||||
</td>
|
</td>
|
||||||
{updatedColumns.map((col) => (
|
{updatedColumns.map((col) => (
|
||||||
<td className="text-start mx-2" key={col.key}>
|
<td className={`text-start mx-2 py-3 ${col.key === "description" && "d-none d-md-table-cell"}`} key={col.key} >
|
||||||
{col.key === "description" ? (
|
{col.key === "description" ? (
|
||||||
item[col.key] !== undefined &&
|
item[col.key] !== undefined &&
|
||||||
item[col.key] !== null ? (
|
item[col.key] !== null ? (
|
||||||
@ -133,7 +134,7 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => {
|
|||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
))}
|
))}
|
||||||
<td className={!hasMasterPermission ? "d-none" : ""}>
|
<td className={!hasMasterPermission ? "d-none" : "py-3"}>
|
||||||
{(selectedMaster === "Application Role" ||
|
{(selectedMaster === "Application Role" ||
|
||||||
selectedMaster === "Work Category") &&
|
selectedMaster === "Work Category") &&
|
||||||
item?.isSystem ? (
|
item?.isSystem ? (
|
||||||
|
@ -85,6 +85,8 @@ const ProjectRepository = {
|
|||||||
api.get(`/api/Project/get/assigned/services/${projectId}`),
|
api.get(`/api/Project/get/assigned/services/${projectId}`),
|
||||||
getProjectAssignedOrganizations: (projectId) =>
|
getProjectAssignedOrganizations: (projectId) =>
|
||||||
api.get(`/api/Project/get/assigned/organization/${projectId}`),
|
api.get(`/api/Project/get/assigned/organization/${projectId}`),
|
||||||
|
getProjectAssignedOrganizationsName: (projectId) =>
|
||||||
|
api.get(`/api/Project/get/assigned/organization/dropdown/${projectId}`),
|
||||||
|
|
||||||
getEmployeeForTaskAssign: (projectId, serviceId, organizationId) => {
|
getEmployeeForTaskAssign: (projectId, serviceId, organizationId) => {
|
||||||
let url = `/api/Project/get/task/team/${projectId}`;
|
let url = `/api/Project/get/task/team/${projectId}`;
|
||||||
|
@ -91,4 +91,47 @@ const date = new Date(
|
|||||||
Date.UTC(Number(year), Number(month) - 1, Number(day), 0, 0, 0)
|
Date.UTC(Number(year), Number(month) - 1, Number(day), 0, 0, 0)
|
||||||
);
|
);
|
||||||
return isNaN(date.getTime()) ? null : date.toISOString();
|
return isNaN(date.getTime()) ? null : date.toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flexible number formatter for currency, numbers, or percentages.
|
||||||
|
*
|
||||||
|
* @param {number} amount - The value to format.
|
||||||
|
* @param {Object} options - Formatting options.
|
||||||
|
* @param {"currency"|"number"|"percent"} [options.type="number"] - Type of format.
|
||||||
|
* @param {string} [options.currency="INR"] - Currency code (only used when type="currency").
|
||||||
|
* @param {string} [options.locale="en-US"] - Locale for formatting.
|
||||||
|
* @param {"short"|"long"|"standard"} [options.notation="compact"] - Display style for large numbers.
|
||||||
|
* @param {number} [options.minimumFractionDigits=0] - Minimum decimal places.
|
||||||
|
* @param {number} [options.maximumFractionDigits=2] - Maximum decimal places.
|
||||||
|
* @returns {string} Formatted number string.
|
||||||
|
*/
|
||||||
|
export const formatFigure = (
|
||||||
|
amount,
|
||||||
|
{
|
||||||
|
type = "number",
|
||||||
|
currency = "INR",
|
||||||
|
locale = "en-US",
|
||||||
|
notation = "compact",
|
||||||
|
compactDisplay = "short",
|
||||||
|
minimumFractionDigits = 0,
|
||||||
|
maximumFractionDigits = 2,
|
||||||
|
} = {}
|
||||||
|
) => {
|
||||||
|
if (amount == null || isNaN(amount)) return "-";
|
||||||
|
|
||||||
|
const formatterOptions = {
|
||||||
|
style: type === "currency" ? "currency" : type === "percent" ? "percent" : "decimal",
|
||||||
|
notation: notation,
|
||||||
|
compactDisplay,
|
||||||
|
minimumFractionDigits,
|
||||||
|
maximumFractionDigits,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type === "currency") {
|
||||||
|
formatterOptions.currency = currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Intl.NumberFormat(locale, formatterOptions).format(amount);
|
||||||
|
};
|
||||||
|
@ -3,6 +3,11 @@ export const DURATION_TIME = 10; // minutes
|
|||||||
export const ITEMS_PER_PAGE = 20;
|
export const ITEMS_PER_PAGE = 20;
|
||||||
export const OTP_EXPIRY_SECONDS = 300; // OTP time
|
export const OTP_EXPIRY_SECONDS = 300; // OTP time
|
||||||
|
|
||||||
|
|
||||||
|
export const BASE_URL = process.env.VITE_BASE_URL;
|
||||||
|
|
||||||
|
// export const BASE_URL = "https://api.marcoaiot.com";
|
||||||
|
|
||||||
export const MANAGE_MASTER = "588a8824-f924-4955-82d8-fc51956cf323";
|
export const MANAGE_MASTER = "588a8824-f924-4955-82d8-fc51956cf323";
|
||||||
|
|
||||||
export const VIEW_MASTER = "5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d";
|
export const VIEW_MASTER = "5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d";
|
||||||
@ -142,6 +147,3 @@ export const PROJECT_STATUS = [
|
|||||||
];
|
];
|
||||||
export const DEFAULT_EMPTY_STATUS_ID = "00000000-0000-0000-0000-000000000000";
|
export const DEFAULT_EMPTY_STATUS_ID = "00000000-0000-0000-0000-000000000000";
|
||||||
|
|
||||||
export const BASE_URL = process.env.VITE_BASE_URL;
|
|
||||||
|
|
||||||
// export const BASE_URL = "https://api.marcoaiot.com";
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user