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 DatePicker from "../common/DatePicker";
|
||||||
import ErrorPage from "../../pages/ErrorPage";
|
import ErrorPage from "../../pages/ErrorPage";
|
||||||
import Label from "../common/Label";
|
import Label from "../common/Label";
|
||||||
|
import EmployeeSearchInput from "../common/EmployeeSearchInput";
|
||||||
|
|
||||||
const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||||
const {
|
const {
|
||||||
@ -57,7 +58,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const selectedproject = watch("projectId");
|
const selectedproject = watch("projectId");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
projectNames,
|
projectNames,
|
||||||
loading: projectLoading,
|
loading: projectLoading,
|
||||||
@ -142,8 +143,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (expenseToEdit && data ) {
|
if (expenseToEdit && data) {
|
||||||
|
|
||||||
reset({
|
reset({
|
||||||
projectId: data.project.id || "",
|
projectId: data.project.id || "",
|
||||||
expensesTypeId: data.expensesType.id || "",
|
expensesTypeId: data.expensesType.id || "",
|
||||||
@ -156,7 +156,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
supplerName: data.supplerName || "",
|
supplerName: data.supplerName || "",
|
||||||
amount: data.amount || "",
|
amount: data.amount || "",
|
||||||
noOfPersons: data.noOfPersons || "",
|
noOfPersons: data.noOfPersons || "",
|
||||||
gstNumber:data.gstNumber || "",
|
gstNumber: data.gstNumber || "",
|
||||||
billAttachments: data.documents
|
billAttachments: data.documents
|
||||||
? data.documents.map((doc) => ({
|
? data.documents.map((doc) => ({
|
||||||
fileName: doc.fileName,
|
fileName: doc.fileName,
|
||||||
@ -183,8 +183,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
const onSubmit = (fromdata) => {
|
const onSubmit = (fromdata) => {
|
||||||
let payload = {
|
let payload = {
|
||||||
...fromdata,
|
...fromdata,
|
||||||
transactionDate: localToUtc(fromdata.transactionDate)
|
transactionDate: localToUtc(fromdata.transactionDate),
|
||||||
|
|
||||||
};
|
};
|
||||||
if (expenseToEdit) {
|
if (expenseToEdit) {
|
||||||
const editPayload = { ...payload, id: data.id };
|
const editPayload = { ...payload, id: data.id };
|
||||||
@ -206,7 +205,6 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
if (StatusLoadding || projectLoading || ExpenseLoading || isLoading)
|
if (StatusLoadding || projectLoading || ExpenseLoading || isLoading)
|
||||||
return <ExpenseSkeleton />;
|
return <ExpenseSkeleton />;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container p-3">
|
<div className="container p-3">
|
||||||
<h5 className="m-0">
|
<h5 className="m-0">
|
||||||
@ -215,7 +213,9 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
<form id="expenseForm" onSubmit={handleSubmit(onSubmit)}>
|
<form id="expenseForm" onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="row my-2 text-start">
|
<div className="row my-2 text-start">
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<Label className="form-label" required>Select Project</Label>
|
<Label className="form-label" required>
|
||||||
|
Select Project
|
||||||
|
</Label>
|
||||||
<select
|
<select
|
||||||
className="form-select form-select-sm"
|
className="form-select form-select-sm"
|
||||||
{...register("projectId")}
|
{...register("projectId")}
|
||||||
@ -296,11 +296,11 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-md-6">
|
<div className="col-12 col-md-6 text-start">
|
||||||
<Label htmlFor="paidById" className="form-label" required>
|
<Label htmlFor="paidById" className="form-label" required>
|
||||||
Paid By
|
Paid By
|
||||||
</Label>
|
</Label>
|
||||||
<select
|
{/* <select
|
||||||
className="form-select form-select-sm"
|
className="form-select form-select-sm"
|
||||||
id="paymentModeId"
|
id="paymentModeId"
|
||||||
{...register("paidById")}
|
{...register("paidById")}
|
||||||
@ -321,7 +321,13 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
</select>
|
</select>
|
||||||
{errors.paidById && (
|
{errors.paidById && (
|
||||||
<small className="danger-text">{errors.paidById.message}</small>
|
<small className="danger-text">{errors.paidById.message}</small>
|
||||||
)}
|
)} */}
|
||||||
|
|
||||||
|
<EmployeeSearchInput
|
||||||
|
control={control}
|
||||||
|
name="paidById"
|
||||||
|
projectId={null}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -330,7 +336,11 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
<Label htmlFor="transactionDate" className="form-label" required>
|
<Label htmlFor="transactionDate" className="form-label" required>
|
||||||
Transaction Date
|
Transaction Date
|
||||||
</Label>
|
</Label>
|
||||||
<DatePicker name="transactionDate" control={control} maxDate={new Date()}/>
|
<DatePicker
|
||||||
|
name="transactionDate"
|
||||||
|
control={control}
|
||||||
|
maxDate={new Date()}
|
||||||
|
/>
|
||||||
|
|
||||||
{errors.transactionDate && (
|
{errors.transactionDate && (
|
||||||
<small className="danger-text">
|
<small className="danger-text">
|
||||||
@ -409,9 +419,9 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
</small>
|
</small>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<label htmlFor="statusId" className="form-label ">
|
<label htmlFor="statusId" className="form-label ">
|
||||||
GST Number
|
GST Number
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@ -421,9 +431,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
{...register("gstNumber")}
|
{...register("gstNumber")}
|
||||||
/>
|
/>
|
||||||
{errors.gstNumber && (
|
{errors.gstNumber && (
|
||||||
<small className="danger-text">
|
<small className="danger-text">{errors.gstNumber.message}</small>
|
||||||
{errors.gstNumber.message}
|
|
||||||
</small>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -448,7 +456,9 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
|
|
||||||
<div className="row my-2 text-start">
|
<div className="row my-2 text-start">
|
||||||
<div className="col-md-12">
|
<div className="col-md-12">
|
||||||
<Label htmlFor="description" className="form-label" required>Description</Label>
|
<Label htmlFor="description" className="form-label" required>
|
||||||
|
Description
|
||||||
|
</Label>
|
||||||
<textarea
|
<textarea
|
||||||
id="description"
|
id="description"
|
||||||
className="form-control form-control-sm"
|
className="form-control form-control-sm"
|
||||||
@ -465,7 +475,9 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
|
|
||||||
<div className="row my-2 text-start">
|
<div className="row my-2 text-start">
|
||||||
<div className="col-md-12">
|
<div className="col-md-12">
|
||||||
<Label className="form-label" required>Upload Bill </Label>
|
<Label className="form-label" required>
|
||||||
|
Upload Bill{" "}
|
||||||
|
</Label>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="border border-secondary border-dashed rounded p-4 text-center bg-textMuted position-relative"
|
className="border border-secondary border-dashed rounded p-4 text-center bg-textMuted position-relative"
|
||||||
@ -549,7 +561,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
|
|
||||||
<div className="d-flex justify-content-end gap-3">
|
<div className="d-flex justify-content-end gap-3">
|
||||||
{" "}
|
{" "}
|
||||||
<button
|
<button
|
||||||
type="reset"
|
type="reset"
|
||||||
disabled={isPending || createPending}
|
disabled={isPending || createPending}
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
@ -568,7 +580,6 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
|||||||
? "Update"
|
? "Update"
|
||||||
: "Submit"}
|
: "Submit"}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,7 +9,7 @@ import { useForm } from "react-hook-form";
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { defaultActionValues, ExpenseActionScheam } from "./ExpenseSchema";
|
import { defaultActionValues, ExpenseActionScheam } from "./ExpenseSchema";
|
||||||
import { useExpenseContext } from "../../pages/Expense/ExpensePage";
|
import { useExpenseContext } from "../../pages/Expense/ExpensePage";
|
||||||
import { getColorNameFromHex, getIconByFileType } from "../../utils/appUtils";
|
import { getColorNameFromHex, getIconByFileType, localToUtc } from "../../utils/appUtils";
|
||||||
import { ExpenseDetailsSkeleton } from "./ExpenseSkeleton";
|
import { ExpenseDetailsSkeleton } from "./ExpenseSkeleton";
|
||||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
import {
|
import {
|
||||||
@ -91,9 +91,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
|||||||
const onSubmit = (formData) => {
|
const onSubmit = (formData) => {
|
||||||
const Payload = {
|
const Payload = {
|
||||||
...formData,
|
...formData,
|
||||||
reimburseDate: moment
|
reimburseDate: localToUtc(formData.reimburseDate),
|
||||||
.utc(formData.reimburseDate, "DD-MM-YYYY")
|
|
||||||
.toISOString(),
|
|
||||||
expenseId: ExpenseId,
|
expenseId: ExpenseId,
|
||||||
comment: formData.comment,
|
comment: formData.comment,
|
||||||
};
|
};
|
||||||
@ -397,7 +395,8 @@ const ViewExpense = ({ ExpenseId }) => {
|
|||||||
<DatePicker
|
<DatePicker
|
||||||
name="reimburseDate"
|
name="reimburseDate"
|
||||||
control={control}
|
control={control}
|
||||||
minDate={data?.transactionDate}
|
minDate={data?.createdAt}
|
||||||
|
maxDate={new Date()}
|
||||||
/>
|
/>
|
||||||
{errors.reimburseDate && (
|
{errors.reimburseDate && (
|
||||||
<small className="danger-text">
|
<small className="danger-text">
|
||||||
|
@ -548,6 +548,7 @@ export const useUpdateNote = (onSuccessCallBack) => {
|
|||||||
mutationFn: async ({ noteId, notePayload }) =>
|
mutationFn: async ({ noteId, notePayload }) =>
|
||||||
await DirectoryRepository.UpdateNote(noteId, notePayload),
|
await DirectoryRepository.UpdateNote(noteId, notePayload),
|
||||||
onSuccess: (_, variables) => {
|
onSuccess: (_, variables) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["Contact"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["Notes"] });
|
queryClient.invalidateQueries({ queryKey: ["Notes"] });
|
||||||
queryClient.invalidateQueries({ queryKey: ["ContactNotes"] });
|
queryClient.invalidateQueries({ queryKey: ["ContactNotes"] });
|
||||||
showToast("Note updated Successfully", "success");
|
showToast("Note updated Successfully", "success");
|
||||||
|
@ -14,7 +14,6 @@ export const useProjectAccess = (projectId) => {
|
|||||||
const canView = useHasUserPermission(VIEW_PROJECTS);
|
const canView = useHasUserPermission(VIEW_PROJECTS);
|
||||||
|
|
||||||
const loading = isLoading || !isFetched;
|
const loading = isLoading || !isFetched;
|
||||||
debugger
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (projectId && !loading && !canView) {
|
if (projectId && !loading && !canView) {
|
||||||
showToast("You don't have permission to view project details", "warning");
|
showToast("You don't have permission to view project details", "warning");
|
||||||
|
@ -8,7 +8,7 @@ import showToast from "./toastService";
|
|||||||
import eventBus from "./eventBus";
|
import eventBus from "./eventBus";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { clearApiCacheKey } from "../slices/apiCacheSlice";
|
import { clearApiCacheKey } from "../slices/apiCacheSlice";
|
||||||
import {BASE_URL} from "../utils/constants";
|
import { BASE_URL } from "../utils/constants";
|
||||||
import { queryClient } from "../layouts/AuthLayout";
|
import { queryClient } from "../layouts/AuthLayout";
|
||||||
const base_Url = BASE_URL;
|
const base_Url = BASE_URL;
|
||||||
let connection = null;
|
let connection = null;
|
||||||
@ -32,103 +32,108 @@ export function startSignalR(loggedUser) {
|
|||||||
.toISOString()
|
.toISOString()
|
||||||
.split("T")[0];
|
.split("T")[0];
|
||||||
connection.on("NotificationEventHandler", (data) => {
|
connection.on("NotificationEventHandler", (data) => {
|
||||||
if (data.loggedInUserId != loggedUser?.employeeInfo.id) {
|
const { loggedInUserId, keyword, response, employeeList, numberOfImages } =
|
||||||
// console.log("Notification received:", data);
|
data;
|
||||||
// if action taken on attendance module
|
const loggedInId = loggedUser?.employeeInfo?.id;
|
||||||
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));
|
|
||||||
|
|
||||||
var afterTwoDay =
|
if (loggedInUserId === loggedInId) return;
|
||||||
checkIn.substring(0, 8) + (onlyDate + 2).toString().padStart(2, "0");
|
|
||||||
if (
|
// ---- Handlers for invalidate or remove ----
|
||||||
afterTwoDay <= today &&
|
const queryInvalidators = {
|
||||||
(data.response.activity == 4 || data.response.activity == 5)
|
Expanse: () => {
|
||||||
) {
|
queryClient.invalidateQueries({ queryKey: ["Expenses"] }),
|
||||||
eventBus.emit("regularization", data);
|
queryClient.invalidateQueries({ queryKey: ["Expense"] });
|
||||||
}
|
},
|
||||||
eventBus.emit("attendance_log", data);
|
Create_Project: () => queryClient.invalidateQueries(["projectslist"]),
|
||||||
}
|
Update_Project: () => queryClient.invalidateQueries(["projectslist"]),
|
||||||
if(data.keyword == "Expanse"){
|
Infra: () => queryClient.removeQueries({ queryKey: ["ProjectInfra"] }),
|
||||||
queryClient.invalidateQueries({queryKey:["Expenses"]})
|
Task_Report: () => queryClient.invalidateQueries({ queryKey: ["Infra"] }),
|
||||||
}
|
WorkItem: () =>
|
||||||
// if create or update project
|
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 (
|
if (
|
||||||
data.keyword == "Create_Project" ||
|
afterTwoDay <= today &&
|
||||||
data.keyword == "Update_Project"
|
(response.activity === 4 || response.activity === 5)
|
||||||
) {
|
) {
|
||||||
// clearCacheKey("projectslist");
|
eventBus.emit("regularization", data);
|
||||||
queryClient.invalidateQueries(['projectslist']);
|
|
||||||
eventBus.emit("project", data);
|
|
||||||
}
|
}
|
||||||
|
eventBus.emit("attendance_log", data);
|
||||||
|
}
|
||||||
|
|
||||||
// if assign or deassign employee to any project
|
// ---- Invalidate/Remove cache by keywords ----
|
||||||
if (data.keyword == "Assign_Project") {
|
if (queryInvalidators[keyword]) {
|
||||||
if (
|
queryInvalidators[keyword]();
|
||||||
data.employeeList.some((item) => item === loggedUser?.employeeInfo.id)
|
}
|
||||||
) {
|
|
||||||
try {
|
|
||||||
cacheData("hasReceived", false);
|
|
||||||
eventBus.emit("assign_project_one", data);
|
|
||||||
} catch (e) {
|
|
||||||
// console.error("Error in cacheData:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( data.keyword == "WorkItem" )
|
// ---- Project creation/update ----
|
||||||
{
|
if (keyword === "Create_Project" || keyword === "Update_Project") {
|
||||||
queryClient.removeQueries({queryKey:["WorkItems"]})
|
emitters.project();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if created or updated Employee
|
// ---- Assign/deassign project ----
|
||||||
if (data.keyword == "Employee") {
|
if (keyword === "Assign_Project") {
|
||||||
// clearCacheKey("employeeListByProject");
|
if (employeeList?.includes(loggedInId)) {
|
||||||
// clearCacheKey("allEmployeeList");
|
try {
|
||||||
// clearCacheKey("allInactiveEmployeeList");
|
cacheData("hasReceived", false);
|
||||||
// clearCacheKey("employeeProfile");
|
eventBus.emit("assign_project_one", data);
|
||||||
clearCacheKey("Attendance");
|
} catch {}
|
||||||
clearCacheKey("regularizedList")
|
}
|
||||||
clearCacheKey("AttendanceLogs")
|
emitters.assign_project_all();
|
||||||
|
}
|
||||||
|
|
||||||
// ---we can do also----
|
// ---- Employee update ----
|
||||||
// queryClient.removeQueries(['allEmployee', true]);
|
if (keyword === "Employee") {
|
||||||
// but best practies is refetch
|
clearCacheKey("Attendance");
|
||||||
queryClient.invalidateQueries(['allEmployee', true]);
|
clearCacheKey("regularizedList");
|
||||||
queryClient.invalidateQueries(['allEmployee', false]);
|
clearCacheKey("AttendanceLogs");
|
||||||
queryClient.invalidateQueries(['employeeProfile', data.response?.employeeId]);
|
|
||||||
queryClient.invalidateQueries(['employeeListByProject']); // optional if scope
|
|
||||||
eventBus.emit("employee", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.keyword == "Task_Report") {
|
queryClient.invalidateQueries(["allEmployee", true]);
|
||||||
if(data.numberOfImages > 0){
|
queryClient.invalidateQueries(["allEmployee", false]);
|
||||||
eventBus.emit("image_gallery", data);
|
queryClient.invalidateQueries(["employeeProfile", response?.employeeId]);
|
||||||
}
|
queryClient.invalidateQueries(["employeeListByProject"]);
|
||||||
}
|
|
||||||
if (data.keyword == "Task_Comment") {
|
emitters.employee();
|
||||||
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
|
connection.start();
|
||||||
.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stopSignalR() {
|
export function stopSignalR() {
|
||||||
|
@ -69,15 +69,26 @@ export const normalizeAllowedContentTypes = (allowedContentType) => {
|
|||||||
return allowedContentType.split(",");
|
return allowedContentType.split(",");
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
export function localToUtc(localDateString) {
|
export function localToUtc(dateString) {
|
||||||
if (!localDateString || typeof localDateString !== "string") return null;
|
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) {
|
||||||
const date = new Date(Number(year), Number(month) - 1, Number(day), 0, 0, 0);
|
// Format: yyyy-mm-dd
|
||||||
|
[year, month, day] = parts;
|
||||||
return isNaN(date.getTime()) ? null : date.toISOString();
|
} else {
|
||||||
|
// Format: dd-mm-yyyy
|
||||||
|
[day, month, year] = parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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