import 'package:flutter/material.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:uuid/uuid.dart'; import 'dart:async'; // Tambahkan import untuk TimeoutException class AddFieldBottomSheet extends StatefulWidget { final Function? onFieldAdded; const AddFieldBottomSheet({super.key, this.onFieldAdded}); @override State createState() => _AddFieldBottomSheetState(); } class _AddFieldBottomSheetState extends State { final _formKey = GlobalKey(); final _nameController = TextEditingController(); final _locationController = TextEditingController(); final _sizeController = TextEditingController(); final _notesController = TextEditingController(); bool _isLoading = false; final _fieldNameFocus = FocusNode(); final _locationFocus = FocusNode(); final _areaFocus = FocusNode(); @override void initState() { super.initState(); // Pastikan keyboard tidak terbuka saat dialog muncul WidgetsBinding.instance.addPostFrameCallback((_) { FocusScope.of(context).unfocus(); }); } @override void dispose() { _nameController.dispose(); _locationController.dispose(); _sizeController.dispose(); _notesController.dispose(); _fieldNameFocus.dispose(); _locationFocus.dispose(); _areaFocus.dispose(); super.dispose(); } Future _submit() async { if (!_formKey.currentState!.validate()) return; setState(() => _isLoading = true); try { final id = const Uuid().v4(); final userId = Supabase.instance.client.auth.currentUser?.id; if (userId == null) { _showError('User ID is null'); return; } // PENTING: Hanya kirim data yang ada di database // Berdasarkan struktur database yang terlihat, hanya kolom ini yang ada final data = { 'id': id, 'user_id': userId, 'name': _nameController.text, 'plot_count': 1, 'created_at': DateTime.now().toIso8601String(), }; // Insert to database await Supabase.instance.client.from('fields').insert(data); if (mounted) { // Call the callback if provided if (widget.onFieldAdded != null) { widget.onFieldAdded!(); } Navigator.of(context).pop(true); // Return true to indicate success } } catch (e) { debugPrint('Error adding field: $e'); if (mounted) { setState(() => _isLoading = false); _showError( 'Gagal menambahkan lahan: ${e.toString().contains("timeout") ? "Koneksi timeout" : "Terjadi kesalahan"}', ); } } } void _showError(String message) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message), backgroundColor: Colors.red), ); } Widget _buildTextField({ required TextEditingController controller, required String label, required IconData icon, String? Function(String?)? validator, TextInputType keyboardType = TextInputType.text, FocusNode? focusNode, }) { return TextFormField( controller: controller, focusNode: focusNode, autofocus: false, decoration: InputDecoration( labelText: label, prefixIcon: Icon(icon), border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), ), keyboardType: keyboardType, validator: validator, textInputAction: TextInputAction.next, onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(), ); } @override Widget build(BuildContext context) { // Using simpler widgets to avoid crashes return Container( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, left: 16, right: 16, top: 16, ), child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title const Center( child: Text( 'Tambah Lahan', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), const SizedBox(height: 16), // Field Name _buildTextField( controller: _nameController, label: 'Nama Lahan', icon: Icons.landscape, validator: (value) => value == null || value.isEmpty ? 'Nama lahan harus diisi' : null, focusNode: _fieldNameFocus, ), const SizedBox(height: 16), // Location _buildTextField( controller: _locationController, label: 'Lokasi (Opsional)', icon: Icons.location_on, focusNode: _locationFocus, ), const SizedBox(height: 16), // Size _buildTextField( controller: _sizeController, label: 'Luas Lahan (m²)', icon: Icons.straighten, keyboardType: TextInputType.number, validator: (value) { if (value == null || value.isEmpty) { return 'Luas lahan harus diisi'; } if (int.tryParse(value) == null) { return 'Luas lahan harus berupa angka'; } return null; }, focusNode: _areaFocus, ), const SizedBox(height: 16), // Notes TextFormField( controller: _notesController, decoration: const InputDecoration( labelText: 'Catatan (opsional)', border: UnderlineInputBorder(), ), maxLines: 2, ), const SizedBox(height: 24), // Buttons Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: _isLoading ? null : () => Navigator.pop(context), child: const Text('Batal'), ), const SizedBox(width: 16), ElevatedButton( onPressed: _isLoading ? null : _submit, style: ElevatedButton.styleFrom( backgroundColor: Colors.green, foregroundColor: Colors.white, ), child: _isLoading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Text('Simpan'), ), ], ), const SizedBox(height: 8), ], ), ), ); } } // Helper method to show the bottom sheet Future showAddFieldBottomSheet({ required BuildContext context, Function? onFieldAdded, }) async { await showModalBottomSheet( context: context, isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) => AddFieldBottomSheet(onFieldAdded: onFieldAdded), ); }