|
|
@@ -14,36 +14,53 @@ interface Props { |
|
|
|
financialSummByProject: FinancialByProject[] |
|
|
|
} |
|
|
|
|
|
|
|
type InputDate = { |
|
|
|
startDate: string; |
|
|
|
endDate: string; |
|
|
|
} |
|
|
|
type InputDate = { |
|
|
|
startDate: string; |
|
|
|
endDate: string; |
|
|
|
} |
|
|
|
|
|
|
|
type DateParams = { |
|
|
|
[key: number]: InputDate; |
|
|
|
} |
|
|
|
|
|
|
|
type ComboParams = { |
|
|
|
[key: number]: string; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type DateParams = { |
|
|
|
0: InputDate; |
|
|
|
2: InputDate; |
|
|
|
3: InputDate; |
|
|
|
4: InputDate; |
|
|
|
5: InputDate; |
|
|
|
} |
|
|
|
const FinancialSummaryPage: React.FC<Props> = ({ |
|
|
|
_teamId, |
|
|
|
financialSummByProject |
|
|
|
}) => { |
|
|
|
console.log(financialSummByProject) |
|
|
|
const { t } = useTranslation(); |
|
|
|
const curr = useMemo(() => dayjs().format(INPUT_DATE_FORMAT), []) |
|
|
|
const currYear = useMemo(() => dayjs().get("year"), []) |
|
|
|
var currDate: string = useMemo(() => dayjs().format(INPUT_DATE_FORMAT), []) |
|
|
|
var currYear: number = useMemo(() => dayjs().get("year"), []) |
|
|
|
// testing date |
|
|
|
// currDate = "2024-10-28" |
|
|
|
// currYear = 2024 |
|
|
|
const startDate = "10-01" |
|
|
|
const endDate = "09-30" |
|
|
|
const currFinancialYear = useMemo(() => curr > `${currYear}-${startDate}` ? currYear + 1 : currYear, [currYear]) |
|
|
|
const lengthOfCombo = 10 |
|
|
|
const currFinancialYear = useMemo(() => currDate > `${currYear}-${startDate}` ? currYear + 1 : currYear, [currYear]) |
|
|
|
const [mainData, setMainData] = useState<FinancialByProject[]>(financialSummByProject) |
|
|
|
const [byTeam, setByTeam] = useState<SumOfByTeam[]>(() => sumUpByTeam(mainData)) // do fetch to set |
|
|
|
const [byProject, setByProject] = useState<FinancialByProject[]>(financialSummByProject) |
|
|
|
const [byClient, setByClient] = useState<SumOfByClient[]>(() => sumUpByClient(mainData)) |
|
|
|
const [isLoading, setIsLoading] = useState(false) |
|
|
|
const allTeam = useMemo(()=> { |
|
|
|
var _allTeam: SumOfByTeam = { |
|
|
|
const allTeam = useMemo(() => { |
|
|
|
return byTeam.reduce((acc, curr) => ({ |
|
|
|
id: 0, |
|
|
|
team: "All Team", |
|
|
|
totalFee: acc.totalFee + curr.totalFee, |
|
|
|
totalBudget: acc.totalBudget + curr.totalBudget, |
|
|
|
manhourExpense: acc.manhourExpense + curr.manhourExpense, |
|
|
|
projectExpense: acc.projectExpense + curr.projectExpense, |
|
|
|
invoicedAmount: acc.invoicedAmount + curr.invoicedAmount, |
|
|
|
uninvoicedAmount: acc.uninvoicedAmount + curr.uninvoicedAmount, |
|
|
|
paidAmount: acc.paidAmount + curr.paidAmount, |
|
|
|
activeProject: acc.activeProject + curr.activeProject |
|
|
|
}), { |
|
|
|
id: 0, |
|
|
|
team: "All Team", |
|
|
|
totalFee: 0, |
|
|
@@ -51,34 +68,60 @@ const FinancialSummaryPage: React.FC<Props> = ({ |
|
|
|
manhourExpense: 0, |
|
|
|
projectExpense: 0, |
|
|
|
invoicedAmount: 0, |
|
|
|
uninvoicedAmount: 0, |
|
|
|
paidAmount: 0, |
|
|
|
activeProject: 0, |
|
|
|
} |
|
|
|
for (let i = 0; i < byTeam.length; i++) { |
|
|
|
var curr = byTeam[i] |
|
|
|
_allTeam["totalFee"] += curr.totalFee |
|
|
|
_allTeam["totalBudget"] += curr.totalBudget |
|
|
|
_allTeam["manhourExpense"] += curr.manhourExpense |
|
|
|
_allTeam["projectExpense"] += curr.projectExpense |
|
|
|
_allTeam["invoicedAmount"] += curr.invoicedAmount |
|
|
|
_allTeam["paidAmount"] += curr.paidAmount |
|
|
|
_allTeam["activeProject"] += curr.activeProject |
|
|
|
} |
|
|
|
return _allTeam |
|
|
|
activeProject: 0 |
|
|
|
}) |
|
|
|
}, [mainData]) |
|
|
|
console.log(allTeam) |
|
|
|
|
|
|
|
const [teamId, setTeamId] = useState(_teamId) |
|
|
|
const [isCardClickedIndex, setIsCardClickedIndex] = useState(_teamId || 0); |
|
|
|
const [period, setPeriod] = useState(0); |
|
|
|
|
|
|
|
const dateMap: DateParams = useMemo(() => ({ |
|
|
|
0: {startDate: "", endDate: ""}, |
|
|
|
2: {startDate: `${currFinancialYear-2}-${startDate}`, endDate: `${currFinancialYear-1}-${endDate}`}, |
|
|
|
3: {startDate: `${currFinancialYear-3}-${startDate}`, endDate: `${currFinancialYear-2}-${endDate}`}, |
|
|
|
4: {startDate: `${currFinancialYear-4}-${startDate}`, endDate: `${currFinancialYear-3}-${endDate}`}, |
|
|
|
5: {startDate: "", endDate: `${currFinancialYear-4}-${endDate}`}, |
|
|
|
}), [currYear, startDate, endDate]) |
|
|
|
const dateMap: DateParams = useMemo(() => { |
|
|
|
const thisYear = currDate <= `${currYear}-${endDate}` ? |
|
|
|
{startDate: `${currYear-1}-${startDate}`, endDate: `${currYear}-${endDate}`} : |
|
|
|
{startDate: `${currYear}-${startDate}`, endDate: `${currFinancialYear}-${endDate}`} |
|
|
|
const map: DateParams = { |
|
|
|
0: {startDate: "", endDate: ""}, |
|
|
|
1: thisYear, |
|
|
|
[lengthOfCombo - 1]: {startDate: "", endDate: `${currFinancialYear-(lengthOfCombo - 2)}-${endDate}`} |
|
|
|
} |
|
|
|
for (let i = 2; i < lengthOfCombo - 1; i++) { |
|
|
|
map[i] = { |
|
|
|
startDate: `${currFinancialYear-i}-${startDate}`, |
|
|
|
endDate: `${currFinancialYear-(i - 1)}-${endDate}` |
|
|
|
} |
|
|
|
} |
|
|
|
return map |
|
|
|
}, [currDate, currYear, currFinancialYear, startDate, endDate, lengthOfCombo]) |
|
|
|
|
|
|
|
// const comboList: string[] = useMemo(() => { |
|
|
|
// const list = ["All"] |
|
|
|
// var lastYear = "" |
|
|
|
// for (let i = 1; i < lengthOfCombo; i++) { |
|
|
|
// var currYearStr = t(" (current year) ") |
|
|
|
// var yearsStr = `${currFinancialYear - i} - ${currFinancialYear - i + 1}` |
|
|
|
// var str = yearsStr |
|
|
|
// if (i == 1) str = yearsStr + currYearStr |
|
|
|
// lastYear = `${currFinancialYear - i}` |
|
|
|
// list.push(str) |
|
|
|
// } |
|
|
|
// list[lengthOfCombo - 1] = `< ${lastYear}` |
|
|
|
// return list |
|
|
|
// }, []) |
|
|
|
|
|
|
|
const comboList: string[] = useMemo(() => { |
|
|
|
const list = ["All"]; |
|
|
|
for (let i = 1; i < lengthOfCombo - 1; i++) { |
|
|
|
const yearRange = `${currFinancialYear - i} - ${currFinancialYear - i + 1}`; |
|
|
|
const label = i === 1 ? `${yearRange} ${t("(current year)")}` : yearRange; |
|
|
|
list.push(label); |
|
|
|
} |
|
|
|
const oldestYear = currFinancialYear - (lengthOfCombo - 2); |
|
|
|
list.push(`< ${oldestYear}`); |
|
|
|
return list; |
|
|
|
}, [currFinancialYear, lengthOfCombo, t]); |
|
|
|
|
|
|
|
const fetchFinancialSummaryByProject = useCallback(async (endDate: string, startDate: string) => { |
|
|
|
setIsLoading(true) |
|
|
@@ -95,27 +138,14 @@ const FinancialSummaryPage: React.FC<Props> = ({ |
|
|
|
setTeamId(teamId) |
|
|
|
}, []); |
|
|
|
|
|
|
|
const handleFilter = useCallback((value: number) => { |
|
|
|
const handleFilter = useCallback(async (value: number) => { |
|
|
|
setPeriod(value) |
|
|
|
console.log(value) |
|
|
|
var _startDate: string = "" |
|
|
|
var _endDate = "" |
|
|
|
if (value == 1) { |
|
|
|
if (curr <= `${currYear}-${endDate}`) { |
|
|
|
_startDate = `${currYear - 1}-${startDate}` |
|
|
|
_endDate = `${currYear}-${endDate}` |
|
|
|
} else { |
|
|
|
_startDate = `${currYear}-${startDate}` |
|
|
|
_endDate = `${currFinancialYear}-${endDate}` |
|
|
|
} |
|
|
|
} else { |
|
|
|
_startDate = dateMap[value as keyof DateParams].startDate |
|
|
|
_endDate = dateMap[value as keyof DateParams].endDate |
|
|
|
} |
|
|
|
var _startDate = dateMap[value as keyof DateParams].startDate |
|
|
|
var _endDate = dateMap[value as keyof DateParams].endDate |
|
|
|
console.log(_startDate) |
|
|
|
console.log(_endDate) |
|
|
|
fetchFinancialSummaryByProject(_endDate, _startDate) |
|
|
|
|
|
|
|
await fetchFinancialSummaryByProject(_endDate, _startDate) |
|
|
|
}, [isCardClickedIndex]) |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
@@ -144,18 +174,11 @@ const FinancialSummaryPage: React.FC<Props> = ({ |
|
|
|
label="Age" |
|
|
|
onChange={(e) => handleFilter(Number(e.target.value))} |
|
|
|
> |
|
|
|
{Array.from({ length: 6 }).map((_, i) => { |
|
|
|
if (i == 0) { |
|
|
|
return <MenuItem key={i} value={i}>{`All`}</MenuItem> |
|
|
|
} else if (i == 1) { |
|
|
|
return <MenuItem key={i} value={i}>{`${currFinancialYear - i} - ${currFinancialYear - i + 1} (current year)`}</MenuItem> |
|
|
|
} else if (i == 5) { |
|
|
|
return <MenuItem value={i}>{`< ${currYear - i + 1}`}</MenuItem> |
|
|
|
} else { |
|
|
|
return <MenuItem key={i} value={i}>{`${currFinancialYear - i} - ${currFinancialYear - i + 1}`}</MenuItem> |
|
|
|
} |
|
|
|
} |
|
|
|
)} |
|
|
|
{ |
|
|
|
comboList.map((str, i) => { |
|
|
|
return <MenuItem key={i} value={i}>{str}</MenuItem> |
|
|
|
}) |
|
|
|
} |
|
|
|
</Select> |
|
|
|
</FormControl> |
|
|
|
</Box> |
|
|
@@ -168,20 +191,21 @@ const FinancialSummaryPage: React.FC<Props> = ({ |
|
|
|
{_teamId == 0 && allTeam && |
|
|
|
<div className="hover:cursor-pointer ml-4 inline-block" key={0} onClick={() => handleCardClick(0)}> |
|
|
|
<ProjectFinancialCard |
|
|
|
Title={t("All Team")} |
|
|
|
TeamId={0} |
|
|
|
Title={t("All Team")} |
|
|
|
TeamId={0} |
|
|
|
TotalActiveProjectNumber={allTeam.activeProject} |
|
|
|
TotalFees={allTeam.totalFee} |
|
|
|
TotalBudget={allTeam.totalBudget} |
|
|
|
TotalCumulative={allTeam.manhourExpense + allTeam.projectExpense} |
|
|
|
TotalProjectExpense={allTeam.projectExpense} |
|
|
|
TotalInvoicedAmount={allTeam.invoicedAmount} |
|
|
|
TotalUnInvoicedAmount={allTeam.totalFee - allTeam.invoicedAmount} |
|
|
|
TotalInvoicedAmount={allTeam.invoicedAmount} |
|
|
|
// TotalUnInvoicedAmount={allTeam.totalFee - allTeam.invoicedAmount} |
|
|
|
TotalUnInvoicedAmount={allTeam.uninvoicedAmount} |
|
|
|
TotalReceivedAmount={allTeam.paidAmount} |
|
|
|
CashFlowStatus={allTeam.invoicedAmount >= (allTeam.projectExpense + allTeam.manhourExpense) ? "Positive" : "Negative"} |
|
|
|
CostPerformanceIndex={allTeam.invoicedAmount/(allTeam.projectExpense + allTeam.manhourExpense) || 0} |
|
|
|
CostPerformanceIndex={isFinite(allTeam.invoicedAmount/(allTeam.projectExpense + allTeam.manhourExpense)) ? 0 : allTeam.invoicedAmount/(allTeam.projectExpense + allTeam.manhourExpense) || 0} |
|
|
|
ProjectedCashFlowStatus={allTeam.totalFee >= (allTeam.projectExpense + allTeam.manhourExpense) ? "Positive" : "Negative"} |
|
|
|
ProjectedCPI={allTeam.totalFee/(allTeam.projectExpense + allTeam.manhourExpense)} |
|
|
|
ProjectedCPI={isFinite(allTeam.totalFee/(allTeam.projectExpense + allTeam.manhourExpense)) ? 0 : allTeam.totalFee/(allTeam.projectExpense + allTeam.manhourExpense) || 0} |
|
|
|
ClickedIndex={isCardClickedIndex} |
|
|
|
Index={0}/> |
|
|
|
</div>} |
|
|
@@ -196,12 +220,13 @@ const FinancialSummaryPage: React.FC<Props> = ({ |
|
|
|
TotalCumulative={record.projectExpense + record.manhourExpense} |
|
|
|
TotalProjectExpense={record.projectExpense} |
|
|
|
TotalInvoicedAmount={record.invoicedAmount} |
|
|
|
TotalUnInvoicedAmount={Math.abs(record.totalFee - record.invoicedAmount)} |
|
|
|
// TotalUnInvoicedAmount={Math.abs(record.totalFee - record.invoicedAmount)} |
|
|
|
TotalUnInvoicedAmount={Math.abs(record.uninvoicedAmount)} |
|
|
|
TotalReceivedAmount={record.paidAmount} |
|
|
|
CashFlowStatus={record.invoicedAmount >= (record.projectExpense + record.manhourExpense) ? "Positive" : "Negative"} |
|
|
|
CostPerformanceIndex={record.invoicedAmount/(record.projectExpense + record.manhourExpense) || 0} |
|
|
|
ProjectedCashFlowStatus={record.totalFee >= (record.projectExpense + record.manhourExpense) ? "Positive" : "Negative"} |
|
|
|
ProjectedCPI={record.totalFee/(record.projectExpense + record.manhourExpense)} |
|
|
|
ProjectedCPI={record.totalFee/(record.projectExpense + record.manhourExpense) || 0} |
|
|
|
ClickedIndex={isCardClickedIndex} |
|
|
|
Index={record.id}/> |
|
|
|
</div> |
|
|
|