guesstimate/client/src/routes/project/financial-preview.tsx

86 lines
3.3 KiB
TypeScript
Raw Normal View History

2020-07-09 13:00:42 +02:00
import React, { FunctionComponent } from "react";
2020-04-20 11:14:46 +02:00
import { Project } from "../../models/project";
2020-04-21 14:10:50 +02:00
import { useProjectEstimations } from "../../hooks/use-project-estimations";
2020-04-23 14:00:56 +02:00
import { getCurrency, defaults, getTaskCategoryCost, getRoundUpEstimations } from "../../models/params";
import { getMinMaxCosts, Cost } from "../../util/stat";
import * as style from './style.module.css';
import ProjectTimeUnit from "../../components/project-time-unit";
2020-04-20 11:14:46 +02:00
export interface FinancialPreviewProps {
project: Project
}
2020-07-09 13:00:42 +02:00
const FinancialPreview: FunctionComponent<FinancialPreviewProps> = ({ project }) => {
2020-04-21 14:10:50 +02:00
const estimations = useProjectEstimations(project);
const costs = getMinMaxCosts(project, estimations.p99);
2020-04-23 14:00:56 +02:00
const roundUp = getRoundUpEstimations(project);
2020-04-20 11:14:46 +02:00
return (
2020-07-09 13:00:42 +02:00
<div className="table-container">
<table className="table is-bordered is-striped is-fullwidth">
2020-04-20 11:14:46 +02:00
<thead>
<tr>
<th colSpan={2}>
<span>Prévisionnel financier</span><br />
2020-07-09 13:00:42 +02:00
<span className="is-size-7 has-text-weight-normal">confiance >= 99.7%</span>
</th>
2020-04-20 11:14:46 +02:00
</tr>
<tr>
2020-07-09 13:00:42 +02:00
<th className="is-narrow">Temps</th>
2020-04-20 11:14:46 +02:00
<th>Coût</th>
</tr>
</thead>
<tbody>
<tr>
2020-07-09 13:00:42 +02:00
<td className="is-narrow">Maximum</td>
2020-04-22 23:18:18 +02:00
<td>
2020-04-23 14:00:56 +02:00
<CostDetails project={project} cost={costs.max} roundUp={roundUp} />
2020-04-22 23:18:18 +02:00
</td>
2020-04-20 11:14:46 +02:00
</tr>
<tr>
2020-07-09 13:00:42 +02:00
<td className="is-narrow">Minimum</td>
2020-04-22 23:18:18 +02:00
<td>
2020-04-23 14:00:56 +02:00
<CostDetails project={project} cost={costs.min} roundUp={roundUp} />
2020-04-22 23:18:18 +02:00
</td>
2020-04-20 11:14:46 +02:00
</tr>
</tbody>
</table>
</div>
);
};
export interface CostDetailsProps {
project: Project
cost: Cost
2020-04-23 14:00:56 +02:00
roundUp: boolean
}
2020-07-09 13:00:42 +02:00
export const CostDetails:FunctionComponent<CostDetailsProps> = ({ project, cost, roundUp }) => {
return (
<details>
<summary><strong>
{cost.totalCost} {getCurrency(project)}</strong>
2020-07-09 13:00:42 +02:00
<span className="is-pulled-right">{ roundUp ? Math.ceil(cost.totalTime) : cost.totalTime.toFixed(2) } <ProjectTimeUnit project={project} /></span>
</summary>
2020-07-09 13:00:42 +02:00
<table className={`table is-fullwidth`}>
<tbody>
{
Object.keys(cost.details).map(taskCategoryId => {
const taskCategory = project.params.taskCategories[taskCategoryId];
const details = cost.details[taskCategoryId];
return (
<tr key={`task-category-cost-${taskCategory.id}`}>
2020-07-09 13:00:42 +02:00
<td className={`${style.noBorder} is-size-6`}>{taskCategory.label}</td>
<td className={`${style.noBorder} is-size-6`}>{details.cost} {getCurrency(project)}</td>
<td className={`${style.noBorder} is-size-6`}>{ roundUp ? Math.ceil(details.time) : details.time.toFixed(2) } <ProjectTimeUnit project={project} /> × {getTaskCategoryCost(taskCategory)} {getCurrency(project)}</td>
</tr>
)
})
}
</tbody>
</table>
</details>
);
};
2020-04-20 11:14:46 +02:00
export default FinancialPreview;