You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

140 lines
3.5 KiB

  1. import { manhourFormatter } from "@/app/utils/formatUtil";
  2. import {
  3. Box,
  4. Stack,
  5. Table,
  6. TableBody,
  7. TableCell,
  8. TableContainer,
  9. TableHead,
  10. TableRow,
  11. Typography,
  12. } from "@mui/material";
  13. import { useMemo } from "react";
  14. import { useTranslation } from "react-i18next";
  15. const mockItems: ResourceItem[] = [
  16. {
  17. grade: "Grade 1",
  18. title: "A. QS / QS Trainee",
  19. headcount: 20,
  20. totalAvailableManhours: 39520,
  21. loadedManhours: 3760,
  22. remainingAvailableManhours: 35760,
  23. },
  24. {
  25. grade: "Grade 2",
  26. title: "QS",
  27. headcount: 20,
  28. totalAvailableManhours: 39520,
  29. loadedManhours: 3760,
  30. remainingAvailableManhours: 35760,
  31. },
  32. {
  33. grade: "Grade 3",
  34. title: "Senior QS",
  35. headcount: 10,
  36. totalAvailableManhours: 19760,
  37. loadedManhours: 1530,
  38. remainingAvailableManhours: 18230,
  39. },
  40. {
  41. grade: "Grade 4",
  42. title: "A. Manager / Deputy Manager / Manager / S. Manager",
  43. headcount: 5,
  44. totalAvailableManhours: 9880,
  45. loadedManhours: 2760,
  46. remainingAvailableManhours: 7120,
  47. },
  48. {
  49. grade: "Grade 5",
  50. title: "A. Director / Deputy Director / Director",
  51. headcount: 20,
  52. totalAvailableManhours: 1976,
  53. loadedManhours: 374,
  54. remainingAvailableManhours: 1602,
  55. },
  56. ];
  57. interface ResourceColumn {
  58. label: string;
  59. name: keyof ResourceItem;
  60. }
  61. interface ResourceItem {
  62. grade: string;
  63. title: string;
  64. headcount: number;
  65. totalAvailableManhours: number;
  66. loadedManhours: number;
  67. remainingAvailableManhours: number;
  68. }
  69. interface Props {
  70. items?: ResourceItem[];
  71. }
  72. const ResourceCapacity: React.FC<Props> = ({ items = mockItems }) => {
  73. const { t } = useTranslation();
  74. const columns = useMemo<ResourceColumn[]>(
  75. () => [
  76. { label: t("Grade"), name: "grade" },
  77. { label: t("Title"), name: "title" },
  78. { label: t("Headcount"), name: "headcount" },
  79. { label: t("Total Available Manhours"), name: "totalAvailableManhours" },
  80. { label: t("Loaded Manhours"), name: "loadedManhours" },
  81. {
  82. label: t("Remaining Available Manhours"),
  83. name: "remainingAvailableManhours",
  84. },
  85. ],
  86. [t],
  87. );
  88. return (
  89. <Stack gap={2}>
  90. <Typography variant="overline" display="block">
  91. {t("Resource Capacity")}
  92. </Typography>
  93. <Box sx={{ marginInline: -3 }}>
  94. <TableContainer>
  95. <Table>
  96. <TableHead>
  97. <TableRow>
  98. {columns.map((column, idx) => (
  99. <TableCell key={`${column.name.toString()}${idx}`}>
  100. {column.label}
  101. </TableCell>
  102. ))}
  103. </TableRow>
  104. </TableHead>
  105. <TableBody>
  106. {items.map((item, index) => {
  107. return (
  108. <TableRow hover tabIndex={-1} key={`${item.grade}-${index}`}>
  109. {columns.map((column, idx) => {
  110. const columnName = column.name;
  111. const cellData = item[columnName];
  112. return (
  113. <TableCell key={`${columnName.toString()}-${idx}`}>
  114. {columnName !== "headcount" &&
  115. typeof cellData === "number"
  116. ? manhourFormatter.format(cellData)
  117. : cellData}
  118. </TableCell>
  119. );
  120. })}
  121. </TableRow>
  122. );
  123. })}
  124. </TableBody>
  125. </Table>
  126. </TableContainer>
  127. </Box>
  128. </Stack>
  129. );
  130. };
  131. export default ResourceCapacity;