initially setup poject infra in PmsGrid
This commit is contained in:
parent
7b0659e820
commit
d96a1a88ec
35
src/components/Project/pmsInfrastructure/BuildingTable.jsx
Normal file
35
src/components/Project/pmsInfrastructure/BuildingTable.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import FloorTable from "./FloorTable";
|
||||||
|
import { useSelectedProject } from "../../../slices/apiDataManager";
|
||||||
|
import { useProjectInfra } from "../../../hooks/useProjects";
|
||||||
|
import { PmsGrid } from "../../../services/pmsGrid";
|
||||||
|
|
||||||
|
export default function BuildingTable() {
|
||||||
|
const project = useSelectedProject()
|
||||||
|
|
||||||
|
const {projectInfra} = useProjectInfra(project,null)
|
||||||
|
const columns = [
|
||||||
|
{ key: "buildingName", title: "Building", sortable: true,},
|
||||||
|
{ key: "plannedWork", title: "Planned Work" },
|
||||||
|
{ key: "completedWork", title: "Completed Work" },
|
||||||
|
{ key: "percentage", title: "Completion %" },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PmsGrid
|
||||||
|
columns={columns}
|
||||||
|
data={projectInfra}
|
||||||
|
rowKey="id"
|
||||||
|
features={{
|
||||||
|
expand: true,
|
||||||
|
pinning: true,
|
||||||
|
resizing: true,
|
||||||
|
selection: true,
|
||||||
|
}}
|
||||||
|
renderExpanded={(building) => (
|
||||||
|
<FloorTable floors={building.floors} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
28
src/components/Project/pmsInfrastructure/FloorTable.jsx
Normal file
28
src/components/Project/pmsInfrastructure/FloorTable.jsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React from "react";
|
||||||
|
import WorkAreaTable from "./WorkAreaTable";
|
||||||
|
import { PmsGrid } from "../../../services/pmsGrid";
|
||||||
|
|
||||||
|
export default function FloorTable({ floors }) {
|
||||||
|
const columns = [
|
||||||
|
{ key: "floorName", title: "Floor", sortable: true, },
|
||||||
|
{ key: "plannedWork", title: "Planned Work" },
|
||||||
|
{ key: "completedWork", title: "Completed Work" },
|
||||||
|
{ key: "percentage", title: "Completion %" },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PmsGrid
|
||||||
|
columns={columns}
|
||||||
|
data={floors}
|
||||||
|
rowKey="id"
|
||||||
|
features={{
|
||||||
|
expand: true,
|
||||||
|
pinning: true,
|
||||||
|
resizing: true,
|
||||||
|
}}
|
||||||
|
renderExpanded={(floor) => (
|
||||||
|
<WorkAreaTable workAreas={floor.workAreas} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
39
src/components/Project/pmsInfrastructure/WorkAreaTable.jsx
Normal file
39
src/components/Project/pmsInfrastructure/WorkAreaTable.jsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { PmsGrid } from "../../../services/pmsGrid";
|
||||||
|
// import { GridService } from "./gridService";
|
||||||
|
// import TaskTable from "./TaskTable";
|
||||||
|
|
||||||
|
export default function WorkAreaTable({ workAreas }) {
|
||||||
|
const [taskData, setTaskData] = useState({}); // workAreaId → tasks
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ key: "areaName", title: "Work Area", },
|
||||||
|
{ key: "plannedWork", title: "Planned Work" },
|
||||||
|
{ key: "completedWork", title: "Completed Work" },
|
||||||
|
{ key: "percentage", title: "Completion %" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// const loadTasks = async (workAreaId) => {
|
||||||
|
// if (!taskData[workAreaId]) {
|
||||||
|
// const res = await GridService.getTasksByWorkArea(workAreaId);
|
||||||
|
// setTaskData((prev) => ({ ...prev, [workAreaId]: res }));
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PmsGrid
|
||||||
|
columns={columns}
|
||||||
|
data={workAreas}
|
||||||
|
rowKey="id"
|
||||||
|
features={{
|
||||||
|
expand: true,
|
||||||
|
pinning: true,
|
||||||
|
resizing: true,
|
||||||
|
}}
|
||||||
|
// renderExpanded={(area) => {
|
||||||
|
// loadTasks(area.id);
|
||||||
|
// return <TaskTable tasks={taskData[area.id]} />;
|
||||||
|
// }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -24,6 +24,7 @@ import { useProjectAccess } from "../../hooks/useProjectAccess";
|
|||||||
|
|
||||||
import "./ProjectDetails.css";
|
import "./ProjectDetails.css";
|
||||||
import ProjectOrganizations from "../../components/Project/ProjectOrganizations";
|
import ProjectOrganizations from "../../components/Project/ProjectOrganizations";
|
||||||
|
import BuildingTable from "../../components/Project/pmsInfrastructure/BuildingTable";
|
||||||
|
|
||||||
const ProjectDetails = () => {
|
const ProjectDetails = () => {
|
||||||
const projectId = useSelectedProject();
|
const projectId = useSelectedProject();
|
||||||
@ -88,7 +89,7 @@ const ProjectDetails = () => {
|
|||||||
case "teams":
|
case "teams":
|
||||||
return <Teams />;
|
return <Teams />;
|
||||||
case "infra":
|
case "infra":
|
||||||
return <ProjectInfra data={projects_Details} onDataChange={refetch} />;
|
return <BuildingTable/>
|
||||||
case "workplan":
|
case "workplan":
|
||||||
return <WorkPlan data={projects_Details} onDataChange={refetch} />;
|
return <WorkPlan data={projects_Details} onDataChange={refetch} />;
|
||||||
case "directory":
|
case "directory":
|
||||||
|
|||||||
@ -738,7 +738,7 @@ export default function DemoBOQGrid() {
|
|||||||
reorder: true,
|
reorder: true,
|
||||||
columnVisibility: true,
|
columnVisibility: true,
|
||||||
pageSizeSelector: true,
|
pageSizeSelector: true,
|
||||||
// groupByKey: "category",
|
// groupByKey: "status",
|
||||||
aggregation: true,
|
aggregation: true,
|
||||||
expand: true,
|
expand: true,
|
||||||
maxHeight: "70vh",
|
maxHeight: "70vh",
|
||||||
@ -753,11 +753,7 @@ export default function DemoBOQGrid() {
|
|||||||
icon: "bx-trash text-danger",
|
icon: "bx-trash text-danger",
|
||||||
onClick: (row) => console.log("Delete", row),
|
onClick: (row) => console.log("Delete", row),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: "View",
|
|
||||||
icon: "bx-show text-info",
|
|
||||||
onClick: (row) => console.log("View ", row),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
renderExpanded={(row) => (
|
renderExpanded={(row) => (
|
||||||
|
|||||||
@ -170,6 +170,7 @@ export default function PmsGrid({
|
|||||||
Export CSV
|
Export CSV
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-4 ">
|
<div className="col-4 ">
|
||||||
@ -235,10 +236,8 @@ export default function PmsGrid({
|
|||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
)}
|
)}
|
||||||
{features.expand && (
|
{features.expand && (
|
||||||
<th
|
<th className="text-center ticky-action-column">
|
||||||
className="text-center ticky-action-column"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="form-check-input mx-3"
|
className="form-check-input mx-3"
|
||||||
@ -270,7 +269,7 @@ export default function PmsGrid({
|
|||||||
key={col.key}
|
key={col.key}
|
||||||
draggable={features.reorder}
|
draggable={features.reorder}
|
||||||
onDragStart={(e) => onDragStart(e, col.key)}
|
onDragStart={(e) => onDragStart(e, col.key)}
|
||||||
onDragOver={(e)=> e.preventDefault()}
|
onDragOver={(e) => e.preventDefault()}
|
||||||
onDrop={(e) => onDrop(e, col.key)}
|
onDrop={(e) => onDrop(e, col.key)}
|
||||||
className={`pms-col-header vs-th ${
|
className={`pms-col-header vs-th ${
|
||||||
col.pinned ? `pinned pinned-${col.pinned}` : ""
|
col.pinned ? `pinned pinned-${col.pinned}` : ""
|
||||||
@ -356,6 +355,7 @@ export default function PmsGrid({
|
|||||||
(features.selection ? 1 : 0) +
|
(features.selection ? 1 : 0) +
|
||||||
(features.actions ? 1 : 0)
|
(features.actions ? 1 : 0)
|
||||||
}
|
}
|
||||||
|
className="text-start"
|
||||||
>
|
>
|
||||||
<strong>{g.key}</strong>
|
<strong>{g.key}</strong>
|
||||||
{features.aggregation &&
|
{features.aggregation &&
|
||||||
@ -406,128 +406,127 @@ export default function PmsGrid({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// render a single row (function hoisted so it can reference visibleColumns)
|
// render a single row (function hoisted so it can reference visibleColumns)
|
||||||
function renderRow(row) {
|
function renderRow(row) {
|
||||||
const isSelected = selected.has(row[rowKey]);
|
const isSelected = selected.has(row[rowKey]);
|
||||||
const isExpanded = expanded.has(row[rowKey]);
|
const isExpanded = expanded.has(row[rowKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={row[rowKey]}>
|
<React.Fragment key={row[rowKey]}>
|
||||||
<tr>
|
<tr>
|
||||||
{/* Selection checkbox (always left) */}
|
{/* Selection checkbox (always left) */}
|
||||||
{features.selection && (
|
{features.selection && (
|
||||||
<td className="text-center align-middle p-2">
|
<td className="text-center align-middle p-2">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="form-check-input"
|
className="form-check-input"
|
||||||
checked={isSelected}
|
checked={isSelected}
|
||||||
onChange={() => toggleSelect(row[rowKey])}
|
onChange={() => toggleSelect(row[rowKey])}
|
||||||
/>
|
/>
|
||||||
</td>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Expand toggle next to selection */}
|
|
||||||
{features.expand && (
|
|
||||||
<td className="text-center align-middle p-2">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-link p-0 border-0 text-secondary"
|
|
||||||
onClick={() => toggleExpand(row[rowKey])}
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
className={`bx ${
|
|
||||||
isExpanded ? "bxs-chevron-up" : "bxs-chevron-down"
|
|
||||||
} bx-sm`}
|
|
||||||
></i>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Data columns */}
|
|
||||||
{visibleColumns.map((col) => {
|
|
||||||
const style = {
|
|
||||||
minWidth: col.width || 120,
|
|
||||||
width: col.width || undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (col.pinned) style.position = "sticky";
|
|
||||||
if (col.pinned === "left")
|
|
||||||
style.left = `${getLeftOffset(colState, col.key)}px`;
|
|
||||||
if (col.pinned === "right")
|
|
||||||
style.right = `${getRightOffset(colState, col.key)}px`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<td
|
|
||||||
key={col.key}
|
|
||||||
style={style}
|
|
||||||
className={`${col.className ?? ""} ${
|
|
||||||
col.pinned
|
|
||||||
? "pinned-left px-3 bg-white pms-grid td pinned"
|
|
||||||
: "px-3"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{col.render ? col.render(row) : row[col.key] ?? ""}
|
|
||||||
</td>
|
</td>
|
||||||
);
|
)}
|
||||||
})}
|
|
||||||
|
|
||||||
{/* Actions column (always right) */}
|
{/* Expand toggle next to selection */}
|
||||||
{features.actions && (
|
{features.expand && (
|
||||||
<td
|
<td className="text-center align-middle p-2">
|
||||||
className="text-center sticky-action-column bg-white td-lastChild"
|
<button
|
||||||
style={{
|
type="button"
|
||||||
position: "sticky",
|
className="btn btn-link p-0 border-0 text-secondary"
|
||||||
right: 0,
|
onClick={() => toggleExpand(row[rowKey])}
|
||||||
zIndex: 2,
|
>
|
||||||
width: "1%",
|
<i
|
||||||
whiteSpace: "nowrap",
|
className={`bx ${
|
||||||
}}
|
isExpanded ? "bxs-chevron-up" : "bxs-chevron-down"
|
||||||
>
|
} bx-sm`}
|
||||||
<div
|
></i>
|
||||||
className="d-inline-flex justify-content-center align-items-center gap-2"
|
</button>
|
||||||
style={{ minWidth: "fit-content", padding: "0 4px" }}
|
</td>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Data columns */}
|
||||||
|
{visibleColumns.map((col) => {
|
||||||
|
const style = {
|
||||||
|
minWidth: col.width || 120,
|
||||||
|
width: col.width || undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (col.pinned) style.position = "sticky";
|
||||||
|
if (col.pinned === "left")
|
||||||
|
style.left = `${getLeftOffset(colState, col.key)}px`;
|
||||||
|
if (col.pinned === "right")
|
||||||
|
style.right = `${getRightOffset(colState, col.key)}px`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td
|
||||||
|
key={col.key}
|
||||||
|
style={style}
|
||||||
|
className={`${col.className ?? ""} ${
|
||||||
|
col.pinned
|
||||||
|
? "pinned-left px-3 bg-white pms-grid td pinned"
|
||||||
|
: "px-3"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{col.render ? col.render(row) : row[col.key] ?? ""}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
{/* Actions column (always right) */}
|
||||||
|
{features.actions && (
|
||||||
|
<td
|
||||||
|
className="text-center sticky-action-column bg-white td-lastChild"
|
||||||
|
style={{
|
||||||
|
position: "sticky",
|
||||||
|
right: 0,
|
||||||
|
zIndex: 2,
|
||||||
|
width: "1%",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{Array.isArray(features.actions)
|
<div
|
||||||
? features.actions.map((act, i) => (
|
className="d-inline-flex justify-content-center align-items-center gap-2"
|
||||||
<button
|
style={{ minWidth: "fit-content", padding: "0 4px" }}
|
||||||
key={i}
|
>
|
||||||
type="button"
|
{Array.isArray(features.actions)
|
||||||
className="btn btn-link p-0 border-0"
|
? features.actions.map((act, i) => (
|
||||||
title={act.label}
|
<button
|
||||||
onClick={(e) => {
|
key={i}
|
||||||
e.stopPropagation();
|
type="button"
|
||||||
act.onClick && act.onClick(row);
|
className="btn btn-link p-0 border-0"
|
||||||
}}
|
title={act.label}
|
||||||
>
|
onClick={(e) => {
|
||||||
<i className={`bx ${act.icon}`} />
|
e.stopPropagation();
|
||||||
</button>
|
act.onClick && act.onClick(row);
|
||||||
))
|
}}
|
||||||
: typeof features.actions === "function"
|
>
|
||||||
? features.actions(row, toggleExpand)
|
<i className={`bx ${act.icon}`} />
|
||||||
: null}
|
</button>
|
||||||
</div>
|
))
|
||||||
</td>
|
: typeof features.actions === "function"
|
||||||
)}
|
? features.actions(row, toggleExpand)
|
||||||
</tr>
|
: null}
|
||||||
|
</div>
|
||||||
{/* 🔹 5. Expanded row content (full width) */}
|
</td>
|
||||||
{isExpanded && renderExpanded && (
|
)}
|
||||||
<tr className="table-active">
|
|
||||||
<td
|
|
||||||
colSpan={
|
|
||||||
visibleColumns.length +
|
|
||||||
(features.selection ? 1 : 0) +
|
|
||||||
(features.expand ? 1 : 0) +
|
|
||||||
(features.actions ? 1 : 0)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{renderExpanded(row)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
{/* 🔹 5. Expanded row content (full width) */}
|
||||||
|
{isExpanded && renderExpanded && (
|
||||||
|
<tr className="table-active">
|
||||||
|
<td
|
||||||
|
colSpan={
|
||||||
|
visibleColumns.length +
|
||||||
|
(features.selection ? 1 : 0) +
|
||||||
|
(features.expand ? 1 : 0) +
|
||||||
|
(features.actions ? 1 : 0)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{renderExpanded(row)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// small helpers to compute sticky offsets
|
// small helpers to compute sticky offsets
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user