changed date utils and added search employee inside manage expense
This commit is contained in:
parent
6928bbd309
commit
7872e21477
@ -28,6 +28,7 @@ import moment from "moment";
|
||||
import DatePicker from "../common/DatePicker";
|
||||
import ErrorPage from "../../pages/ErrorPage";
|
||||
import Label from "../common/Label";
|
||||
import EmployeeSearchInput from "../common/EmployeeSearchInput";
|
||||
|
||||
const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
const {
|
||||
@ -143,7 +144,6 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (expenseToEdit && data) {
|
||||
|
||||
reset({
|
||||
projectId: data.project.id || "",
|
||||
expensesTypeId: data.expensesType.id || "",
|
||||
@ -183,8 +183,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
const onSubmit = (fromdata) => {
|
||||
let payload = {
|
||||
...fromdata,
|
||||
transactionDate: localToUtc(fromdata.transactionDate)
|
||||
|
||||
transactionDate: localToUtc(fromdata.transactionDate),
|
||||
};
|
||||
if (expenseToEdit) {
|
||||
const editPayload = { ...payload, id: data.id };
|
||||
@ -206,7 +205,6 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
if (StatusLoadding || projectLoading || ExpenseLoading || isLoading)
|
||||
return <ExpenseSkeleton />;
|
||||
|
||||
|
||||
return (
|
||||
<div className="container p-3">
|
||||
<h5 className="m-0">
|
||||
@ -215,7 +213,9 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
<form id="expenseForm" onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="row my-2 text-start">
|
||||
<div className="col-md-6">
|
||||
<Label className="form-label" required>Select Project</Label>
|
||||
<Label className="form-label" required>
|
||||
Select Project
|
||||
</Label>
|
||||
<select
|
||||
className="form-select form-select-sm"
|
||||
{...register("projectId")}
|
||||
@ -296,11 +296,11 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="col-md-6">
|
||||
<div className="col-12 col-md-6 text-start">
|
||||
<Label htmlFor="paidById" className="form-label" required>
|
||||
Paid By
|
||||
</Label>
|
||||
<select
|
||||
{/* <select
|
||||
className="form-select form-select-sm"
|
||||
id="paymentModeId"
|
||||
{...register("paidById")}
|
||||
@ -321,7 +321,13 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
</select>
|
||||
{errors.paidById && (
|
||||
<small className="danger-text">{errors.paidById.message}</small>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
<EmployeeSearchInput
|
||||
control={control}
|
||||
name="paidById"
|
||||
projectId={null}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -330,7 +336,11 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
<Label htmlFor="transactionDate" className="form-label" required>
|
||||
Transaction Date
|
||||
</Label>
|
||||
<DatePicker name="transactionDate" control={control} maxDate={new Date()}/>
|
||||
<DatePicker
|
||||
name="transactionDate"
|
||||
control={control}
|
||||
maxDate={new Date()}
|
||||
/>
|
||||
|
||||
{errors.transactionDate && (
|
||||
<small className="danger-text">
|
||||
@ -421,9 +431,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
{...register("gstNumber")}
|
||||
/>
|
||||
{errors.gstNumber && (
|
||||
<small className="danger-text">
|
||||
{errors.gstNumber.message}
|
||||
</small>
|
||||
<small className="danger-text">{errors.gstNumber.message}</small>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -448,7 +456,9 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
|
||||
<div className="row my-2 text-start">
|
||||
<div className="col-md-12">
|
||||
<Label htmlFor="description" className="form-label" required>Description</Label>
|
||||
<Label htmlFor="description" className="form-label" required>
|
||||
Description
|
||||
</Label>
|
||||
<textarea
|
||||
id="description"
|
||||
className="form-control form-control-sm"
|
||||
@ -465,7 +475,9 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
|
||||
<div className="row my-2 text-start">
|
||||
<div className="col-md-12">
|
||||
<Label className="form-label" required>Upload Bill </Label>
|
||||
<Label className="form-label" required>
|
||||
Upload Bill{" "}
|
||||
</Label>
|
||||
|
||||
<div
|
||||
className="border border-secondary border-dashed rounded p-4 text-center bg-textMuted position-relative"
|
||||
@ -568,7 +580,6 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
? "Update"
|
||||
: "Submit"}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@ import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { defaultActionValues, ExpenseActionScheam } from "./ExpenseSchema";
|
||||
import { useExpenseContext } from "../../pages/Expense/ExpensePage";
|
||||
import { getColorNameFromHex, getIconByFileType } from "../../utils/appUtils";
|
||||
import { getColorNameFromHex, getIconByFileType, localToUtc } from "../../utils/appUtils";
|
||||
import { ExpenseDetailsSkeleton } from "./ExpenseSkeleton";
|
||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||
import {
|
||||
@ -91,9 +91,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
const onSubmit = (formData) => {
|
||||
const Payload = {
|
||||
...formData,
|
||||
reimburseDate: moment
|
||||
.utc(formData.reimburseDate, "DD-MM-YYYY")
|
||||
.toISOString(),
|
||||
reimburseDate: localToUtc(formData.reimburseDate),
|
||||
expenseId: ExpenseId,
|
||||
comment: formData.comment,
|
||||
};
|
||||
@ -397,7 +395,8 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
<DatePicker
|
||||
name="reimburseDate"
|
||||
control={control}
|
||||
minDate={data?.transactionDate}
|
||||
minDate={data?.createdAt}
|
||||
maxDate={new Date()}
|
||||
/>
|
||||
{errors.reimburseDate && (
|
||||
<small className="danger-text">
|
||||
|
@ -548,6 +548,7 @@ export const useUpdateNote = (onSuccessCallBack) => {
|
||||
mutationFn: async ({ noteId, notePayload }) =>
|
||||
await DirectoryRepository.UpdateNote(noteId, notePayload),
|
||||
onSuccess: (_, variables) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["Contact"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["Notes"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["ContactNotes"] });
|
||||
showToast("Note updated Successfully", "success");
|
||||
|
@ -14,7 +14,6 @@ export const useProjectAccess = (projectId) => {
|
||||
const canView = useHasUserPermission(VIEW_PROJECTS);
|
||||
|
||||
const loading = isLoading || !isFetched;
|
||||
debugger
|
||||
useEffect(() => {
|
||||
if (projectId && !loading && !canView) {
|
||||
showToast("You don't have permission to view project details", "warning");
|
||||
|
@ -32,103 +32,108 @@ export function startSignalR(loggedUser) {
|
||||
.toISOString()
|
||||
.split("T")[0];
|
||||
connection.on("NotificationEventHandler", (data) => {
|
||||
if (data.loggedInUserId != loggedUser?.employeeInfo.id) {
|
||||
// console.log("Notification received:", data);
|
||||
// if action taken on attendance module
|
||||
if (data.keyword == "Attendance") {
|
||||
const checkIn = data.response.checkInTime.substring(0, 10);
|
||||
if (today === checkIn) {
|
||||
eventBus.emit("attendance", data);
|
||||
}
|
||||
var onlyDate = Number(checkIn.substring(8, 10));
|
||||
const { loggedInUserId, keyword, response, employeeList, numberOfImages } =
|
||||
data;
|
||||
const loggedInId = loggedUser?.employeeInfo?.id;
|
||||
|
||||
var afterTwoDay =
|
||||
checkIn.substring(0, 8) + (onlyDate + 2).toString().padStart(2, "0");
|
||||
if (loggedInUserId === loggedInId) return;
|
||||
|
||||
// ---- Handlers for invalidate or remove ----
|
||||
const queryInvalidators = {
|
||||
Expanse: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["Expenses"] }),
|
||||
queryClient.invalidateQueries({ queryKey: ["Expense"] });
|
||||
},
|
||||
Create_Project: () => queryClient.invalidateQueries(["projectslist"]),
|
||||
Update_Project: () => queryClient.invalidateQueries(["projectslist"]),
|
||||
Infra: () => queryClient.removeQueries({ queryKey: ["ProjectInfra"] }),
|
||||
Task_Report: () => queryClient.invalidateQueries({ queryKey: ["Infra"] }),
|
||||
WorkItem: () =>
|
||||
queryClient.invalidateQueries({ queryKey: ["WorkItems"] }),
|
||||
Directory_Notes: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["directoryNotes"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["Notes"] });
|
||||
},
|
||||
Directory_Buckets: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["bucketList"] });
|
||||
},
|
||||
Directory: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["contacts"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["Contact"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["ContactProfile"] });
|
||||
},
|
||||
};
|
||||
|
||||
// ---- Keyword based event emitters ----
|
||||
const emitters = {
|
||||
employee: () => eventBus.emit("employee", data),
|
||||
project: () => eventBus.emit("project", data),
|
||||
infra: () => eventBus.emit("infra", data),
|
||||
assign_project_all: () => eventBus.emit("assign_project_all", data),
|
||||
image_gallery: () => eventBus.emit("image_gallery", data),
|
||||
};
|
||||
|
||||
// ---- Handle Attendance ----
|
||||
if (keyword === "Attendance") {
|
||||
const checkIn = response.checkInTime.substring(0, 10);
|
||||
if (today === checkIn) eventBus.emit("attendance", data);
|
||||
|
||||
const onlyDate = Number(checkIn.substring(8, 10));
|
||||
const afterTwoDay = checkIn.substring(0,8) + (onlyDate + 2).toString().padStart(2, "0");
|
||||
if (
|
||||
afterTwoDay <= today &&
|
||||
(data.response.activity == 4 || data.response.activity == 5)
|
||||
(response.activity === 4 || response.activity === 5)
|
||||
) {
|
||||
eventBus.emit("regularization", data);
|
||||
}
|
||||
eventBus.emit("attendance_log", data);
|
||||
}
|
||||
if(data.keyword == "Expanse"){
|
||||
queryClient.invalidateQueries({queryKey:["Expenses"]})
|
||||
}
|
||||
// if create or update project
|
||||
if (
|
||||
data.keyword == "Create_Project" ||
|
||||
data.keyword == "Update_Project"
|
||||
) {
|
||||
// clearCacheKey("projectslist");
|
||||
queryClient.invalidateQueries(['projectslist']);
|
||||
eventBus.emit("project", data);
|
||||
|
||||
// ---- Invalidate/Remove cache by keywords ----
|
||||
if (queryInvalidators[keyword]) {
|
||||
queryInvalidators[keyword]();
|
||||
}
|
||||
|
||||
// if assign or deassign employee to any project
|
||||
if (data.keyword == "Assign_Project") {
|
||||
if (
|
||||
data.employeeList.some((item) => item === loggedUser?.employeeInfo.id)
|
||||
) {
|
||||
// ---- Project creation/update ----
|
||||
if (keyword === "Create_Project" || keyword === "Update_Project") {
|
||||
emitters.project();
|
||||
}
|
||||
|
||||
// ---- Assign/deassign project ----
|
||||
if (keyword === "Assign_Project") {
|
||||
if (employeeList?.includes(loggedInId)) {
|
||||
try {
|
||||
cacheData("hasReceived", false);
|
||||
eventBus.emit("assign_project_one", data);
|
||||
} catch (e) {
|
||||
// console.error("Error in cacheData:", e);
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
eventBus.emit("assign_project_all", data);
|
||||
}
|
||||
// if created or updated infra
|
||||
if (data.keyword == "Infra") {
|
||||
queryClient.removeQueries({queryKey:["ProjectInfra"]})
|
||||
// eventBus.emit("infra", data);
|
||||
}
|
||||
if (data.keyword == "Task_Report") {
|
||||
queryClient.removeQueries({queryKey:["Infra"]})
|
||||
// eventBus.emit("infra", data);
|
||||
emitters.assign_project_all();
|
||||
}
|
||||
|
||||
if ( data.keyword == "WorkItem" )
|
||||
{
|
||||
queryClient.removeQueries({queryKey:["WorkItems"]})
|
||||
}
|
||||
|
||||
// if created or updated Employee
|
||||
if (data.keyword == "Employee") {
|
||||
// clearCacheKey("employeeListByProject");
|
||||
// clearCacheKey("allEmployeeList");
|
||||
// clearCacheKey("allInactiveEmployeeList");
|
||||
// clearCacheKey("employeeProfile");
|
||||
// ---- Employee update ----
|
||||
if (keyword === "Employee") {
|
||||
clearCacheKey("Attendance");
|
||||
clearCacheKey("regularizedList")
|
||||
clearCacheKey("AttendanceLogs")
|
||||
clearCacheKey("regularizedList");
|
||||
clearCacheKey("AttendanceLogs");
|
||||
|
||||
// ---we can do also----
|
||||
// queryClient.removeQueries(['allEmployee', true]);
|
||||
// but best practies is refetch
|
||||
queryClient.invalidateQueries(['allEmployee', true]);
|
||||
queryClient.invalidateQueries(['allEmployee', false]);
|
||||
queryClient.invalidateQueries(['employeeProfile', data.response?.employeeId]);
|
||||
queryClient.invalidateQueries(['employeeListByProject']); // optional if scope
|
||||
eventBus.emit("employee", data);
|
||||
queryClient.invalidateQueries(["allEmployee", true]);
|
||||
queryClient.invalidateQueries(["allEmployee", false]);
|
||||
queryClient.invalidateQueries(["employeeProfile", response?.employeeId]);
|
||||
queryClient.invalidateQueries(["employeeListByProject"]);
|
||||
|
||||
emitters.employee();
|
||||
}
|
||||
|
||||
if (data.keyword == "Task_Report") {
|
||||
if(data.numberOfImages > 0){
|
||||
eventBus.emit("image_gallery", data);
|
||||
}
|
||||
}
|
||||
if (data.keyword == "Task_Comment") {
|
||||
if(data.numberOfImages > 0){
|
||||
eventBus.emit("image_gallery", data);
|
||||
}
|
||||
}
|
||||
// ---- Image related events ----
|
||||
if (
|
||||
["Task_Report", "Task_Comment"].includes(keyword) &&
|
||||
numberOfImages > 0
|
||||
) {
|
||||
emitters.image_gallery();
|
||||
}
|
||||
});
|
||||
|
||||
connection
|
||||
.start();
|
||||
connection.start();
|
||||
}
|
||||
|
||||
export function stopSignalR() {
|
||||
|
@ -69,15 +69,26 @@ export const normalizeAllowedContentTypes = (allowedContentType) => {
|
||||
return allowedContentType.split(",");
|
||||
return [];
|
||||
};
|
||||
export function localToUtc(localDateString) {
|
||||
if (!localDateString || typeof localDateString !== "string") return null;
|
||||
export function localToUtc(dateString) {
|
||||
if (!dateString || typeof dateString !== "string") return null;
|
||||
|
||||
const [year, month, day] = localDateString.trim().split("-");
|
||||
const parts = dateString.trim().split("-");
|
||||
if (parts.length !== 3) return null;
|
||||
|
||||
if (!year || !month || !day) return null;
|
||||
let day, month, year;
|
||||
|
||||
if (parts[0].length === 4) {
|
||||
// Format: yyyy-mm-dd
|
||||
[year, month, day] = parts;
|
||||
} else {
|
||||
// Format: dd-mm-yyyy
|
||||
[day, month, year] = parts;
|
||||
}
|
||||
|
||||
const date = new Date(Number(year), Number(month) - 1, Number(day), 0, 0, 0);
|
||||
if (!day || !month || !year) return null;
|
||||
|
||||
const date = new Date(
|
||||
Date.UTC(Number(year), Number(month) - 1, Number(day), 0, 0, 0)
|
||||
);
|
||||
return isNaN(date.getTime()) ? null : date.toISOString();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user