added layout for Expense veiw modal

This commit is contained in:
pramod.mahajan 2025-11-04 23:17:43 +05:30
parent f688a7169e
commit e8698473db
2 changed files with 260 additions and 434 deletions

View File

@ -114,19 +114,25 @@ const ViewExpense = ({ ExpenseId }) => {
<div className="col-12 mb-1"> <div className="col-12 mb-1">
<h5 className="fw-semibold m-0">Expense Details</h5> <h5 className="fw-semibold m-0">Expense Details</h5>
</div> </div>
<div className="row mb-1">
<div className="col-12 col-md-7"> <div className="row mb-1 border-top border-2 border-light-subtle">
<div className="col-12 col-lg-7 col-xl-8 border-end border-2 border-light-subtle mb-3">
<div className="row"> <div className="row">
<div className="col-12 text-start fw-semibold my-2"> <div className="col-12 d-flex justify-content-between text-start fw-semibold my-2">
{data?.expenseUId} <span>{data?.expenseUId}</span>
<span
className={`badge bg-label-${
getColorNameFromHex(data?.status?.color) || "secondary"
}`}t
>
{data?.status?.name}
</span>
</div> </div>
{/* Row 1 */} {/* Row 1 */}
<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" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
Transaction Date : Transaction Date :
</label> </label>
<div className="text-muted"> <div className="text-muted">
@ -134,12 +140,10 @@ const ViewExpense = ({ ExpenseId }) => {
</div> </div>
</div> </div>
</div> </div>
<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" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
Expense Type : Expense Type :
</label> </label>
<div className="text-muted">{data?.expensesType?.name}</div> <div className="text-muted">{data?.expensesType?.name}</div>
@ -149,21 +153,16 @@ const ViewExpense = ({ ExpenseId }) => {
{/* Row 2 */} {/* Row 2 */}
<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" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
Supplier : Supplier :
</label> </label>
<div className="text-muted">{data?.supplerName}</div> <div className="text-muted">{data?.supplerName}</div>
</div> </div>
</div> </div>
<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" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
Amount : Amount :
</label> </label>
<div className="text-muted"> {data.amount}</div> <div className="text-muted"> {data.amount}</div>
@ -173,22 +172,17 @@ const ViewExpense = ({ ExpenseId }) => {
{/* Row 3 */} {/* Row 3 */}
<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" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
Payment Mode : Payment Mode :
</label> </label>
<div className="text-muted">{data?.paymentMode?.name}</div> <div className="text-muted">{data?.paymentMode?.name}</div>
</div> </div>
</div> </div>
{data?.gstNumber && ( {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" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
GST Number : GST Number :
</label> </label>
<div className="text-muted">{data?.gstNumber}</div> <div className="text-muted">{data?.gstNumber}</div>
@ -196,135 +190,89 @@ const ViewExpense = ({ ExpenseId }) => {
</div> </div>
)} )}
{/* Row 4 */}
<div className="col-md-6 mb-3">
<div className="d-flex">
<label
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
Status :
</label>
<span
className={`badge bg-label-${
getColorNameFromHex(data?.status?.color) || "secondary"
}`}
>
{data?.status?.name}
</span>
</div>
</div>
<div className="col-md-6 mb-3">
<div className="d-flex">
<label
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
Pre-Approved :
</label>
<div className="text-muted">
{data.preApproved ? "Yes" : "No"}
</div>
</div>
</div>
<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" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold text-start" Pre-Approved :
style={{ minWidth: "130px" }} </label>
> <div className="text-muted">{data.preApproved ? "Yes" : "No"}</div>
</div>
</div>
{/* Row 5 */}
<div className="col-md-6 mb-3">
<div className="d-flex">
<label className="form-label me-2 mb-0 fw-semibold text-start" style={{ minWidth: "130px" }}>
Project : Project :
</label> </label>
<div className="text-muted">{data?.project?.name}</div> <div className="text-muted">{data?.project?.name}</div>
</div> </div>
</div> </div>
<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" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold text-start"
style={{ minWidth: "130px" }}
>
Created At : Created At :
</label> </label>
<div className="text-muted"> <div className="text-muted">{formatUTCToLocalTime(data?.createdAt, true)}</div>
{formatUTCToLocalTime(data?.createdAt, true)}
</div>
</div> </div>
</div> </div>
{/* Row 6 */} {/* Created & Paid By */}
{data.createdBy && ( {data.createdBy && (
<div className="col-md-6 text-start"> <div className="col-md-6 text-start mb-3">
<div className="d-flex align-items-center"> <div className="d-flex align-items-center">
<label <label className="form-label me-2 mb-0 fw-semibold" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold"
style={{ minWidth: "130px" }}
>
Created By : Created By :
</label> </label>
<div className="d-flex align-items-center">
<Avatar <Avatar
size="xs" size="xs"
classAvatar="m-0" classAvatar="m-0 me-1"
firstName={data.createdBy?.firstName} firstName={data.createdBy?.firstName}
lastName={data.createdBy?.lastName} lastName={data.createdBy?.lastName}
/> />
<span className="text-muted"> <span className="text-muted">
{`${data.createdBy?.firstName ?? ""} ${ {`${data.createdBy?.firstName ?? ""} ${data.createdBy?.lastName ?? ""}`.trim() || "N/A"}
data.createdBy?.lastName ?? ""
}`.trim() || "N/A"}
</span> </span>
</div> </div>
</div> </div>
</div>
)} )}
<div className="col-md-6 text-start">
<div className="col-md-6 text-start mb-3">
<div className="d-flex align-items-center"> <div className="d-flex align-items-center">
<label <label className="form-label me-2 mb-0 fw-semibold" style={{ minWidth: "130px" }}>
className="form-label me-2 mb-0 fw-semibold"
style={{ minWidth: "130px" }}
>
Paid By : Paid By :
</label> </label>
<div className="d-flex align-items-center ">
<Avatar <Avatar
size="xs" size="xs"
classAvatar="m-0" classAvatar="m-0 me-1"
firstName={data.paidBy?.firstName} firstName={data.paidBy?.firstName}
lastName={data.paidBy?.lastName} lastName={data.paidBy?.lastName}
/> />
<span className="text-muted"> <span className="text-muted">
{`${data.paidBy?.firstName ?? ""} ${ {`${data.paidBy?.firstName ?? ""} ${data.paidBy?.lastName ?? ""}`.trim() || "N/A"}
data.paidBy?.lastName ?? ""
}`.trim() || "N/A"}
</span> </span>
</div> </div>
</div> </div>
</div>
<div className="text-start my-1"> {/* Description */}
<div className="col-12 text-start mb-2">
<label className="fw-semibold form-label">Description : </label> <label className="fw-semibold form-label">Description : </label>
<div className="text-muted">{data?.description}</div> <div className="text-muted">{data?.description}</div>
</div> </div>
<div className="col-12 text-start"> {/* Attachments */}
<label className="form-label me-2 mb-2 fw-semibold"> <div className="col-12 text-start mb-2">
Attachment : <label className="form-label me-2 mb-2 fw-semibold">Attachment :</label>
</label>
<div className="d-flex flex-wrap gap-2"> <div className="d-flex flex-wrap gap-2">
{data?.documents?.map((doc) => { {data?.documents?.map((doc) => {
const isImage = doc.contentType?.includes("image"); const isImage = doc.contentType?.includes("image");
return ( return (
<div <div
key={doc.documentId} key={doc.documentId}
className="border rounded hover-scale p-2 d-flex flex-column align-items-center" className="d-flex align-items-center cusor-pointer"
style={{
width: "80px",
cursor: isImage ? "pointer" : "default",
}}
onClick={() => { onClick={() => {
if (isImage) { if (isImage) {
setDocumentView({ setDocumentView({
@ -334,14 +282,8 @@ const ViewExpense = ({ ExpenseId }) => {
} }
}} }}
> >
<i <i className={`bx ${getIconByFileType(doc.contentType)}`} style={{ fontSize: "30px" }}></i>
className={`bx ${getIconByFileType(doc.contentType)}`} <small className="text-center text-tiny text-truncate w-100" title={doc.fileName}>
style={{ fontSize: "30px" }}
></i>
<small
className="text-center text-tiny text-truncate w-100"
title={doc.fileName}
>
{doc.fileName} {doc.fileName}
</small> </small>
</div> </div>
@ -350,141 +292,19 @@ const ViewExpense = ({ ExpenseId }) => {
</div> </div>
</div> </div>
{data.expensesReimburse && ( {/* ... your remaining conditional sections */}
<div className="row text-start mt-2">
<div className="col-md-6 mb-sm-0 mb-2">
<label className="form-label me-2 mb-0 fw-semibold">
Transaction ID :
</label>
{data.expensesReimburse.reimburseTransactionId || "N/A"}
</div> </div>
<div className="col-md-6 ">
<label className="form-label me-2 mb-0 fw-semibold">
Reimburse Date :
</label>
{formatUTCToLocalTime(data.expensesReimburse.reimburseDate)}
</div> </div>
{data.expensesReimburse && ( <div className="col-12 col-lg-5 col-xl-4">
<> <div className="d-flex align-items-center text-secondary my-2">
<div className="col-md-6 d-flex align-items-center"> <i className='bx bx-time-five me-2'></i> <p className=" m-0">TimeLine</p>
<label className="form-label me-2 mb-0 fw-semibold">
Reimburse By :
</label>
<Avatar
size="xs"
classAvatar="m-0 me-1"
firstName={
data?.expensesReimburse?.reimburseBy?.firstName
}
lastName={
data?.expensesReimburse?.reimburseBy?.lastName
}
/>
<span className="text-muted">
{`${data?.expensesReimburse?.reimburseBy?.firstName} ${data?.expensesReimburse?.reimburseBy?.lastName}`.trim()}
</span>
</div> </div>
</>
)}
</div>
)}
{Array.isArray(data?.nextStatus) && data.nextStatus.length > 0 && (
<>
{IsPaymentProcess && nextStatusWithPermission?.length > 0 && (
<div className="row">
<div className="col-12 col-md-6 text-start">
<label className="form-label">Transaction Id </label>
<input
type="text"
className="form-control form-control-sm"
{...register("reimburseTransactionId")}
/>
{errors.reimburseTransactionId && (
<small className="danger-text">
{errors.reimburseTransactionId.message}
</small>
)}
</div>
<div className="col-12 col-md-6 text-start">
<label className="form-label">Transaction Date </label>
<DatePicker
name="reimburseDate"
control={control}
minDate={data?.createdAt}
maxDate={new Date()}
/>
{errors.reimburseDate && (
<small className="danger-text">
{errors.reimburseDate.message}
</small>
)}
</div>
<div className="col-12 col-md-6 text-start">
<label className="form-label">Reimburse By </label>
<EmployeeSearchInput
control={control}
name="reimburseById"
projectId={null}
/>
</div>
</div>
)}
<div className="col-12 mb-3 text-start">
{((nextStatusWithPermission.length > 0 &&
!IsRejectedExpense) ||
(IsRejectedExpense && isCreatedBy)) && (
<>
<Label className="form-label me-2 mb-0" required>
Comment
</Label>
<textarea
className="form-control form-control-sm"
{...register("comment")}
rows="2"
/>
{errors.comment && (
<small className="danger-text">
{errors.comment.message}
</small>
)}
</>
)}
{nextStatusWithPermission?.length > 0 &&
(!IsRejectedExpense || isCreatedBy) && (
<div className="text-end flex-wrap gap-2 my-2 mt-3">
{nextStatusWithPermission.map((status, index) => (
<button
key={status.id || index}
type="button"
onClick={() => {
setClickedStatusId(status.id);
setValue("statusId", status.id);
handleSubmit(onSubmit)();
}}
disabled={isPending || isFetching}
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>
</>
)}
</div>
</div>
<div className="col-12 col-md-5">
<div className="row">
<ExpenseStatusLogs data={data} /> <ExpenseStatusLogs data={data} />
</div> </div>
</div> </div>
</div>
</form> </form>
); );
}; };

View File

@ -11,7 +11,8 @@ const Timeline = ({ items = [], transparent = true }) => {
transparent ? "timeline-transparent text-start" : "" transparent ? "timeline-transparent text-start" : ""
}`} }`}
> >
{items && items?.map((item) => ( {items &&
items?.map((item) => (
<li <li
key={item.id} key={item.id}
className={`timeline-item ${ className={`timeline-item ${
@ -27,7 +28,11 @@ const Timeline = ({ items = [], transparent = true }) => {
<div className="timeline-event"> <div className="timeline-event">
<div className="timeline-header mb-3 d-flex justify-content-between"> <div className="timeline-header mb-3 d-flex justify-content-between">
<h6 className="mb-0 text-body">{item.title}</h6> <h6 className="mb-0 text-body">{item.title}</h6>
<small className="text-body-secondary"><Tooltip text={formatUTCToLocalTime(item.timeAgo,true)}>{moment.utc(item.timeAgo).local().fromNow()}</Tooltip></small> <small className="text-body-secondary">
<Tooltip text={formatUTCToLocalTime(item.timeAgo, true)}>
{moment.utc(item.timeAgo).local().fromNow()}
</Tooltip>
</small>
</div> </div>
{item.description && <p className="mb-2">{item.description}</p>} {item.description && <p className="mb-2">{item.description}</p>}
@ -89,7 +94,8 @@ const Timeline = ({ items = [], transparent = true }) => {
</li> </li>
))} ))}
{!items || items.length == 0 && ( {!items ||
(items.length == 0 && (
<li <li
className={`timeline-item text-center ${ className={`timeline-item text-center ${
transparent ? "timeline-item-transparent" : "" transparent ? "timeline-item-transparent" : ""
@ -97,7 +103,7 @@ const Timeline = ({ items = [], transparent = true }) => {
> >
Not action yet. Not action yet.
</li> </li>
)} ))}
</ul> </ul>
); );
}; };