FPSMS-frontend
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 

198 rader
5.3 KiB

  1. "use client";
  2. import React from "react";
  3. import {
  4. Box,
  5. Card,
  6. CardContent,
  7. Grid,
  8. Typography,
  9. } from "@mui/material";
  10. import Inventory2OutlinedIcon from "@mui/icons-material/Inventory2Outlined";
  11. import MonetizationOnOutlinedIcon from "@mui/icons-material/MonetizationOnOutlined";
  12. import LayersOutlinedIcon from "@mui/icons-material/LayersOutlined";
  13. import SearchOutlinedIcon from "@mui/icons-material/SearchOutlined";
  14. import LocalShippingOutlinedIcon from "@mui/icons-material/LocalShippingOutlined";
  15. import OutboundOutlinedIcon from "@mui/icons-material/OutboundOutlined";
  16. import BarChartOutlinedIcon from "@mui/icons-material/BarChartOutlined";
  17. import PieChartOutlineOutlinedIcon from "@mui/icons-material/PieChartOutlineOutlined";
  18. import type { SvgIconComponent } from "@mui/icons-material";
  19. import { REPORTS } from "@/config/reportConfig";
  20. import { REPORT_CATEGORIES, type ReportCategoryConfig } from "./reportCategories";
  21. import { useReportLabels } from "./reportI18n";
  22. const REPORT_ICON_MAP: Record<string, SvgIconComponent> = {
  23. "rep-011": Inventory2OutlinedIcon,
  24. "rep-020": Inventory2OutlinedIcon,
  25. "rep-007": MonetizationOnOutlinedIcon,
  26. "rep-012": LayersOutlinedIcon,
  27. "rep-021": Inventory2OutlinedIcon,
  28. "rep-010": SearchOutlinedIcon,
  29. "rep-004": LocalShippingOutlinedIcon,
  30. "rep-014": LocalShippingOutlinedIcon,
  31. "rep-008": OutboundOutlinedIcon,
  32. "rep-009": OutboundOutlinedIcon,
  33. "rep-013": LocalShippingOutlinedIcon,
  34. "rep-016": OutboundOutlinedIcon,
  35. "rep-017": LocalShippingOutlinedIcon,
  36. "rep-018": SearchOutlinedIcon,
  37. "rep-006": BarChartOutlinedIcon,
  38. "rep-005": PieChartOutlineOutlinedIcon,
  39. "rep-015": LayersOutlinedIcon,
  40. };
  41. const reportById = Object.fromEntries(REPORTS.map((r) => [r.id, r]));
  42. interface ReportSelectionDashboardProps {
  43. selectedReportId: string;
  44. onSelectReport: (reportId: string) => void;
  45. }
  46. function ReportCard({
  47. reportId,
  48. title,
  49. accent,
  50. selected,
  51. onClick,
  52. }: {
  53. reportId: string;
  54. title: string;
  55. accent: string;
  56. selected: boolean;
  57. onClick: () => void;
  58. }) {
  59. const Icon = REPORT_ICON_MAP[reportId] ?? Inventory2OutlinedIcon;
  60. return (
  61. <Box
  62. component="button"
  63. type="button"
  64. onClick={onClick}
  65. sx={{
  66. display: "flex",
  67. alignItems: "center",
  68. gap: 1.5,
  69. width: "100%",
  70. p: 1.5,
  71. textAlign: "left",
  72. cursor: "pointer",
  73. border: "1px solid",
  74. borderColor: selected ? accent : "divider",
  75. borderRadius: 1.5,
  76. bgcolor: "background.paper",
  77. boxShadow: selected ? 2 : "0 1px 3px rgba(0,0,0,0.06)",
  78. transition: "border-color 0.15s, box-shadow 0.15s",
  79. "&:hover": {
  80. borderColor: accent,
  81. boxShadow: 2,
  82. },
  83. }}
  84. >
  85. <Box
  86. sx={{
  87. display: "flex",
  88. alignItems: "center",
  89. justifyContent: "center",
  90. width: 40,
  91. height: 40,
  92. borderRadius: 1,
  93. bgcolor: `${accent}18`,
  94. color: accent,
  95. flexShrink: 0,
  96. }}
  97. >
  98. <Icon fontSize="small" />
  99. </Box>
  100. <Typography variant="body2" fontWeight={selected ? 600 : 400} sx={{ lineHeight: 1.35 }}>
  101. {title}
  102. </Typography>
  103. </Box>
  104. );
  105. }
  106. function CategoryColumn({
  107. category,
  108. selectedReportId,
  109. onSelectReport,
  110. }: {
  111. category: ReportCategoryConfig;
  112. selectedReportId: string;
  113. onSelectReport: (reportId: string) => void;
  114. }) {
  115. const { reportTitle, categoryTitle } = useReportLabels();
  116. const reports = category.reportIds
  117. .map((id) => reportById[id])
  118. .filter(Boolean);
  119. return (
  120. <Box
  121. sx={{
  122. display: "flex",
  123. flexDirection: "column",
  124. height: "100%",
  125. borderRadius: 1.5,
  126. overflow: "hidden",
  127. border: "1px solid",
  128. borderColor: "divider",
  129. }}
  130. >
  131. <Box
  132. sx={{
  133. px: 2,
  134. py: 1.25,
  135. bgcolor: category.headerBg,
  136. }}
  137. >
  138. <Typography variant="subtitle1" fontWeight="bold">
  139. {categoryTitle(category.id, category.title)}
  140. </Typography>
  141. </Box>
  142. <Box
  143. sx={{
  144. flex: 1,
  145. p: 1.5,
  146. bgcolor: category.bodyBg,
  147. }}
  148. >
  149. <Grid container spacing={1.5}>
  150. {reports.map((report) => (
  151. <Grid item xs={6} key={report.id}>
  152. <ReportCard
  153. reportId={report.id}
  154. title={reportTitle(report)}
  155. accent={category.accent}
  156. selected={selectedReportId === report.id}
  157. onClick={() => onSelectReport(report.id)}
  158. />
  159. </Grid>
  160. ))}
  161. </Grid>
  162. </Box>
  163. </Box>
  164. );
  165. }
  166. /** FP-MTMS Version Checklist | Functions Ref. No. 69 | v1.0.2 | 2026-09-10 */
  167. export default function ReportSelectionDashboard({
  168. selectedReportId,
  169. onSelectReport,
  170. }: ReportSelectionDashboardProps) {
  171. return (
  172. <Card sx={{ mb: 4, boxShadow: 2, border: "1px solid", borderColor: "divider" }}>
  173. <CardContent sx={{ p: { xs: 2, sm: 3 } }}>
  174. <Grid container spacing={2}>
  175. {REPORT_CATEGORIES.map((category) => (
  176. <Grid item xs={12} md={4} key={category.id}>
  177. <CategoryColumn
  178. category={category}
  179. selectedReportId={selectedReportId}
  180. onSelectReport={onSelectReport}
  181. />
  182. </Grid>
  183. ))}
  184. </Grid>
  185. </CardContent>
  186. </Card>
  187. );
  188. }