Files
TravelMate/lib/data/models/trip.dart
Dayron d0a76b5043 feat: Enhance trip management features and improve UI responsiveness
- Implemented AutomaticKeepAliveClientMixin in HomeContent to maintain state during navigation.
- Modified trip loading logic to trigger after the first frame for better performance.
- Updated trip loading events to use LoadTripsByUserId for consistency.
- Added temporary success messages for trip creation and operations.
- Improved UI elements for better user experience, including updated text styles and spacing.
- Refactored trip model to support Firestore timestamps and improved error handling during parsing.
- Streamlined trip repository methods for better clarity and performance.
- Enhanced trip service methods to ensure correct mapping from Firestore documents.
- Removed unnecessary trip reset logic on logout.
2025-10-20 14:31:41 +02:00

209 lines
5.7 KiB
Dart

import 'dart:convert';
import 'package:cloud_firestore/cloud_firestore.dart';
class Trip {
final String? id;
final String title;
final String description;
final String location;
final DateTime startDate;
final DateTime endDate;
final double? budget;
final List<String> participants;
final String createdBy;
final DateTime createdAt;
final DateTime updatedAt;
final String status;
Trip({
this.id,
required this.title,
required this.description,
required this.location,
required this.startDate,
required this.endDate,
this.budget,
required this.participants,
required this.createdBy,
required this.createdAt,
required this.updatedAt,
this.status = 'draft',
});
// NOUVELLE MÉTHODE HELPER pour convertir n'importe quel format de date
static DateTime _parseDateTime(dynamic value) {
if (value == null) return DateTime.now();
// Si c'est déjà un Timestamp Firebase
if (value is Timestamp) {
return value.toDate();
}
// Si c'est un int (millisecondes depuis epoch)
if (value is int) {
return DateTime.fromMillisecondsSinceEpoch(value);
}
// Si c'est un String (ISO 8601)
if (value is String) {
return DateTime.parse(value);
}
// Si c'est déjà un DateTime
if (value is DateTime) {
return value;
}
// Par défaut
return DateTime.now();
}
// Constructeur pour créer un Trip depuis un Map (utile pour Firebase)
factory Trip.fromMap(Map<String, dynamic> map, String id) {
try {
return Trip(
id: id,
title: map['title'] as String? ?? '',
description: map['description'] as String? ?? '',
location: map['location'] as String? ?? '',
startDate: _parseDateTime(map['startDate']),
endDate: _parseDateTime(map['endDate']),
budget: (map['budget'] as num?)?.toDouble(),
createdBy: map['createdBy'] as String? ?? '',
participants: List<String>.from(map['participants'] as List? ?? []),
createdAt: _parseDateTime(map['createdAt']),
updatedAt: _parseDateTime(map['updatedAt']),
status: map['status'] as String? ?? 'draft',
);
} catch (e) {
print('❌ Erreur parsing Trip: $e');
print('Map reçue: $map');
rethrow;
}
}
// MODIFIÉ : Convertir en Map avec Timestamp pour Firestore
Map<String, dynamic> toMap() {
return {
'title': title,
'description': description,
'location': location,
'startDate': Timestamp.fromDate(startDate),
'endDate': Timestamp.fromDate(endDate),
'budget': budget,
'participants': participants,
'createdBy': createdBy,
'createdAt': Timestamp.fromDate(createdAt),
'updatedAt': Timestamp.fromDate(updatedAt),
'status': status,
};
}
// Méthode pour convertir un Trip en JSON
String toJson() {
return json.encode(toMap());
}
// Méthode pour créer une copie avec des modifications
Trip copyWith({
String? id,
String? title,
String? description,
String? location,
DateTime? startDate,
DateTime? endDate,
double? budget,
List<String>? participants,
String? createdBy,
DateTime? createdAt,
DateTime? updatedAt,
String? status,
}) {
return Trip(
id: id ?? this.id,
title: title ?? this.title,
description: description ?? this.description,
location: location ?? this.location,
startDate: startDate ?? this.startDate,
endDate: endDate ?? this.endDate,
budget: budget ?? this.budget,
participants: participants ?? this.participants,
createdBy: createdBy ?? this.createdBy,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
status: status ?? this.status,
);
}
// Méthode pour obtenir la durée du voyage en jours
int get durationInDays {
return endDate.difference(startDate).inDays + 1;
}
// Méthode pour vérifier si le voyage est en cours
bool get isActive {
final now = DateTime.now();
return status == 'active' &&
now.isAfter(startDate) &&
now.isBefore(endDate.add(Duration(days: 1)));
}
// Méthode pour vérifier si le voyage est à venir
bool get isUpcoming {
final now = DateTime.now();
return status == 'active' && now.isBefore(startDate);
}
// Méthode pour vérifier si le voyage est terminé
bool get isCompleted {
final now = DateTime.now();
return status == 'completed' ||
(status == 'active' && now.isAfter(endDate));
}
// Méthode pour obtenir le budget par participant
double? get budgetPerParticipant {
if (budget == null || participants.isEmpty) return null;
return budget! / (participants.length + 1);
}
// Méthode pour obtenir le nombre total de participants (incluant le créateur)
int get totalParticipants {
return participants.length + 1;
}
// Méthode pour formater les dates
String get formattedDates {
return '${startDate.day}/${startDate.month}/${startDate.year} - ${endDate.day}/${endDate.month}/${endDate.year}';
}
// Méthode pour obtenir le statut formaté
String get formattedStatus {
switch (status) {
case 'draft':
return 'Brouillon';
case 'active':
return 'Actif';
case 'completed':
return 'Terminé';
case 'cancelled':
return 'Annulé';
default:
return 'Inconnu';
}
}
@override
String toString() {
return 'Trip(id: $id, title: $title, location: $location, status: $status)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Trip && other.id == id;
}
@override
int get hashCode => id.hashCode;
}