Version propre - Dashboard enhanced
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../../shared/theme/app_theme.dart';
|
||||
|
||||
/// Widget d'élément d'activité récente réutilisable
|
||||
///
|
||||
/// Affiche une activité avec:
|
||||
/// - Icône colorée avec indicateur "nouveau" optionnel
|
||||
/// - Titre et description
|
||||
/// - Horodatage avec mise en évidence pour les nouveaux éléments
|
||||
/// - Badge "NOUVEAU" pour les activités récentes
|
||||
/// - Indicateur visuel pour les nouvelles activités
|
||||
class ActivityItemWidget extends StatelessWidget {
|
||||
/// Titre de l'activité
|
||||
final String title;
|
||||
|
||||
/// Description détaillée de l'activité
|
||||
final String description;
|
||||
|
||||
/// Icône représentative
|
||||
final IconData icon;
|
||||
|
||||
/// Couleur thématique
|
||||
final Color color;
|
||||
|
||||
/// Horodatage de l'activité
|
||||
final String time;
|
||||
|
||||
/// Indique si l'activité est nouvelle
|
||||
final bool isNew;
|
||||
|
||||
const ActivityItemWidget({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.icon,
|
||||
required this.color,
|
||||
required this.time,
|
||||
this.isNew = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
children: [
|
||||
Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: color,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
if (isNew)
|
||||
Positioned(
|
||||
top: -2,
|
||||
right: -2,
|
||||
child: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppTheme.errorColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: isNew ? FontWeight.w700 : FontWeight.w600,
|
||||
color: isNew ? AppTheme.textPrimary : AppTheme.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isNew)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.errorColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Text(
|
||||
'NOUVEAU',
|
||||
style: TextStyle(
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
description,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isNew ? AppTheme.textPrimary : AppTheme.textSecondary,
|
||||
fontWeight: isNew ? FontWeight.w500 : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
time,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isNew ? AppTheme.primaryColor : AppTheme.textHint,
|
||||
fontWeight: isNew ? FontWeight.w600 : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
if (isNew)
|
||||
const SizedBox(height: 2),
|
||||
if (isNew)
|
||||
const Icon(
|
||||
Icons.fiber_new,
|
||||
size: 12,
|
||||
color: AppTheme.errorColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../../shared/theme/app_theme.dart';
|
||||
import 'activity_item_widget.dart';
|
||||
|
||||
/// Widget de section des activités récentes en temps réel
|
||||
///
|
||||
/// Affiche un flux d'activités en temps réel avec:
|
||||
/// - En-tête avec indicateur "Live" et bouton "Tout voir"
|
||||
/// - Liste d'activités avec indicateurs visuels pour les nouveaux éléments
|
||||
/// - Séparateurs entre les éléments
|
||||
/// - Horodatage précis pour chaque activité
|
||||
/// - Icônes et couleurs thématiques par type d'activité
|
||||
class RecentActivitiesWidget extends StatelessWidget {
|
||||
const RecentActivitiesWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Flux d\'activités en temps réel',
|
||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppTheme.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.successColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 4,
|
||||
height: 4,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppTheme.successColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 3),
|
||||
const Text(
|
||||
'Live',
|
||||
style: TextStyle(
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppTheme.successColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
minimumSize: Size.zero,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
child: const Text(
|
||||
'Tout',
|
||||
style: TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
ActivityItemWidget(
|
||||
title: 'Paiement Mobile Money reçu',
|
||||
description: 'Kouassi Yao - 25,000 FCFA via Orange Money',
|
||||
icon: Icons.phone_android,
|
||||
color: const Color(0xFFFF9800),
|
||||
time: 'Il y a 3 min',
|
||||
isNew: true,
|
||||
),
|
||||
const Divider(height: 1),
|
||||
ActivityItemWidget(
|
||||
title: 'Nouveau membre validé',
|
||||
description: 'Adjoua Marie inscrite depuis Abidjan',
|
||||
icon: Icons.person_add,
|
||||
color: AppTheme.successColor,
|
||||
time: 'Il y a 15 min',
|
||||
isNew: true,
|
||||
),
|
||||
const Divider(height: 1),
|
||||
ActivityItemWidget(
|
||||
title: 'Relance automatique envoyée',
|
||||
description: '12 SMS de rappel cotisations expédiés',
|
||||
icon: Icons.sms,
|
||||
color: AppTheme.infoColor,
|
||||
time: 'Il y a 1h',
|
||||
),
|
||||
const Divider(height: 1),
|
||||
ActivityItemWidget(
|
||||
title: 'Rapport OHADA généré',
|
||||
description: 'Bilan financier T4 2024 exporté',
|
||||
icon: Icons.description,
|
||||
color: const Color(0xFF795548),
|
||||
time: 'Il y a 2h',
|
||||
),
|
||||
const Divider(height: 1),
|
||||
ActivityItemWidget(
|
||||
title: 'Événement: Forte participation',
|
||||
description: 'AG Extraordinaire - 89% de présence',
|
||||
icon: Icons.trending_up,
|
||||
color: AppTheme.successColor,
|
||||
time: 'Il y a 3h',
|
||||
),
|
||||
const Divider(height: 1),
|
||||
ActivityItemWidget(
|
||||
title: 'Alerte: Cotisations en retard',
|
||||
description: '23 membres avec +30 jours de retard',
|
||||
icon: Icons.warning,
|
||||
color: AppTheme.warningColor,
|
||||
time: 'Il y a 4h',
|
||||
),
|
||||
const Divider(height: 1),
|
||||
ActivityItemWidget(
|
||||
title: 'Synchronisation réussie',
|
||||
description: 'Données sauvegardées sur le cloud',
|
||||
icon: Icons.cloud_done,
|
||||
color: AppTheme.successColor,
|
||||
time: 'Il y a 6h',
|
||||
),
|
||||
const Divider(height: 1),
|
||||
ActivityItemWidget(
|
||||
title: 'Message diffusé',
|
||||
description: 'Info COVID-19 envoyée à 1,247 membres',
|
||||
icon: Icons.campaign,
|
||||
color: const Color(0xFF9C27B0),
|
||||
time: 'Hier 18:30',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user