Generare i dati in recharts grafico a barre con l'Elenco dei DTO

0

Domanda

Ho questo DTO oggetto generato dal Resto API utilizzando Dattiloscritto:

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`
  );
}

Esempio grafico:

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>
    </>
  );
}

Come posso utilizzare i dati BillingSummaryDTO[] per generare il grafico?

1

Migliore risposta

2

Fare una funzione che associa oltre BillingSummaryDTO[] e la converte in dati del modello (come visibile nella variabile data) che è stato specificato per il consumo da parte della <BarChart/> è un approccio valido.

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

const data : BarChartDataModel []

Tali dati saranno utilizzati in <BarChart/> come


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

Tale funzione seguirà la map reduce approccio con un piccolo aiuto da un JS data management library come momentjs

4 passo la soluzione

  1. Organizzare tutte le fatture in ordine cronologico (dal più vecchio bill primo) per una più facile ridurre la mappa successiva
  2. Secchio bollette dal anno in segmenti chiamati 'yearwise-secchi'
  3. Secchio bollette in ogni yearwise-secchio in segmenti chiamati 'monthwise-secchio'
  4. Ridurre tutte le bollette in ogni monthwise-secchio per un oggetto a seguito della BarChartDataModel l'interfaccia. Una collezione di oggetti seguendo le BarChartDataModel l'interfaccia è la data passiamo al nostro <BarChart/> componente
  5. Consumare questa collezione di oggetti inn nostro <BarChart/> componente

Il codice per la stessa sarebbe :

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
}
 

Io inseriti in bucket dal anno prima e poi inseriti in bucket dal mese anziché direttamente bucket per mese, perché non vogliamo combinare i rapporti mensili di dire "Maggio dei 1997", e "Maggio dei 1998" in proprio "Maggio" per il nostro grafico. Ci vorrebbe loro di essere separato

2021-11-24 05:49:15

Ho più errori. Sei sicuro che questa dovrebbe essere la giusta soluzione?
Peter Penzov

Si può, si prega di condividere i tuoi errori ? Il metodo per ridurre la mappa è perfetta, quindi la logica bastoni. La sintassi si potrebbero verificare problemi (soprattutto di tipo a-controllo errori).
Ankit Sanghvi

In altre lingue

Questa pagina è in altre lingue

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