import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import '../controllers/schedule_controller.dart'; import '../../../widgets/schedule_card.dart'; import '../../../widgets/modal_schedule_add_edit.dart'; class ScheduleView extends GetView { const ScheduleView({super.key}); @override Widget build(BuildContext context) { Get.put(ScheduleController()); return Scaffold( backgroundColor: Colors.white, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(context), const SizedBox(height: 12), Expanded(child: _buildScheduleList()), ], ), ), ); } Widget _buildHeader(BuildContext context) { return Container( color: Colors.white, padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Schedule Obat', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFF424242), ), ), const SizedBox(height: 16), Row( children: [ Expanded(child: _buildDatePicker(context)), const SizedBox(width: 12), _buildAddButton(), ], ), const SizedBox(height: 16), _buildTimeFilterTabs(), ], ), ); } Widget _buildDatePicker(BuildContext context) { return GestureDetector( onTap: () => _selectDate(context), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade300), ), child: Row( children: [ const Icon( Icons.calendar_today, size: 18, color: Color(0xFF0091EA), ), const SizedBox(width: 10), Obx( () => Text( DateFormat( 'EEEE, dd MMMM yyyy', 'id_ID', ).format(controller.selectedDate.value), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF424242), ), ), ), const Spacer(), Icon(Icons.arrow_drop_down, color: Colors.grey[600]), ], ), ), ); } Widget _buildAddButton() { return Container( decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF0091EA), Color(0xFF0277BD)], ), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: const Color(0xFF0091EA).withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Material( color: Colors.transparent, child: InkWell( onTap: () => Get.dialog( const ModalScheduleAddEdit(isEdit: false), barrierDismissible: true, ), borderRadius: BorderRadius.circular(12), child: const Padding( padding: EdgeInsets.all(12), child: Icon(Icons.add, color: Colors.white, size: 24), ), ), ), ); } Widget _buildTimeFilterTabs() { return Obx( () => Row( children: [ Expanded(child: _buildTabButton('Pagi', 0)), const SizedBox(width: 8), Expanded(child: _buildTabButton('Siang', 1)), const SizedBox(width: 8), Expanded(child: _buildTabButton('Sore', 2)), const SizedBox(width: 8), Expanded(child: _buildTabButton('Malam', 3)), ], ), ); } Widget _buildTabButton(String title, int index) { final isSelected = controller.selectedTab.value == index; return GestureDetector( onTap: () => controller.changeTab(index), child: Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( color: isSelected ? const Color(0xFF0091EA) : Colors.transparent, borderRadius: BorderRadius.circular(10), border: Border.all( color: isSelected ? const Color(0xFF0091EA) : Colors.grey.shade300, ), ), child: Text( title, textAlign: TextAlign.center, style: TextStyle( color: isSelected ? Colors.white : Colors.grey[600], fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, fontSize: 14, ), ), ), ); } Widget _buildScheduleList() { return Obx(() { if (controller.isLoading.value) { return const Center( child: CircularProgressIndicator(color: Color(0xFF0091EA)), ); } if (controller.filteredSchedules.isEmpty) { return RefreshIndicator( onRefresh: () async { controller.refreshSchedules(); await Future.delayed(const Duration(milliseconds: 500)); }, color: const Color(0xFF0091EA), child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: SizedBox( height: MediaQuery.of(Get.context!).size.height * 0.6, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.event_note, size: 80, color: Colors.grey[400]), const SizedBox(height: 16), Text( 'Tidak ada jadwal', style: TextStyle(fontSize: 16, color: Colors.grey[600]), ), const SizedBox(height: 8), Text( 'Tarik ke bawah untuk refresh', style: TextStyle(fontSize: 12, color: Colors.grey[400]), ), ], ), ), ), ), ); } return RefreshIndicator( onRefresh: () async { controller.refreshSchedules(); await Future.delayed(const Duration(milliseconds: 500)); }, color: const Color(0xFF0091EA), child: ListView.builder( physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), itemCount: controller.filteredSchedules.length, itemBuilder: (context, index) { final schedule = controller.filteredSchedules[index]; return ScheduleCard( schedule: schedule, onEditTap: () => Get.dialog( ModalScheduleAddEdit(schedule: schedule, isEdit: true), barrierDismissible: true, ), onDeleteTap: () => _showDeleteDialog(schedule.id), ); }, ), ); }); } void _showDeleteDialog(String scheduleId) { Get.dialog( AlertDialog( backgroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), title: const Text( 'Hapus Jadwal', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), ), content: const Text( 'Yakin ingin menghapus jadwal ini?', style: TextStyle(fontSize: 16), ), actions: [ TextButton( onPressed: () => Get.back(), style: TextButton.styleFrom( foregroundColor: Colors.blue, padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text('Batal'), ), TextButton( onPressed: () { controller.deleteSchedule(scheduleId); Get.back(); }, style: TextButton.styleFrom( foregroundColor: Colors.white, backgroundColor: Colors.red, padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text( 'Hapus', style: TextStyle(fontWeight: FontWeight.bold), ), ), ], ), ); } Future _selectDate(BuildContext context) async { final DateTime? picked = await showDatePicker( context: context, initialDate: controller.selectedDate.value, 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) controller.selectDate(picked); } }