Enhance data processing: add utility functions for year extraction and graph data population
This commit is contained in:
parent
76ad6d53ad
commit
43a686bb3b
@ -79,6 +79,8 @@ export function CativoXLivreChart({ title, subtitle, chartData, label, dataset1,
|
||||
|
||||
const options: any = config(miniature)
|
||||
|
||||
const hasEstimated = chartData?.some((value) => value.dad_estimado)
|
||||
|
||||
const data: any = {
|
||||
labels,
|
||||
datasets: chartData?.map(value => value.dad_estimado)?.includes(true) ? [
|
||||
@ -184,7 +186,7 @@ export function CativoXLivreChart({ title, subtitle, chartData, label, dataset1,
|
||||
|
||||
return (
|
||||
<CativoXLivreChartView>
|
||||
<ChartTitle title={title} subtitle={subtitle}/>
|
||||
{/* <ChartTitle title={title} subtitle={subtitle}/> */}
|
||||
<div>
|
||||
<Chart ref={chartRef} type='bar' options={options} data={data} />
|
||||
</div>
|
||||
|
||||
@ -80,7 +80,7 @@ export default function CostIndicatorChart({ title, data1, data2, label, subtitl
|
||||
|
||||
return (
|
||||
<CostIndicatorChartView>
|
||||
<ChartTitle title={title} subtitle={subtitle} />
|
||||
{/* <ChartTitle title={title} subtitle={subtitle} /> */}
|
||||
<Bar
|
||||
options={options}
|
||||
data={data}
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { BarElement, CategoryScale, Chart as ChartJS, layouts, Legend, LinearScale, Title, Tooltip } from 'chart.js';
|
||||
import { BarElement, CategoryScale, Chart as ChartJS, Legend, LinearScale, Title, Tooltip } from 'chart.js';
|
||||
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
||||
import 'chartjs-plugin-style';
|
||||
import { draw } from 'patternomaly';
|
||||
import { Chart } from 'react-chartjs-2';
|
||||
|
||||
import ChartTitle from '../ChartTitle';
|
||||
import { GrossAnualChartView } from './GrossAnualChartView';
|
||||
|
||||
ChartJS.register(
|
||||
@ -40,7 +39,7 @@ export function GrossAnualChart({ title, subtitle, dataProps = [], label, datase
|
||||
// maintainAspectRatio: false,
|
||||
layout: {
|
||||
padding: {
|
||||
top: 50,
|
||||
top: 0,
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
@ -56,7 +55,7 @@ export function GrossAnualChart({ title, subtitle, dataProps = [], label, datase
|
||||
},
|
||||
},
|
||||
y: {
|
||||
stacked: false,
|
||||
stacked: true,
|
||||
//max: Number.parseInt(dataProps.reduce((prev, current) => prev.economia_acumulada < current.economia_acumulada ? prev.economia_acumulada : current.economia_acumulada, 0)) + 350,
|
||||
min: 0,
|
||||
grid: {
|
||||
@ -79,26 +78,28 @@ export function GrossAnualChart({ title, subtitle, dataProps = [], label, datase
|
||||
},
|
||||
plugins: {
|
||||
datalabels: {
|
||||
display: true,
|
||||
color: '#255488',
|
||||
clip: false,
|
||||
formatter: (value, ctx) => {
|
||||
const percentage = (dataProps[ctx.dataIndex]?.econ_percentual * 100).toFixed(0) + "%";
|
||||
const result = `${spacement(parseInt(value).toLocaleString('pt-br'))}${percentage}\n${parseInt(value).toLocaleString('pt-br')}${spacement(parseInt(value).toLocaleString('pt-br'))}`
|
||||
|
||||
return value == null ? null : result
|
||||
},
|
||||
display: true,
|
||||
anchor: "end",
|
||||
align: "end",
|
||||
anchor: 'end',
|
||||
align: 'end',
|
||||
offset: 5,
|
||||
font: {
|
||||
weight: 'bold',
|
||||
size: !miniature ? window.innerWidth / 80 : window.innerWidth / 125,
|
||||
},
|
||||
color: '#255488',
|
||||
},
|
||||
legend: {
|
||||
position: 'bottom' as const,
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
display: true,
|
||||
text: '',
|
||||
},
|
||||
},
|
||||
@ -126,7 +127,7 @@ export function GrossAnualChart({ title, subtitle, dataProps = [], label, datase
|
||||
{
|
||||
type: 'bar',
|
||||
label: dataset,
|
||||
stacked: true,
|
||||
// stacked: true,
|
||||
data: consolidatedData,
|
||||
datalabels: {
|
||||
// backgroundColor: '#255488',
|
||||
@ -134,19 +135,19 @@ export function GrossAnualChart({ title, subtitle, dataProps = [], label, datase
|
||||
// opacity: .8,
|
||||
display: (ctx) => ctx.dataIndex === 0, // Exibe apenas o primeiro
|
||||
},
|
||||
borderRadius: 10,
|
||||
skipNull: true,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#255488',
|
||||
},
|
||||
{
|
||||
type: 'bar',
|
||||
stacked: true,
|
||||
label: 'Estimado',
|
||||
spanGaps: true,
|
||||
datalabels: {
|
||||
// keep the previous behaviour of offsetting the second estimated bar if needed
|
||||
},
|
||||
data: estimatedData,
|
||||
borderRadius: 10,
|
||||
skipNull: true,
|
||||
borderRadius: 8,
|
||||
backgroundColor: draw('diagonal-right-left', '#C2d5fb'),
|
||||
},
|
||||
],
|
||||
@ -154,8 +155,7 @@ export function GrossAnualChart({ title, subtitle, dataProps = [], label, datase
|
||||
|
||||
return (
|
||||
<GrossAnualChartView>
|
||||
|
||||
<Chart options={options} data={data} type='bar' height={150} />
|
||||
<Chart options={options} data={data} type='bar' height={'156'} />
|
||||
</GrossAnualChartView>
|
||||
)
|
||||
}
|
||||
|
||||
@ -3,21 +3,23 @@ import styled from "styled-components"
|
||||
export const GrossAnualChartView = styled.div`
|
||||
width: 90%;
|
||||
|
||||
transform: translateY(-25px);
|
||||
|
||||
@media (max-width: 900px) {
|
||||
min-width: 20rem
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
export const ChartTitleView = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 30px;
|
||||
// export const ChartTitleView = styled.div`
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
// margin-top: 30px;
|
||||
|
||||
flex-direction: column;
|
||||
// flex-direction: column;
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
`
|
||||
// * {
|
||||
// margin: 0;
|
||||
// }
|
||||
// `
|
||||
|
||||
@ -88,7 +88,7 @@ export default function GrossMensalChart({
|
||||
datalabels: {
|
||||
display: true,
|
||||
color: '#255488',
|
||||
clip: true,
|
||||
clip: false,
|
||||
formatter: (value, ctx) => {
|
||||
let sum = 0
|
||||
const dataArr = ctx.chart.data.datasets[0].data
|
||||
@ -152,7 +152,7 @@ export default function GrossMensalChart({
|
||||
|
||||
return (
|
||||
<GrossMensalChartView>
|
||||
<ChartTitle title={title} subtitle={subtitle} />
|
||||
{/* <ChartTitle title={title} subtitle={subtitle} /> */}
|
||||
<ChartJs options={options} data={data} type={'bar'} height={'156'} />
|
||||
</GrossMensalChartView>
|
||||
)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { GetServerSideProps } from 'next'
|
||||
import Head from 'next/head'
|
||||
import { parseCookies } from 'nookies'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
// import Chart2 from '../../components/graph/Chart2'
|
||||
import GrossMensalChart from '../../components/graph/grossMensalChart/GrossMensalChart'
|
||||
@ -10,6 +10,7 @@ import PageTitle from '../../components/pageTitle/PageTitle'
|
||||
|
||||
import getAPIClient from '../../services/ssrApi'
|
||||
import { AccumulatedSavingsView } from '../../styles/layouts/economy/accumulatedSavings/AccumulatedSavingsView'
|
||||
import { getLastConsolidatedYear, populateGraphDataForYear } from '../../utils/dataProcessing'
|
||||
|
||||
export default function AccumulatedSavings({graphData, years, userName}: any) {
|
||||
const months = [
|
||||
@ -27,6 +28,19 @@ export default function AccumulatedSavings({graphData, years, userName}: any) {
|
||||
'Dez'
|
||||
]
|
||||
|
||||
const [processedData, setProcessedData] = useState(graphData)
|
||||
const [lastConsolidatedYear, setLastConsolidatedYear] = useState<number | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
// Calculate the last consolidated year
|
||||
const lastYear = getLastConsolidatedYear(graphData, true)
|
||||
setLastConsolidatedYear(lastYear)
|
||||
|
||||
// Populate graph data with consolidated and estimated data for that year
|
||||
const populatedData = populateGraphDataForYear(graphData, lastYear)
|
||||
setProcessedData(populatedData)
|
||||
}, [graphData])
|
||||
|
||||
return (
|
||||
<AccumulatedSavingsView>
|
||||
<Head>
|
||||
@ -37,8 +51,8 @@ export default function AccumulatedSavings({graphData, years, userName}: any) {
|
||||
</Header>
|
||||
<section>
|
||||
<GrossMensalChart title='' subtitle=''
|
||||
data1={graphData}
|
||||
data2={graphData}
|
||||
data1={processedData}
|
||||
data2={processedData}
|
||||
label={months}
|
||||
/>
|
||||
{/* <SingleBar title='' subtitle='' dataset='Consolidada'
|
||||
|
||||
@ -15,6 +15,7 @@ import PageTitle from '../../components/pageTitle/PageTitle'
|
||||
import getAPIClient from '../../services/ssrApi'
|
||||
import { CostIndicatorView } from '../../styles/layouts/economy/costIndicator/CostIndicatorView'
|
||||
import { api } from '../../services/api';
|
||||
import { getLastConsolidatedYear, populateGraphDataForYear } from '../../utils/dataProcessing'
|
||||
|
||||
export default function CostIndicator({graphData, userName, clients}: any) {
|
||||
const [unity, setUnity] = useState('');
|
||||
@ -35,6 +36,18 @@ export default function CostIndicator({graphData, userName, clients}: any) {
|
||||
]
|
||||
|
||||
const [graphDataState, setGraphDataState] = useState([]);
|
||||
const [processedGraphData, setProcessedGraphData] = useState(graphData)
|
||||
const [lastConsolidatedYear, setLastConsolidatedYear] = useState<number | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
// Calculate the last consolidated year
|
||||
const lastYear = getLastConsolidatedYear(graphData, true)
|
||||
setLastConsolidatedYear(lastYear)
|
||||
|
||||
// Populate graph data with consolidated and estimated data for that year
|
||||
const populatedData = populateGraphDataForYear(graphData, lastYear)
|
||||
setProcessedGraphData(populatedData)
|
||||
}, [graphData])
|
||||
|
||||
useEffect(() => {
|
||||
api.post('/economy/estimates', unity!==''?{
|
||||
@ -42,7 +55,14 @@ export default function CostIndicator({graphData, userName, clients}: any) {
|
||||
{"type" : "=", "field":"dados_cadastrais.cod_smart_unidade", "value": unity}
|
||||
]
|
||||
}:{}).then(res => {
|
||||
setGraphDataState(res.data.data)
|
||||
// Apply data processing to filtered result
|
||||
if (res.data.data && res.data.data.length > 0) {
|
||||
const lastYear = getLastConsolidatedYear(res.data.data, true)
|
||||
const populatedData = populateGraphDataForYear(res.data.data, lastYear)
|
||||
setGraphDataState(populatedData)
|
||||
} else {
|
||||
setGraphDataState(res.data.data)
|
||||
}
|
||||
})
|
||||
}, [unity])
|
||||
|
||||
@ -75,12 +95,16 @@ export default function CostIndicator({graphData, userName, clients}: any) {
|
||||
</FormControl>
|
||||
<section>
|
||||
<CostIndicatorChart title='' subtitle=''
|
||||
data1={unity!==''? graphDataState.filter((value, index) => value.mes.slice(4, 8).includes('2021'))
|
||||
data1={unity!==''? graphDataState.filter((value, index) => value.mes.slice(0, 4).includes(lastConsolidatedYear?.toString() || ''))
|
||||
.map(value => value?.custo_unit && !!parseInt(value?.custo_unit) ? value.custo_unit : null)
|
||||
:
|
||||
graphData.filter((value, index) => value.mes.slice(4, 8).includes('2021'))}
|
||||
data2={unity!==''? graphDataState.filter((value, index) => value.mes.slice(4, 8).includes('2022'))
|
||||
processedGraphData.filter((value, index) => value.mes.slice(0, 4).includes(lastConsolidatedYear?.toString() || ''))
|
||||
.map(value => value?.custo_unit && !!parseInt(value?.custo_unit) ? value.custo_unit : null)}
|
||||
data2={unity!==''? graphDataState.filter((value, index) => value.mes.slice(0, 4).includes(lastConsolidatedYear?.toString() || ''))
|
||||
.map(value => value?.custo_unit && !!parseInt(value?.custo_unit) ? value.custo_unit : null)
|
||||
:
|
||||
graphData.filter((value, index) => value.mes.slice(4, 8).includes('2022'))}
|
||||
processedGraphData.filter((value, index) => value.mes.slice(0, 4).includes(lastConsolidatedYear?.toString() || ''))
|
||||
.map(value => value?.custo_unit && !!parseInt(value?.custo_unit) ? value.custo_unit : null)}
|
||||
label={months}
|
||||
/>
|
||||
</section>
|
||||
|
||||
@ -18,6 +18,7 @@ import CostIndicatorChart from '../../components/graph/costIndicatorChart'
|
||||
import { GrossAnualChart } from '../../components/graph/grossAnualChart/GrossAnualChart'
|
||||
import GrossMensalChart from '../../components/graph/grossMensalChart/GrossMensalChart'
|
||||
import getAPIClient from '../../services/ssrApi'
|
||||
import { getLastConsolidatedYear, populateGraphDataForYear } from '../../utils/dataProcessing'
|
||||
|
||||
import Box from '@mui/material/Box'
|
||||
import Modal from '@mui/material/Modal'
|
||||
@ -66,30 +67,41 @@ export default function Dashboard({ grossAnualGraph, grossAnualYears, grossMensa
|
||||
|
||||
const [lastDataBrutaMensalS, setLastDataBrutaMensal] = useState('')
|
||||
const [lastDataBrutaAnualS, setLastDataBrutaAnual] = useState('')
|
||||
const [processedMensalData, setProcessedMensalData] = useState(grossMensalGraph)
|
||||
const [lastConsolidatedYear, setLastConsolidatedYear] = useState<number | null>(null)
|
||||
|
||||
const [open, setOpen] = useState(true);
|
||||
const handleOpen = () => setOpen(true);
|
||||
const handleClose = () => setOpen(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Calculate the last consolidated year
|
||||
const lastYear = getLastConsolidatedYear(grossMensalGraph, true)
|
||||
setLastConsolidatedYear(lastYear)
|
||||
|
||||
// Populate graph data with consolidated and estimated data for that year
|
||||
const populatedData = populateGraphDataForYear(grossMensalGraph, lastYear)
|
||||
setProcessedMensalData(populatedData)
|
||||
|
||||
// Calculate last data values
|
||||
let lastDataMensal = '0'
|
||||
let lastDataAnual = '0'
|
||||
let index = 0
|
||||
|
||||
while (index < grossMensalGraph.length) {
|
||||
if (!grossMensalGraph[index].dad_estimado && grossMensalGraph[index].economia_acumulada !== null)
|
||||
lastDataMensal = grossMensalGraph[index].economia_acumulada
|
||||
while (index < populatedData.length) {
|
||||
if (!populatedData[index].dad_estimado && populatedData[index].economia_acumulada !== null)
|
||||
lastDataMensal = String(populatedData[index].economia_acumulada)
|
||||
index++
|
||||
}
|
||||
setLastDataBrutaMensal(`${parseFloat(lastDataMensal).toFixed(3)}`)
|
||||
index = 0
|
||||
while (index < grossAnualGraph.length) {
|
||||
if (!grossAnualGraph[index].dad_estimado)
|
||||
lastDataAnual = grossAnualGraph[index].economia_acumulada
|
||||
lastDataAnual = String(grossAnualGraph[index].economia_acumulada)
|
||||
index++
|
||||
}
|
||||
setLastDataBrutaAnual(`${parseFloat(lastDataAnual).toFixed(3)}`)
|
||||
}, [])
|
||||
}, [grossMensalGraph, grossAnualGraph])
|
||||
|
||||
return (
|
||||
<DashboardView>
|
||||
@ -126,8 +138,8 @@ export default function Dashboard({ grossAnualGraph, grossAnualYears, grossMensa
|
||||
<GraphCard title='Economia Mensal' subtitle='Economia Bruta Estimada e Acumulada Mensal - Valores em R$ x mil'>
|
||||
<AccumulatedEconomyTitle value={lastDataBrutaMensalS} />
|
||||
<GrossMensalChart title='' subtitle=''
|
||||
data1={grossMensalGraph}
|
||||
data2={grossMensalGraph}
|
||||
data1={processedMensalData}
|
||||
data2={processedMensalData}
|
||||
label={months}
|
||||
miniature
|
||||
/>
|
||||
|
||||
@ -13,6 +13,7 @@ import { api } from '../../services/api';
|
||||
import getAPIClient from '../../services/ssrApi';
|
||||
import { TableHeader } from '../../styles/layouts/pld/PldView';
|
||||
import RenderIf from '../../utils/renderIf';
|
||||
import { getLastConsolidatedYear, populateGraphDataForYear } from '../../utils/dataProcessing';
|
||||
|
||||
import Tab from '@mui/material/Tab';
|
||||
import Tabs from '@mui/material/Tabs';
|
||||
@ -32,6 +33,8 @@ export default function economy({ userName, anual, years, brutaMensal, catLiv, c
|
||||
|
||||
const [catLivDataState, setCatLivDataState] = useState(null);
|
||||
const [indicatorDataState, setIndicatorDataState] = useState(null);
|
||||
const [processedBrutaMensal, setProcessedBrutaMensal] = useState(brutaMensal)
|
||||
const [lastConsolidatedYear, setLastConsolidatedYear] = useState<number | null>(null)
|
||||
|
||||
const currentYear = new Date().getUTCFullYear()
|
||||
const previousYear = new Date().getUTCFullYear() - 1
|
||||
@ -52,13 +55,24 @@ export default function economy({ userName, anual, years, brutaMensal, catLiv, c
|
||||
]
|
||||
|
||||
const [lastDataBruta, setLastDataBruta] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
// Calculate the last consolidated year
|
||||
const lastYear = getLastConsolidatedYear(brutaMensal, true)
|
||||
setLastConsolidatedYear(lastYear)
|
||||
|
||||
// Populate graph data with consolidated and estimated data for that year
|
||||
const populatedData = populateGraphDataForYear(brutaMensal, lastYear)
|
||||
setProcessedBrutaMensal(populatedData)
|
||||
}, [brutaMensal])
|
||||
|
||||
useEffect(() => {
|
||||
let lastData = '0'
|
||||
let index = 0
|
||||
if (economyMenu) {
|
||||
while (index < brutaMensal.length) {
|
||||
if (!brutaMensal[index].dad_estimado)
|
||||
lastData = brutaMensal[index].economia_acumulada
|
||||
while (index < processedBrutaMensal.length) {
|
||||
if (!processedBrutaMensal[index].dad_estimado)
|
||||
lastData = processedBrutaMensal[index].economia_acumulada
|
||||
index++
|
||||
}
|
||||
} else {
|
||||
@ -69,7 +83,7 @@ export default function economy({ userName, anual, years, brutaMensal, catLiv, c
|
||||
}
|
||||
}
|
||||
setLastDataBruta(`${parseFloat(lastData).toFixed(3)}`)
|
||||
}, [economyMenu])
|
||||
}, [economyMenu, processedBrutaMensal])
|
||||
useEffect(() => {
|
||||
console.log(indicatorDataState)
|
||||
}, [indicatorDataState])
|
||||
@ -148,8 +162,8 @@ export default function economy({ userName, anual, years, brutaMensal, catLiv, c
|
||||
<RenderIf isTrue={economyMenu === 1}>
|
||||
<section>
|
||||
<GrossMensalChart title='' subtitle=''
|
||||
data1={brutaMensal}
|
||||
data2={brutaMensal}
|
||||
data1={processedBrutaMensal}
|
||||
data2={processedBrutaMensal}
|
||||
label={months}
|
||||
/>
|
||||
</section>
|
||||
|
||||
@ -16,11 +16,24 @@ import getAPIClient from '../../services/ssrApi'
|
||||
import { EstimatedCostView } from '../../styles/layouts/economy/estimatedCost/EstimatedCostView'
|
||||
|
||||
import { api } from '../../services/api'
|
||||
import { getLastConsolidatedYear, populateGraphDataForYear } from '../../utils/dataProcessing'
|
||||
|
||||
export default function EstimatedCost({graphData, userName, clients}: any) {
|
||||
const [unity, setUnity] = useState<string>(null);
|
||||
|
||||
const [graphDataState, setGraphDataState] = useState(null);
|
||||
const [processedGraphData, setProcessedGraphData] = useState(graphData)
|
||||
const [lastConsolidatedYear, setLastConsolidatedYear] = useState<number | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
// Calculate the last consolidated year
|
||||
const lastYear = getLastConsolidatedYear(graphData, true)
|
||||
setLastConsolidatedYear(lastYear)
|
||||
|
||||
// Populate graph data with consolidated and estimated data for that year
|
||||
const populatedData = populateGraphDataForYear(graphData, lastYear)
|
||||
setProcessedGraphData(populatedData)
|
||||
}, [graphData])
|
||||
|
||||
useEffect(() => {
|
||||
api.post('/economy/estimates', unity!==''?{
|
||||
@ -28,7 +41,14 @@ export default function EstimatedCost({graphData, userName, clients}: any) {
|
||||
{"type" : "=", "field":"dados_cadastrais.cod_smart_unidade", "value": unity}
|
||||
]
|
||||
}:{}).then(res => {
|
||||
setGraphDataState(res.data.data)
|
||||
// Apply data processing to filtered result
|
||||
if (res.data.data && res.data.data.length > 0) {
|
||||
const lastYear = getLastConsolidatedYear(res.data.data, true)
|
||||
const populatedData = populateGraphDataForYear(res.data.data, lastYear)
|
||||
setGraphDataState(populatedData)
|
||||
} else {
|
||||
setGraphDataState(res.data.data)
|
||||
}
|
||||
})
|
||||
}, [unity])
|
||||
|
||||
@ -60,7 +80,7 @@ export default function EstimatedCost({graphData, userName, clients}: any) {
|
||||
</Select>
|
||||
</FormControl>
|
||||
<section>
|
||||
<CativoXLivreChart chartData={unity!==null? graphDataState : graphData}
|
||||
<CativoXLivreChart chartData={unity!==null? graphDataState : processedGraphData}
|
||||
dataset1="Economia (R$)" dataset2='Est. Cativo' dataset3='Est. Livre'
|
||||
label={['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']} title='' subtitle='' barLabel hashurado/>
|
||||
</section>
|
||||
|
||||
287
src/utils/dataProcessing.ts
Normal file
287
src/utils/dataProcessing.ts
Normal file
@ -0,0 +1,287 @@
|
||||
/**
|
||||
* Utility functions to process economy data from API
|
||||
* Calculates the year with the last consolidated data and populates graphs accordingly
|
||||
*/
|
||||
|
||||
interface EconomyData {
|
||||
ano?: string | number;
|
||||
mes?: string;
|
||||
economia_acumulada?: number;
|
||||
economia_mensal?: number;
|
||||
dad_estimado: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract year from mes field supporting multiple formats
|
||||
* Supports: "YYYY-MM-DD", "MMM/YYYY", "MM/YYYY"
|
||||
* @param mesValue - The mes field value
|
||||
* @returns Year as number
|
||||
*/
|
||||
function extractYearFromMes(mesValue: string): number {
|
||||
const mesStr = mesValue.toString();
|
||||
|
||||
// Handle "YYYY-MM-DD" format
|
||||
if (mesStr.includes('-')) {
|
||||
const yearStr = mesStr.split('-')[0];
|
||||
return parseInt(yearStr);
|
||||
}
|
||||
|
||||
// Handle "MMM/YYYY" or "MM/YYYY" format
|
||||
if (mesStr.includes('/')) {
|
||||
const yearStr = mesStr.split('/')[1];
|
||||
return parseInt(yearStr);
|
||||
}
|
||||
|
||||
// Fallback: try to parse as number if it's just a year
|
||||
const parsed = parseInt(mesStr);
|
||||
return !isNaN(parsed) ? parsed : new Date().getFullYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the year with the last consolidated (non-estimated) data
|
||||
* @param data - Array of economy data
|
||||
* @param isMonthly - If true, extract year from 'mes' field; if false, use 'ano' field
|
||||
* @returns The year with the last consolidated data
|
||||
*/
|
||||
export function getLastConsolidatedYear(data: EconomyData[], isMonthly: boolean = false): number {
|
||||
if (!data || data.length === 0) {
|
||||
return new Date().getFullYear();
|
||||
}
|
||||
|
||||
// Filter only consolidated data (dad_estimado === false)
|
||||
const consolidatedData = data.filter(item => !item.dad_estimado);
|
||||
|
||||
// Extract all years present in the dataset (consolidated + estimated)
|
||||
const allYears = data
|
||||
.map(item => {
|
||||
if (isMonthly && item.mes) {
|
||||
return extractYearFromMes(item.mes);
|
||||
}
|
||||
return parseInt(item.ano?.toString() || new Date().getFullYear().toString());
|
||||
})
|
||||
.filter(year => !Number.isNaN(year));
|
||||
|
||||
// Extract years from consolidated records
|
||||
const consolidatedYears = consolidatedData
|
||||
.map(item => {
|
||||
if (isMonthly && item.mes) {
|
||||
return extractYearFromMes(item.mes);
|
||||
}
|
||||
return parseInt(item.ano?.toString() || new Date().getFullYear().toString());
|
||||
})
|
||||
.filter(year => !Number.isNaN(year));
|
||||
|
||||
// Prefer the latest consolidated year; if none, fall back to the latest year available
|
||||
if (consolidatedYears.length > 0) {
|
||||
return Math.max(...consolidatedYears);
|
||||
}
|
||||
|
||||
if (allYears.length > 0) {
|
||||
return Math.max(...allYears);
|
||||
}
|
||||
|
||||
return new Date().getFullYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter and prepare graph data for a specific year
|
||||
* Uses consolidated data for that year and estimated data for remaining months
|
||||
* @param data - Array of economy data (monthly)
|
||||
* @param targetYear - The year to filter by
|
||||
* @returns Processed array with consolidated and estimated data
|
||||
*/
|
||||
export function populateGraphDataForYear(data: EconomyData[], targetYear: number | string): EconomyData[] {
|
||||
if (!data || data.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const year = parseInt(targetYear.toString());
|
||||
const currentMonth = new Date().getMonth() + 1; // 1-12
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
// Filter data for the target year
|
||||
const yearData = data.filter(item => {
|
||||
if (item.mes) {
|
||||
const itemYear = extractYearFromMes(item.mes);
|
||||
return itemYear === year;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// If no data for the year, try to use the latest year available to avoid empty charts
|
||||
if (yearData.length === 0) {
|
||||
const fallbackYear = data
|
||||
.map(item => (item.mes ? extractYearFromMes(item.mes) : parseInt(item.ano?.toString() || '0')))
|
||||
.filter(year => !Number.isNaN(year))
|
||||
.sort((a, b) => b - a)[0];
|
||||
|
||||
if (!fallbackYear) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return populateGraphDataForYear(data, fallbackYear);
|
||||
}
|
||||
|
||||
// Create a map of months for quick lookup
|
||||
const dataMap = new Map<number, EconomyData>();
|
||||
yearData.forEach(item => {
|
||||
if (item.mes) {
|
||||
const mesStr = item.mes.toString();
|
||||
let month = 0;
|
||||
|
||||
// Extract month from different formats
|
||||
if (mesStr.includes('-')) {
|
||||
// YYYY-MM-DD format
|
||||
month = parseInt(mesStr.split('-')[1]);
|
||||
} else if (mesStr.includes('/')) {
|
||||
// MMM/YYYY or MM/YYYY format
|
||||
const parts = mesStr.split('/');
|
||||
const monthPart = parts[0];
|
||||
// Try to parse as number first
|
||||
month = parseInt(monthPart);
|
||||
// If it's NaN, it's a month name, so we need to convert it
|
||||
if (isNaN(month)) {
|
||||
const monthNames = ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'];
|
||||
month = monthNames.indexOf(monthPart.toLowerCase()) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (month > 0) {
|
||||
dataMap.set(month, item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Build complete year data (1-12 months)
|
||||
const completeYearData: EconomyData[] = [];
|
||||
for (let month = 1; month <= 12; month++) {
|
||||
if (dataMap.has(month)) {
|
||||
completeYearData.push(dataMap.get(month)!);
|
||||
} else {
|
||||
// Fill missing months with estimated data
|
||||
// Find the last consolidated data or use the last available data as base
|
||||
const lastConsolidated = Array.from(dataMap.values())
|
||||
.filter(item => !item.dad_estimado)
|
||||
.sort((a, b) => {
|
||||
const mesA = a.mes?.toString() || '';
|
||||
const mesB = b.mes?.toString() || '';
|
||||
|
||||
let monthA = 0, monthB = 0;
|
||||
|
||||
if (mesA.includes('-')) {
|
||||
monthA = parseInt(mesA.split('-')[1]);
|
||||
} else if (mesA.includes('/')) {
|
||||
const part = mesA.split('/')[0];
|
||||
monthA = parseInt(part) || getMonthNumber(part);
|
||||
}
|
||||
|
||||
if (mesB.includes('-')) {
|
||||
monthB = parseInt(mesB.split('-')[1]);
|
||||
} else if (mesB.includes('/')) {
|
||||
const part = mesB.split('/')[0];
|
||||
monthB = parseInt(part) || getMonthNumber(part);
|
||||
}
|
||||
|
||||
return monthB - monthA;
|
||||
})[0];
|
||||
|
||||
if (lastConsolidated) {
|
||||
const lastConsolidatedMonth = extractMonthFromMes(lastConsolidated.mes || '');
|
||||
if (month > lastConsolidatedMonth) {
|
||||
// Create estimated data entry for future months
|
||||
completeYearData.push({
|
||||
...lastConsolidated,
|
||||
mes: `${month < 10 ? '0' : ''}${month}/${year}`,
|
||||
dad_estimado: true
|
||||
});
|
||||
} else if (dataMap.size > 0) {
|
||||
// Use the first available data as template for earlier months
|
||||
const firstData = Array.from(dataMap.values())[0];
|
||||
completeYearData.push({
|
||||
...firstData,
|
||||
mes: `${month < 10 ? '0' : ''}${month}/${year}`,
|
||||
dad_estimado: true
|
||||
});
|
||||
}
|
||||
} else if (dataMap.size > 0) {
|
||||
// Use the first available data as template
|
||||
const firstData = Array.from(dataMap.values())[0];
|
||||
completeYearData.push({
|
||||
...firstData,
|
||||
mes: `${month < 10 ? '0' : ''}${month}/${year}`,
|
||||
dad_estimado: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return completeYearData.sort((a, b) => {
|
||||
const monthA = extractMonthFromMes(a.mes || '');
|
||||
const monthB = extractMonthFromMes(b.mes || '');
|
||||
return monthA - monthB;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract month number from mes field
|
||||
* @param mesValue - The mes field value
|
||||
* @returns Month number (1-12)
|
||||
*/
|
||||
function extractMonthFromMes(mesValue: string): number {
|
||||
const mesStr = mesValue.toString();
|
||||
|
||||
// Handle "YYYY-MM-DD" format
|
||||
if (mesStr.includes('-')) {
|
||||
return parseInt(mesStr.split('-')[1]);
|
||||
}
|
||||
|
||||
// Handle "MMM/YYYY" or "MM/YYYY" format
|
||||
if (mesStr.includes('/')) {
|
||||
const monthPart = mesStr.split('/')[0];
|
||||
const parsed = parseInt(monthPart);
|
||||
if (!isNaN(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
return getMonthNumber(monthPart);
|
||||
}
|
||||
|
||||
return 1; // Default to January
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert month name to month number
|
||||
* @param monthName - Month name (Jan, Feb, etc. or jan, fev, etc.)
|
||||
* @returns Month number (1-12)
|
||||
*/
|
||||
function getMonthNumber(monthName: string): number {
|
||||
const months = ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'];
|
||||
return months.indexOf(monthName.toLowerCase()) + 1 || 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get consolidated and estimated data split for a specific year
|
||||
* Returns both consolidated and estimated datasets separately
|
||||
* @param data - Array of economy data
|
||||
* @param targetYear - The year to filter by
|
||||
* @returns Object with consolidated and estimated arrays
|
||||
*/
|
||||
export function getConsolidatedAndEstimatedData(
|
||||
data: EconomyData[],
|
||||
targetYear: number | string
|
||||
): { consolidated: EconomyData[]; estimated: EconomyData[] } {
|
||||
const year = parseInt(targetYear.toString());
|
||||
|
||||
const yearData = data.filter(item => {
|
||||
if (item.mes) {
|
||||
const itemYear = extractYearFromMes(item.mes);
|
||||
return itemYear === year;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const consolidated = yearData.filter(item => !item.dad_estimado);
|
||||
const estimated = yearData.filter(item => item.dad_estimado);
|
||||
|
||||
return { consolidated, estimated };
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user