fixed PmsGrid header
This commit is contained in:
parent
7329319417
commit
73f437e911
18
public/assets/vendor/css/core.css
vendored
18
public/assets/vendor/css/core.css
vendored
@ -480,6 +480,24 @@ th {
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
.vs-th {
|
||||
position: relative;
|
||||
border: none;
|
||||
background-color: #f8f9fa;
|
||||
padding: 0.75rem 1rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
.vs-th::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 6px;
|
||||
bottom: 6px;
|
||||
width: 1px;
|
||||
background-color: #dee2e6;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
|
||||
@ -26,14 +26,18 @@ import { useNavigate } from "react-router-dom";
|
||||
const ExpenseList = ({ filters, groupBy = "transactionDate", searchText }) => {
|
||||
const [deletingId, setDeletingId] = useState(null);
|
||||
const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const { setViewExpense, setManageExpenseModal, filterData, removeFilterChip } = useExpenseContext();
|
||||
const {
|
||||
setViewExpense,
|
||||
setManageExpenseModal,
|
||||
filterData,
|
||||
removeFilterChip,
|
||||
} = useExpenseContext();
|
||||
const IsExpenseEditable = useHasUserPermission();
|
||||
const IsExpesneApprpve = useHasUserPermission(APPROVE_EXPENSE);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const debouncedSearch = useDebounce(searchText, 500);
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
const { mutate: DeleteExpense, isPending } = useDeleteExpense();
|
||||
const { data, isLoading, isError, isInitialLoading, error } = useExpenseList(
|
||||
ITEMS_PER_PAGE,
|
||||
@ -80,8 +84,9 @@ const ExpenseList = ({ filters, groupBy = "transactionDate", searchText }) => {
|
||||
displayField = "Status";
|
||||
break;
|
||||
case "submittedBy":
|
||||
key = `${item?.createdBy?.firstName ?? ""} ${item.createdBy?.lastName ?? ""
|
||||
}`.trim();
|
||||
key = `${item?.createdBy?.firstName ?? ""} ${
|
||||
item.createdBy?.lastName ?? ""
|
||||
}`.trim();
|
||||
displayField = "Submitted By";
|
||||
break;
|
||||
case "project":
|
||||
@ -139,11 +144,14 @@ const ExpenseList = ({ filters, groupBy = "transactionDate", searchText }) => {
|
||||
label: "Submitted By",
|
||||
align: "text-start",
|
||||
getValue: (e) =>
|
||||
`${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? ""
|
||||
}`.trim() || "N/A",
|
||||
`${e.createdBy?.firstName ?? ""} ${
|
||||
e.createdBy?.lastName ?? ""
|
||||
}`.trim() || "N/A",
|
||||
customRender: (e) => (
|
||||
<div className="d-flex align-items-center cursor-pointer"
|
||||
onClick={() => navigate(`/employee/${e.createdBy?.id}`)}>
|
||||
<div
|
||||
className="d-flex align-items-center cursor-pointer"
|
||||
onClick={() => navigate(`/employee/${e.createdBy?.id}`)}
|
||||
>
|
||||
<Avatar
|
||||
size="xs"
|
||||
classAvatar="m-0"
|
||||
@ -151,8 +159,9 @@ const ExpenseList = ({ filters, groupBy = "transactionDate", searchText }) => {
|
||||
lastName={e.createdBy?.lastName}
|
||||
/>
|
||||
<span className="text-truncate">
|
||||
{`${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? ""
|
||||
}`.trim() || "N/A"}
|
||||
{`${e.createdBy?.firstName ?? ""} ${
|
||||
e.createdBy?.lastName ?? ""
|
||||
}`.trim() || "N/A"}
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
@ -176,10 +185,9 @@ const ExpenseList = ({ filters, groupBy = "transactionDate", searchText }) => {
|
||||
align: "text-center",
|
||||
getValue: (e) => (
|
||||
<span
|
||||
className={`badge bg-label-${getColorNameFromHex(e?.status?.color) || "secondary"
|
||||
}`}
|
||||
className={`badge bg-label-${getColorNameFromHex(e?.status?.color) || "secondary"
|
||||
}`}
|
||||
className={`badge bg-label-${
|
||||
getColorNameFromHex(e?.status?.color) || "secondary"
|
||||
}`}
|
||||
>
|
||||
{e.status?.name || "Unknown"}
|
||||
</span>
|
||||
|
||||
@ -107,8 +107,8 @@ const router = createBrowserRouter(
|
||||
{ path: "/tenant/self", element: <SelfTenantDetails /> },
|
||||
{ path: "/organizations", element: <OrganizationPage /> },
|
||||
{ path: "/help/support", element: <Support /> },
|
||||
{ path: "/help/docs", element: <Documentation /> },
|
||||
{ path: "/help/connect", element: <DemoBOQGrid /> },
|
||||
{ path: "/help/docs", element: <DemoBOQGrid /> },
|
||||
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@ -190,7 +190,6 @@ const boqColumns = [
|
||||
*/
|
||||
export default function DemoBOQGrid() {
|
||||
useEffect(() => {
|
||||
// 🔥 Initialize Bootstrap popovers after first render
|
||||
initPopover();
|
||||
}, []);
|
||||
const wrapperRef = useRef()
|
||||
@ -204,15 +203,7 @@ useEffect(() => {
|
||||
}, []);
|
||||
return (
|
||||
<div className="container-fluid py-3">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary"
|
||||
data-bs-toggle="popover"
|
||||
data-bs-placement="right"
|
||||
data-bs-content="This is a popover via CDN!"
|
||||
>
|
||||
Click me
|
||||
</button>
|
||||
|
||||
|
||||
<div className="card p-3">
|
||||
<PmsGrid
|
||||
|
||||
@ -135,16 +135,20 @@ export default function PmsGrid({
|
||||
|
||||
return (
|
||||
<div className="pms-grid">
|
||||
<div className="d-flex justify-content-between mb-2">
|
||||
<div className="d-flex gap-2 align-items-center">
|
||||
{features.search && (
|
||||
<div className="row mb-2">
|
||||
<div className="col-8">
|
||||
<div className="d-flex flex-row gap-2 gap-2 ">
|
||||
<div>
|
||||
{features.search && (
|
||||
<input
|
||||
type="search"
|
||||
className="form-control form-control-sm"
|
||||
placeholder="Search..."
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{features.export && (
|
||||
<button
|
||||
className="btn btn-sm btn-outline-secondary"
|
||||
@ -159,8 +163,9 @@ export default function PmsGrid({
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="d-flex gap-2">
|
||||
</div>
|
||||
<div className="col-4 ">
|
||||
<div className="d-flex justify-content-end gap-2">
|
||||
{features.columnVisibility && (
|
||||
<ColumnVisibilityPanel
|
||||
columns={colState}
|
||||
@ -186,15 +191,16 @@ export default function PmsGrid({
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className="grid-wrapper"
|
||||
className="grid-wrapper text-nowrap"
|
||||
style={{ maxHeight: features.maxHeight || "60vh" }}
|
||||
>
|
||||
<table className="table table-sm table-bordered mb-0">
|
||||
<table className="table table-sm mb-0">
|
||||
<thead
|
||||
className="table-light"
|
||||
className="bg-light-secondary"
|
||||
style={{ position: "sticky", top: 0, zIndex: 3 }}
|
||||
>
|
||||
<tr>
|
||||
@ -202,7 +208,7 @@ export default function PmsGrid({
|
||||
<th style={{ width: 32 }} className="text-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
className="form-check-input mx-3"
|
||||
checked={
|
||||
currentRows.length > 0 &&
|
||||
currentRows.every((r) => selected.has(r[rowKey]))
|
||||
@ -232,19 +238,25 @@ export default function PmsGrid({
|
||||
onDragStart={(e) => onDragStart(e, col.key)}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
onDrop={(e) => onDrop(e, col.key)}
|
||||
className={`pms-col-header ${col.pinned ? "pinned" : ""}`}
|
||||
className={`pms-col-header vs-th ${
|
||||
col.pinned ? "pinned" : ""
|
||||
}`}
|
||||
style={style}
|
||||
>
|
||||
<div className="d-flex align-items-center justify-content-between">
|
||||
<div className="d-flex align-items-center justify-content-between px-1">
|
||||
<div
|
||||
onClick={() => col.sortable && changeSort(col.key)}
|
||||
style={{ cursor: col.sortable ? "pointer" : "default" }}
|
||||
>
|
||||
<strong>{col.title}</strong>
|
||||
{sortBy.key === col.key && (
|
||||
<small className="ms-2 text-muted">
|
||||
[{sortBy.dir}]
|
||||
</small>
|
||||
<i
|
||||
className={`bx bx-sm ${
|
||||
sortBy.dir === "asc"
|
||||
? "bxs-chevron-up"
|
||||
: "bxs-chevron-down"
|
||||
}`}
|
||||
></i>
|
||||
)}
|
||||
</div>
|
||||
<div className="d-flex align-items-center gap-1">
|
||||
@ -270,7 +282,7 @@ export default function PmsGrid({
|
||||
})}
|
||||
{features.actions && (
|
||||
<th
|
||||
className="text-center sticky-action-column"
|
||||
className="text-center sticky-action-column vs-th bg-white"
|
||||
style={{ position: "sticky", right: 0, zIndex: 5 }}
|
||||
>
|
||||
Actions
|
||||
@ -357,12 +369,12 @@ export default function PmsGrid({
|
||||
function renderRow(row) {
|
||||
return (
|
||||
<React.Fragment key={row[rowKey]}>
|
||||
<tr>
|
||||
<tr className={`${selected.has(row[rowKey]) ? "bg-light" : ""}`}>
|
||||
{features.selection && (
|
||||
<td className="text-center p-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
className="form-check-input"
|
||||
checked={selected.has(row[rowKey])}
|
||||
onChange={() => toggleSelect(row[rowKey])}
|
||||
/>
|
||||
@ -379,13 +391,17 @@ export default function PmsGrid({
|
||||
if (col.pinned === "right")
|
||||
style.right = `${getRightOffset(colState, col.key)}px`;
|
||||
return (
|
||||
<td key={col.key} style={style}>
|
||||
<td
|
||||
key={col.key}
|
||||
style={style}
|
||||
className={col.pinned ? "bg-white" : ""}
|
||||
>
|
||||
{col.render ? col.render(row) : row[col.key] ?? ""}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
{features.actions && (
|
||||
<td className="text-center sticky-action-column">
|
||||
<td className="text-center sticky-action-column bg-white">
|
||||
{features.actions(row, toggleExpand)}
|
||||
</td>
|
||||
)}
|
||||
@ -461,3 +477,4 @@ function ColumnVisibilityPanel({ columns, onToggle }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user