Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 

221 рядки
9.2 KiB

  1. "use client";
  2. import { FinancialByProject, fetchFinancialSummaryByProjectV2 } from '@/app/api/financialsummary';
  3. import { Box, Card, CardContent, CardHeader, FormControl, InputLabel, MenuItem, Select, Stack } from '@mui/material';
  4. import { useCallback, useEffect, useMemo, useState } from 'react';
  5. import { useTranslation } from "react-i18next";
  6. import ProjectFinancialCard from '../ProjectFinancialSummary/ProjectFinancialCard';
  7. import dayjs from 'dayjs';
  8. import { INPUT_DATE_FORMAT } from '@/app/utils/formatUtil';
  9. import { SumOfByClient, SumOfByTeam, sumUpByClient, sumUpByTeam } from './gptFn';
  10. import FinancialStatusByProject from './FinnancialStatusByProject';
  11. interface Props {
  12. _teamId: number,
  13. financialSummByProject: FinancialByProject[]
  14. }
  15. type InputDate = {
  16. startDate: string;
  17. endDate: string;
  18. }
  19. type DateParams = {
  20. 0: InputDate;
  21. 2: InputDate;
  22. 3: InputDate;
  23. 4: InputDate;
  24. 5: InputDate;
  25. }
  26. const FinancialSummaryPage: React.FC<Props> = ({
  27. _teamId,
  28. financialSummByProject
  29. }) => {
  30. console.log(financialSummByProject)
  31. const { t } = useTranslation();
  32. const curr = useMemo(() => dayjs().format(INPUT_DATE_FORMAT), [])
  33. const currYear = useMemo(() => dayjs().get("year"), [])
  34. const startDate = "10-01"
  35. const endDate = "09-30"
  36. const currFinancialYear = useMemo(() => curr > `${currYear}-${startDate}` ? currYear + 1 : currYear, [currYear])
  37. const [mainData, setMainData] = useState<FinancialByProject[]>(financialSummByProject)
  38. const [byTeam, setByTeam] = useState<SumOfByTeam[]>(() => sumUpByTeam(mainData)) // do fetch to set
  39. const [byProject, setByProject] = useState<FinancialByProject[]>(financialSummByProject)
  40. const [byClient, setByClient] = useState<SumOfByClient[]>(() => sumUpByClient(mainData))
  41. const [isLoading, setIsLoading] = useState(false)
  42. const allTeam = useMemo(()=> {
  43. var _allTeam: SumOfByTeam = {
  44. id: 0,
  45. team: "All Team",
  46. totalFee: 0,
  47. totalBudget: 0,
  48. manhourExpense: 0,
  49. projectExpense: 0,
  50. invoicedAmount: 0,
  51. paidAmount: 0,
  52. activeProject: 0,
  53. }
  54. for (let i = 0; i < byTeam.length; i++) {
  55. var curr = byTeam[i]
  56. _allTeam["totalFee"] += curr.totalFee
  57. _allTeam["totalBudget"] += curr.totalBudget
  58. _allTeam["manhourExpense"] += curr.manhourExpense
  59. _allTeam["projectExpense"] += curr.projectExpense
  60. _allTeam["invoicedAmount"] += curr.invoicedAmount
  61. _allTeam["paidAmount"] += curr.paidAmount
  62. _allTeam["activeProject"] += curr.activeProject
  63. }
  64. return _allTeam
  65. }, [mainData])
  66. console.log(allTeam)
  67. const [teamId, setTeamId] = useState(_teamId)
  68. const [isCardClickedIndex, setIsCardClickedIndex] = useState(_teamId || 0);
  69. const [period, setPeriod] = useState(0);
  70. const dateMap: DateParams = useMemo(() => ({
  71. 0: {startDate: "", endDate: ""},
  72. 2: {startDate: `${currFinancialYear-2}-${startDate}`, endDate: `${currFinancialYear-1}-${endDate}`},
  73. 3: {startDate: `${currFinancialYear-3}-${startDate}`, endDate: `${currFinancialYear-2}-${endDate}`},
  74. 4: {startDate: `${currFinancialYear-4}-${startDate}`, endDate: `${currFinancialYear-3}-${endDate}`},
  75. 5: {startDate: "", endDate: `${currFinancialYear-4}-${endDate}`},
  76. }), [currYear, startDate, endDate])
  77. const fetchFinancialSummaryByProject = useCallback(async (endDate: string, startDate: string) => {
  78. setIsLoading(true)
  79. const data = await fetchFinancialSummaryByProjectV2(_teamId, endDate, startDate)
  80. setMainData(data)
  81. setByTeam(sumUpByTeam(data))
  82. setByProject(data)
  83. setByClient(sumUpByClient(data))
  84. setIsLoading(false)
  85. }, [setMainData, setByTeam, setByProject, setByClient])
  86. const handleCardClick = useCallback((teamId: number) => {
  87. setIsCardClickedIndex(teamId)
  88. setTeamId(teamId)
  89. }, []);
  90. const handleFilter = useCallback((value: number) => {
  91. setPeriod(value)
  92. console.log(value)
  93. var _startDate: string = ""
  94. var _endDate = ""
  95. if (value == 1) {
  96. if (curr <= `${currYear}-${endDate}`) {
  97. _startDate = `${currYear - 1}-${startDate}`
  98. _endDate = `${currYear}-${endDate}`
  99. } else {
  100. _startDate = `${currYear}-${startDate}`
  101. _endDate = `${currFinancialYear}-${endDate}`
  102. }
  103. } else {
  104. _startDate = dateMap[value as keyof DateParams].startDate
  105. _endDate = dateMap[value as keyof DateParams].endDate
  106. }
  107. console.log(_startDate)
  108. console.log(_endDate)
  109. fetchFinancialSummaryByProject(_endDate, _startDate)
  110. }, [isCardClickedIndex])
  111. useEffect(() => {
  112. if (teamId > 0) {
  113. var filterByTeam = mainData.filter(item => item.teamId == teamId)
  114. setByProject(filterByTeam)
  115. setByClient(sumUpByClient(filterByTeam))
  116. } else {
  117. setByProject(financialSummByProject)
  118. setByClient(sumUpByClient(mainData))
  119. }
  120. }, [teamId])
  121. return (
  122. <>
  123. <Card sx={{ display: "block" }}>
  124. {/* <CardHeader className="text-slate-500" title= {t("Filter")}/> */}
  125. <CardContent component={Stack} spacing={1}>
  126. <Box sx={{ minWidth: 120 }}>
  127. <FormControl fullWidth>
  128. <InputLabel id="demo-simple-select-label">Financial Year</InputLabel>
  129. <Select
  130. labelId="demo-simple-select-label"
  131. id="demo-simple-select"
  132. value={period}
  133. label="Age"
  134. onChange={(e) => handleFilter(Number(e.target.value))}
  135. >
  136. {Array.from({ length: 6 }).map((_, i) => {
  137. if (i == 0) {
  138. return <MenuItem key={i} value={i}>{`All`}</MenuItem>
  139. } else if (i == 1) {
  140. return <MenuItem key={i} value={i}>{`${currFinancialYear - i} - ${currFinancialYear - i + 1} (current year)`}</MenuItem>
  141. } else if (i == 5) {
  142. return <MenuItem value={i}>{`< ${currYear - i + 1}`}</MenuItem>
  143. } else {
  144. return <MenuItem key={i} value={i}>{`${currFinancialYear - i} - ${currFinancialYear - i + 1}`}</MenuItem>
  145. }
  146. }
  147. )}
  148. </Select>
  149. </FormControl>
  150. </Box>
  151. </CardContent>
  152. </Card>
  153. <Card sx={{ display: "block" }}>
  154. <CardHeader className="text-slate-500" title= {t("Active Project Financial Status")}/>
  155. <CardContent component={Stack} spacing={4}>
  156. <div className="ml-10 mr-10" style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'start'}}>
  157. {_teamId == 0 && allTeam &&
  158. <div className="hover:cursor-pointer ml-4 inline-block" key={0} onClick={() => handleCardClick(0)}>
  159. <ProjectFinancialCard
  160. Title={t("All Team")}
  161. TeamId={0}
  162. TotalActiveProjectNumber={allTeam.activeProject}
  163. TotalFees={allTeam.totalFee}
  164. TotalBudget={allTeam.totalBudget}
  165. TotalCumulative={allTeam.manhourExpense + allTeam.projectExpense}
  166. TotalProjectExpense={allTeam.projectExpense}
  167. TotalInvoicedAmount={allTeam.invoicedAmount}
  168. TotalUnInvoicedAmount={allTeam.totalFee - allTeam.invoicedAmount}
  169. TotalReceivedAmount={allTeam.paidAmount}
  170. CashFlowStatus={allTeam.invoicedAmount >= (allTeam.projectExpense + allTeam.manhourExpense) ? "Positive" : "Negative"}
  171. CostPerformanceIndex={allTeam.invoicedAmount/(allTeam.projectExpense + allTeam.manhourExpense) || 0}
  172. ProjectedCashFlowStatus={allTeam.totalFee >= (allTeam.projectExpense + allTeam.manhourExpense) ? "Positive" : "Negative"}
  173. ProjectedCPI={allTeam.totalFee/(allTeam.projectExpense + allTeam.manhourExpense)}
  174. ClickedIndex={isCardClickedIndex}
  175. Index={0}/>
  176. </div>}
  177. {byTeam.length > 0 && byTeam.map((record) => (
  178. <div className="hover:cursor-pointer ml-4 inline-block" key={record.id} onClick={() => handleCardClick(record.id)}>
  179. <ProjectFinancialCard
  180. Title={record.team}
  181. TeamId={record.id}
  182. TotalActiveProjectNumber={record.activeProject}
  183. TotalFees={record.totalFee}
  184. TotalBudget={record.totalBudget}
  185. TotalCumulative={record.projectExpense + record.manhourExpense}
  186. TotalProjectExpense={record.projectExpense}
  187. TotalInvoicedAmount={record.invoicedAmount}
  188. TotalUnInvoicedAmount={Math.abs(record.totalFee - record.invoicedAmount)}
  189. TotalReceivedAmount={record.paidAmount}
  190. CashFlowStatus={record.invoicedAmount >= (record.projectExpense + record.manhourExpense) ? "Positive" : "Negative"}
  191. CostPerformanceIndex={record.invoicedAmount/(record.projectExpense + record.manhourExpense) || 0}
  192. ProjectedCashFlowStatus={record.totalFee >= (record.projectExpense + record.manhourExpense) ? "Positive" : "Negative"}
  193. ProjectedCPI={record.totalFee/(record.projectExpense + record.manhourExpense)}
  194. ClickedIndex={isCardClickedIndex}
  195. Index={record.id}/>
  196. </div>
  197. ))}
  198. </div>
  199. </CardContent>
  200. </Card>
  201. <FinancialStatusByProject
  202. financialSummByProject={byProject}
  203. financialSummByClient={byClient}
  204. isLoading={isLoading}
  205. />
  206. </>
  207. )
  208. }
  209. export default FinancialSummaryPage