import 'package:cloud_firestore/cloud_firestore.dart'; // ----------------------------------------------------------- // Modelos de Utilizador e Transações // ----------------------------------------------------------- // ✅ Modelo para o Perfil do Utilizador class AppUser { final String uid; final String username; final String? email; final double currentBalance; final int points; final List badges; final String? goal; final double? monthlyIncome; final String? profession; final String? educationLevel; final String? profileImageUrl; // ✅ URL da imagem de perfil (usado no Firestore) final String? profileImage; // Caminho local (se necessário, ou ajuste para usar apenas a URL) AppUser({ required this.uid, required this.username, this.email, this.currentBalance = 0.0, this.points = 0, this.badges = const [], this.goal, this.monthlyIncome, this.profession, this.educationLevel, this.profileImageUrl, this.profileImage, // Mantido como String? para compatibilidade, se representar um path }); // ✅ CORRIGIDO: Lógica de mapeamento para incluir todos os campos, // e correções nas chaves de profileImageUrl/profileImage factory AppUser.fromMap(Map data) { return AppUser( uid: data['uid'] ?? '', username: data['username'] ?? '', email: data['email'], currentBalance: (data['currentBalance'] as num?)?.toDouble() ?? 0.0, points: (data['points'] as num?)?.toInt() ?? 0, badges: (data['badges'] as List?) ?? [], goal: data['goal'], monthlyIncome: (data['monthlyIncome'] as num?)?.toDouble(), profession: data['profession'], educationLevel: data['educationLevel'], profileImageUrl: data['profileImageUrl'] as String?, // ✅ CHAVE CORRETA profileImage: data['profileImage'] as String?, // ✅ CHAVE CORRETA ); } // ✅ CORRIGIDO: Agora aceita QueryDocumentSnapshot e inclui todos os campos factory AppUser.fromFirestore(QueryDocumentSnapshot doc) { final data = doc.data() as Map; return AppUser( uid: doc.id, username: data['username'] ?? '', email: data['email'], currentBalance: (data['currentBalance'] as num?)?.toDouble() ?? 0.0, points: (data['points'] as num?)?.toInt() ?? 0, badges: (data['badges'] as List?) ?? [], goal: data['goal'], monthlyIncome: (data['monthlyIncome'] as num?)?.toDouble(), profession: data['profession'], educationLevel: data['educationLevel'], profileImageUrl: data['profileImageUrl'] as String?, profileImage: data['profileImage'] as String?, ); } factory AppUser.newProfile({ required String uid, required String username, String? email, }) { return AppUser( uid: uid, username: username, email: email, ); } Map toMap() { return { 'uid': uid, 'username': username, 'email': email, 'currentBalance': currentBalance, 'points': points, 'badges': badges, 'goal': goal, 'monthlyIncome': monthlyIncome, 'profession': profession, 'educationLevel': educationLevel, 'profileImageUrl': profileImageUrl, 'profileImage': profileImage, }; } // ✅ CORRIGIDO: O copyWith agora tem as duas chaves corretas e resolve o erro AppUser copyWith({ String? uid, String? username, String? email, double? currentBalance, int? points, List? badges, String? goal, double? monthlyIncome, String? profession, String? educationLevel, String? profileImageUrl, String? profileImage, }) { return AppUser( uid: uid ?? this.uid, username: username ?? this.username, email: email ?? this.email, currentBalance: currentBalance ?? this.currentBalance, points: points ?? this.points, badges: badges ?? this.badges, goal: goal ?? this.goal, monthlyIncome: monthlyIncome ?? this.monthlyIncome, profession: profession ?? this.profession, educationLevel: educationLevel ?? this.educationLevel, profileImageUrl: profileImageUrl ?? this.profileImageUrl, // ✅ CORRIGIDO profileImage: profileImage ?? this.profileImage, // ✅ CORRIGIDO ); } } // ----------------------------------------------------------- // Transações e Orçamentos // ----------------------------------------------------------- // ✅ Enum para tipos de transação enum TransactionType { income, expense, } // ✅ Enum para categorias de transação enum TransactionCategory { food, transport, social, education, medical, shopping, others, salary, invest, business, } // ✅ Renomeado de 'Transaction' para 'FinancialTransaction' class FinancialTransaction { final String? id; final String? title; final double amount; final TransactionType type; final TransactionCategory category; final DateTime date; final String? note; FinancialTransaction({ this.id, this.title, required this.amount, required this.type, required this.category, required this.date, this.note, }); factory FinancialTransaction.fromMap(Map data) { return FinancialTransaction( id: data['id'], title: data['title'], amount: (data['amount'] as num).toDouble(), type: TransactionType.values.byName(data['type']), category: TransactionCategory.values.byName(data['category']), date: (data['date'] as Timestamp).toDate(), note: data['note'], ); } // ✅ CORRIGIDO: Agora aceita QueryDocumentSnapshot para consistência. factory FinancialTransaction.fromFirestore(QueryDocumentSnapshot doc) { final data = doc.data() as Map; return FinancialTransaction( id: doc.id, title: data['title'], amount: (data['amount'] as num).toDouble(), type: TransactionType.values.byName(data['type']), category: TransactionCategory.values.byName(data['category']), date: (data['date'] as Timestamp).toDate(), note: data['note'], ); } Map toMap() { return { 'title': title, 'amount': amount, 'type': type.name, 'category': category.name, 'date': Timestamp.fromDate(date), 'note': note, }; } } // Model para Orçamento class Budget { final String id; final String nome; final double valor; final double gasto; final String categoria; Budget({ required this.id, required this.nome, required this.valor, required this.gasto, required this.categoria, }); factory Budget.fromFirestore(QueryDocumentSnapshot doc) { Map data = doc.data() as Map; return Budget( id: doc.id, nome: data['nome'] ?? '', valor: (data['valor'] as num?)?.toDouble() ?? 0.0, gasto: (data['gasto'] as num?)?.toDouble() ?? 0.0, categoria: data['categoria'] ?? '', ); } } // ----------------------------------------------------------- // Modelos de Educação e Simulação // ----------------------------------------------------------- // Model para Simulação de Poupança class SavingsSimulation { final String id; final double valorInicial; final double depositoMensal; final double taxaJuros; final int periodoMeses; final double resultadoFinal; final List simulationData; final String timestamp; SavingsSimulation({ required this.id, required this.valorInicial, required this.depositoMensal, required this.taxaJuros, required this.periodoMeses, required this.resultadoFinal, required this.simulationData, required this.timestamp, }); factory SavingsSimulation.fromFirestore(QueryDocumentSnapshot doc) { Map data = doc.data() as Map; return SavingsSimulation( id: doc.id, valorInicial: (data['valorInicial'] as num?)?.toDouble() ?? 0.0, depositoMensal: (data['depositoMensal'] as num?)?.toDouble() ?? 0.0, taxaJuros: (data['taxaJuros'] as num?)?.toDouble() ?? 0.0, periodoMeses: (data['periodoMeses'] as num?)?.toInt() ?? 0, resultadoFinal: (data['resultadoFinal'] as num?)?.toDouble() ?? 0.0, simulationData: (data['simulationData'] as List?) ?? [], timestamp: data['timestamp'] ?? '', ); } Map toFirestore() { return { 'valorInicial': valorInicial, 'depositoMensal': depositoMensal, 'taxaJuros': taxaJuros, 'periodoMeses': periodoMeses, 'resultadoFinal': resultadoFinal, 'simulationData': simulationData, 'timestamp': timestamp, }; } } // Model para Desafio Financeiro class FinancialChallenge { final String id; final String nome; final String meta; final int points; FinancialChallenge({required this.id, required this.nome, required this.meta, required this.points}); factory FinancialChallenge.fromFirestore(QueryDocumentSnapshot doc) { Map data = doc.data() as Map; return FinancialChallenge( id: doc.id, nome: data['nome'] ?? '', meta: data['meta'] ?? '', points: (data['points'] as num?)?.toInt() ?? 0, ); } } // Model para Desafio do Utilizador (aceite) class UserChallenge { final String id; final String challengeId; final String nome; final String meta; final int progresso; final String acceptedAt; final String? lastUpdated; UserChallenge({ required this.id, required this.challengeId, required this.nome, required this.meta, required this.progresso, required this.acceptedAt, this.lastUpdated, }); factory UserChallenge.fromFirestore(QueryDocumentSnapshot doc) { Map data = doc.data() as Map; return UserChallenge( id: doc.id, challengeId: data['challengeId'] ?? '', nome: data['nome'] ?? '', meta: data['meta'] ?? '', progresso: (data['progresso'] as num?)?.toInt() ?? 0, acceptedAt: data['acceptedAt'] ?? '', lastUpdated: data['lastUpdated'], ); } } // Model para Aula Rápida class QuickLesson { final String id; final String titulo; final String duracao; final String? conteudo; final String? videoUrl; final String? bookUrl; QuickLesson({ required this.id, required this.titulo, required this.duracao, this.conteudo, this.videoUrl, this.bookUrl, }); factory QuickLesson.fromFirestore(QueryDocumentSnapshot doc) { Map data = doc.data() as Map; return QuickLesson( id: doc.id, titulo: (data['titulo'] as String?) ?? '', duracao: (data['duracao'] as String?) ?? '', conteudo: (data['conteudo'] as String?), videoUrl: (data['videoUrl'] as String?), bookUrl: (data['bookUrl'] as String?), ); } } // Model para Aula Concluída pelo Utilizador class UserCompletedLesson { final String id; // lessonId final String completedAt; UserCompletedLesson({required this.id, required this.completedAt}); factory UserCompletedLesson.fromFirestore(QueryDocumentSnapshot doc) { Map data = doc.data() as Map; return UserCompletedLesson( id: doc.id, completedAt: data['completedAt'] ?? '', ); } } // Model para Pergunta de Quiz class QuizQuestion { final String id; final String question; final List options; final String answer; final String explanation; QuizQuestion({ required this.id, required this.question, required this.options, required this.answer, required this.explanation, }); factory QuizQuestion.fromFirestore(QueryDocumentSnapshot doc) { Map data = doc.data() as Map; return QuizQuestion( id: doc.id, question: data['question'] ?? '', options: (data['options'] as List?) ?? [], answer: data['answer'] ?? '', explanation: data['explanation'] ?? '', ); } } // Model para Resultado de Quiz do Utilizador class UserQuizResult { final String id; final int score; final int totalQuestions; final String timestamp; UserQuizResult({ required this.id, required this.score, required this.totalQuestions, required this.timestamp, }); factory UserQuizResult.fromFirestore(QueryDocumentSnapshot doc) { Map data = doc.data() as Map; return UserQuizResult( id: doc.id, score: (data['score'] as num?)?.toInt() ?? 0, totalQuestions: (data['totalQuestions'] as num?)?.toInt() ?? 0, timestamp: data['timestamp'] ?? '', ); } }