|
|
@@ -1,8 +1,19 @@ |
|
|
|
import React from "react"; |
|
|
|
import { Box, Card, CardContent, Grid, Typography } from "@mui/material"; |
|
|
|
import React, { useCallback, useState } from "react"; |
|
|
|
import { |
|
|
|
Box, |
|
|
|
Card, |
|
|
|
CardContent, |
|
|
|
Grid, |
|
|
|
ToggleButton, |
|
|
|
ToggleButtonGroup, |
|
|
|
ToggleButtonProps, |
|
|
|
Tooltip, |
|
|
|
Typography, |
|
|
|
} from "@mui/material"; |
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
import { manhourFormatter } from "@/app/utils/formatUtil"; |
|
|
|
import { AssignedProject } from "@/app/api/projects"; |
|
|
|
import { ViewList, ViewModule } from "@mui/icons-material"; |
|
|
|
|
|
|
|
interface Props { |
|
|
|
projects: AssignedProject[]; |
|
|
@@ -10,68 +21,128 @@ interface Props { |
|
|
|
maintainManagementStaffWorkspaceAbility?: boolean; |
|
|
|
} |
|
|
|
|
|
|
|
const ProjectGrid: React.FC<Props> = ({ projects, maintainNormalStaffWorkspaceAbility, maintainManagementStaffWorkspaceAbility }) => { |
|
|
|
const ProjectGrid: React.FC<Props> = ({ |
|
|
|
projects, |
|
|
|
maintainNormalStaffWorkspaceAbility, |
|
|
|
maintainManagementStaffWorkspaceAbility, |
|
|
|
}) => { |
|
|
|
const { t } = useTranslation("home"); |
|
|
|
const [view, setView] = useState<"grid" | "list">("grid"); |
|
|
|
|
|
|
|
const handleViewChange = useCallback< |
|
|
|
NonNullable<ToggleButtonProps["onChange"]> |
|
|
|
>((e, value) => { |
|
|
|
if (value) { |
|
|
|
setView(value); |
|
|
|
} |
|
|
|
}, []); |
|
|
|
|
|
|
|
return ( |
|
|
|
<Box> |
|
|
|
<Grid container columns={{ xs: 4, sm: 8, md: 12, lg: 16 }} spacing={2}> |
|
|
|
<ToggleButtonGroup |
|
|
|
color="primary" |
|
|
|
value={view} |
|
|
|
exclusive |
|
|
|
onChange={handleViewChange} |
|
|
|
sx={{ marginBlockEnd: 2 }} |
|
|
|
> |
|
|
|
<ToggleButton value="grid"> |
|
|
|
<Tooltip title={t("Grid view")}> |
|
|
|
<ViewModule /> |
|
|
|
</Tooltip> |
|
|
|
</ToggleButton> |
|
|
|
<ToggleButton value="list"> |
|
|
|
<Tooltip title={t("List view")}> |
|
|
|
<ViewList /> |
|
|
|
</Tooltip> |
|
|
|
</ToggleButton> |
|
|
|
</ToggleButtonGroup> |
|
|
|
<Grid |
|
|
|
container |
|
|
|
columns={view === "list" ? 4 : { xs: 4, sm: 8, md: 12, lg: 16 }} |
|
|
|
spacing={2} |
|
|
|
alignItems="stretch" |
|
|
|
> |
|
|
|
{projects.map((project, idx) => ( |
|
|
|
<Grid key={`${project.code}${idx}`} item xs={4}> |
|
|
|
<Card> |
|
|
|
<CardContent> |
|
|
|
<Card sx={{ height: "100%" }}> |
|
|
|
<CardContent |
|
|
|
sx={{ |
|
|
|
display: "flex", |
|
|
|
flexDirection: "column", |
|
|
|
height: "100%", |
|
|
|
}} |
|
|
|
> |
|
|
|
<Typography variant="overline">{project.code}</Typography> |
|
|
|
<Typography |
|
|
|
variant="h6" |
|
|
|
sx={{ |
|
|
|
overflow: "hidden", |
|
|
|
textOverflow: "ellipsis", |
|
|
|
whiteSpace: "nowrap", |
|
|
|
marginBlockEnd: 3, |
|
|
|
}} |
|
|
|
> |
|
|
|
{project.name} |
|
|
|
</Typography> |
|
|
|
{/* Spacer */} |
|
|
|
<Box sx={{ flex: 1 }} /> |
|
|
|
{/* Hours Spent */} |
|
|
|
{(Boolean(maintainNormalStaffWorkspaceAbility) || Boolean(maintainManagementStaffWorkspaceAbility)) && <><Typography variant="subtitle2">{t("Hours Spent:")}</Typography> |
|
|
|
<Box |
|
|
|
sx={{ |
|
|
|
display: "flex", |
|
|
|
justifyContent: "space-between", |
|
|
|
alignItems: "baseline", |
|
|
|
}} |
|
|
|
> |
|
|
|
<Typography variant="caption">{t("Normal")}</Typography> |
|
|
|
<Typography> |
|
|
|
{manhourFormatter.format(Boolean(maintainManagementStaffWorkspaceAbility) ? project.hoursSpent : project.currentStaffHoursSpent)} |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
<Box |
|
|
|
sx={{ |
|
|
|
display: "flex", |
|
|
|
justifyContent: "space-between", |
|
|
|
alignItems: "baseline", |
|
|
|
}} |
|
|
|
> |
|
|
|
<Typography variant="caption">{t("Others")}</Typography> |
|
|
|
<Typography>{`${manhourFormatter.format( |
|
|
|
Boolean(maintainManagementStaffWorkspaceAbility) ? project.hoursSpentOther : project.currentStaffHoursSpentOther, |
|
|
|
)}`}</Typography> |
|
|
|
</Box></>} |
|
|
|
{(Boolean(maintainNormalStaffWorkspaceAbility) || |
|
|
|
Boolean(maintainManagementStaffWorkspaceAbility)) && ( |
|
|
|
<> |
|
|
|
<Typography variant="subtitle2"> |
|
|
|
{t("Hours Spent:")} |
|
|
|
</Typography> |
|
|
|
<Box |
|
|
|
sx={{ |
|
|
|
display: "flex", |
|
|
|
justifyContent: "space-between", |
|
|
|
alignItems: "baseline", |
|
|
|
}} |
|
|
|
> |
|
|
|
<Typography variant="caption">{t("Normal")}</Typography> |
|
|
|
<Typography> |
|
|
|
{manhourFormatter.format( |
|
|
|
Boolean(maintainManagementStaffWorkspaceAbility) |
|
|
|
? project.hoursSpent |
|
|
|
: project.currentStaffHoursSpent, |
|
|
|
)} |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
<Box |
|
|
|
sx={{ |
|
|
|
display: "flex", |
|
|
|
justifyContent: "space-between", |
|
|
|
alignItems: "baseline", |
|
|
|
}} |
|
|
|
> |
|
|
|
<Typography variant="caption">{t("Others")}</Typography> |
|
|
|
<Typography>{`${manhourFormatter.format( |
|
|
|
Boolean(maintainManagementStaffWorkspaceAbility) |
|
|
|
? project.hoursSpentOther |
|
|
|
: project.currentStaffHoursSpentOther, |
|
|
|
)}`}</Typography> |
|
|
|
</Box> |
|
|
|
</> |
|
|
|
)} |
|
|
|
{/* Hours Allocated */} |
|
|
|
{Boolean(maintainManagementStaffWorkspaceAbility) && <Box |
|
|
|
sx={{ |
|
|
|
display: "flex", |
|
|
|
justifyContent: "space-between", |
|
|
|
alignItems: "baseline", |
|
|
|
}} |
|
|
|
> |
|
|
|
<Typography variant="subtitle2" sx={{ marginBlockStart: 2 }}> |
|
|
|
{t("Hours Allocated:")} |
|
|
|
</Typography> |
|
|
|
<Typography> |
|
|
|
{manhourFormatter.format(project.hoursAllocated)} |
|
|
|
</Typography> |
|
|
|
</Box>} |
|
|
|
{Boolean(maintainManagementStaffWorkspaceAbility) && ( |
|
|
|
<Box |
|
|
|
sx={{ |
|
|
|
display: "flex", |
|
|
|
justifyContent: "space-between", |
|
|
|
alignItems: "baseline", |
|
|
|
}} |
|
|
|
> |
|
|
|
<Typography |
|
|
|
variant="subtitle2" |
|
|
|
sx={{ marginBlockStart: 2 }} |
|
|
|
> |
|
|
|
{t("Hours Allocated:")} |
|
|
|
</Typography> |
|
|
|
<Typography> |
|
|
|
{manhourFormatter.format(project.hoursAllocated)} |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
)} |
|
|
|
</CardContent> |
|
|
|
</Card> |
|
|
|
</Grid> |
|
|
|