// lib/features/home/tabs/settings_tab.dart import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // Penting untuk FilteringTextInputFormatter import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:smpn1_lengkong/core/constants/app_colors.dart'; import 'package:smpn1_lengkong/core/models/student_model.dart'; import 'package:smpn1_lengkong/core/routes/app_routes.dart'; import 'package:smpn1_lengkong/core/service/auth_service.dart'; import 'package:smpn1_lengkong/core/service/student_service.dart'; class SettingsTab extends StatelessWidget { final StudentModel student; final VoidCallback onRefresh; const SettingsTab({ super.key, required this.student, required this.onRefresh, }); // Helper untuk membersihkan nilai "-" agar menjadi string kosong di Form String _cleanValue(String? val) { if (val == null || val.trim() == "-") return ""; return val; } // --- HELPER DIALOG SUKSES --- void _showSuccessDialog(BuildContext context, String message) { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), ), content: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.check_circle_outline_rounded, color: AppColors.successGreen, size: 64.sp, ), SizedBox(height: 16.h), Text( "Berhasil!", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18.sp, ), ), SizedBox(height: 8.h), Text(message, textAlign: TextAlign.center), ], ), actions: [ ElevatedButton( onPressed: () => Navigator.pop(context), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, ), child: const Text("Tutup"), ), ], ), ); } // --- HELPER DIALOG PERINGATAN (TIDAK ADA PERUBAHAN) --- void _showNoChangesDialog(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), ), title: const Text( "Tidak Ada Perubahan", style: TextStyle(fontWeight: FontWeight.bold), ), content: const Text( "Tidak ada perubahan data yang dilakukan. Silakan ubah data terlebih dahulu sebelum menyimpan.", ), actions: [ ElevatedButton( onPressed: () => Navigator.pop(context), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, ), child: const Text("Tutup"), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.backgroundWhite, body: CustomScrollView( slivers: [ SliverAppBar( expandedHeight: 120.h, pinned: true, automaticallyImplyLeading: false, backgroundColor: AppColors.primaryBlue, flexibleSpace: FlexibleSpaceBar( titlePadding: EdgeInsets.only(left: 20.w, bottom: 16.h), title: Text( "Pengaturan", style: TextStyle( color: Colors.white, fontSize: 18.sp, fontWeight: FontWeight.bold, ), ), background: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [AppColors.primaryBlue, Color(0xFF2C64B8)], ), ), ), ), ), SliverToBoxAdapter( child: Padding( padding: EdgeInsets.symmetric(vertical: 20.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionHeader("PENGATURAN & DUKUNGAN"), _buildSettingsCard([ _buildSettingsTile( icon: Icons.person_outline_rounded, title: "Informasi Pribadi", subtitle: "Detail data orang tua dan alamat", onTap: () => _showPersonalInfo(context), ), _buildSettingsTile( icon: Icons.phone_rounded, title: "Pusat Bantuan", subtitle: "Hubungi kami melalui WhatsApp", onTap: () async { showDialog( context: context, barrierDismissible: false, builder: (context) => const Center( child: CircularProgressIndicator(), ), ); try { final String? contactUrl = await StudentService().getContactLink(); if (context.mounted) Navigator.pop(context); if (contactUrl != null && contactUrl.isNotEmpty) { await StudentService().launchWhatsApp(contactUrl); } else { throw "Kontak tidak ditemukan di server"; } } catch (e) { if (context.mounted) { if (Navigator.canPop(context)) { Navigator.pop(context); } ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(e.toString())), ); } } }, ), ]), SizedBox(height: 120.h), Padding( padding: EdgeInsets.symmetric(horizontal: 20.w), child: ElevatedButton.icon( onPressed: () => _showLogoutDialog(context), icon: const Icon( Icons.logout_rounded, color: AppColors.primaryBlue, ), label: const Text("Keluar Aplikasi"), style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: AppColors.primaryBlue, minimumSize: Size(double.infinity, 52.h), side: const BorderSide( color: AppColors.primaryBlue, width: 1.5, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), ), ), ), ), SizedBox(height: 20.h), Center( child: Text( "Versi 1.0.0", style: TextStyle(color: Colors.grey, fontSize: 12.sp), ), ), ], ), ), ), ], ), ); } void _showPersonalInfo(BuildContext context) { bool isEditMode = false; bool isSaving = false; final formKey = GlobalKey(); // Ambil data asli yang sudah dibersihkan final origFather = _cleanValue(student.parentInfo.fatherName); final origMother = _cleanValue(student.parentInfo.motherName); final origJob = _cleanValue(student.parentInfo.job); final origPhone = _cleanValue(student.parentInfo.phoneNumber); final origAddress = _cleanValue(student.parentInfo.address); // Controller menggunakan data asli yang bersih final fatherCtrl = TextEditingController(text: origFather); final motherCtrl = TextEditingController(text: origMother); final jobCtrl = TextEditingController(text: origJob); final phoneCtrl = TextEditingController(text: origPhone); final addressCtrl = TextEditingController(text: origAddress); showModalBottomSheet( context: context, // Menggunakan context utama dari Scaffold isScrollControlled: true, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24.r)), ), builder: (sheetContext) => StatefulBuilder( builder: (modalStateContext, setState) => Container( padding: EdgeInsets.fromLTRB( 24.w, 12.h, 24.w, MediaQuery.of(modalStateContext).viewInsets.bottom + 32.h, ), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Container( width: 40.w, height: 4.h, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(10), ), ), ), SizedBox(height: 24.h), Text( isEditMode ? "Ubah Informasi Pribadi" : "Detail Informasi Pribadi", style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.bold, color: AppColors.primaryBlue, ), ), SizedBox(height: 20.h), if (!isEditMode) ...[ _buildInfoDisplay( "Nama Ayah", student.parentInfo.fatherName, ), _buildInfoDisplay( "Nama Ibu", student.parentInfo.motherName, ), _buildInfoDisplay( "Pekerjaan Orang Tua", student.parentInfo.job, ), _buildInfoDisplay( "No. Telepon", student.parentInfo.phoneNumber, ), _buildInfoDisplay( "Alamat Lengkap", student.parentInfo.address, ), SizedBox(height: 24.h), SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: () => setState(() => isEditMode = true), icon: const Icon(Icons.edit_note_rounded), label: const Text("Ubah Informasi Pribadi"), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, padding: EdgeInsets.symmetric(vertical: 14.h), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), ), ), ), ), ] else ...[ Form( key: formKey, child: Column( children: [ _buildEditField( "Nama Ayah", fatherCtrl, inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(r'[a-zA-Z\s]'), ), ], ), _buildEditField( "Nama Ibu", motherCtrl, inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(r'[a-zA-Z\s]'), ), ], ), _buildEditField( "Pekerjaan", jobCtrl, inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(r'[a-zA-Z\s]'), ), ], ), _buildEditField( "No. Telepon", phoneCtrl, keyboardType: TextInputType.phone, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, ], ), _buildEditField( "Alamat", addressCtrl, maxLines: 2, ), SizedBox(height: 24.h), Row( children: [ Expanded( child: OutlinedButton( onPressed: () => setState( () => isEditMode = false, ), style: OutlinedButton.styleFrom( padding: EdgeInsets.symmetric( vertical: 14.h, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 12.r, ), ), ), child: const Text("Batal"), ), ), SizedBox(width: 12.w), Expanded( child: ElevatedButton( onPressed: isSaving ? null : () { if (formKey.currentState! .validate()) { final currFather = fatherCtrl.text.trim(); final currMother = motherCtrl.text.trim(); final currJob = jobCtrl.text.trim(); final currPhone = phoneCtrl.text.trim(); final currAddress = addressCtrl.text.trim(); // Cek apakah ada perubahan data final bool hasChanges = currFather != origFather || currMother != origMother || currJob != origJob || currPhone != origPhone || currAddress != origAddress; if (!hasChanges) { // Menampilkan pop up alert jika tidak ada perubahan _showNoChangesDialog( context, ); return; } // Lanjut ke dialog konfirmasi jika data berubah _showConfirmUpdateDialog( context, setState, fatherCtrl, motherCtrl, jobCtrl, addressCtrl, phoneCtrl, (val) => isSaving = val, ); } }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, padding: EdgeInsets.symmetric( vertical: 14.h, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 12.r, ), ), elevation: 0, ), child: isSaving ? SizedBox( height: 20.w, width: 20.w, child: const CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : Text( "Simpan", style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.bold, ), ), ), ), ], ), ], ), ), ], ], ), ), ), ), ); } void _showConfirmUpdateDialog( BuildContext context, StateSetter setState, TextEditingController fatherCtrl, TextEditingController motherCtrl, TextEditingController jobCtrl, TextEditingController addressCtrl, TextEditingController phoneCtrl, Function(bool) setSaving, ) { showDialog( context: context, builder: (confirmContext) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), ), title: const Text("Konfirmasi Perubahan"), content: const Text( "Apakah Anda yakin ingin memperbarui informasi pribadi ini?", ), actions: [ TextButton( onPressed: () => Navigator.pop(confirmContext), child: const Text( "Batal", style: TextStyle(color: Colors.black), ), ), ElevatedButton( onPressed: () async { Navigator.pop(confirmContext); // Tutup dialog konfirmasi setState(() => setSaving(true)); // Loading di BottomSheet try { await StudentService().updateStudentPersonalData( student: student, fatherName: fatherCtrl.text.trim(), motherName: motherCtrl.text.trim(), job: jobCtrl.text.trim(), address: addressCtrl.text.trim(), phoneNumber: phoneCtrl.text.trim(), ); if (context.mounted) { Navigator.pop(context); // Tutup BottomSheet onRefresh(); // Refresh data utama _showSuccessDialog(context, "Data berhasil diperbarui."); } } catch (e) { if (context.mounted) { setState(() => setSaving(false)); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text("Gagal: ${e.toString()}"), backgroundColor: AppColors.dangerRed, ), ); } } }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, ), child: const Text("Simpan"), ), ], ), ); } Widget _buildInfoDisplay(String label, String value) { return Padding( padding: EdgeInsets.only(bottom: 16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle(fontSize: 12.sp, color: Colors.grey[500]), ), SizedBox(height: 4.h), Text( value, style: TextStyle( fontSize: 15.sp, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), ), SizedBox(height: 8.h), Divider(color: Colors.grey.shade100, height: 1), ], ), ); } Widget _buildEditField( String label, TextEditingController ctrl, { TextInputType? keyboardType, int maxLines = 1, List? inputFormatters, }) { return Padding( padding: EdgeInsets.only(bottom: 12.h), child: TextFormField( controller: ctrl, keyboardType: keyboardType, maxLines: maxLines, inputFormatters: inputFormatters, // Disamakan persis dengan _buildInfoDisplay style style: TextStyle( fontSize: 15.sp, fontWeight: FontWeight.w600, color: AppColors.textPrimary, ), decoration: InputDecoration( labelText: label, labelStyle: TextStyle(fontSize: 12.sp, color: Colors.grey), isDense: true, border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.r)), ), validator: (v) => (v == null || v.trim().isEmpty) ? "Wajib diisi" : null, ), ); } Widget _buildSectionHeader(String title) => Padding( padding: EdgeInsets.fromLTRB(24.w, 0, 24.w, 12.h), child: Text( title, style: TextStyle( fontSize: 11.sp, fontWeight: FontWeight.w800, color: AppColors.textSecondary, letterSpacing: 1.2, ), ), ); Widget _buildSettingsCard(List children) => Container( margin: EdgeInsets.symmetric(horizontal: 20.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Column(children: children), ); Widget _buildSettingsTile({ required IconData icon, required String title, String? subtitle, VoidCallback? onTap, }) => ListTile( onTap: onTap, leading: Container( padding: EdgeInsets.all(10.w), decoration: BoxDecoration( color: AppColors.primaryBlue.withOpacity(0.08), borderRadius: BorderRadius.circular(12.r), ), child: Icon(icon, color: AppColors.primaryBlue, size: 22.sp), ), title: Text( title, style: TextStyle(fontSize: 15.sp, fontWeight: FontWeight.w600), ), subtitle: subtitle != null ? Text(subtitle, style: TextStyle(fontSize: 12.sp)) : null, trailing: Icon(Icons.chevron_right_rounded, color: Colors.grey[400]), ); void _showLogoutDialog(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20.r), ), title: const Text("Konfirmasi Keluar"), content: const Text("Apakah Anda yakin ingin mengakhiri sesi?"), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text("Batal"), ), ElevatedButton( onPressed: () async { await AuthService().logout(); if (context.mounted) { Navigator.pushNamedAndRemoveUntil( context, AppRoutes.login, (r) => false, ); } }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primaryBlue, foregroundColor: Colors.white, ), child: const Text("Keluar"), ), ], ), ); } }