Compare commits

..

No commits in common. "f3e60bf8bcfb15ce56f1b034e28a72a8be851f57" and "9112f9f673d13ad3a46e65456778c09cdd8c33f1" have entirely different histories.

7 changed files with 86 additions and 107 deletions

View File

@ -162,7 +162,7 @@ const ExpenseList = ({ filters, groupBy = "transactionDate", searchText }) => {
]; ];
if (isInitialLoading) return <ExpenseTableSkeleton />; if (isInitialLoading) return <ExpenseTableSkeleton />;
if (isError) return <div>{error.message}</div>; if (isError) return <div>{error}</div>;
const grouped = groupBy const grouped = groupBy
? groupByField(data?.data ?? [], groupBy) ? groupByField(data?.data ?? [], groupBy)

View File

@ -1,19 +1,14 @@
import { useState,useMemo } from "react"; import { useState } from "react";
import Avatar from "../common/Avatar"; import Avatar from "../common/Avatar";
import { formatUTCToLocalTime } from "../../utils/dateUtils"; import { formatUTCToLocalTime } from "../../utils/dateUtils";
const ExpenseStatusLogs = ({ data }) => { const ExpenseStatusLogs = ({ data }) => {
const [visibleCount, setVisibleCount] = useState(4); const [visibleCount, setVisibleCount] = useState(4);
const sortedLogs = useMemo(() => { const logsToShow = [...(data?.expenseLogs || [])]
if (!data?.expenseLogs) return []; .sort((a, b) => new Date(b.updateAt) - new Date(a.updateAt))
return [...data.expenseLogs].sort( .slice(0, visibleCount);
(a, b) => new Date(b.updateAt) - new Date(a.updateAt)
);
}, [data?.expenseLogs]);
const logsToShow = sortedLogs.slice(0, visibleCount);
const handleShowMore = () => { const handleShowMore = () => {
setVisibleCount((prev) => prev + 4); setVisibleCount((prev) => prev + 4);
@ -22,8 +17,11 @@ const ExpenseStatusLogs = ({ data }) => {
return ( return (
<> <>
<div className="row g-2"> <div className="row g-2">
{logsToShow.map((log) => ( {logsToShow.map((log, index) => (
<div key={log.id} className="col-12 d-flex align-items-start mb-1"> <div
key={log.id}
className="col-12 d-flex align-items-start mb-1"
>
<Avatar <Avatar
size="xs" size="xs"
firstName={log.updatedBy.firstName} firstName={log.updatedBy.firstName}
@ -31,18 +29,20 @@ const ExpenseStatusLogs = ({ data }) => {
/> />
<div className="flex-grow-1"> <div className="flex-grow-1">
<div className="text-start"> <div className="d-flex justify-content-start">
<div className="flex"> <div className="text-start">
<span>{`${log.updatedBy.firstName} ${log.updatedBy.lastName}`}</span> <div >
<small className="text-secondary text-tiny ms-2"> <div className="flex">
<em>{log.action}</em> <span>{`${log.updatedBy.firstName} ${log.updatedBy.lastName}`}</span>
</small> <small className="text-secondary text-tiny ms-2">
<span className="text-tiny text-secondary d-block" > <em>{log.action}</em>
{formatUTCToLocalTime(log.updateAt,true)} </small>
</span> <span className="text-tiny text-secondary d-block small">{formatUTCToLocalTime(log?.updateAt)}</span>
</div> </div>
<div className="d-flex align-items-center text-muted small mt-1"> </div>
<span>{log.comment}</span> <div className="d-flex align-items-center text-muted small mt-1">
<span className="small">{log.comment}</span>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -50,7 +50,7 @@ const ExpenseStatusLogs = ({ data }) => {
))} ))}
</div> </div>
{sortedLogs.length > visibleCount && ( {data?.expenseLogs?.length > visibleCount && (
<div className="text-center my-1"> <div className="text-center my-1">
<button <button
className="btn btn-xs btn-outline-primary" className="btn btn-xs btn-outline-primary"
@ -64,5 +64,4 @@ const ExpenseStatusLogs = ({ data }) => {
); );
}; };
export default ExpenseStatusLogs; export default ExpenseStatusLogs;

View File

@ -548,7 +548,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
</div> </div>
</div> </div>
<div className="d-flex justify-content-center gap-3"> <div className="d-flex justify-content-center gap-2">
{" "} {" "}
<button <button
type="submit" type="submit"

View File

@ -177,19 +177,20 @@ const ViewExpense = ({ ExpenseId }) => {
<div className="text-muted">{data?.paymentMode?.name}</div> <div className="text-muted">{data?.paymentMode?.name}</div>
</div> </div>
</div> </div>
{data?.gstNumber && ( <div className="col-md-6 mb-3">
<div className="col-md-6 mb-3"> <div className="d-flex">
<div className="d-flex"> <label
<label className="form-label me-2 mb-0 fw-semibold text-start"
className="form-label me-2 mb-0 fw-semibold text-start" style={{ minWidth: "130px" }}
style={{ minWidth: "130px" }} >
> GST Number :
GST Number : </label>
</label> <div className="text-muted">
<div className="text-muted">{data?.gstNumber}</div> {data?.gstNumber}
</div> </div>
</div> </div>
)} </div>
{/* Row 4 */} {/* Row 4 */}
<div className="col-md-6 mb-3"> <div className="col-md-6 mb-3">
@ -256,7 +257,7 @@ const ViewExpense = ({ ExpenseId }) => {
> >
Created By : Created By :
</label> </label>
<div className="d-flex align-items-center"> <div className="d-flex align-items-center gap-1">
<Avatar <Avatar
size="xs" size="xs"
classAvatar="m-0" classAvatar="m-0"
@ -272,26 +273,16 @@ const ViewExpense = ({ ExpenseId }) => {
</div> </div>
</div> </div>
)} )}
<div className="col-md-6 text-start"> <div className="col-md-6 mb-3">
<div className="d-flex align-items-center"> <div className="d-flex">
<label <label
className="form-label me-2 mb-0 fw-semibold" className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }} style={{ minWidth: "130px" }}
> >
Paid By: Paid By :
</label> </label>
<div className="d-flex align-items-center "> <div className="text-muted">
<Avatar {data?.paidBy?.firstName} {data?.paidBy?.lastName}
size="xs"
classAvatar="m-0"
firstName={data.paidBy?.firstName}
lastName={data.paidBy?.lastName}
/>
<span className="text-muted">
{`${data.paidBy?.firstName ?? ""} ${
data.paidBy?.lastName ?? ""
}`.trim() || "N/A"}
</span>
</div> </div>
</div> </div>
</div> </div>
@ -372,7 +363,7 @@ const ViewExpense = ({ ExpenseId }) => {
)} )}
</div> </div>
)} )}
<hr className="divider my-1 border-2 divider-primary my-2" /> <hr className="divider my-1 border-2 divider-primary my-2"/>
{Array.isArray(data?.nextStatus) && data.nextStatus.length > 0 && ( {Array.isArray(data?.nextStatus) && data.nextStatus.length > 0 && (
<> <>

View File

@ -30,8 +30,8 @@ const DatePicker = ({
? flatpickr.parseDate(value, "Y-m-d") ? flatpickr.parseDate(value, "Y-m-d")
: null, : null,
maxDate:maxDate, maxDate:maxDate,
minDate:new Date(minDate?.split("T")[0]) ?? null, minDate:new Date(minDate?.split("T")[0]) ?? undefined,
onChange: (selectedDates, dateStr) => { onChange: function (selectedDates, dateStr) {
onChange(dateStr); onChange(dateStr);
}, },
...rest ...rest

View File

@ -1,27 +1,20 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import showToast from '../services/toastService'; import showToast from '../services/toastService';
let hasShownLocationErrorToast = false; // global flag
export const usePositionTracker = () => { export const usePositionTracker = () => {
const [coords, setCoords] = useState({ latitude: 0, longitude: 0 }); const [coords, setCoords] = useState({ latitude: 0, longitude: 0 });
useEffect(() => { useEffect(() => {
const locationID = navigator.geolocation.watchPosition( const locationID = navigator.geolocation.watchPosition(
({ coords }) => { ({ coords }) => {
setCoords(coords); setCoords(coords);
}, },
(error) => { (error) => {
if (!hasShownLocationErrorToast) { showToast("Please Allow Location","warn");
showToast("Please Allow Location", "warn"); },
hasShownLocationErrorToast = true; { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
} );
}, return () => navigator.geolocation.clearWatch(locationID);
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 } }, []);
); return coords;
};
return () => navigator.geolocation.clearWatch(locationID);
}, []);
return coords;
};

View File

@ -27,7 +27,7 @@ const AttendancePage = () => {
const [ShowPending, setShowPending] = useState(false); const [ShowPending, setShowPending] = useState(false);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const loginUser = getCachedProfileData(); const loginUser = getCachedProfileData();
const selectedProject = useSelector((store) => store.localVariables.projectId); var selectedProject = useSelector((store) => store.localVariables.projectId);
const dispatch = useDispatch(); const dispatch = useDispatch();
const [attendances, setAttendances] = useState(); const [attendances, setAttendances] = useState();
@ -155,32 +155,28 @@ const AttendancePage = () => {
</button> </button>
</li> </li>
</ul> </ul>
<div className="tab-content attedanceTabs py-0 px-1 px-sm-3"> <div className="tab-content attedanceTabs py-0 px-1 px-sm-3" >
{selectedProject ? ( {activeTab === "all" && (
<> <div className="tab-pane fade show active py-0">
{activeTab === "all" && ( <Attendance
<div className="tab-pane fade show active py-0"> handleModalData={handleModalData}
<Attendance handleModalData={handleModalData} getRole={getRole} /> getRole={getRole}
</div> />
)} </div>
{activeTab === "logs" && ( )}
<div className="tab-pane fade show active py-0"> {activeTab === "logs" && (
<AttendanceLog handleModalData={handleModalData} /> <div className="tab-pane fade show active py-0">
</div> <AttendanceLog
)} handleModalData={handleModalData}
{activeTab === "regularization" && DoRegularized && ( />
<div className="tab-pane fade show active py-0"> </div>
<Regularization /> )}
</div> {activeTab === "regularization" && DoRegularized && (
)} <div className="tab-pane fade show active py-0">
</> <Regularization />
) : ( </div>
<div className="py-2"> )}
<small className="py-2">Please Select Project!</small> </div>
</div>
)}
</div>
</div> </div>
</div> </div>
</> </>