Files
unionflow-server-impl-quarkus/unionflow-mobile-apps/lib/features/dashboard/presentation/widgets/activity_feed.dart
2025-08-20 21:00:35 +00:00

218 lines
6.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../../shared/theme/app_theme.dart';
class ActivityFeed extends StatelessWidget {
const ActivityFeed({super.key});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 15,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Activités récentes',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppTheme.textPrimary,
),
),
TextButton(
onPressed: () {},
child: const Text('Voir tout'),
),
],
),
),
..._getActivities().map((activity) => _buildActivityItem(activity)),
],
),
);
}
Widget _buildActivityItem(ActivityItem activity) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
decoration: const BoxDecoration(
border: Border(
top: BorderSide(color: AppTheme.borderColor, width: 0.5),
),
),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: activity.color.withOpacity(0.15),
borderRadius: BorderRadius.circular(20),
),
child: Icon(
activity.icon,
color: activity.color,
size: 20,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
activity.title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppTheme.textPrimary,
),
),
const SizedBox(height: 4),
Text(
activity.description,
style: const TextStyle(
fontSize: 14,
color: AppTheme.textSecondary,
),
),
const SizedBox(height: 8),
Row(
children: [
Icon(
Icons.access_time,
size: 14,
color: AppTheme.textHint,
),
const SizedBox(width: 4),
Text(
_formatTime(activity.timestamp),
style: const TextStyle(
fontSize: 12,
color: AppTheme.textHint,
),
),
],
),
],
),
),
if (activity.actionRequired)
Container(
width: 8,
height: 8,
decoration: const BoxDecoration(
color: AppTheme.errorColor,
shape: BoxShape.circle,
),
),
],
),
);
}
List<ActivityItem> _getActivities() {
final now = DateTime.now();
return [
ActivityItem(
title: 'Nouveau membre inscrit',
description: 'Marie Dupont a rejoint l\'association',
icon: Icons.person_add,
color: AppTheme.successColor,
timestamp: now.subtract(const Duration(hours: 2)),
actionRequired: false,
),
ActivityItem(
title: 'Cotisation en retard',
description: 'Pierre Martin - Cotisation échue depuis 5 jours',
icon: Icons.warning,
color: AppTheme.warningColor,
timestamp: now.subtract(const Duration(hours: 4)),
actionRequired: true,
),
ActivityItem(
title: 'Paiement reçu',
description: 'Jean Dubois - Cotisation annuelle 2024',
icon: Icons.payment,
color: AppTheme.primaryColor,
timestamp: now.subtract(const Duration(hours: 6)),
actionRequired: false,
),
ActivityItem(
title: 'Événement créé',
description: 'Assemblée générale 2024 - 15 mars 2024',
icon: Icons.event,
color: AppTheme.accentColor,
timestamp: now.subtract(const Duration(days: 1)),
actionRequired: false,
),
ActivityItem(
title: 'Mise à jour profil',
description: 'Sophie Bernard a modifié ses informations',
icon: Icons.edit,
color: AppTheme.infoColor,
timestamp: now.subtract(const Duration(days: 1, hours: 3)),
actionRequired: false,
),
ActivityItem(
title: 'Nouveau document',
description: 'Procès-verbal ajouté aux archives',
icon: Icons.file_upload,
color: AppTheme.secondaryColor,
timestamp: now.subtract(const Duration(days: 2)),
actionRequired: false,
),
];
}
String _formatTime(DateTime timestamp) {
final now = DateTime.now();
final difference = now.difference(timestamp);
if (difference.inMinutes < 60) {
return 'Il y a ${difference.inMinutes} min';
} else if (difference.inHours < 24) {
return 'Il y a ${difference.inHours}h';
} else if (difference.inDays == 1) {
return 'Hier';
} else if (difference.inDays < 7) {
return 'Il y a ${difference.inDays} jours';
} else {
return DateFormat('dd/MM/yyyy').format(timestamp);
}
}
}
class ActivityItem {
final String title;
final String description;
final IconData icon;
final Color color;
final DateTime timestamp;
final bool actionRequired;
ActivityItem({
required this.title,
required this.description,
required this.icon,
required this.color,
required this.timestamp,
this.actionRequired = false,
});
}