@@ -1,6 +1,6 @@ | |||||
"use server" | "use server" | ||||
import { serverFetchJson, serverFetchString } from "@/app/utils/fetchUtil"; | |||||
import { serverFetchJson, serverFetchString, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; | |||||
import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
import { revalidateTag } from "next/cache"; | import { revalidateTag } from "next/cache"; | ||||
import { cache } from "react"; | import { cache } from "react"; | ||||
@@ -117,4 +117,17 @@ export const updateInvoice = async (data: any) => { | |||||
revalidateTag("invoices") | revalidateTag("invoices") | ||||
return updateInvoice; | return updateInvoice; | ||||
} | |||||
} | |||||
export const deleteInvoice = async (id: number) => { | |||||
const invoice = await serverFetchWithNoContent( | |||||
`${BASE_API_URL}/invoices/${id}`, | |||||
{ | |||||
method: "DELETE", | |||||
headers: { "Content-Type": "application/json" }, | |||||
}, | |||||
); | |||||
revalidateTag("invoices"); | |||||
return invoice; | |||||
}; |
@@ -8,8 +8,8 @@ import EditNote from "@mui/icons-material/EditNote"; | |||||
import { moneyFormatter } from "@/app/utils/formatUtil" | import { moneyFormatter } from "@/app/utils/formatUtil" | ||||
import { Button, ButtonGroup, Stack, Tab, Tabs, TabsProps, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, TextField, CardContent, Typography, Divider, Card } from "@mui/material"; | import { Button, ButtonGroup, Stack, Tab, Tabs, TabsProps, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, TextField, CardContent, Typography, Divider, Card } from "@mui/material"; | ||||
import FileUploadIcon from '@mui/icons-material/FileUpload'; | import FileUploadIcon from '@mui/icons-material/FileUpload'; | ||||
import { importIssuedInovice, importReceivedInovice, updateInvoice } from "@/app/api/invoices/actions"; | |||||
import { errorDialogWithContent, successDialog } from "../Swal/CustomAlerts"; | |||||
import { deleteInvoice, importIssuedInovice, importReceivedInovice, updateInvoice } from "@/app/api/invoices/actions"; | |||||
import { deleteDialog, errorDialogWithContent, successDialog } from "../Swal/CustomAlerts"; | |||||
import { invoiceList, issuedInvoiceList, issuedInvoiceSearchForm, receivedInvoiceList, receivedInvoiceSearchForm } from "@/app/api/invoices"; | import { invoiceList, issuedInvoiceList, issuedInvoiceSearchForm, receivedInvoiceList, receivedInvoiceSearchForm } from "@/app/api/invoices"; | ||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; | import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; | ||||
import { GridCellParams, GridColDef, GridEventListener, GridRowId, GridRowModes, GridRowModesModel } from "@mui/x-data-grid"; | import { GridCellParams, GridColDef, GridEventListener, GridRowId, GridRowModes, GridRowModesModel } from "@mui/x-data-grid"; | ||||
@@ -43,7 +43,7 @@ type SearchQuery2 = Partial<Omit<receivedInvoiceSearchForm, "id">>; | |||||
type SearchParamNames2 = keyof SearchQuery2; | type SearchParamNames2 = keyof SearchQuery2; | ||||
const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoices }) => { | const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoices }) => { | ||||
console.log(invoices) | |||||
// console.log(invoices) | |||||
const { t } = useTranslation("invoices"); | const { t } = useTranslation("invoices"); | ||||
const [tabIndex, setTabIndex] = useState(0); | const [tabIndex, setTabIndex] = useState(0); | ||||
@@ -268,6 +268,19 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoic | |||||
// setSelectedRow([]); | // setSelectedRow([]); | ||||
}; | }; | ||||
const handleDeleteInvoice = useCallback(() => { | |||||
deleteDialog(async() => { | |||||
//console.log(selectedRow[0]) | |||||
await deleteInvoice(selectedRow[0].id!!) | |||||
setDialogOpen(false); | |||||
const result = await successDialog("Delete Success", t); | |||||
if (result) { | |||||
window.location.reload() | |||||
} | |||||
}, t) | |||||
}, [selectedRow]); | |||||
const handleSaveDialog = async () => { | const handleSaveDialog = async () => { | ||||
// setDialogOpen(false); | // setDialogOpen(false); | ||||
await updateInvoice(selectedRow[0]) | await updateInvoice(selectedRow[0]) | ||||
@@ -562,6 +575,9 @@ const InvoiceSearch: React.FC<Props> = ({ issuedInvoice, receivedInvoice, invoic | |||||
/> | /> | ||||
</DialogContent> | </DialogContent> | ||||
<DialogActions> | <DialogActions> | ||||
<Button onClick={handleDeleteInvoice} color="error"> | |||||
{t("Delete")} | |||||
</Button> | |||||
<Button onClick={handleCloseDialog} color="primary"> | <Button onClick={handleCloseDialog} color="primary"> | ||||
{t("Cancel")} | {t("Cancel")} | ||||
</Button> | </Button> | ||||
@@ -300,6 +300,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
id: "budgetedManhour", | id: "budgetedManhour", | ||||
field: "budgetedManhour", | field: "budgetedManhour", | ||||
headerName: t("Budgeted Manhours"), | headerName: t("Budgeted Manhours"), | ||||
type: "number", | |||||
minWidth: 70, | minWidth: 70, | ||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | ||||
@@ -309,6 +310,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
id: "spentManhour", | id: "spentManhour", | ||||
field: "spentManhour", | field: "spentManhour", | ||||
headerName: t("Spent Manhours"), | headerName: t("Spent Manhours"), | ||||
type: "number", | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -325,6 +327,7 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
id: "remainedManhour", | id: "remainedManhour", | ||||
field: "remainedManhour", | field: "remainedManhour", | ||||
headerName: t("Remained Manhours"), | headerName: t("Remained Manhours"), | ||||
type: "number", | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -397,6 +400,14 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
legend: { | legend: { | ||||
show: false, | show: false, | ||||
}, | }, | ||||
tooltip: { | |||||
enabled: true, | |||||
y: { | |||||
formatter: function (val) { | |||||
return val.toFixed(1) + "%"; | |||||
} | |||||
} | |||||
}, | |||||
responsive: [ | responsive: [ | ||||
{ | { | ||||
breakpoint: 480, | breakpoint: 480, | ||||
@@ -431,11 +442,11 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
<div style="width: auto;"> | <div style="width: auto;"> | ||||
<span style="font-weight: bold;">${projectCode} - ${projectName}</span> | <span style="font-weight: bold;">${projectCode} - ${projectName}</span> | ||||
<br> | <br> | ||||
${t("Budget Manhours")}: ${budgetManhours} hours | |||||
${t("Budget Manhours")}: ${budgetManhours.toFixed(2)} hours | |||||
<br> | <br> | ||||
${t("Spent Manhours")}: ${spentManhours} hours | |||||
${t("Spent Manhours")}: ${spentManhours.toFixed(2)} hours | |||||
<br> | <br> | ||||
Percentage: ${value}% | |||||
Percentage: ${value.toFixed(1)}% | |||||
</div> | </div> | ||||
`; | `; | ||||
@@ -707,9 +718,9 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{projectBudgetManhour}</span> | |||||
<span style={{ margin: "5%" }}>{projectBudgetManhour}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -718,13 +729,13 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{actualManhourSpent}</span> | |||||
<span style={{ margin: "5%" }}>{actualManhourSpent}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -733,13 +744,13 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Remained Manhours")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Remained Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{remainedManhour}</span> | |||||
<span style={{ margin: "5%" }}>{remainedManhour}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -748,13 +759,13 @@ const ProgressByClient: React.FC<Props> = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Last Update")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Last Update")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 mb-5 text-2xl font-extrabold" | className="mt-2 mb-5 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{lastUpdate}</span> | |||||
<span style={{ margin: "5%" }}>{lastUpdate}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</Card> | </Card> | ||||
@@ -335,6 +335,7 @@ const ProgressByTeam: React.FC = () => { | |||||
field: "budgetedManhour", | field: "budgetedManhour", | ||||
headerName: t("Budgeted Manhours"), | headerName: t("Budgeted Manhours"), | ||||
minWidth: 70, | minWidth: 70, | ||||
type: "number", | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | ||||
} | } | ||||
@@ -343,6 +344,7 @@ const ProgressByTeam: React.FC = () => { | |||||
id: "spentManhour", | id: "spentManhour", | ||||
field: "spentManhour", | field: "spentManhour", | ||||
headerName: t("Spent Manhours"), | headerName: t("Spent Manhours"), | ||||
type: "number", | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -358,6 +360,7 @@ const ProgressByTeam: React.FC = () => { | |||||
id: "remainedManhour", | id: "remainedManhour", | ||||
field: "remainedManhour", | field: "remainedManhour", | ||||
headerName: t("Remained Manhours"), | headerName: t("Remained Manhours"), | ||||
type: "number", | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -474,6 +477,14 @@ const ProgressByTeam: React.FC = () => { | |||||
legend: { | legend: { | ||||
show: false, | show: false, | ||||
}, | }, | ||||
tooltip: { | |||||
enabled: true, | |||||
y: { | |||||
formatter: function (val) { | |||||
return val.toFixed(1) + "%"; | |||||
} | |||||
} | |||||
}, | |||||
responsive: [ | responsive: [ | ||||
{ | { | ||||
breakpoint: 480, | breakpoint: 480, | ||||
@@ -507,12 +518,9 @@ const ProgressByTeam: React.FC = () => { | |||||
const tooltipContent = ` | const tooltipContent = ` | ||||
<div style="width: auto;"> | <div style="width: auto;"> | ||||
<span style="font-weight: bold;">${projectCode} - ${projectName}</span> | <span style="font-weight: bold;">${projectCode} - ${projectName}</span> | ||||
<br> | |||||
${t("Budget Manhours")}: ${budgetManhours} hours | |||||
<br> | |||||
${t("Spent Manhours")}: ${spentManhours} hours | |||||
<br> | |||||
Percentage: ${value}% | |||||
<br>${t("Budget Manhours")}:${budgetManhours.toFixed(2)} hours | |||||
<br>${t("Spent Manhours")}:${spentManhours.toFixed(2)} hours | |||||
<br>Percentage:${value.toFixed(1)}% | |||||
</div> | </div> | ||||
`; | `; | ||||
@@ -816,13 +824,13 @@ const ProgressByTeam: React.FC = () => { | |||||
className="mt-5 text-lg font-medium" | className="mt-5 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Project Budget Manhours")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Project Budget Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{projectBudgetManhour}</span> | |||||
<span style={{ margin: "5%" }}>{projectBudgetManhour}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -831,13 +839,13 @@ const ProgressByTeam: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{actualManhourSpent}</span> | |||||
<span style={{ margin: "5%" }}>{actualManhourSpent}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -846,13 +854,13 @@ const ProgressByTeam: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Remained Manhours")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Remained Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{remainedManhour}</span> | |||||
<span style={{ margin: "5%" }}>{remainedManhour}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -861,13 +869,13 @@ const ProgressByTeam: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Last Update")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Last Update")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 mb-5 text-2xl font-extrabold" | className="mt-2 mb-5 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{lastUpdate}</span> | |||||
<span style={{ margin: "5%" }}>{lastUpdate}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</Card> | </Card> | ||||
@@ -297,6 +297,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
field: "expenditure", | field: "expenditure", | ||||
headerName: t("Expenditure (HKD)"), | headerName: t("Expenditure (HKD)"), | ||||
flex: 0.6, | flex: 0.6, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.expenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.expenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -308,6 +309,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
field: "income", | field: "income", | ||||
headerName: t("Income (HKD)"), | headerName: t("Income (HKD)"), | ||||
flex: 0.6, | flex: 0.6, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.income.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.income.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -319,6 +321,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
field: "balance", | field: "balance", | ||||
headerName: t("Cash Flow Balance (HKD)"), | headerName: t("Cash Flow Balance (HKD)"), | ||||
flex: 0.6, | flex: 0.6, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
if (params.row.balance < 0) { | if (params.row.balance < 0) { | ||||
return ( | return ( | ||||
@@ -876,8 +879,8 @@ const ProjectCashFlow: React.FC = () => { | |||||
{t("Total Project Fee")} | {t("Total Project Fee")} | ||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | |||||
style={{ color: "#6b87cf" }} | |||||
className="text-lg font-medium mx-5" | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
${totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ${totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
@@ -889,8 +892,8 @@ const ProjectCashFlow: React.FC = () => { | |||||
{t("Total Invoiced Amount")} | {t("Total Invoiced Amount")} | ||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | |||||
style={{ color: "#6b87cf" }} | |||||
className="text-lg font-medium mx-5" | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
${totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ${totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
@@ -902,8 +905,8 @@ const ProjectCashFlow: React.FC = () => { | |||||
{t("Total Received Amount")} | {t("Total Received Amount")} | ||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | |||||
style={{ color: "#6b87cf" }} | |||||
className="text-lg font-medium mx-5" | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
${totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ${totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
@@ -915,8 +918,8 @@ const ProjectCashFlow: React.FC = () => { | |||||
{t("Accounts Receivable")} | {t("Accounts Receivable")} | ||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5 mb-2" | |||||
style={{ color: "#6b87cf" }} | |||||
className="text-lg font-medium mx-5 mb-2" | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
${receivable.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ${receivable.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
@@ -951,8 +954,8 @@ const ProjectCashFlow: React.FC = () => { | |||||
{t("Total Budget")} | {t("Total Budget")} | ||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | |||||
style={{ color: "#6b87cf" }} | |||||
className="text-lg font-medium mx-5" | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
${totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ${totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
@@ -964,8 +967,8 @@ const ProjectCashFlow: React.FC = () => { | |||||
{t("Total Cumulative Expenditure")} | {t("Total Cumulative Expenditure")} | ||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5" | |||||
style={{ color: "#6b87cf" }} | |||||
className="text-lg font-medium mx-5" | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
${totalExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ${totalExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
@@ -977,8 +980,8 @@ const ProjectCashFlow: React.FC = () => { | |||||
{t("Remaining Budget")} | {t("Remaining Budget")} | ||||
</div> | </div> | ||||
<div | <div | ||||
className="text-lg font-medium ml-5 mb-2" | |||||
style={{ color: "#6b87cf" }} | |||||
className="text-lg font-medium mx-5 mb-2" | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
${expenditureReceivable.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ${expenditureReceivable.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ||||
</div> | </div> | ||||
@@ -211,6 +211,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
field: 'totalFee', | field: 'totalFee', | ||||
headerName: t("Total Fees")+t("HKD"), | headerName: t("Total Fees")+t("HKD"), | ||||
minWidth:50, | minWidth:50, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalFee.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -222,6 +223,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
field: 'totalBudget', | field: 'totalBudget', | ||||
headerName: t("Total Budget")+t("HKD"), | headerName: t("Total Budget")+t("HKD"), | ||||
minWidth:50, | minWidth:50, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -233,6 +235,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
field: 'cumulativeExpenditure', | field: 'cumulativeExpenditure', | ||||
headerName: t("Total Cumulative Expenditure")+t("HKD"), | headerName: t("Total Cumulative Expenditure")+t("HKD"), | ||||
minWidth:280, | minWidth:280, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -244,6 +247,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
field: 'totalInvoiced', | field: 'totalInvoiced', | ||||
headerName: t("Total Invoiced Amount")+t("HKD"), | headerName: t("Total Invoiced Amount")+t("HKD"), | ||||
minWidth:250, | minWidth:250, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -255,6 +259,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
field: 'totalUnInvoiced', | field: 'totalUnInvoiced', | ||||
headerName: t("Total Un-Invoiced Amount")+t("HKD"), | headerName: t("Total Un-Invoiced Amount")+t("HKD"), | ||||
minWidth:250, | minWidth:250, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -266,6 +271,7 @@ const ProjectFinancialSummary: React.FC = () => { | |||||
field: 'totalReceived', | field: 'totalReceived', | ||||
headerName: t("Total Received Amount")+t("HKD"), | headerName: t("Total Received Amount")+t("HKD"), | ||||
minWidth:250, | minWidth:250, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -426,6 +432,7 @@ const columns2 = [ | |||||
id: 'totalFees', | id: 'totalFees', | ||||
field: 'totalFees', | field: 'totalFees', | ||||
headerName: t("Total Fees")+t("HKD"), | headerName: t("Total Fees")+t("HKD"), | ||||
type: "number", | |||||
minWidth:50, | minWidth:50, | ||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
@@ -438,6 +445,7 @@ const columns2 = [ | |||||
field: 'totalBudget', | field: 'totalBudget', | ||||
headerName: t("Total Budget")+t("HKD"), | headerName: t("Total Budget")+t("HKD"), | ||||
minWidth:50, | minWidth:50, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalBudget.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -449,6 +457,7 @@ const columns2 = [ | |||||
field: 'totalCumulativeExpenditure', | field: 'totalCumulativeExpenditure', | ||||
headerName: t("Total Cumulative Expenditure")+t("HKD"), | headerName: t("Total Cumulative Expenditure")+t("HKD"), | ||||
minWidth:250, | minWidth:250, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.cumulativeExpenditure.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -460,6 +469,7 @@ const columns2 = [ | |||||
field: 'totalInvoicedAmount', | field: 'totalInvoicedAmount', | ||||
headerName: t("Total Invoiced Amount")+t("HKD"), | headerName: t("Total Invoiced Amount")+t("HKD"), | ||||
minWidth:250, | minWidth:250, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalInvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -471,6 +481,7 @@ const columns2 = [ | |||||
field: 'totalUnInvoicedAmount', | field: 'totalUnInvoicedAmount', | ||||
headerName: t("Total Un-Invoiced Amount")+t("HKD"), | headerName: t("Total Un-Invoiced Amount")+t("HKD"), | ||||
minWidth:250, | minWidth:250, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalUninvoiced.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -482,6 +493,7 @@ const columns2 = [ | |||||
field: 'totalReceivedAmount', | field: 'totalReceivedAmount', | ||||
headerName: t("Total Received Amount") +t("HKD"), | headerName: t("Total Received Amount") +t("HKD"), | ||||
minWidth:250, | minWidth:250, | ||||
type: "number", | |||||
renderCell: (params:any) => { | renderCell: (params:any) => { | ||||
return ( | return ( | ||||
<span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | <span>${params.row.totalReceived.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span> | ||||
@@ -419,6 +419,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
field: "budgetedManhour", | field: "budgetedManhour", | ||||
headerName: t("Budgeted Manhours"), | headerName: t("Budgeted Manhours"), | ||||
minWidth: 70, | minWidth: 70, | ||||
type: "number", | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | return <span>{params.row.budgetedManhour.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>; | ||||
} | } | ||||
@@ -427,6 +428,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
id: "spentManhour", | id: "spentManhour", | ||||
field: "spentManhour", | field: "spentManhour", | ||||
headerName: t("Spent Manhours"), | headerName: t("Spent Manhours"), | ||||
type: "number", | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -442,6 +444,7 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
id: "remainedManhour", | id: "remainedManhour", | ||||
field: "remainedManhour", | field: "remainedManhour", | ||||
headerName: t("Remained Manhours"), | headerName: t("Remained Manhours"), | ||||
type: "number", | |||||
renderCell: (params: any) => { | renderCell: (params: any) => { | ||||
if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | if (params.row.budgetedManhour - params.row.spentManhour <= 0) { | ||||
return ( | return ( | ||||
@@ -558,6 +561,14 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
legend: { | legend: { | ||||
show: false, | show: false, | ||||
}, | }, | ||||
tooltip: { | |||||
enabled: true, | |||||
y: { | |||||
formatter: function (val) { | |||||
return val.toFixed(1) + "%"; | |||||
} | |||||
} | |||||
}, | |||||
responsive: [ | responsive: [ | ||||
{ | { | ||||
breakpoint: 480, | breakpoint: 480, | ||||
@@ -592,11 +603,11 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
<div style="width: 250px;"> | <div style="width: 250px;"> | ||||
<span style="font-weight: bold;">${projectCode} - ${projectName}</span> | <span style="font-weight: bold;">${projectCode} - ${projectName}</span> | ||||
<br> | <br> | ||||
${t("Budget Manhours")}: ${budgetManhours} ${t("hours")} | |||||
${t("Budget Manhours")}: ${budgetManhours.toFixed(2)} ${t("hours")} | |||||
<br> | <br> | ||||
${t("Spent Manhours")}: ${spentManhours} ${t("hours")} | |||||
${t("Spent Manhours")}: ${spentManhours.toFixed(2)} ${t("hours")} | |||||
<br> | <br> | ||||
Percentage: ${value}% | |||||
Percentage: ${value.toFixed(1)}% | |||||
</div> | </div> | ||||
`; | `; | ||||
@@ -934,13 +945,13 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
className="mt-5 text-lg font-medium" | className="mt-5 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Project Budget Manhours")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Project Budget Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{projectBudgetManhour}</span> | |||||
<span style={{ margin: "5%" }}>{projectBudgetManhour}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -949,13 +960,13 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Actual Manhours Spent")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{actualManhourSpent}</span> | |||||
<span style={{ margin: "5%" }}>{actualManhourSpent}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -964,13 +975,13 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Remained Manhours")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Remained Manhours")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 text-2xl font-extrabold" | className="mt-2 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{remainedManhour}</span> | |||||
<span style={{ margin: "5%" }}>{remainedManhour}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<hr /> | <hr /> | ||||
@@ -979,13 +990,13 @@ const ProjectResourceConsumptionRanking: React.FC = () => { | |||||
className="mt-2 text-lg font-medium" | className="mt-2 text-lg font-medium" | ||||
style={{ color: "#898d8d" }} | style={{ color: "#898d8d" }} | ||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{t("Last Update")}</span> | |||||
<span style={{ margin: "5%" }}>{t("Last Update")}</span> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="mt-2 mb-5 text-2xl font-extrabold" | className="mt-2 mb-5 text-2xl font-extrabold" | ||||
style={{ color: "#6b87cf" }} | |||||
style={{ color: "#6b87cf", textAlign: "right" }} | |||||
> | > | ||||
<span style={{ marginLeft: "5%" }}>{lastUpdate}</span> | |||||
<span style={{ margin: "5%" }}>{lastUpdate}</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</Card> | </Card> | ||||
@@ -234,6 +234,11 @@ const ProjectResourceSummary: React.FC = () => { | |||||
// createTaskData("1.1 Preparation of preliminary...","-","-","172.00","-","54.00","-","42.00","-","12.00","-","3.00","-","283.00"), | // createTaskData("1.1 Preparation of preliminary...","-","-","172.00","-","54.00","-","42.00","-","12.00","-","3.00","-","283.00"), | ||||
// ]; | // ]; | ||||
const colBaseStyle:any = {fontSize:13, textAlign:"right"}; | |||||
const headerBaseStyle:any = {fontSize:11, minWidth:30, textAlign:"right"} | |||||
const infoHeaderStyle:any = { fontSize:"1em", fontWeight:"bold"};//, textAlign: "right"}; | |||||
const infoDataStyle:any = { fontSize:"1em"};//, textAlign: "right"}; | |||||
function Row(props:any) { | function Row(props:any) { | ||||
const { row } = props; | const { row } = props; | ||||
const [open, setOpen] = React.useState(false); | const [open, setOpen] = React.useState(false); | ||||
@@ -253,19 +258,19 @@ const ProjectResourceSummary: React.FC = () => { | |||||
)} | )} | ||||
</TableCell> | </TableCell> | ||||
<TableCell style={{fontSize:13}}>{row.stage}</TableCell> | <TableCell style={{fontSize:13}}>{row.stage}</TableCell> | ||||
<TableCell style={{fontSize:13}}>{row.taskCount}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g1Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g1Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g2Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g2Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g3Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g3Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g4Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g4Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.g5Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.g5Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#808aff"}}>{row.totalPlanned.toFixed(2)}</TableCell> | |||||
<TableCell style={{fontSize:13, color:"#69dbac"}}>{row.totalActual.toFixed(2)}</TableCell> | |||||
<TableCell style={colBaseStyle}>{row.taskCount}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#808aff"}}>{row.g1Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#69dbac"}}>{row.g1Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#808aff"}}>{row.g2Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#69dbac"}}>{row.g2Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#808aff"}}>{row.g3Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#69dbac"}}>{row.g3Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#808aff"}}>{row.g4Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#69dbac"}}>{row.g4Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#808aff"}}>{row.g5Planned.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#69dbac"}}>{row.g5Actual.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#808aff"}}>{row.totalPlanned.toFixed(2)}</TableCell> | |||||
<TableCell style={{...colBaseStyle, color:"#69dbac"}}>{row.totalActual.toFixed(2)}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
{row.task.map((taskRow:any) => ( | {row.task.map((taskRow:any) => ( | ||||
<TableRow key={taskRow[0]} style={{backgroundColor:"#f0f3f7"}} className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300"> | <TableRow key={taskRow[0]} style={{backgroundColor:"#f0f3f7"}} className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300"> | ||||
@@ -622,92 +627,92 @@ const columns2 = [ | |||||
<CardHeader className="text-slate-500" title= {t("Project Information")}/> | <CardHeader className="text-slate-500" title= {t("Project Information")}/> | ||||
<div className="ml-6 mr-6"> | <div className="ml-6 mr-6"> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Project")} | {t("Project")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
<div style={infoDataStyle}> | |||||
{projectName} | {projectName} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Project Fee")} | {t("Project Fee")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
<div style={infoDataStyle}> | |||||
HKD ${projectFee.toFixed(2)} | HKD ${projectFee.toFixed(2)} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Total Budget")} | {t("Total Budget")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
<div style={infoDataStyle}> | |||||
HKD ${projectBudget.toFixed(2)} | HKD ${projectBudget.toFixed(2)} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Cumulative Expenditure")} | {t("Cumulative Expenditure")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
<div style={infoDataStyle}> | |||||
HKD ${expenditure.toFixed(2)} | HKD ${expenditure.toFixed(2)} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Remaining Budget")} | {t("Remaining Budget")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
<div style={infoDataStyle}> | |||||
HKD ${remainingBudget.toFixed(2)} | HKD ${remainingBudget.toFixed(2)} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Status")} | {t("Status")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
<div style={infoDataStyle}> | |||||
{t(status)} | {t(status)} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Planned Resources")} | {t("Planned Resources")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
<div style={infoDataStyle}> | |||||
{plannedResources.toFixed(2)} {t("Manhours")} | {plannedResources.toFixed(2)} {t("Manhours")} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Actual Resources Spent")} | {t("Actual Resources Spent")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}}> | |||||
<div style={infoDataStyle}> | |||||
{(actualResourcesSpent ?? 0).toFixed(2)} {t("Manhours")} ({(actualResourcesSpent/plannedResources*100).toFixed(2)}%) | {(actualResourcesSpent ?? 0).toFixed(2)} {t("Manhours")} ({(actualResourcesSpent/plannedResources*100).toFixed(2)}%) | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div style={{ display: "inline-block", width: "33%"}}> | <div style={{ display: "inline-block", width: "33%"}}> | ||||
<div style={{ fontSize:"1em", fontWeight:"bold"}}> | |||||
<div style={infoHeaderStyle}> | |||||
<u> | <u> | ||||
{t("Remaining Resources")} | {t("Remaining Resources")} | ||||
</u> | </u> | ||||
</div> | </div> | ||||
<div style={{fontSize:"1em"}} className={"mb-5"}> | |||||
<div style={infoDataStyle} className={"mb-5"}> | |||||
{(remainingResources ?? 0).toFixed(2)} {t("Manhours")} ({(remainingResources/plannedResources*100).toFixed(2)}%) | {(remainingResources ?? 0).toFixed(2)} {t("Manhours")} ({(remainingResources/plannedResources*100).toFixed(2)}%) | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -748,19 +753,19 @@ const columns2 = [ | |||||
<TableRow className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300"> | <TableRow className="border-t-2 border-b-0 border-l-0 border-r-0 border-solid border-slate-300"> | ||||
<TableCell style={{minWidth:30}}/> | <TableCell style={{minWidth:30}}/> | ||||
<TableCell style={{fontSize:11, minWidth:150}}>{t("Stage")}</TableCell> | <TableCell style={{fontSize:11, minWidth:150}}>{t("Stage")}</TableCell> | ||||
<TableCell style={{fontSize:11, minWidth:30}}>{t("Task Count")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{fontSize:11, minWidth:30, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={headerBaseStyle}>{t("Task Count")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#808aff"}}>{t("Planned")}</TableCell> | |||||
<TableCell style={{...headerBaseStyle, color:"#69dbac"}}>{t("Actual")}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableHead> | </TableHead> | ||||
<TableBody> | <TableBody> | ||||