user can not select reimburseDate before transaction date

This commit is contained in:
pramod mahajan 2025-08-01 18:39:03 +05:30
parent 28fb1c9387
commit e0f130e6a6
4 changed files with 107 additions and 87 deletions

View File

@ -57,7 +57,7 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
(store) => store.localVariables.projectId (store) => store.localVariables.projectId
); );
const { projectNames, loading: projectLoading, error } = useProjectName(); const { projectNames, loading: projectLoading, error } = useProjectName();
debugger
const { const {
PaymentModes, PaymentModes,
loading: PaymentModeLoading, loading: PaymentModeLoading,

View File

@ -12,7 +12,11 @@ import { useExpenseContext } from "../../pages/Expense/ExpensePage";
import { getColorNameFromHex } from "../../utils/appUtils"; import { getColorNameFromHex } from "../../utils/appUtils";
import { ExpenseDetailsSkeleton } from "./ExpenseSkeleton"; import { ExpenseDetailsSkeleton } from "./ExpenseSkeleton";
import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { EXPENSE_REJECTEDBY, PROCESS_EXPENSE, REVIEW_EXPENSE } from "../../utils/constants"; import {
EXPENSE_REJECTEDBY,
PROCESS_EXPENSE,
REVIEW_EXPENSE,
} from "../../utils/constants";
import { useProfile } from "../../hooks/useProfile"; import { useProfile } from "../../hooks/useProfile";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -69,22 +73,25 @@ const ViewExpense = ({ ExpenseId }) => {
}); });
}, [data, userPermissions]); }, [data, userPermissions]);
const IsRejectedExpense = useMemo(()=>{ const IsRejectedExpense = useMemo(() => {
return EXPENSE_REJECTEDBY.includes(data?.status?.id) return EXPENSE_REJECTEDBY.includes(data?.status?.id);
},[data]) }, [data]);
const isCreatedBy = useMemo(() => { const isCreatedBy = useMemo(() => {
return data?.createdBy.id === CurrentUser?.id; return data?.createdBy.id === CurrentUser?.id;
}, [data, CurrentUser]); }, [data, CurrentUser]);
const { mutate: MakeAction,isPending } = useActionOnExpense(() => { const { mutate: MakeAction, isPending } = useActionOnExpense(() => {
setClickedStatusId(null); setClickedStatusId(null);
reset()}); reset();
});
const onSubmit = (formData) => { const onSubmit = (formData) => {
const Payload = { const Payload = {
...formData, ...formData,
reimburseDate:moment.utc(formData.reimburseDate, "DD-MM-YYYY").toISOString(), reimburseDate: moment
.utc(formData.reimburseDate, "DD-MM-YYYY")
.toISOString(),
expenseId: ExpenseId, expenseId: ExpenseId,
comment: formData.comment, comment: formData.comment,
}; };
@ -340,42 +347,51 @@ const ViewExpense = ({ ExpenseId }) => {
</div> </div>
)} )}
</div> </div>
{data.expensesReimburse && (<div className="row text-start"> {data.expensesReimburse && (
<div className="col-md-6 mb-3"> <div className="row text-start">
<strong>Transaction ID :</strong> {data.expensesReimburse.reimburseTransactionId || "N/A"} <div className="col-md-6 mb-3">
</div> <label className="form-label me-2 mb-0 fw-semibold">
<div className="col-md-6 mb-3"> Transaction ID :
<strong>Reimburse Date :</strong>{" "} </label>
{ moment(data.expensesReimburse.reimburseDate).format("DD-MM-YYYY") } {data.expensesReimburse.reimburseTransactionId || "N/A"}
</div> </div>
<div className="col-md-6 mb-3">
<label className="form-label me-2 mb-0 fw-semibold">
Reimburse Date :
</label>
{formatUTCToLocalTime(data.expensesReimburse.reimburseDate)}
</div>
{data.expensesReimburse && ( {data.expensesReimburse && (
<> <>
<div className="col-md-6 mb-3 d-flex align-items-center"> <div className="col-md-6 mb-3 d-flex align-items-center">
<strong className="me-2">Reimburse By :</strong> <label className="form-label me-2 mb-0 fw-semibold">
<Avatar Reimburse By :
size="xs" </label>
classAvatar="m-0 me-1" <Avatar
firstName={data?.expensesReimburse?.reimburseBy?.firstName} size="xs"
lastName={data?.expensesReimburse?.reimburseBy?.lastName} classAvatar="m-0 me-1"
/> firstName={data?.expensesReimburse?.reimburseBy?.firstName}
<span className="text-muted"> lastName={data?.expensesReimburse?.reimburseBy?.lastName}
{`${data?.expensesReimburse?.reimburseBy?.firstName} ${data?.expensesReimburse?.reimburseBy?.lastName}`.trim()} />
</span> <span className="text-muted">
</div> {`${data?.expensesReimburse?.reimburseBy?.firstName} ${data?.expensesReimburse?.reimburseBy?.lastName}`.trim()}
</> </span>
)} </div>
</>
)}
<div className="col-md-6 mb-3"> <div className="col-md-6 mb-3">
<strong>Note :</strong> {data.expensesReimburse.reimburseNote} <label className="form-label me-2 mb-0 fw-semibold"> Note :</label>{" "}
</div> {data.expensesReimburse.reimburseNote}
</div>
</div>)} </div>
)}
<div className="text-start"> <div className="text-start">
<label className="form-label me-2 mb-0 fw-semibold">Description :</label> <label className="form-label me-2 mb-0 fw-semibold">
Description :
</label>
<div className="text-muted">{data?.description}</div> <div className="text-muted">{data?.description}</div>
</div> </div>
<div className="col-12 my-2 text-start"> <div className="col-12 my-2 text-start">
@ -443,7 +459,7 @@ const ViewExpense = ({ ExpenseId }) => {
{Array.isArray(data?.nextStatus) && data.nextStatus.length > 0 && ( {Array.isArray(data?.nextStatus) && data.nextStatus.length > 0 && (
<> <>
{(IsPaymentProcess && nextStatusWithPermission?.length > 0) && ( {IsPaymentProcess && nextStatusWithPermission?.length > 0 && (
<div className="row"> <div className="row">
<div className="col-12 col-md-6 text-start"> <div className="col-12 col-md-6 text-start">
<label className="form-label">Transaction Id </label> <label className="form-label">Transaction Id </label>
@ -460,7 +476,11 @@ const ViewExpense = ({ ExpenseId }) => {
</div> </div>
<div className="col-12 col-md-6 text-start"> <div className="col-12 col-md-6 text-start">
<label className="form-label">Transaction Date </label> <label className="form-label">Transaction Date </label>
<DatePicker name="reimburseDate" control={control} /> <DatePicker
name="reimburseDate"
control={control}
minDate={data?.transactionDate}
/>
{errors.reimburseDate && ( {errors.reimburseDate && (
<small className="danger-text"> <small className="danger-text">
{errors.reimburseDate.message} {errors.reimburseDate.message}
@ -477,49 +497,47 @@ const ViewExpense = ({ ExpenseId }) => {
</div> </div>
</div> </div>
)} )}
<div className="col-12 mb-3 text-start"> <div className="col-12 mb-3 text-start">
{( {((nextStatusWithPermission.length > 0 && !IsRejectedExpense) ||
(nextStatusWithPermission.length > 0 && !IsRejectedExpense) || (IsRejectedExpense && isCreatedBy)) && (
(IsRejectedExpense && isCreatedBy) <>
) && ( <label className="form-label me-2 mb-0">Comment:</label>
<> <textarea
<label className="form-label me-2 mb-0">Comment:</label> className="form-control form-control-sm"
<textarea {...register("comment")}
className="form-control form-control-sm" rows="2"
{...register("comment")} />
rows="2" {errors.comment && (
/> <small className="danger-text">
{errors.comment && ( {errors.comment.message}
<small className="danger-text"> </small>
{errors.comment.message} )}
</small> </>
)} )}
</>
)}
{(nextStatusWithPermission?.length > 0 && (!IsRejectedExpense || isCreatedBy)) && (
<div className="text-center flex-wrap gap-2 my-2">
{nextStatusWithPermission.map((status, index) => (
<button
key={status.id || index}
type="button"
onClick={() => {
setClickedStatusId(status.id);
setValue("statusId", status.id);
handleSubmit(onSubmit)();
}}
disabled={isPending}
className="btn btn-primary btn-sm cursor-pointer mx-2 border-0"
>
{isPending && clickedStatusId === status.id
? "Please Wait..."
: status.displayName || status.name}
</button>
))}
</div>
)}
</div>
{nextStatusWithPermission?.length > 0 &&
(!IsRejectedExpense || isCreatedBy) && (
<div className="text-center flex-wrap gap-2 my-2">
{nextStatusWithPermission.map((status, index) => (
<button
key={status.id || index}
type="button"
onClick={() => {
setClickedStatusId(status.id);
setValue("statusId", status.id);
handleSubmit(onSubmit)();
}}
disabled={isPending}
className="btn btn-primary btn-sm cursor-pointer mx-2 border-0"
>
{isPending && clickedStatusId === status.id
? "Please Wait..."
: status.displayName || status.name}
</button>
))}
</div>
)}
</div>
</> </>
)} )}
</form> </form>

View File

@ -9,6 +9,7 @@ const DatePicker = ({
className = "", className = "",
allowText = false, allowText = false,
maxDate=new Date(), maxDate=new Date(),
minDate,
...rest ...rest
}) => { }) => {
const inputRef = useRef(null); const inputRef = useRef(null);
@ -29,6 +30,7 @@ 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]) ?? undefined,
onChange: function (selectedDates, dateStr) { onChange: function (selectedDates, dateStr) {
onChange(dateStr); onChange(dateStr);
}, },

View File

@ -45,7 +45,7 @@ const EmployeeSearchInput = ({ control, name, projectId }) => {
onChange={(e) => { onChange={(e) => {
setSearch(e.target.value); setSearch(e.target.value);
setShowDropdown(true); setShowDropdown(true);
onChange(""); // Clear previous selection onChange("");
}} }}
onFocus={() => { onFocus={() => {
if (search) setShowDropdown(true); if (search) setShowDropdown(true);