Pages Dashboard Doughnut chart widgetui/src/components/adminDashboard/widgets/DoughnutChartWidget
DoughnutChartWidget is a side widget which is displaying amount of leads for each choosen business.
Data set and fetch perform the same as on other widgets.
For correct display of label inside a chart we should add a custom plugin which will draw a text exactly at the DoughtnutChart center:
Copy const doughnutLabel = {
id : 'dounghnutLabel' ,
afterDatasetsDraw (chart , args , plugins) {
const { ctx } = chart;
const centerX = chart .getDatasetMeta ( 0 ).data[ 0 ].x;
const centerY = chart .getDatasetMeta ( 0 ).data[ 0 ].y;
ctx .save ();
ctx .font = `500 ${ fontSize .lg } Inter` ;
ctx .fillStyle = primitiveColors .gray900;
ctx .textAlign = 'center' ;
ctx .textBaseline = 'middle' ;
ctx .fillText (title , centerX , centerY);
} ,
};
Also for correct display of labels exactly on chart we will use custom plugin ChartDataLabels from chartjs-plugin-datalabels
library. Then we write plugin to chart options and add dataLabels styles:
Copy plugins : {
tooltip : {
enabled : false ,
} ,
datalabels : {
display : true ,
backgroundColor : function (context) {
return primitiveColors .gray0;
} ,
backgroundShadowColor : colors .black ,
borderColor : primitiveColors .gray100 ,
borderRadius : 8 ,
borderWidth : 1 ,
color : colors .black ,
font : {
family : 'Inter' ,
weight : 500 ,
size : 16 ,
} ,
padding : {
top : 2 ,
bottom : 2 ,
left : 8 ,
right : 8 ,
} ,
shadowOffsetX : 0 ,
shadowOffsetY : 3 ,
shadowBlur : 5 ,
shadowColor : colors .black ,
} ,
Backend
On backend we have a function getLeadsPerBusinesses
that return us required dataset:
Copy async getLeadsPerBusinesses (
startDate: string ,
endDate: string ,
businessIds: number[] ,
teamId: string
): Promise < { [businessName: string]: number } > {
const start = dayjs (startDate) .startOf ( 'day' ) .toDate ();
const end = dayjs (endDate) .endOf ( 'day' ) .toDate ();
if (!start || !end) {
throw new BadRequestException ( 'Invalid date format' );
}
const leadsData = await this .leadsRepository
.createQueryBuilder( 'lead' )
.innerJoin( 'lead.business' , 'business' )
.select( 'business.name' , 'businessName' )
.addSelect( 'COUNT(lead.id)' , 'leadCount' )
.where( 'lead.createdAt BETWEEN :start AND :end' , { start , end })
.andWhere( 'lead.teamId = :teamId' , { teamId })
.andWhere( 'business.id IN (:...businessIds)' , { businessIds })
.groupBy( 'business.name' )
.getRawMany();
const result : { [businessName: string] : number } = {};
leadsData .forEach (row => {
result[ row .businessName] = parseInt ( row .leadCount , 10 );
});
return result;
}
Here is used query that will count leads for each business based on their createdAt
column. The result of query will be an array of following objects:
{ businessName: 'Retail', leadCount: '126' }
Because of that here used a loop which will combine data in acceptable way for DoughnutChart .