import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import '../modules/schedule/controllers/schedule_controller.dart'; class ModalScheduleAddEdit extends StatefulWidget { final PatientSchedule? schedule; final bool isEdit; const ModalScheduleAddEdit({super.key, this.schedule, this.isEdit = false}); @override State createState() => _ModalScheduleAddEditState(); } class _ModalScheduleAddEditState extends State { final _formKey = GlobalKey(); String? _selectedPatientId; String? _selectedTime; DateTime? _selectedDate; late TextEditingController _medicineController; late TextEditingController _fluidController; List> _patients = []; bool _isLoadingPatients = true; final List _times = ['Pagi', 'Siang', 'Sore', 'Malam']; @override void initState() { super.initState(); _medicineController = TextEditingController( text: widget.schedule?.medicineTime ?? '', ); _fluidController = TextEditingController( text: widget.schedule?.fluidTime ?? '', ); _selectedDate = DateTime.now(); if (widget.isEdit && widget.schedule != null) { _selectedTime = widget.schedule!.timeOfDay; // _selectedPatientId akan diset setelah _loadPatients() selesai } _loadPatients(); } Future _loadPatients() async { try { final controller = Get.find(); final patientsList = await controller.getPatientsList(); if (mounted) { setState(() { _patients = patientsList; _isLoadingPatients = false; // Set selected patient ID untuk mode edit if (widget.isEdit && widget.schedule != null) { _selectedPatientId = widget.schedule!.patientId; } }); } } catch (e) { if (mounted) { setState(() { _isLoadingPatients = false; }); } } } @override void dispose() { _medicineController.dispose(); _fluidController.dispose(); super.dispose(); } Map? get _selectedPatientData { if (_selectedPatientId == null) return null; return _patients.firstWhereOrNull((p) => p['id'] == _selectedPatientId); } @override Widget build(BuildContext context) { return Dialog( backgroundColor: Colors.transparent, insetPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 40), child: Container( constraints: const BoxConstraints(maxWidth: 500), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ _buildHeader(), Flexible( child: _isLoadingPatients ? const Center( child: Padding( padding: EdgeInsets.all(40), child: CircularProgressIndicator( color: Color(0xFF0091EA), ), ), ) : SingleChildScrollView( padding: const EdgeInsets.all(24), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildLabel('Pilih Tanggal', Icons.calendar_today), const SizedBox(height: 8), _buildDatePicker(context), const SizedBox(height: 20), _buildLabel('Pilih Pasien', Icons.person), const SizedBox(height: 8), _buildPatientDropdown(), if (_selectedPatientData != null) ...[ const SizedBox(height: 12), _buildSelectedPatientInfo(), ], const SizedBox(height: 20), _buildLabel('Pilih Waktu', Icons.access_time), const SizedBox(height: 8), _buildTimeDropdown(), const SizedBox(height: 20), _buildLabel('Informasi Obat', Icons.medication), const SizedBox(height: 8), _buildTextField( controller: _medicineController, hint: 'Contoh: Amoxicillin 3 ml', validator: (value) { if (value == null || value.isEmpty) { return 'Informasi obat harus diisi'; } return null; }, ), const SizedBox(height: 20), _buildLabel( 'Detail Cairan & Tetes', Icons.water_drop, ), const SizedBox(height: 8), _buildTextField( controller: _fluidController, hint: 'Contoh: Mnt 30 tetes/jam', validator: (value) { if (value == null || value.isEmpty) { return 'Detail cairan harus diisi'; } return null; }, ), ], ), ), ), ), _buildBottomButtons(), ], ), ), ); } Widget _buildHeader() { return Container( padding: const EdgeInsets.all(24), decoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF0091EA), Color(0xFF0277BD)], ), borderRadius: BorderRadius.only( topLeft: Radius.circular(24), topRight: Radius.circular(24), ), ), child: Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(12), ), child: const Icon( Icons.calendar_today, color: Colors.white, size: 24, ), ), const SizedBox(width: 16), Expanded( child: Text( widget.isEdit ? 'Edit Jadwal' : 'Tambah Jadwal Baru', style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), IconButton( onPressed: () => Get.back(), icon: const Icon(Icons.close, color: Colors.white), splashRadius: 20, ), ], ), ); } Widget _buildLabel(String text, IconData icon) { return Row( children: [ Icon(icon, size: 20, color: const Color(0xFF0091EA)), const SizedBox(width: 8), Text( text, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: Color(0xFF424242), ), ), ], ); } Widget _buildDatePicker(BuildContext context) { return GestureDetector( onTap: () async { final DateTime? picked = await showDatePicker( context: context, initialDate: _selectedDate ?? DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: const ColorScheme.light( primary: Color(0xFF0091EA), onPrimary: Colors.white, onSurface: Color(0xFF424242), ), ), child: child!, ); }, ); if (picked != null) { setState(() { _selectedDate = picked; }); } }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( color: Colors.grey[50], borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade200), ), child: Row( children: [ const Icon( Icons.calendar_today, size: 18, color: Color(0xFF0091EA), ), const SizedBox(width: 12), Text( _selectedDate != null ? DateFormat( 'EEEE, dd MMMM yyyy', 'id_ID', ).format(_selectedDate!) : 'Pilih tanggal...', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: _selectedDate != null ? const Color(0xFF424242) : Colors.grey[400], ), ), const Spacer(), Icon(Icons.arrow_drop_down, color: Colors.grey[600]), ], ), ), ); } Widget _buildPatientDropdown() { if (_patients.isEmpty) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade200), ), child: Text( 'Tidak ada pasien tersedia', style: TextStyle(color: Colors.grey[600]), ), ); } return DropdownButtonFormField( value: _selectedPatientId, dropdownColor: Colors.white, decoration: InputDecoration( hintText: 'Cari dan pilih pasien...', hintStyle: TextStyle(color: Colors.grey[400], fontSize: 14), filled: true, fillColor: Colors.grey[50], border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Color(0xFF0091EA), width: 2), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Colors.redAccent), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14, ), ), icon: const Icon(Icons.arrow_drop_down, color: Color(0xFF0091EA)), isExpanded: true, items: _patients.map((patient) { return DropdownMenuItem( value: patient['id'], child: Text( patient['name']!, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF424242), ), ), ); }).toList(), onChanged: widget.isEdit ? null : (value) { setState(() { _selectedPatientId = value; }); }, validator: (value) { if (value == null) { return 'Pilih pasien terlebih dahulu'; } return null; }, ); } Widget _buildSelectedPatientInfo() { final patient = _selectedPatientData!; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0091EA).withOpacity(0.05), borderRadius: BorderRadius.circular(12), border: Border.all( color: const Color(0xFF0091EA).withOpacity(0.2), width: 1, ), ), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFF0091EA).withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: const Icon(Icons.person, color: Color(0xFF0091EA), size: 20), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( patient['name']!, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.bold, color: Color(0xFF424242), ), ), const SizedBox(height: 6), Row( children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 4, ), decoration: BoxDecoration( color: const Color(0xFFE3F2FD), borderRadius: BorderRadius.circular(6), ), child: Text( patient['room']!, style: const TextStyle( fontSize: 11, color: Color(0xFF2196F3), fontWeight: FontWeight.w600, ), ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 4, ), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(6), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 6, height: 6, decoration: const BoxDecoration( color: Color(0xFF4CAF50), shape: BoxShape.circle, ), ), const SizedBox(width: 6), Text( patient['device']!, style: TextStyle( fontSize: 11, color: Colors.grey[700], fontWeight: FontWeight.w600, ), ), ], ), ), ], ), ], ), ), ], ), ); } Widget _buildTimeDropdown() { return DropdownButtonFormField( value: _selectedTime, dropdownColor: Colors.white, decoration: InputDecoration( hintText: 'Pilih waktu...', hintStyle: TextStyle(color: Colors.grey[400], fontSize: 14), filled: true, fillColor: Colors.grey[50], border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Color(0xFF0091EA), width: 2), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Colors.redAccent), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14, ), ), icon: const Icon(Icons.arrow_drop_down, color: Color(0xFF0091EA)), isExpanded: true, items: _times.map((time) { IconData icon; Color color; switch (time) { case 'Pagi': icon = Icons.wb_sunny; color = Colors.orange; break; case 'Siang': icon = Icons.wb_sunny_outlined; color = Colors.amber; break; case 'Sore': icon = Icons.wb_twilight; color = Colors.deepOrange; break; case 'Malam': icon = Icons.nights_stay; color = Colors.indigo; break; default: icon = Icons.access_time; color = Colors.grey; } return DropdownMenuItem( value: time, child: Row( children: [ Icon(icon, size: 18, color: color), const SizedBox(width: 12), Text( time, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF424242), ), ), ], ), ); }).toList(), onChanged: (value) { setState(() { _selectedTime = value; }); }, validator: (value) { if (value == null) { return 'Pilih waktu terlebih dahulu'; } return null; }, ); } Widget _buildTextField({ required TextEditingController controller, required String hint, String? Function(String?)? validator, }) { return TextFormField( controller: controller, validator: validator, decoration: InputDecoration( hintText: hint, hintStyle: TextStyle(color: Colors.grey[400], fontSize: 14), filled: true, fillColor: Colors.grey[50], border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Color(0xFF0091EA), width: 2), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Colors.redAccent), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Colors.redAccent, width: 2), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14, ), ), ); } Widget _buildBottomButtons() { return Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: Colors.grey[50], borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24), ), ), child: Row( children: [ Expanded( child: OutlinedButton( onPressed: () => Get.back(), style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), side: BorderSide(color: Colors.grey.shade300, width: 2), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text( 'Batal', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.grey[700], ), ), ), ), const SizedBox(width: 12), Expanded( child: Container( decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF0091EA), Color(0xFF0277BD)], ), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: const Color(0xFF0091EA).withOpacity(0.4), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: ElevatedButton( onPressed: _handleSave, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text( widget.isEdit ? 'Simpan' : 'Tambah', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white, ), ), ), ), ), ], ), ); } void _handleSave() { if (_formKey.currentState!.validate()) { if (_selectedDate == null) { Get.snackbar( 'Error', 'Pilih tanggal terlebih dahulu', backgroundColor: Colors.redAccent, colorText: Colors.white, ); return; } final controller = Get.find(); final patientData = _selectedPatientData!; final schedule = PatientSchedule( id: widget.isEdit ? widget.schedule!.id : '', patientId: _selectedPatientId!, name: patientData['name']!, room: patientData['room']!, deviceId: patientData['device']!, medicineTime: _medicineController.text.trim(), fluidTime: _fluidController.text.trim(), timeOfDay: _selectedTime!, ); if (widget.isEdit && widget.schedule != null) { controller.updateSchedule( widget.schedule!.id, schedule, _selectedDate!, ); } else { controller.addSchedule(schedule, _selectedDate!); } Get.back(); } } }