import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:intl/intl.dart'; class ProfileTab extends StatefulWidget { final VoidCallback? onLogoutSuccess; const ProfileTab({super.key, this.onLogoutSuccess}); @override State createState() => _ProfileTabState(); } class _ProfileTabState extends State { final _formKey = GlobalKey(); bool _isTrainer = false; bool _isLoading = false; Map _trainingTimes = {}; Map _trainingDurations = {}; String _name = ''; String _email = ''; String _club = ''; String? _userRole; DateTime? _joinDate; @override void initState() { super.initState(); _loadUserData(); } Future _loadUserData() async { final user = FirebaseAuth.instance.currentUser; if (user == null) return; setState(() => _isLoading = true); try { final doc = await FirebaseFirestore.instance.collection('User').doc(user.uid).get(); if (doc.exists) { final data = doc.data()!; final trainingTimes = data['trainingTimes'] as Map? ?? {}; final trainingDurations = data['trainingDurations'] as Map? ?? {}; final convertedTrainingTimes = {}; trainingTimes.forEach((key, value) { if (value != null) { final timeStr = value.toString(); final timeParts = timeStr.split(':'); if (timeParts.length == 2) { final hour = int.tryParse(timeParts[0]) ?? 0; final minute = int.tryParse(timeParts[1]) ?? 0; convertedTrainingTimes[key] = TimeOfDay(hour: hour, minute: minute); } } }); setState(() { _name = data['name'] ?? ''; _email = data['email'] ?? ''; _club = data['club'] ?? ''; _isTrainer = data['role'] == 'trainer'; _userRole = data['role'] as String?; _trainingTimes = convertedTrainingTimes; _trainingDurations = Map.from(trainingDurations); _joinDate = (data['createdAt'] as Timestamp?)?.toDate(); }); } } catch (e) { print('Error loading user data: $e'); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Fehler beim Laden der Daten: $e')), ); } } finally { if (mounted) { setState(() => _isLoading = false); } } } Future _saveTrainingTime(String day, TimeOfDay? time, int? duration) async { if (time == null || duration == null) return; setState(() => _isLoading = true); try { final user = FirebaseAuth.instance.currentUser; if (user == null) return; final timeString = '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}'; // Update training times and durations await FirebaseFirestore.instance.collection('User').doc(user.uid).update({ 'trainingTimes.$day': timeString, 'trainingDurations.$day': duration, }); // Trainings ab 1. Januar des aktuellen Jahres bis 52 Wochen in die Zukunft anlegen final now = DateTime.now(); final yearStart = DateTime(now.year, 1, 1); final weekdays = { 'Montag': 1, 'Dienstag': 2, 'Mittwoch': 3, 'Donnerstag': 4, 'Freitag': 5, 'Samstag': 6, 'Sonntag': 7, }; final targetWeekday = weekdays[day] ?? 1; // Finde das erste gewünschte Wochentags-Datum ab Jahresanfang DateTime firstDate = yearStart; while (firstDate.weekday != targetWeekday) { firstDate = firstDate.add(const Duration(days: 1)); } final newTrainingDates = []; for (var i = 0; i < 52; i++) { final date = firstDate.add(Duration(days: i * 7)); final normalizedDate = DateTime(date.year, date.month, date.day, time.hour, time.minute); final dateString = DateTime(normalizedDate.year, normalizedDate.month, normalizedDate.day).toIso8601String(); newTrainingDates.add(dateString); } // Load existing trainingExercises and cancelledTrainings final userDoc = await FirebaseFirestore.instance.collection('User').doc(user.uid).get(); final data = userDoc.data() ?? {}; final trainingExercises = Map.from(data['trainingExercises'] ?? {}); final cancelledTrainings = List>.from(data['cancelledTrainings'] ?? []); // Add empty training only if not already present for (final dateString in newTrainingDates) { if (!trainingExercises.containsKey(dateString)) { trainingExercises[dateString] = []; } } // Remove cancelledTrainings for these dates cancelledTrainings.removeWhere((cancelled) => cancelled is Map && cancelled.containsKey('date') && newTrainingDates.contains(cancelled['date']) ); await FirebaseFirestore.instance.collection('User').doc(user.uid).update({ 'cancelledTrainings': cancelledTrainings, 'trainingExercises': trainingExercises, }); setState(() { _trainingTimes[day] = time; _trainingDurations[day] = duration; }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Trainingszeit gespeichert')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Fehler beim Speichern: $e')), ); } } finally { if (mounted) { setState(() => _isLoading = false); } } } Future _removeTrainingTime(String day) async { setState(() => _isLoading = true); try { final user = FirebaseAuth.instance.currentUser; if (user == null) return; await FirebaseFirestore.instance.collection('User').doc(user.uid).update({ 'trainingTimes.$day': FieldValue.delete(), 'trainingDurations.$day': FieldValue.delete(), }); setState(() { _trainingTimes.remove(day); _trainingDurations.remove(day); }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Trainingszeit entfernt')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Fehler beim Entfernen: $e')), ); } } finally { if (mounted) { setState(() => _isLoading = false); } } } Future _selectTime(BuildContext context, String day) async { final TimeOfDay? picked = await showTimePicker( context: context, initialTime: _trainingTimes[day] ?? TimeOfDay.now(), ); if (picked != null) { final duration = await showDialog( context: context, builder: (context) => _DurationDialog( initialDuration: _trainingDurations[day] ?? 60, ), ); if (duration != null) { await _saveTrainingTime(day, picked, duration); } } } Future _saveUserData() async { if (FirebaseAuth.instance.currentUser == null) return; setState(() => _isLoading = true); try { final trainingTimesMap = {}; _trainingTimes.forEach((key, value) { if (value != null) { trainingTimesMap[key] = '${value.hour.toString().padLeft(2, '0')}:${value.minute.toString().padLeft(2, '0')}'; } }); await FirebaseFirestore.instance .collection('User') .doc(FirebaseAuth.instance.currentUser!.uid) .update({ 'name': _name, 'club': _club, 'trainingTimes': trainingTimesMap, 'trainingDurations': _trainingDurations, }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Profil wurde aktualisiert')), ); } } catch (e) { print('Error saving user data: $e'); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Fehler beim Speichern des Profils')), ); } } finally { if (mounted) { setState(() => _isLoading = false); } } } @override Widget build(BuildContext context) { final user = FirebaseAuth.instance.currentUser; if (user == null) { return const Center(child: Text('Nicht eingeloggt')); } return Scaffold( appBar: AppBar( title: const Text('Profil'), actions: [ IconButton( icon: const Icon(Icons.logout), onPressed: () async { await FirebaseAuth.instance.signOut(); if (widget.onLogoutSuccess != null) { widget.onLogoutSuccess!(); } }, ), IconButton( icon: const Icon(Icons.save), onPressed: _isLoading ? null : _saveUserData, ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Card( elevation: 4, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Persönliche Informationen', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), TextField( controller: TextEditingController(text: _name), decoration: const InputDecoration( labelText: 'Name', border: OutlineInputBorder(), prefixIcon: Icon(Icons.person), ), onChanged: (value) => _name = value, ), const SizedBox(height: 16), TextField( controller: TextEditingController(text: _email), decoration: const InputDecoration( labelText: 'E-Mail', border: OutlineInputBorder(), prefixIcon: Icon(Icons.email), ), enabled: false, ), const SizedBox(height: 16), TextField( controller: TextEditingController(text: _club), decoration: const InputDecoration( labelText: 'Verein', border: OutlineInputBorder(), prefixIcon: Icon(Icons.sports), hintText: 'Geben Sie Ihren Verein ein', ), onChanged: (value) => _club = value, ), const SizedBox(height: 16), // Rolle TextField( controller: TextEditingController(text: _userRole == 'trainer' ? 'Trainer' : 'Spieler'), decoration: const InputDecoration( labelText: 'Rolle', border: OutlineInputBorder(), prefixIcon: Icon(Icons.work), ), enabled: false, ), if (_joinDate != null) ...[ const SizedBox(height: 16), TextField( controller: TextEditingController(text: DateFormat('dd.MM.yyyy').format(_joinDate!)), decoration: const InputDecoration( labelText: 'Beigetreten am', border: OutlineInputBorder(), prefixIcon: Icon(Icons.calendar_today), ), enabled: false, ), ], ], ), ), ), if (_userRole == 'trainer') ...[ const SizedBox(height: 24), Card( elevation: 4, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Trainingszeiten', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), ...['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'] .map((day) => Card( margin: const EdgeInsets.only(bottom: 8), child: ListTile( leading: const Icon(Icons.access_time), title: Text(day), subtitle: _trainingTimes[day] != null ? Text( '${_trainingTimes[day]!.format(context)} - ${_trainingDurations[day]} Minuten', ) : const Text('Keine Trainingszeit'), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon( _trainingTimes[day] != null ? Icons.edit : Icons.add, ), onPressed: _isLoading ? null : () => _selectTime(context, day), ), if (_trainingTimes[day] != null) IconButton( icon: const Icon(Icons.delete), onPressed: _isLoading ? null : () => _removeTrainingTime(day), ), ], ), ), )) .toList(), ], ), ), ), ], ], ), ), ); } } class _DurationDialog extends StatefulWidget { final int initialDuration; const _DurationDialog({required this.initialDuration}); @override State<_DurationDialog> createState() => _DurationDialogState(); } class _DurationDialogState extends State<_DurationDialog> { late int _duration; @override void initState() { super.initState(); _duration = widget.initialDuration; } @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Trainingsdauer'), content: Column( mainAxisSize: MainAxisSize.min, children: [ const Text('Wähle die Dauer der Trainingseinheit in Minuten:'), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( icon: const Icon(Icons.remove), onPressed: () { if (_duration > 15) { setState(() => _duration -= 15); } }, ), Text( '$_duration Minuten', style: const TextStyle(fontSize: 18), ), IconButton( icon: const Icon(Icons.add), onPressed: _duration < 300 ? () => setState(() => _duration += 15) : null, ), ], ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Abbrechen'), ), ElevatedButton( onPressed: () => Navigator.pop(context, _duration), child: const Text('Bestätigen'), ), ], ); } }