added expense status logs
This commit is contained in:
parent
1e26b1261c
commit
68bd0d6bb5
5
public/assets/vendor/css/core.css
vendored
5
public/assets/vendor/css/core.css
vendored
@ -20473,7 +20473,10 @@ li:not(:first-child) .dropdown-item,
|
||||
word-wrap: break-word !important;
|
||||
word-break: break-word !important;
|
||||
}
|
||||
|
||||
/* text-size */
|
||||
.text-tiny{
|
||||
font-size: 13px;
|
||||
}
|
||||
/* rtl:end:remove */
|
||||
.text-primary {
|
||||
--bs-text-opacity: 1;
|
||||
|
||||
63
src/components/Expenses/ExpenseStatusLogs.jsx
Normal file
63
src/components/Expenses/ExpenseStatusLogs.jsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { useState } from "react";
|
||||
import Avatar from "../common/Avatar";
|
||||
|
||||
const ExpenseStatusLogs = ({ data }) => {
|
||||
const [visibleCount, setVisibleCount] = useState(4);
|
||||
|
||||
const logsToShow = data?.expenseLogs?.slice(0, visibleCount) || [];
|
||||
|
||||
const handleShowMore = () => {
|
||||
setVisibleCount((prev) => prev + 4);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="row g-2">
|
||||
{logsToShow.map((log, index) => (
|
||||
<div
|
||||
key={log.id}
|
||||
className="col-12 d-flex align-items-start mb-2"
|
||||
>
|
||||
<Avatar
|
||||
size="xs"
|
||||
firstName={log.updatedBy.firstName}
|
||||
lastName={log.updatedBy.lastName}
|
||||
/>
|
||||
|
||||
<div className="flex-grow-1">
|
||||
<div className="d-flex justify-content-start">
|
||||
<div className="text-start">
|
||||
<div >
|
||||
<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 small">{log?.updateAt ?? "14-Aug-2025"}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex align-items-center text-muted small mt-1">
|
||||
<span className="small">{log.comment}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{data?.expenseLogs?.length > visibleCount && (
|
||||
<div className="text-center my-1">
|
||||
<button
|
||||
className="btn btn-xs btn-outline-primary"
|
||||
onClick={handleShowMore}
|
||||
>
|
||||
Show More
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExpenseStatusLogs;
|
||||
@ -27,6 +27,7 @@ import { useEmployeeRoles, useEmployeesName } from "../../hooks/useEmployees";
|
||||
import EmployeeSearchInput from "../common/EmployeeSearchInput";
|
||||
import { z } from "zod";
|
||||
import moment from "moment";
|
||||
import ExpenseStatusLogs from "./ExpenseStatusLogs";
|
||||
|
||||
const ViewExpense = ({ ExpenseId }) => {
|
||||
const { data, isLoading, isError, error } = useExpense(ExpenseId);
|
||||
@ -111,7 +112,12 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
<h5 className="fw-semibold">Expense Details</h5>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div className="text-start mb-2">
|
||||
{/* <label className="form-label me-2 mb-0 fw-semibold">
|
||||
Description :
|
||||
</label> */}
|
||||
<div className="text-muted">{data?.description}</div>
|
||||
</div>
|
||||
{/* Row 1 */}
|
||||
<div className="col-md-6 mb-3">
|
||||
<div className="d-flex">
|
||||
@ -270,7 +276,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{data.reviewedBy && (
|
||||
{/* {data.reviewedBy && (
|
||||
<div className="col-md-6 mb-3 text-start">
|
||||
<div className="d-flex align-items-center">
|
||||
<label
|
||||
@ -345,17 +351,17 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
{data.expensesReimburse && (
|
||||
<div className="row text-start">
|
||||
<div className="col-md-6 mb-3">
|
||||
<div className="col-md-6 ">
|
||||
<label className="form-label me-2 mb-0 fw-semibold">
|
||||
Transaction ID :
|
||||
</label>
|
||||
{data.expensesReimburse.reimburseTransactionId || "N/A"}
|
||||
</div>
|
||||
<div className="col-md-6 mb-3">
|
||||
<div className="col-md-6 ">
|
||||
<label className="form-label me-2 mb-0 fw-semibold">
|
||||
Reimburse Date :
|
||||
</label>
|
||||
@ -364,7 +370,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
|
||||
{data.expensesReimburse && (
|
||||
<>
|
||||
<div className="col-md-6 mb-3 d-flex align-items-center">
|
||||
<div className="col-md-6 d-flex align-items-center">
|
||||
<label className="form-label me-2 mb-0 fw-semibold">
|
||||
Reimburse By :
|
||||
</label>
|
||||
@ -380,20 +386,15 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="col-md-6 mb-3">
|
||||
<label className="form-label me-2 mb-0 fw-semibold"> Note :</label>{" "}
|
||||
{data.expensesReimburse.reimburseNote}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="text-start">
|
||||
{/* <div className="text-start">
|
||||
<label className="form-label me-2 mb-0 fw-semibold">
|
||||
Description :
|
||||
</label>
|
||||
<div className="text-muted">{data?.description}</div>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="col-12 my-2 text-start">
|
||||
<label className="form-label me-2 mb-0 fw-semibold">Attachment :</label>
|
||||
|
||||
@ -488,7 +489,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
)}
|
||||
</div>
|
||||
<div className="col-12 col-md-6 text-start">
|
||||
<label className="form-label">Reimburse By </label>
|
||||
<label className="form-label">Reimburse By </label>
|
||||
<EmployeeSearchInput
|
||||
control={control}
|
||||
name="reimburseById"
|
||||
@ -540,7 +541,12 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<ExpenseStatusLogs data={data}/>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,24 +1,56 @@
|
||||
import React from 'react';
|
||||
import { useRouteError, isRouteErrorResponse } from 'react-router-dom';
|
||||
|
||||
const ErrorPage =() =>{
|
||||
const ErrorPage = () => {
|
||||
const error = useRouteError();
|
||||
console.error(error);
|
||||
console.error('Route Error:', error);
|
||||
|
||||
if (isRouteErrorResponse(error)) {
|
||||
const { status, statusText, data } = error;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{error.status}</h1>
|
||||
<p>{error.statusText}</p>
|
||||
<div className="container mt-5">
|
||||
<h1 className="text-danger">Oops! Something went wrong.</h1>
|
||||
<p className="lead">We couldn’t load the page you requested.</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<h4>Error Details</h4>
|
||||
<ul>
|
||||
<li><strong>Status:</strong> {status}</li>
|
||||
<li><strong>Status Text:</strong> {statusText}</li>
|
||||
{data && <li><strong>Message:</strong> {typeof data === 'string' ? data : JSON.stringify(data)}</li>}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
message = 'An unexpected error occurred.',
|
||||
name,
|
||||
stack,
|
||||
} = error || {};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Something went wrong.</h1>
|
||||
<p>{error?.message || 'Unknown error occurred'}</p>
|
||||
<div className="container mt-5">
|
||||
<h1 className="text-danger">Something went wrong.</h1>
|
||||
<p className="lead">Sorry, we couldn’t complete your request.</p>
|
||||
|
||||
{message && (
|
||||
<div className="alert alert-warning mt-4">
|
||||
<strong>{name ? `${name}: ` : ''}</strong>
|
||||
{message}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{stack && (
|
||||
<details className="mt-3 text-muted">
|
||||
<summary>Developer Details (Stack Trace)</summary>
|
||||
<pre>{stack}</pre>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default ErrorPage
|
||||
};
|
||||
|
||||
export default ErrorPage;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user