Gerar dados para recharts gráfico de barras usando a Lista de DTO

0

Pergunta

Eu tenho esse DTO objeto gerado a partir de API Rest usando Transcrito:

export interface BillingSummaryDTO {
    paid?: number,
    outstanding?: number,
    pastDue?: number,
    cancelled?: number,
    createdAt?: Moment | null,
}

export async function getBillingSummary(): Promise<AxiosResponse<BillingSummaryDTO[]>> {
  return await axios.get<BillingSummaryDTO[]>(
      `${baseUrl}/management/billing/summary`
  );
}

Exemplo de gráfico:

import {
  BarChart,
  Bar,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  Legend,
} from "recharts";
import {Box} from "@material-ui/core";

const data = [
  {
    name: "Jan",
    Chargebacks: 4000,
    Transactions: 2400,
    USD: 2400,
  },
  {
    name: "Feb",
    Chargebacks: 3000,
    Transactions: 1398,
    USD: 2210,
  },
  {
    name: "Mar",
    Chargebacks: 2000,
    Transactions: 9800,
    USD: 2290,
  },
  {
    name: "Apr",
    Chargebacks: 2780,
    Transactions: 3908,
    USD: 2000,
  },
  {
    name: "May",
    Chargebacks: 1890,
    Transactions: 4800,
    USD: 2181,
  },
  {
    name: "Jun",
    Chargebacks: 2390,
    Transactions: 3800,
    USD: 2500,
  },
  {
    name: "Jul",
    Chargebacks: 3490,
    Transactions: 4300,
    USD: 2100,
  },
  {
    name: "Aug",
    Chargebacks: 3490,
    Transactions: 4300,
    USD: 2100,
  },
  {
    name: "Sep",
    Chargebacks: 3490,
    Transactions: 4300,
    USD: 2100,
  },
];

const useStyles = makeStyles((theme) =>
  createStyles({
    root: {
      flexGrow: 1,
    },
    paper: {
      padding: theme.spacing(2),
      textAlign: "center",
      color: theme.palette.text.secondary,
    },
  })
);

const usePaperStyles = makeStyles((theme) =>
  createStyles({
    root: {
      display: "flex",
      flexWrap: "wrap",
      "& > *": {
        margin: theme.spacing(1),
        width: theme.spacing(16),
        height: theme.spacing(16),
      },
    },
  })
);

const useTimelineStyles = makeStyles((theme) => ({
  paper: {
    padding: "6px 16px",
  },
  secondaryTail: {
    backgroundColor: theme.palette.secondary.main,
  },
}));

export default function Billing() {
  const [click, setClick] = useState(false);
  const closeMobileMenu = () => setClick(false);
  const classes = useStyles();
  const classesPaper = usePaperStyles();
  const classesTimeline = useTimelineStyles();

  return (
    <>
      <Grid container justifyContent="center" alignItems="center">
        <Grid item xs={11}>
          {/*Padding on the top*/}
          <Box m="5rem" />
        </Grid>

        <Grid item xs={12} >
          <h4 className="chart-label">Invoices Summary</h4>
          <BarChart
            width={1000}
            height={300}
            data={data}
            margin={{
              top: 5,
              right: 30,
              left: 20,
              bottom: 5,
            }}
            barSize={30}
          >
            <XAxis
              dataKey="name"
              scale="point"
              padding={{ left: 10, right: 10 }}
            />
            <YAxis />
            <Tooltip />
            <Legend />
            <CartesianGrid strokeDasharray="3 3" />
            <Bar
              dataKey="Transactions"
              fill="#8884d8"
              background={{ fill: "#eee" }}
            />
          </BarChart>
        </Grid>
      </Grid>
    </>
  );
}

Como eu posso usar os dados da BillingSummaryDTO[] para gerar o gráfico?

1

Melhor resposta

2

Fazer uma função que mapeia mais de BillingSummaryDTO[] e converte-o para o modelo de dados (como é visível na variável data) que você especificou para o consumo do <BarChart/> é uma abordagem válida.

export interface BarChartDataModel {
  name: string,
  Chargebacks: number,
  Transactions: number,
  USD: number,
}

const data : BarChartDataModel []

Estes dados serão utilizados em <BarChart/> como


<BarChart
            data={data}
            // ....
          >
         // ...
 </BarChart>

Tal função vai seguir o map reduce abordagem com uma pequena ajuda de um JS data de gerenciamento de biblioteca como momentjs

4 passo de solução de

  1. Organizar todas as contas em ordem cronológica (do mais antigo projeto de lei de primeira) para facilitar o mapa-reduzir mais tarde
  2. Balde de contas por ano em baldes chamado 'yearwise-baldes'
  3. Balde de contas em cada yearwise-balde em baldes chamado 'monthwise-balde"
  4. Reduzir todas as contas em cada monthwise-balde para um objeto o seguinte BarChartDataModel interface. Uma coleção de objetos a seguir o BarChartDataModel a interface é o data vamos passar para o nosso <BarChart/> componente
  5. Consumir este objeto de coleção inn <BarChart/> componente

O seu código para que o mesmo seria :

export interface BillingSummaryDTO {
    paid?: number,
    outstanding?: number,
    pastDue?: number,
    cancelled?: number,
    createdAt?: Moment | null,
}

export interface BarChartDataModel {
  name: string,
  Chargebacks: number,
  Transactions: number,
  USD: number,
}

export async function getBillingSummary(): Promise<AxiosResponse<BillingSummaryDTO[]>> {
  const response = await axios.get<BillingSummaryDTO[]>(
      `${baseUrl}/management/billing/summary`
  );
  // STEP 1 : Chronological ordering. Oldest bills will show first
  const chronologicallyOrdered = response.sort((a:BillingSummaryDTO,b:BillingSummaryDTO)=> a.createdAt - b.createdAt )

  // STEP 2 : Bucket by year
  const groupByYear = chronologicallyOrdered.reduce((yearwiseBills : any, bill:BillingSummaryDTO, currIdx:number)) => 
     {
        const year = moment(bill.createdAt).year().toString()
        if(!yearwiseBills[year]){ 
          yearwiseBills[year] = []
        } 
        yearwiseBills[year].push(bill)
        return yearwiseBills
     }
  ,{})

  // STEP 3 : In each yearwise bucket -> bucket by month
  const groupByMonth = Object.keys(groupByYear).map((year, yearwiseBills) => yearwiseBills.reduce((monthwiseBills: any, bill:BillingSummaryDTO, currIdx:number)) => 
     {
        const moment = moment(bill.createdAt).month().toString()
        if(!yearAcc[month]){ 
          monthwiseBills[month] = []
        } 
        monthwiseBills[month].push(bill)
        return monthwiseBills
     }
  ,{}) );

 // STEP 4 : Reduce all bills in a monthwise bucket into a monthlyReport object and store all monthlyReport objects in an monthlyReportArray
 const monthlyReportArray:BarChartDataModel[] = Object.keys(groupByMonth).map((year, yearwiseBills) => 
   Object.keys(bills).map((month, monthwiseBills) => monthwiseBills.reduce((monthlyReport:BarChartDataModel,bill:BillingSummaryDTO) => {
    if(bill.cancelled){
      monthlyReport.Chargebacks++
    }else{
      monthlyReport.Transactions++,
      monthlyReport.USD += bill.paid
    }
    return monthlyReport
  },{
    name : moment(month, 'M').format('MMM')
    Transactions : 0,
    USD : 0,
    Chargebacks:0
   } )
 )


 // STEP 5 : Consume this as the "data" for the "<BarChart/>" component
 return monthlyReportArray
}
 

Eu bucketed por ano, primeiro e, em seguida, bucketed por mês, em vez de diretamente bucketing por mês, porque não queremos combinar os relatórios mensais de dizer "Maio de 1997" e "de Maio de 1998, que" só "Pode" para o nosso gráfico. Nós queremos ser separado

2021-11-24 05:49:15

Eu recebo vários erros. Tem certeza de que esta deve ser a solução adequada?
Peter Penzov

Por favor você pode compartilhar os seus erros ? O método para o mapa-reduzir é perfeito, portanto, a lógica de varas. Problemas de sintaxe podem ocorrer (principalmente o tipo de verificação de erros).
Ankit Sanghvi

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................