Dashboard
This commit is contained in:
parent
2633a2e1a1
commit
0f9355f17e
|
|
@ -4,6 +4,15 @@ import 'package:memoize/memoize.dart';
|
||||||
import 'package:built_collection/built_collection.dart';
|
import 'package:built_collection/built_collection.dart';
|
||||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||||
|
|
||||||
|
class ChartDataGroup {
|
||||||
|
ChartDataGroup(this.name);
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
final List<ChartMoneyData> rawSeries = [];
|
||||||
|
dynamic chartSeries;
|
||||||
|
double total = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
class ChartMoneyData {
|
class ChartMoneyData {
|
||||||
ChartMoneyData(this.date, this.amount);
|
ChartMoneyData(this.date, this.amount);
|
||||||
|
|
||||||
|
|
@ -32,14 +41,17 @@ var memoizedChartOutstandingQuotes = memo4((CompanyEntity company,
|
||||||
clientMap: clientMap,
|
clientMap: clientMap,
|
||||||
isQuote: true));
|
isQuote: true));
|
||||||
|
|
||||||
List<ChartMoneyData> chartOutstandingInvoices({
|
List<ChartDataGroup> chartOutstandingInvoices({
|
||||||
CompanyEntity company,
|
CompanyEntity company,
|
||||||
DashboardUIState settings,
|
DashboardUIState settings,
|
||||||
BuiltMap<int, InvoiceEntity> invoiceMap,
|
BuiltMap<int, InvoiceEntity> invoiceMap,
|
||||||
BuiltMap<int, ClientEntity> clientMap,
|
BuiltMap<int, ClientEntity> clientMap,
|
||||||
bool isQuote = false,
|
bool isQuote = false,
|
||||||
}) {
|
}) {
|
||||||
final Map<String, double> totals = {};
|
final Map<String, Map<String, double>> totals = {};
|
||||||
|
|
||||||
|
const STATUS_ACTIVE = 'active';
|
||||||
|
const STATUS_OUTSTANDING = 'outstanding';
|
||||||
|
|
||||||
invoiceMap.forEach((int, invoice) {
|
invoiceMap.forEach((int, invoice) {
|
||||||
final client =
|
final client =
|
||||||
|
|
@ -61,26 +73,41 @@ List<ChartMoneyData> chartOutstandingInvoices({
|
||||||
// skip it
|
// skip it
|
||||||
} else {
|
} else {
|
||||||
if (totals[invoice.invoiceDate] == null) {
|
if (totals[invoice.invoiceDate] == null) {
|
||||||
totals[invoice.invoiceDate] = 0.0;
|
totals[STATUS_ACTIVE][invoice.invoiceDate] = 0.0;
|
||||||
|
totals[STATUS_OUTSTANDING][invoice.invoiceDate] = 0.0;
|
||||||
}
|
}
|
||||||
totals[invoice.invoiceDate] += invoice.amount;
|
|
||||||
|
totals[STATUS_ACTIVE][invoice.invoiceDate] += invoice.amount;
|
||||||
|
totals[STATUS_OUTSTANDING][invoice.invoiceDate] += invoice.balance;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<ChartMoneyData> data = [];
|
final ChartDataGroup activeData = ChartDataGroup(STATUS_ACTIVE);
|
||||||
|
final ChartDataGroup outstandingData = ChartDataGroup(STATUS_OUTSTANDING);
|
||||||
|
|
||||||
var date = DateTime.parse(settings.startDate(company));
|
var date = DateTime.parse(settings.startDate(company));
|
||||||
final endDate = DateTime.parse(settings.endDate(company));
|
final endDate = DateTime.parse(settings.endDate(company));
|
||||||
|
|
||||||
while (!date.isAfter(endDate)) {
|
while (!date.isAfter(endDate)) {
|
||||||
final key = convertDateTimeToSqlDate(date);
|
final key = convertDateTimeToSqlDate(date);
|
||||||
if (totals.containsKey(key)) {
|
if (totals[STATUS_ACTIVE].containsKey(key)) {
|
||||||
data.add(ChartMoneyData(date, totals[key]));
|
activeData.rawSeries.add(ChartMoneyData(date, totals[STATUS_ACTIVE][key]));
|
||||||
|
activeData.total += totals[STATUS_ACTIVE][key];
|
||||||
|
outstandingData.rawSeries
|
||||||
|
.add(ChartMoneyData(date, totals[STATUS_OUTSTANDING][key]));
|
||||||
|
outstandingData.total += totals[STATUS_OUTSTANDING][key];
|
||||||
} else {
|
} else {
|
||||||
data.add(ChartMoneyData(date, 0.0));
|
activeData.rawSeries.add(ChartMoneyData(date, 0.0));
|
||||||
|
outstandingData.rawSeries.add(ChartMoneyData(date, 0.0));
|
||||||
}
|
}
|
||||||
date = date.add(Duration(days: 1));
|
date = date.add(Duration(days: 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final List<ChartDataGroup> data = [
|
||||||
|
activeData,
|
||||||
|
outstandingData,
|
||||||
|
];
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,18 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/dashboard/dashboard_selectors.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
||||||
import 'package:charts_flutter/flutter.dart' as charts;
|
import 'package:charts_flutter/flutter.dart' as charts;
|
||||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||||
|
|
||||||
class DashboardChart extends StatefulWidget {
|
class DashboardChart extends StatefulWidget {
|
||||||
const DashboardChart(
|
const DashboardChart(
|
||||||
{this.series,
|
{this.data,
|
||||||
this.amount,
|
|
||||||
this.previousAmount,
|
|
||||||
this.title,
|
this.title,
|
||||||
this.currencyId});
|
this.currencyId});
|
||||||
|
|
||||||
final List<charts.Series> series;
|
final List<ChartDataGroup> data;
|
||||||
final double previousAmount;
|
|
||||||
final double amount;
|
|
||||||
final String title;
|
final String title;
|
||||||
final int currencyId;
|
final int currencyId;
|
||||||
|
|
||||||
|
|
@ -66,6 +63,7 @@ class _DashboardChartState extends State<DashboardChart> {
|
||||||
? charts.MaterialPalette.white
|
? charts.MaterialPalette.white
|
||||||
: charts.MaterialPalette.gray.shade700;
|
: charts.MaterialPalette.gray.shade700;
|
||||||
|
|
||||||
|
/*
|
||||||
final chart = charts.TimeSeriesChart(
|
final chart = charts.TimeSeriesChart(
|
||||||
widget.series,
|
widget.series,
|
||||||
animate: true,
|
animate: true,
|
||||||
|
|
@ -109,6 +107,7 @@ class _DashboardChartState extends State<DashboardChart> {
|
||||||
final String changeString = widget.amount == 0 || widget.previousAmount == 0
|
final String changeString = widget.amount == 0 || widget.previousAmount == 0
|
||||||
? ''
|
? ''
|
||||||
: '$changeAmount ($changePercent)';
|
: '$changeAmount ($changePercent)';
|
||||||
|
*/
|
||||||
|
|
||||||
return FormCard(
|
return FormCard(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
|
@ -116,6 +115,7 @@ class _DashboardChartState extends State<DashboardChart> {
|
||||||
padding: EdgeInsets.symmetric(vertical: 14.0, horizontal: 4.0),
|
padding: EdgeInsets.symmetric(vertical: 14.0, horizontal: 4.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
Text(widget.title,),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
|
@ -125,6 +125,7 @@ class _DashboardChartState extends State<DashboardChart> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(widget.title,
|
Text(widget.title,
|
||||||
style: Theme.of(context).textTheme.subhead),
|
style: Theme.of(context).textTheme.subhead),
|
||||||
|
/*
|
||||||
Text(
|
Text(
|
||||||
formatNumber(widget.amount, context,
|
formatNumber(widget.amount, context,
|
||||||
currencyId: widget.currencyId),
|
currencyId: widget.currencyId),
|
||||||
|
|
@ -138,6 +139,7 @@ class _DashboardChartState extends State<DashboardChart> {
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -158,7 +160,7 @@ class _DashboardChartState extends State<DashboardChart> {
|
||||||
height: 200.0,
|
height: 200.0,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(top: 10.0),
|
padding: const EdgeInsets.only(top: 10.0),
|
||||||
child: chart,
|
//child: chart,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
final data = memoizedChartOutstandingInvoices(state.selectedCompany,
|
final data = memoizedChartOutstandingInvoices(state.selectedCompany,
|
||||||
settings, state.invoiceState.map, state.clientState.map);
|
settings, state.invoiceState.map, state.clientState.map);
|
||||||
|
|
||||||
final series = [
|
data.forEach((dataGroup) {
|
||||||
charts.Series<ChartMoneyData, DateTime>(
|
dataGroup.chartSeries = charts.Series<ChartMoneyData, DateTime>(
|
||||||
domainFn: (ChartMoneyData chartData, _) => chartData.date,
|
domainFn: (ChartMoneyData chartData, _) => chartData.date,
|
||||||
measureFn: (ChartMoneyData chartData, _) => chartData.amount,
|
measureFn: (ChartMoneyData chartData, _) => chartData.amount,
|
||||||
colorFn: (ChartMoneyData chartData, _) =>
|
colorFn: (ChartMoneyData chartData, _) =>
|
||||||
|
|
@ -122,15 +122,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
displayName: settings.enableComparison
|
displayName: settings.enableComparison
|
||||||
? localization.current
|
? localization.current
|
||||||
: localization.invoices,
|
: localization.invoices,
|
||||||
data: data,
|
data: dataGroup.rawSeries,
|
||||||
),
|
);
|
||||||
];
|
|
||||||
|
|
||||||
double total = 0.0;
|
|
||||||
double previousTotal = 0.0;
|
|
||||||
data.forEach((dynamic item) {
|
|
||||||
total += item.amount;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (settings.enableComparison) {
|
if (settings.enableComparison) {
|
||||||
final offsetData = memoizedChartOutstandingInvoices(
|
final offsetData = memoizedChartOutstandingInvoices(
|
||||||
|
|
@ -140,11 +133,14 @@ class DashboardPanels extends StatelessWidget {
|
||||||
state.clientState.map);
|
state.clientState.map);
|
||||||
|
|
||||||
final List<ChartMoneyData> previousData = [];
|
final List<ChartMoneyData> previousData = [];
|
||||||
for (int i = 0; i < min(data.length, offsetData.length); i++) {
|
for (int i = 0;
|
||||||
previousData.add(ChartMoneyData(data[i].date, offsetData[i].amount));
|
i < min(dataGroup.rawSeries.length, offsetData.length);
|
||||||
|
i++) {
|
||||||
|
previousData.add(ChartMoneyData(dataGroup.rawSeries[i].date,
|
||||||
|
offsetData[data.indexOf(dataGroup)].rawSeries[i].amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
series.add(
|
dataGroup.chartSeries.add(
|
||||||
charts.Series<ChartMoneyData, DateTime>(
|
charts.Series<ChartMoneyData, DateTime>(
|
||||||
domainFn: (ChartMoneyData chartData, _) => chartData.date,
|
domainFn: (ChartMoneyData chartData, _) => chartData.date,
|
||||||
measureFn: (ChartMoneyData chartData, _) => chartData.amount,
|
measureFn: (ChartMoneyData chartData, _) => chartData.amount,
|
||||||
|
|
@ -155,16 +151,11 @@ class DashboardPanels extends StatelessWidget {
|
||||||
data: previousData,
|
data: previousData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
previousData.forEach((dynamic item) {
|
|
||||||
previousTotal += item.amount;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return DashboardChart(
|
return DashboardChart(
|
||||||
series: series,
|
data: data,
|
||||||
amount: total,
|
|
||||||
previousAmount: previousTotal,
|
|
||||||
title: localization.invoices,
|
title: localization.invoices,
|
||||||
currencyId: settings.currencyId > 0
|
currencyId: settings.currencyId > 0
|
||||||
? settings.currencyId
|
? settings.currencyId
|
||||||
|
|
@ -172,6 +163,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
Widget _paymentChart(BuildContext context) {
|
Widget _paymentChart(BuildContext context) {
|
||||||
if (!viewModel.state.paymentState.isLoaded) {
|
if (!viewModel.state.paymentState.isLoaded) {
|
||||||
return LoadingIndicator(useCard: true);
|
return LoadingIndicator(useCard: true);
|
||||||
|
|
@ -324,6 +316,7 @@ class DashboardPanels extends StatelessWidget {
|
||||||
: state.selectedCompany.currencyId,
|
: state.selectedCompany.currencyId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -335,8 +328,8 @@ class DashboardPanels extends StatelessWidget {
|
||||||
height: 74.0,
|
height: 74.0,
|
||||||
),
|
),
|
||||||
_invoiceChart(context),
|
_invoiceChart(context),
|
||||||
_paymentChart(context),
|
//_paymentChart(context),
|
||||||
_quoteChart(context),
|
//_quoteChart(context),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue