Build a sales dashboard Component with KPI cards for revenue, order count, and conversion rate displayed in a 2-column GridView. Add a sparkline trend chart using fl_chart LineChart in a Custom Widget. Show a top-5 products ListView ranked by revenue. Pull all data from a pre-aggregated sales_daily Firestore collection populated by a Cloud Function, and filter by date range using Today, This Week, and This Month buttons.
Building a Sales Dashboard with KPI Cards and Trend Charts in FlutterFlow
E-commerce and CRM apps need at-a-glance sales performance views. This tutorial builds a dashboard Component with key metric cards, a revenue trend sparkline, and a top products ranking — all powered by pre-aggregated Firestore data to keep page loads fast.
Prerequisites
- A FlutterFlow project on the Pro plan (Custom Widget required for charts)
- Firestore configured with an orders collection containing order data
- Firebase Blaze plan for Cloud Function deployment
- fl_chart package added to Pubspec Dependencies
Step-by-step guide
Create the sales_daily Firestore collection and Cloud Function aggregator
Create the sales_daily Firestore collection and Cloud Function aggregator
Create a sales_daily collection in Firestore. Each document represents one day: date (Timestamp), revenue (double, total sales), orderCount (int), conversionRate (double, 0.0-1.0), topProducts (Array of Map: { name: String, revenue: double, quantity: int }). Deploy a Cloud Function triggered daily via Cloud Scheduler that queries the orders collection for the previous day, sums revenue, counts orders, calculates conversion (orders / unique visitors from an analytics source), and writes the summary document. This pre-aggregation avoids expensive real-time queries on the raw orders collection.
Expected result: Firestore has a sales_daily collection with one document per day containing pre-computed sales metrics.
Build KPI metric cards in a 2-column GridView with percentage change indicators
Build KPI metric cards in a 2-column GridView with percentage change indicators
On the dashboard page, add a GridView with crossAxisCount: 2, childAspectRatio: 1.6, crossAxisSpacing: 12, mainAxisSpacing: 12. Add three child Components (MetricCard) with parameters: label (String), value (String), changePercent (double), isPositive (Boolean). Each MetricCard is a Container with borderRadius: 12, elevation: 2, padding: 16. Inside: Column with Text label (bodySmall, grey), Text value (headlineMedium, bold), and a Row with Icon (arrow_upward green or arrow_downward red based on isPositive) + Text changePercent (bodySmall, green or red).
Expected result: Three KPI cards display in a 2-column grid showing revenue, order count, and conversion rate with up/down change indicators.
Create a SparklineChart Custom Widget using fl_chart LineChart in minimal mode
Create a SparklineChart Custom Widget using fl_chart LineChart in minimal mode
Add fl_chart: ^0.65.0 to Pubspec Dependencies. Create a Custom Widget named SparklineChart with parameters: dataPoints (List<double>), color (Color). In the build method, return a SizedBox (height: 80) containing a LineChart. Configure LineChartData with one LineChartBarData: spots mapped from dataPoints (index as x, value as y), isCurved: true, barWidth: 2, color: widget.color, dotData: FlDotData(show: false), belowBarData: BarAreaData(show: true, color: widget.color.withOpacity(0.1)). Hide all axes, grid, border, and titles for a clean sparkline look.
Expected result: A compact sparkline chart renders revenue trends as a smooth curved line with a subtle gradient fill area.
Add a top-5 products ListView ranked by revenue from sales_daily data
Add a top-5 products ListView ranked by revenue from sales_daily data
Below the sparkline, add a Text 'Top Products' (titleMedium, bold) and a ListView (shrinkWrap: true, physics: NeverScrollable) with 5 children. Each item is a Row: rank number Text (bodyLarge, bold, primary color), SizedBox(width: 12), Expanded Column (product name Text bodyMedium, quantity Text bodySmall grey), and trailing revenue Text (bodyLarge, bold). Bind the data from the topProducts array of the current day's sales_daily document. Sort by revenue descending.
Expected result: A ranked list shows the top 5 products by revenue for the selected date range, each with name, quantity sold, and revenue.
Add date range filter buttons for Today, This Week, and This Month
Add date range filter buttons for Today, This Week, and This Month
At the top of the dashboard, add a Row with three ChoiceChip-style buttons: Today, This Week, This Month. Create a Page State dateRange (String, default 'today'). On button tap, update dateRange. The Backend Query on sales_daily uses Conditional Filters: 'today' filters date == today, 'week' filters date >= 7 days ago, 'month' filters date >= 30 days ago. For multi-day ranges, the KPI values display aggregated sums (total revenue, total orders, average conversion). The sparkline dataPoints list contains one value per day in the range.
Expected result: Switching between Today, This Week, and This Month updates all KPI cards, the sparkline chart, and the top products list.
Complete working example
1// Custom Widget: SparklineChart2// Pubspec: fl_chart: ^0.65.034import 'package:flutter/material.dart';5import 'package:fl_chart/fl_chart.dart';67class SparklineChart extends StatelessWidget {8 final double width;9 final double height;10 final List<double> dataPoints;11 final Color color;1213 const SparklineChart({14 Key? key,15 required this.width,16 this.height = 80,17 required this.dataPoints,18 this.color = Colors.blue,19 }) : super(key: key);2021 @override22 Widget build(BuildContext context) {23 if (dataPoints.isEmpty) {24 return SizedBox(width: width, height: height);25 }2627 final spots = dataPoints28 .asMap()29 .entries30 .map((e) => FlSpot(e.key.toDouble(), e.value))31 .toList();3233 return SizedBox(34 width: width,35 height: height,36 child: LineChart(37 LineChartData(38 gridData: const FlGridData(show: false),39 titlesData: const FlTitlesData(show: false),40 borderData: FlBorderData(show: false),41 lineTouchData: LineTouchData(42 touchTooltipData: LineTouchTooltipData(43 getTooltipItems: (spots) => spots.map((s) =>44 LineTooltipItem(45 '\$${s.y.toStringAsFixed(0)}',46 const TextStyle(color: Colors.white, fontSize: 12),47 ),48 ).toList(),49 ),50 ),51 lineBarsData: [52 LineChartBarData(53 spots: spots,54 isCurved: true,55 color: color,56 barWidth: 2,57 isStrokeCapRound: true,58 dotData: const FlDotData(show: false),59 belowBarData: BarAreaData(60 show: true,61 color: color.withOpacity(0.1),62 ),63 ),64 ],65 ),66 ),67 );68 }69}Common mistakes when creating a Custom Sales Widget for Your FlutterFlow App
Why it's a problem: Querying the raw orders collection for real-time aggregation on every dashboard load
How to avoid: Pre-aggregate daily summaries into a sales_daily collection using a Cloud Function. The dashboard reads one summary document instead of thousands of orders.
Why it's a problem: Using fl_chart without hiding axes, grid, and titles for the sparkline
How to avoid: Set gridData: FlGridData(show: false), titlesData: FlTitlesData(show: false), borderData: FlBorderData(show: false) for a clean minimal sparkline.
Why it's a problem: Displaying conversion rate as a raw decimal like 0.032 instead of a percentage
How to avoid: Multiply the stored decimal by 100 and format with one decimal place: '${(conversionRate * 100).toStringAsFixed(1)}%' displays as '3.2%'.
Best practices
- Pre-aggregate sales data with a scheduled Cloud Function to keep dashboard loads under 1 second
- Store topProducts as an array of maps inside the daily summary to avoid extra collection queries
- Show percentage change compared to the previous period (yesterday, last week) for context on each KPI
- Use green for positive change and red for negative change — universal visual language for financial data
- Keep the sparkline height to 60-100 pixels so it stays compact while still showing the trend shape
- Add touch tooltips on the sparkline so users can tap a point to see the exact revenue value for that day
- Default to Today view for the fastest initial load — single document read
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I need to build a sales dashboard in FlutterFlow with KPI metric cards (revenue, orders, conversion rate), a sparkline trend chart using fl_chart, a top products list, and date range filters. Show me the Firestore data model, widget tree, and Custom Widget code for the sparkline.
Create a dashboard page with a row of three metric cards at the top, a small line chart below showing revenue trends, and a list of top-selling products underneath. Add filter buttons for Today, This Week, and This Month.
Frequently asked questions
How do I calculate conversion rate if I do not track unique visitors?
Use a proxy metric like orders divided by app sessions. Alternatively, skip conversion rate and replace that KPI card with average order value (total revenue / order count).
Can I use fl_chart for bar charts or pie charts on the dashboard?
Yes. fl_chart supports LineChart, BarChart, PieChart, RadarChart, and ScatterChart. Create separate Custom Widgets for each chart type using the same package.
How often should the Cloud Function run to update sales_daily?
Run it once daily after midnight (e.g., 1:00 AM) to aggregate the previous day's data. For near-real-time today data, run it every hour and overwrite today's document.
What if the sparkline has only one data point for the Today view?
A single point cannot render a line. Show a Text value instead of the sparkline when dataPoints.length < 2, or include the previous day as a second point for comparison.
Can I export the dashboard data as a CSV?
Yes. Create a Custom Action that queries sales_daily for the selected range, formats each document as a CSV row, and uses the url_launcher or share_plus package to share the file.
Can RapidDev help build a full analytics and reporting platform?
Yes. RapidDev can implement multi-metric dashboards, automated report generation, email report scheduling, user segmentation analytics, and custom chart visualizations.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation