import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../services/firebase_service.dart'; import '../../services/dialog_service.dart'; import '../home/home_screen.dart'; import '../auth/login_screen.dart'; import '../../models/user_model.dart'; // Colors matching the design const Color primaryBrown = Color(0xFF4A3C3C); const Color labelGray = Color(0xFF9E9E9E); const Color borderGray = Color(0xFFE8E8E8); class EarlySetupScreen extends StatefulWidget { const EarlySetupScreen({super.key}); @override State createState() => _EarlySetupScreenState(); } class _EarlySetupScreenState extends State { final PageController _pageController = PageController(); int _currentPage = 0; bool _isLoading = false; // Form controllers final _nicknameController = TextEditingController(); final _addressController = TextEditingController(); // Demographics selections String? _selectedAgeRange; String? _selectedGender; // Preferences selections List _selectedAllergies = []; String _selectedDietaryRestriction = 'None'; // Questionnaire state removed — daily check-in questions // no longer shown during onboarding. // Options final List _ageRanges = ['< 18', '18–24', '25–34', '35+']; final List _genders = ['Laki-laki', 'Perempuan', 'Rahasiakan']; final List _availableAllergies = [ 'Gluten', 'Kacang', 'Susu', 'Telur', 'Seafood', 'Kedelai', 'Wijen', 'Sulfit', ]; final List _availableDietaryRestrictions = [ 'None', 'Vegetarian', 'Vegan', 'Halal', 'Keto', 'Low Carb', ]; @override void initState() { super.initState(); _loadUserData(); } @override void dispose() { _pageController.dispose(); _nicknameController.dispose(); _addressController.dispose(); super.dispose(); } Future _loadUserData() async { try { final user = FirebaseService().currentUser; if (user != null) { final userData = await FirebaseService().getUserData(user.uid); if (userData != null && mounted) { setState(() { if (userData.nickname != null) _nicknameController.text = userData.nickname!; if (userData.address != null) _addressController.text = userData.address!; if (userData.gender != null) _selectedGender = userData.gender; _selectedAllergies = userData.preferences.allergies; _selectedDietaryRestriction = userData.preferences.dietaryRestriction; if (userData.preferences.ageRange != null) { _selectedAgeRange = userData.preferences.ageRange; } }); } } } catch (e) { debugPrint('Error loading user data: $e'); } } void _nextPage() { // Page 0: Demographics Validation if (_currentPage == 0) { if (_nicknameController.text.trim().isEmpty || _addressController.text.trim().isEmpty || _selectedAgeRange == null || _selectedGender == null) { DialogService().showError('Silakan lengkapi semua data profil'); return; } } // Page 1 (Preferensi) — lanjut selesai setup if (_currentPage == 1) { _handleComplete(); return; } _pageController.nextPage( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } void _previousPage() async { if (_currentPage > 0) { _pageController.previousPage( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } else { await FirebaseService().signOut(); if (mounted) { Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => const LoginScreen()), ); } } } Future _handleComplete() async { setState(() => _isLoading = true); try { final firebaseService = FirebaseService(); final currentUser = firebaseService.currentUser; if (currentUser == null) throw Exception('User not logged in'); final existingUser = await firebaseService.getUserData(currentUser.uid); final nickname = _nicknameController.text.trim(); final address = _addressController.text.trim(); // (questionnaire answers no longer saved during onboarding) if (existingUser != null) { final updatedUser = existingUser.copyWith( nickname: nickname.isNotEmpty ? nickname : null, address: address.isNotEmpty ? address : null, gender: _selectedGender, isSetupComplete: true, ); await firebaseService.updateUserData(updatedUser); } else { final newUser = await firebaseService.createUserDocument(currentUser); final updatedNewUser = newUser.copyWith( nickname: nickname.isNotEmpty ? nickname : null, address: address.isNotEmpty ? address : null, gender: _selectedGender, isSetupComplete: true, ); await firebaseService.updateUserData(updatedNewUser); } final currentPrefs = existingUser?.preferences ?? UserPreferences( allergies: [], dietaryRestriction: 'None', ageRange: null, ); final updatedPreferences = currentPrefs.copyWith( ageRange: _selectedAgeRange, allergies: _selectedAllergies, dietaryRestriction: _selectedDietaryRestriction, ); await firebaseService.updateUserPreferences( currentUser.uid, updatedPreferences, ); await firebaseService.setSetupComplete(currentUser.uid); if (mounted) { Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (context) => const HomeScreen()), ); } } catch (e) { if (mounted) DialogService().showError('Gagal menyimpan: $e'); } finally { if (mounted) setState(() => _isLoading = false); } } @override Widget build(BuildContext context) { return PopScope( canPop: false, onPopInvokedWithResult: (didPop, _) { if (!didPop) _previousPage(); }, child: Scaffold( backgroundColor: Colors.white, body: SafeArea( child: Column( children: [ // Header Align( alignment: Alignment.topLeft, child: Padding( padding: const EdgeInsets.only(left: 8, top: 8), child: IconButton( icon: const Icon( Icons.chevron_left, color: Colors.black54, size: 28, ), onPressed: _previousPage, ), ), ), // Title Section Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( children: [ const SizedBox(height: 8), const Text( 'Kenalan Dulu Yuk!', textAlign: TextAlign.center, style: TextStyle( fontFamily: 'Poppins', fontSize: 26, fontWeight: FontWeight.bold, color: primaryBrown, height: 1.25, ), ), const SizedBox(height: 10), Text( _getSubtitle(), textAlign: TextAlign.center, style: const TextStyle( fontFamily: 'Poppins', fontSize: 14, fontWeight: FontWeight.w400, color: labelGray, ), ), const SizedBox(height: 8), _buildProgressIndicator(), ], ), ), const SizedBox(height: 24), // PageView Expanded( child: PageView( controller: _pageController, physics: const NeverScrollableScrollPhysics(), onPageChanged: (index) { setState(() => _currentPage = index); }, children: [_buildDemographicsPage(), _buildPreferencesPage()], ), ), ], ), ), ), ); } String _getSubtitle() { switch (_currentPage) { case 0: return 'Data diri dasar kamu'; case 1: return 'Info alergi & pantangan'; default: return ''; } } Widget _buildProgressIndicator() { return Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(2, (index) { return Container( margin: const EdgeInsets.symmetric(horizontal: 4), width: index == _currentPage ? 24 : 8, height: 8, decoration: BoxDecoration( color: index == _currentPage ? primaryBrown : borderGray, borderRadius: BorderRadius.circular(4), ), ); }), ); } // ============ PAGE 1: Profile & Demographics ============ Widget _buildDemographicsPage() { return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildTextField( controller: _nicknameController, label: 'Nama Panggilan', hint: 'Bagaimana kami harus memanggil Anda?', ), const SizedBox(height: 24), _buildTextField( controller: _addressController, label: 'Alamat Lengkap', hint: 'Domisili Anda saat ini', maxLines: 2, minHeight: 80, keyboardType: TextInputType.streetAddress, ), const SizedBox(height: 24), _buildSectionTitle('Rentang Usia', 'Pilih rentang usia Anda'), const SizedBox(height: 12), _buildChoiceChips( options: _ageRanges, selectedValue: _selectedAgeRange, onSelected: (value) => setState(() => _selectedAgeRange = value), ), const SizedBox(height: 24), _buildSectionTitle('Jenis Kelamin', 'Pilih jenis kelamin Anda'), const SizedBox(height: 12), _buildChoiceChips( options: _genders, selectedValue: _selectedGender, onSelected: (value) => setState(() => _selectedGender = value), ), const SizedBox(height: 48), _buildNavigationButton(), const SizedBox(height: 32), ], ), ); } // ============ PAGE 3: Preferences ============ Widget _buildPreferencesPage() { return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionTitle( 'Alergi & Pantangan', 'Pilih bahan yang harus dihindari', ), const SizedBox(height: 12), _buildFilterChips(), const SizedBox(height: 28), _buildSectionTitle( 'Pembatasan Diet', 'Pilih pola makan yang Anda ikuti', ), const SizedBox(height: 12), _buildChoiceChips( options: _availableDietaryRestrictions, selectedValue: _selectedDietaryRestriction, onSelected: (value) => setState(() => _selectedDietaryRestriction = value), ), const SizedBox(height: 48), _buildNavigationButton(), const SizedBox(height: 32), ], ), ); } // ============ REUSABLE WIDGETS ============ Widget _buildTextField({ required TextEditingController controller, required String label, String? hint, double minHeight = 56, int maxLines = 1, TextInputType keyboardType = TextInputType.text, List? inputFormatters, }) { return Builder( builder: (context) { return Container( constraints: BoxConstraints(minHeight: minHeight), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), border: Border.all(color: borderGray, width: 1), ), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( label, style: const TextStyle( fontFamily: 'Poppins', fontSize: 11, fontWeight: FontWeight.w400, color: labelGray, ), ), const SizedBox(height: 4), TextFormField( controller: controller, maxLines: maxLines, keyboardType: keyboardType, inputFormatters: inputFormatters, onTap: () { Future.delayed(const Duration(milliseconds: 300), () { if (context.mounted) { Scrollable.ensureVisible( context, alignment: 0.5, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } }); }, style: const TextStyle( fontFamily: 'Poppins', fontSize: 14, fontWeight: FontWeight.w600, color: primaryBrown, ), decoration: InputDecoration( isDense: true, contentPadding: EdgeInsets.zero, border: InputBorder.none, hintText: hint, hintStyle: TextStyle( fontFamily: 'Poppins', fontSize: 14, fontWeight: FontWeight.w400, color: labelGray.withOpacity(0.6), ), ), validator: (v) => v!.isEmpty ? '$label is required' : null, ), ], ), ); }, ); } Widget _buildSectionTitle(String title, String subtitle) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontFamily: 'Poppins', fontSize: 16, fontWeight: FontWeight.w600, color: primaryBrown, ), ), const SizedBox(height: 4), Text( subtitle, style: const TextStyle( fontFamily: 'Poppins', fontSize: 12, fontWeight: FontWeight.w400, color: labelGray, ), ), ], ); } Widget _buildChoiceChips({ required List options, required String? selectedValue, required Function(String) onSelected, }) { return Wrap( spacing: 10, runSpacing: 10, children: options.map((option) { final isSelected = selectedValue == option; return ChoiceChip( label: Text(option), selected: isSelected, onSelected: (selected) { if (selected) onSelected(option); }, selectedColor: primaryBrown, backgroundColor: Colors.grey[100], labelStyle: TextStyle( fontFamily: 'Poppins', fontSize: 14, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? Colors.white : labelGray, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), side: BorderSide( color: isSelected ? primaryBrown : borderGray, width: 1, ), ), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), ); }).toList(), ); } Widget _buildFilterChips() { return Wrap( spacing: 8, runSpacing: 8, children: _availableAllergies.map((allergy) { final isSelected = _selectedAllergies.contains(allergy); return FilterChip( label: Text(allergy), selected: isSelected, onSelected: (selected) { setState(() { if (selected) { _selectedAllergies.add(allergy); } else { _selectedAllergies.remove(allergy); } }); }, selectedColor: const Color(0xFFFFEBEE), checkmarkColor: const Color(0xFFD32F2F), backgroundColor: Colors.grey[100], labelStyle: TextStyle( fontFamily: 'Poppins', fontSize: 13, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? const Color(0xFFD32F2F) : primaryBrown, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), side: BorderSide( color: isSelected ? const Color(0xFFD32F2F) : borderGray, width: 1, ), ), ); }).toList(), ); } Widget _buildNavigationButton() { return Align( alignment: Alignment.centerRight, child: _buildCircularButton( onPressed: _isLoading ? null : _nextPage, isLoading: _isLoading, isComplete: _currentPage == 1, // Page 1 = preferensi = halaman terakhir ), ); } Widget _buildCircularButton({ VoidCallback? onPressed, bool isLoading = false, bool isComplete = false, }) { return Stack( clipBehavior: Clip.none, children: [ Positioned( top: -4, left: 4, right: -4, bottom: 4, child: Container( width: 64, height: 64, decoration: BoxDecoration( color: const Color(0xFF5A4A3A).withOpacity(0.3), shape: BoxShape.circle, ), ), ), Material( color: const Color(0xFF5A4A3A), shape: const CircleBorder(), child: InkWell( onTap: onPressed, customBorder: const CircleBorder(), child: Container( width: 64, height: 64, decoration: const BoxDecoration(shape: BoxShape.circle), child: isLoading ? const Padding( padding: EdgeInsets.all(16.0), child: CircularProgressIndicator( color: Colors.white, strokeWidth: 3, ), ) : Icon( isComplete ? Icons.check : Icons.arrow_forward, color: Colors.white, size: 32, ), ), ), ), ], ); } }