import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; enum ExpenseCategory { restaurant, transport, accommodation, activities, shopping, other, } enum ExpenseCurrency { eur, usd, gbp, jpy, chf, cad, aud, } class ExpenseSplit { final String userId; final String userName; final double amount; final bool isPaid; ExpenseSplit({ required this.userId, required this.userName, required this.amount, this.isPaid = false, }); Map toMap() { return { 'userId': userId, 'userName': userName, 'amount': amount, 'isPaid': isPaid, }; } factory ExpenseSplit.fromMap(Map map) { return ExpenseSplit( userId: map['userId'] ?? '', userName: map['userName'] ?? '', amount: (map['amount'] ?? 0.0).toDouble(), isPaid: map['isPaid'] ?? false, ); } } class Expense { final String id; final String groupId; final String description; final double amount; final ExpenseCurrency currency; final double amountInEur; final ExpenseCategory category; final String paidById; final String paidByName; final List splits; final String? receiptUrl; final DateTime date; final DateTime createdAt; final bool isArchived; final bool isEdited; final DateTime? editedAt; Expense({ this.id = '', required this.groupId, required this.description, required this.amount, required this.currency, required this.amountInEur, required this.category, required this.paidById, required this.paidByName, required this.splits, this.receiptUrl, required this.date, DateTime? createdAt, this.isArchived = false, this.isEdited = false, this.editedAt, }) : createdAt = createdAt ?? DateTime.now(); Map toMap() { return { 'groupId': groupId, 'description': description, 'amount': amount, 'currency': currency.name, 'amountInEur': amountInEur, 'category': category.name, 'paidById': paidById, 'paidByName': paidByName, 'splits': splits.map((s) => s.toMap()).toList(), 'receiptUrl': receiptUrl, 'date': Timestamp.fromDate(date), 'createdAt': Timestamp.fromDate(createdAt), 'isArchived': isArchived, 'isEdited': isEdited, 'editedAt': editedAt != null ? Timestamp.fromDate(editedAt!) : null, }; } factory Expense.fromFirestore(DocumentSnapshot doc) { final data = doc.data() as Map; final editedAtTimestamp = data['editedAt'] as Timestamp?; return Expense( id: doc.id, groupId: data['groupId'] ?? '', description: data['description'] ?? '', amount: (data['amount'] ?? 0.0).toDouble(), currency: ExpenseCurrency.values.firstWhere( (e) => e.name == data['currency'], orElse: () => ExpenseCurrency.eur, ), amountInEur: (data['amountInEur'] ?? 0.0).toDouble(), category: ExpenseCategory.values.firstWhere( (e) => e.name == data['category'], orElse: () => ExpenseCategory.other, ), paidById: data['paidById'] ?? '', paidByName: data['paidByName'] ?? '', splits: (data['splits'] as List?) ?.map((s) => ExpenseSplit.fromMap(s as Map)) .toList() ?? [], receiptUrl: data['receiptUrl'], date: (data['date'] as Timestamp?)?.toDate() ?? DateTime.now(), createdAt: (data['createdAt'] as Timestamp?)?.toDate() ?? DateTime.now(), isArchived: data['isArchived'] ?? false, isEdited: data['isEdited'] ?? false, editedAt: editedAtTimestamp?.toDate(), ); } Expense copyWith({ String? id, String? groupId, String? description, double? amount, ExpenseCurrency? currency, double? amountInEur, ExpenseCategory? category, String? paidById, String? paidByName, List? splits, String? receiptUrl, DateTime? date, DateTime? createdAt, bool? isArchived, bool? isEdited, DateTime? editedAt, }) { return Expense( id: id ?? this.id, groupId: groupId ?? this.groupId, description: description ?? this.description, amount: amount ?? this.amount, currency: currency ?? this.currency, amountInEur: amountInEur ?? this.amountInEur, category: category ?? this.category, paidById: paidById ?? this.paidById, paidByName: paidByName ?? this.paidByName, splits: splits ?? this.splits, receiptUrl: receiptUrl ?? this.receiptUrl, date: date ?? this.date, createdAt: createdAt ?? this.createdAt, isArchived: isArchived ?? this.isArchived, isEdited: isEdited ?? this.isEdited, editedAt: editedAt ?? this.editedAt, ); } } extension ExpenseCategoryExtension on ExpenseCategory { String get displayName { switch (this) { case ExpenseCategory.restaurant: return 'Restaurant'; case ExpenseCategory.transport: return 'Transport'; case ExpenseCategory.accommodation: return 'Hébergement'; case ExpenseCategory.activities: return 'Activités'; case ExpenseCategory.shopping: return 'Shopping'; case ExpenseCategory.other: return 'Autre'; } } IconData get icon { switch (this) { case ExpenseCategory.restaurant: return Icons.restaurant; case ExpenseCategory.transport: return Icons.directions_car; case ExpenseCategory.accommodation: return Icons.hotel; case ExpenseCategory.activities: return Icons.attractions; case ExpenseCategory.shopping: return Icons.shopping_bag; case ExpenseCategory.other: return Icons.more_horiz; } } } extension ExpenseCurrencyExtension on ExpenseCurrency { String get symbol { switch (this) { case ExpenseCurrency.eur: return '€'; case ExpenseCurrency.usd: return '\$'; case ExpenseCurrency.gbp: return '£'; case ExpenseCurrency.jpy: return '¥'; case ExpenseCurrency.chf: return 'CHF'; case ExpenseCurrency.cad: return 'CAD'; case ExpenseCurrency.aud: return 'AUD'; } } String get code { return name.toUpperCase(); } }