diff --git a/lib/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_box.dart b/lib/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_box.dart index 25cfd19d..41448f4e 100644 --- a/lib/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_box.dart +++ b/lib/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_box.dart @@ -3,7 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/air_quality_distribution/air_quality_distribution_bloc.dart'; import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart.dart'; import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_title.dart'; +import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart'; import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/style.dart'; class AqiDistributionChartBox extends StatelessWidget { @@ -32,8 +34,20 @@ class AqiDistributionChartBox extends StatelessWidget { const SizedBox(height: 10), const Divider(), const SizedBox(height: 20), - Expanded( - child: AqiDistributionChart(chartData: state.chartData), + Visibility( + visible: state.chartData.isNotEmpty, + replacement: AnalyticsChartEmptyStateWidget( + isLoading: state.status == AirQualityDistributionStatus.loading, + isError: state.status == AirQualityDistributionStatus.failure, + isInitial: state.status == AirQualityDistributionStatus.initial, + errorMessage: state.errorMessage, + iconPath: Assets.emptyBarredChart, + ), + child: Expanded( + child: AqiDistributionChart( + chartData: state.chartData, + ), + ), ), ], ), diff --git a/lib/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_box.dart b/lib/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_box.dart index cb189dce..5ec5158f 100644 --- a/lib/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_box.dart +++ b/lib/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_box.dart @@ -3,7 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/range_of_aqi/range_of_aqi_bloc.dart'; import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart.dart'; import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_title.dart'; +import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart'; import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/style.dart'; class RangeOfAqiChartBox extends StatelessWidget { @@ -32,10 +34,20 @@ class RangeOfAqiChartBox extends StatelessWidget { const SizedBox(height: 10), const Divider(), const SizedBox(height: 20), - Expanded( - child: RangeOfAqiChart( - chartData: state.filteredRangeOfAqi, - selectedAqiType: state.selectedAqiType, + Visibility( + visible: state.filteredRangeOfAqi.isNotEmpty, + replacement: AnalyticsChartEmptyStateWidget( + isLoading: state.status == RangeOfAqiStatus.loading, + isError: state.status == RangeOfAqiStatus.failure, + isInitial: state.status == RangeOfAqiStatus.initial, + errorMessage: state.errorMessage, + iconPath: Assets.emptyRangeOfAqi, + ), + child: Expanded( + child: RangeOfAqiChart( + chartData: state.filteredRangeOfAqi, + selectedAqiType: state.selectedAqiType, + ), ), ), ], diff --git a/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart b/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart index 06b6c529..48c9af94 100644 --- a/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart +++ b/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart @@ -5,8 +5,10 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/ener import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/chart_title.dart'; import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart.dart'; import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_devices_list.dart'; +import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart'; import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart'; import 'package:syncrow_web/pages/analytics/widgets/charts_loading_widget.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/style.dart'; class EnergyConsumptionPerDeviceChartBox extends StatelessWidget { @@ -54,8 +56,24 @@ class EnergyConsumptionPerDeviceChartBox extends StatelessWidget { const SizedBox(height: 20), const Divider(height: 0), const SizedBox(height: 20), - Expanded( - child: EnergyConsumptionPerDeviceChart(chartData: state.chartData), + Visibility( + visible: state.chartData.isNotEmpty && + state.chartData + .every((e) => e.energy.every((e) => e.value != 0)), + replacement: AnalyticsChartEmptyStateWidget( + isLoading: + state.status == EnergyConsumptionPerDeviceStatus.loading, + isError: state.status == EnergyConsumptionPerDeviceStatus.failure, + isInitial: + state.status == EnergyConsumptionPerDeviceStatus.initial, + errorMessage: state.errorMessage, + iconPath: Assets.emptyEnergyManagementPerDevice, + ), + child: Expanded( + child: EnergyConsumptionPerDeviceChart( + chartData: state.chartData, + ), + ), ), ], ), diff --git a/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart_box.dart b/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart_box.dart index 08f7223f..30d96ac5 100644 --- a/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart_box.dart +++ b/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart_box.dart @@ -6,8 +6,10 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/ch import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart'; import 'package:syncrow_web/pages/analytics/modules/occupancy/helpers/fetch_occupancy_data_helper.dart'; import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart'; +import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart'; import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/style.dart'; class OccupancyChartBox extends StatelessWidget { @@ -67,7 +69,24 @@ class OccupancyChartBox extends StatelessWidget { const SizedBox(height: 20), const Divider(), const SizedBox(height: 20), - Expanded(child: OccupancyChart(chartData: state.chartData)), + Visibility( + visible: state.chartData.isNotEmpty && + state.chartData.every( + (e) => e.occupancy.isNotEmpty, + ), + replacement: AnalyticsChartEmptyStateWidget( + isLoading: state.status == OccupancyStatus.loading, + isError: state.status == OccupancyStatus.failure, + isInitial: state.status == OccupancyStatus.initial, + errorMessage: state.errorMessage, + iconPath: Assets.emptyBarredChart, + ), + child: Expanded( + child: OccupancyChart( + chartData: state.chartData, + ), + ), + ), ], ), ); diff --git a/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map_box.dart b/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map_box.dart index a5f56aa4..9c8e3a1b 100644 --- a/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map_box.dart +++ b/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map_box.dart @@ -6,8 +6,10 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/ch import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_heat_map/occupancy_heat_map_bloc.dart'; import 'package:syncrow_web/pages/analytics/modules/occupancy/helpers/fetch_occupancy_data_helper.dart'; import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart'; +import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart'; import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/style.dart'; class OccupancyHeatMapBox extends StatelessWidget { @@ -68,16 +70,29 @@ class OccupancyHeatMapBox extends StatelessWidget { const SizedBox(height: 20), const Divider(), const SizedBox(height: 20), - Expanded( - child: OccupancyHeatMap( - selectedDate: - context.watch().state.yearlyDate, - heatMapData: state.heatMapData.asMap().map( - (_, value) => MapEntry( - value.eventDate, - value.countTotalPresenceDetected, + Visibility( + visible: state.heatMapData.isNotEmpty && + state.heatMapData.every( + (e) => e.countTotalPresenceDetected != 0, + ), + replacement: AnalyticsChartEmptyStateWidget( + isLoading: state.status == OccupancyHeatMapStatus.loading, + isError: state.status == OccupancyHeatMapStatus.failure, + isInitial: state.status == OccupancyHeatMapStatus.initial, + errorMessage: state.errorMessage, + iconPath: Assets.emptyHeatmap, + ), + child: Expanded( + child: OccupancyHeatMap( + selectedDate: + context.watch().state.yearlyDate, + heatMapData: state.heatMapData.asMap().map( + (_, value) => MapEntry( + value.eventDate, + value.countTotalPresenceDetected, + ), ), - ), + ), ), ), ], diff --git a/lib/pages/analytics/widgets/analytics_chart_empty_state_widget.dart b/lib/pages/analytics/widgets/analytics_chart_empty_state_widget.dart index 786fe020..f65e1de0 100644 --- a/lib/pages/analytics/widgets/analytics_chart_empty_state_widget.dart +++ b/lib/pages/analytics/widgets/analytics_chart_empty_state_widget.dart @@ -27,53 +27,37 @@ class AnalyticsChartEmptyStateWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Expanded( - child: () { - if (isLoading) { - return const AppLoadingIndicator(); - } else if (isError) { - return _buildState( - context, - message: errorMessage ?? 'Something went wrong', - color: ColorsManager.red, - ); - } else if (isInitial) { - return _buildState(context, message: initialMessage); - } else { - return _buildState(context, message: noDataMessage); - } - }(), + child: _buildWidgetBasedOnState(context), ); } - Widget _buildState( - BuildContext context, { - required String message, - Color? color, - }) { - final disabledColor = context.theme.disabledColor; + Widget _buildWidgetBasedOnState(BuildContext context) { + final widgetsMap = { + isLoading: const AppLoadingIndicator(), + isInitial: _buildState(context, initialMessage), + isError: _buildState(context, errorMessage ?? 'Something went wrong'), + }; + + return widgetsMap[true] ?? _buildState(context, noDataMessage); + } + + Widget _buildState(BuildContext context, String message) { return Center( child: Column( spacing: 16, mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 16), - Expanded( - child: SvgPicture.asset( - iconPath, - fit: BoxFit.contain, - colorFilter: ColorFilter.mode( - color ?? disabledColor, - BlendMode.srcIn, - ), - ), - ), + Expanded(child: SvgPicture.asset(iconPath, fit: BoxFit.contain)), SelectableText( message, - style: context.textTheme.bodyMedium?.copyWith( - color: color ?? disabledColor, - fontSize: 16, - fontWeight: FontWeight.w700, - ), + style: isError + ? context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.red, + fontSize: 16, + fontWeight: FontWeight.w700, + ) + : null, textAlign: TextAlign.center, ), const SizedBox(height: 16),