Files
unionflow-mobile-apps/lib/features/dashboard/presentation/widgets/connected/connected_stats_card.dart
2026-03-31 09:14:47 +00:00

134 lines
4.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../shared/design_system/unionflow_design_system.dart';
import '../../../../../shared/widgets/core_card.dart';
import '../../bloc/dashboard_bloc.dart';
import '../../../domain/entities/dashboard_entity.dart';
/// Widget de carte de statistiques connecté au backend
class ConnectedStatsCard extends StatelessWidget {
final String title;
final IconData icon;
final String Function(DashboardStatsEntity) valueExtractor;
final String? Function(DashboardStatsEntity)? subtitleExtractor;
final Color? customColor;
final VoidCallback? onTap;
const ConnectedStatsCard({
super.key,
required this.title,
required this.icon,
required this.valueExtractor,
this.subtitleExtractor,
this.customColor,
this.onTap,
});
@override
Widget build(BuildContext context) {
return BlocBuilder<DashboardBloc, DashboardState>(
builder: (context, state) {
if (state is DashboardLoading) {
return _buildLoadingCard();
} else if (state is DashboardLoaded || state is DashboardRefreshing) {
final data = state is DashboardLoaded
? state.dashboardData
: (state as DashboardRefreshing).dashboardData;
return _buildDataCard(data.stats);
} else if (state is DashboardError) {
return _buildErrorCard(state.message);
}
return _buildLoadingCard();
},
);
}
Widget _buildDataCard(DashboardStatsEntity stats) {
final value = valueExtractor(stats);
final subtitle = subtitleExtractor?.call(stats);
final color = customColor ?? AppColors.primaryGreen;
return CoreCard(
onTap: onTap,
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(7),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(
icon,
color: color,
size: 16,
),
),
const SizedBox(width: 8),
Expanded(
child: Text(
title.toUpperCase(),
style: AppTypography.subtitleSmall.copyWith(
fontWeight: FontWeight.bold,
fontSize: 10,
letterSpacing: 1.1,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 8),
Text(
value,
style: AppTypography.headerSmall.copyWith(
color: color,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
if (subtitle != null) ...[
const SizedBox(height: 4),
Text(
subtitle,
style: AppTypography.subtitleSmall.copyWith(fontSize: 10),
),
],
],
),
);
}
Widget _buildLoadingCard() {
return const CoreCard(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// On peut utiliser un Shimmer ici si disponible
CircularProgressIndicator(strokeWidth: 2),
],
),
);
}
Widget _buildErrorCard(String message) {
return CoreCard(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(Icons.error_outline, color: AppColors.error, size: 20),
const SizedBox(height: 8),
Text(message, style: AppTypography.subtitleSmall.copyWith(color: AppColors.error)),
],
),
);
}
}