merged recurring into upgrade expense
This commit is contained in:
parent
4ae0b403a6
commit
1f784f330d
@ -169,7 +169,7 @@ export const defaultActionValues = {
|
||||
reimburseById: null,
|
||||
tdsPercentage: 0,
|
||||
baseAmount:null,
|
||||
taxAmount: 0,
|
||||
taxAmount: null,
|
||||
};
|
||||
|
||||
export const SearchSchema = z.object({
|
||||
|
||||
@ -18,7 +18,7 @@ const ExpenseStatusLogs = ({ data }) => {
|
||||
() => sortedLogs.slice(0, visibleCount),
|
||||
[sortedLogs, visibleCount]
|
||||
);
|
||||
|
||||
console.log(logsToShow)
|
||||
const timelineData = useMemo(() => {
|
||||
|
||||
return logsToShow.map((log, index) => ({
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import React from "react";
|
||||
import { formatFileSize, getIconByFileType } from "../../utils/appUtils";
|
||||
import Tooltip from "../common/Tooltip";
|
||||
|
||||
const Filelist = ({ files, removeFile, expenseToEdit }) => {
|
||||
return (
|
||||
<div className="d-block">
|
||||
<div className="d-flex flex-wrap gap-2 my-1">
|
||||
{files
|
||||
.filter((file) => {
|
||||
if (expenseToEdit) {
|
||||
@ -13,7 +14,7 @@ const Filelist = ({ files, removeFile, expenseToEdit }) => {
|
||||
})
|
||||
.map((file, idx) => (
|
||||
<div className="col-12 col-sm-6 col-md-4 mb-2" key={idx}>
|
||||
<div className="d-flex align-items-center justify-content-between bg-white border rounded p-1 ">
|
||||
<div className="d-flex align-items-center justify-content-between bg-white border rounded p-1">
|
||||
{/* File icon and info */}
|
||||
<div className="d-flex align-items-center flex-grow-1 gap-2 overflow-hidden">
|
||||
<i
|
||||
@ -47,8 +48,49 @@ const Filelist = ({ files, removeFile, expenseToEdit }) => {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export default Filelist;
|
||||
export const FilelistView = ({ files, viewFile }) => {
|
||||
console.log( files)
|
||||
return (
|
||||
<div className="d-flex flex-wrap gap-2 mt-2">
|
||||
{files?.map((file, idx) => (
|
||||
<div className=" bg-white " key={idx}>
|
||||
<div className="row align-items-center">
|
||||
{/* File icon and info */}
|
||||
<div className="col-12 d-flex align-items-center gap-2">
|
||||
<i
|
||||
className={`bx ${getIconByFileType(file?.fileName)} fs-3`}
|
||||
></i>
|
||||
|
||||
<div
|
||||
className="d-flex flex-column text-truncate"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
viewFile({
|
||||
IsOpen: true,
|
||||
Image: file.preSignedUrl,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<span className="fw-medium small text-truncate">
|
||||
{file.fileName}
|
||||
</span>
|
||||
<span className="text-body-secondary small">
|
||||
<Tooltip text={"Click on file"}>
|
||||
{" "}
|
||||
{file.fileSize ? formatFileSize(file.fileSize) : ""}
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -134,7 +134,6 @@ const ManageExpense = ({ closeModal, expenseToEdit = null }) => {
|
||||
reader.onerror = (error) => reject(error);
|
||||
});
|
||||
const removeFile = (index) => {
|
||||
documentId;
|
||||
if (expenseToEdit) {
|
||||
const newFiles = files.map((file, i) => {
|
||||
if (file.documentId !== index) return file;
|
||||
|
||||
@ -109,6 +109,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
const handleImageLoad = (id) => {
|
||||
setImageLoaded((prev) => ({ ...prev, [id]: true }));
|
||||
};
|
||||
console.log(errors)
|
||||
return (
|
||||
<form className="container px-3" onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="col-12 mb-1">
|
||||
|
||||
@ -392,9 +392,6 @@ function ManagePaymentRequest({ closeModal, requestToEdit = null }) {
|
||||
error={errors.payee?.message}
|
||||
/>
|
||||
|
||||
{errors.payee && (
|
||||
<small className="danger-text">{errors.payee.message}</small>
|
||||
)}
|
||||
|
||||
{/* Checkbox below input */}
|
||||
<div className="form-check mt-2">
|
||||
|
||||
@ -45,11 +45,8 @@ export const PaymentRequestSchema = (expenseTypes, isItself) => {
|
||||
description: z.string().optional(),
|
||||
isActive: z.boolean().default(true),
|
||||
})
|
||||
).refine((data)=>{
|
||||
if(isItself){
|
||||
payee.z.string().optional();
|
||||
}
|
||||
}),
|
||||
)
|
||||
,
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
93
src/components/PaymentRequest/PaymentStatusLogs.jsx
Normal file
93
src/components/PaymentRequest/PaymentStatusLogs.jsx
Normal file
@ -0,0 +1,93 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import Avatar from "../common/Avatar";
|
||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
import Timeline from "../common/TimeLine";
|
||||
import moment from "moment";
|
||||
import { getColorNameFromHex } from "../../utils/appUtils";
|
||||
const PaymentStatusLogs = ({ data }) => {
|
||||
const [visibleCount, setVisibleCount] = useState(4);
|
||||
|
||||
const sortedLogs = useMemo(() => {
|
||||
if (!data?.updateLogs) return [];
|
||||
return [...data.updateLogs].sort(
|
||||
(a, b) => new Date(b.updatedAt) - new Date(a.updatedAt)
|
||||
);
|
||||
}, [data?.updateLogs]);
|
||||
|
||||
const logsToShow = useMemo(
|
||||
() => sortedLogs.slice(0, visibleCount),
|
||||
[sortedLogs, visibleCount]
|
||||
);
|
||||
|
||||
const timelineData = useMemo(() => {
|
||||
return logsToShow.map((log, index) => ({
|
||||
id: index + 1,
|
||||
title: log.nextStatus?.name || "Status Updated",
|
||||
description: log.nextStatus?.description || "",
|
||||
timeAgo: log.updatedAt,
|
||||
color: getColorNameFromHex(log.nextStatus?.color) || "primary",
|
||||
users: log.updatedBy
|
||||
? [
|
||||
{
|
||||
firstName: log.updatedBy.firstName || "",
|
||||
lastName: log?.updatedBy?.lastName || "",
|
||||
role: log.updatedBy.jobRoleName || "",
|
||||
avatar: log.updatedBy.photo,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
}));
|
||||
}, [logsToShow]);
|
||||
|
||||
const handleShowMore = () => {
|
||||
setVisibleCount((prev) => prev + 4);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="page-min-h overflow-auto">
|
||||
{/* <div className="row g-2">
|
||||
{logsToShow.map((log) => (
|
||||
<div key={log.id} className="col-12 d-flex align-items-start mb-1">
|
||||
<Avatar
|
||||
size="xs"
|
||||
firstName={log.updatedBy.firstName}
|
||||
lastName={log.updatedBy.lastName}
|
||||
/>
|
||||
|
||||
<div className="flex-grow-1">
|
||||
<div className="text-start">
|
||||
<div className="flex">
|
||||
<span>{`${log.updatedBy.firstName} ${log.updatedBy.lastName}`}</span>
|
||||
<small className="text-secondary text-tiny ms-2">
|
||||
<em>{log.action}</em>
|
||||
</small>
|
||||
<span className="text-tiny text-secondary d-block">
|
||||
{formatUTCToLocalTime(log.updateAt, true)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="d-flex align-items-center text-muted small mt-1">
|
||||
<span>{log.comment}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{sortedLogs.length > visibleCount && (
|
||||
<div className="text-center my-1">
|
||||
<button
|
||||
className="btn btn-xs btn-outline-primary"
|
||||
onClick={handleShowMore}
|
||||
>
|
||||
Show More
|
||||
</button>
|
||||
</div>
|
||||
)} */}
|
||||
|
||||
<Timeline items={timelineData} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PaymentStatusLogs;
|
||||
@ -34,6 +34,8 @@ import {
|
||||
REVIEW_EXPENSE,
|
||||
} from "../../utils/constants";
|
||||
import Label from "../common/Label";
|
||||
import { FilelistView } from "../Expenses/Filelist";
|
||||
import PaymentStatusLogs from "./PaymentStatusLogs";
|
||||
|
||||
const ViewPaymentRequest = ({ requestId }) => {
|
||||
const { data, isLoading, isError, error, isFetching } =
|
||||
@ -125,7 +127,7 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
<hr />
|
||||
</div>
|
||||
<div className="row mb-1">
|
||||
<div className="col-12 col-sm-6 col-md-8">
|
||||
<div className="col-12 col-sm-6 col-md-7">
|
||||
<div className="row">
|
||||
<div className="col-12 text-start fw-semibold mb-2">
|
||||
{data?.paymentRequestUID}
|
||||
@ -537,7 +539,7 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
<i className="bx bx-time-five me-2 "></i>{" "}
|
||||
<p className="fw-medium">TimeLine</p>
|
||||
</div>
|
||||
<PaymentStat data={data} />
|
||||
<PaymentStatusLogs data={data} />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import React from "react";
|
||||
import Avatar from "./Avatar";
|
||||
import Tooltip from "./Tooltip";
|
||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
import moment from "moment";
|
||||
|
||||
const Timeline = ({ items = [], transparent = true }) => {
|
||||
return (
|
||||
@ -24,7 +27,7 @@ const Timeline = ({ items = [], transparent = true }) => {
|
||||
<div className="timeline-event">
|
||||
<div className="timeline-header mb-3 d-flex justify-content-between">
|
||||
<h6 className="mb-0 text-body">{item.title}</h6>
|
||||
<small className="text-body-secondary">{item.timeAgo}</small>
|
||||
<small className="text-body-secondary"><Tooltip text={formatUTCToLocalTime(item.timeAgo,true)}>{moment(item.timeAgo).fromNow()}</Tooltip></small>
|
||||
</div>
|
||||
|
||||
{item.description && <p className="mb-2">{item.description}</p>}
|
||||
|
||||
@ -190,7 +190,7 @@ const ExpensePage = () => {
|
||||
{viewExpense.view && (
|
||||
<GlobalModel
|
||||
isOpen
|
||||
size="lg"
|
||||
size="xl"
|
||||
modalType="top"
|
||||
closeModal={() => setViewExpense({ expenseId: null, view: false })}
|
||||
>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user