import 'package:flutter/material.dart'; import 'package:country_state_city_picker/country_state_city_picker.dart'; import 'package:telemednet/controller/patient_controller.dart'; class PatientAddressScreen extends StatefulWidget { final PatientController? controller; const PatientAddressScreen({super.key, required this.controller}); @override State createState() => _PatientAddressScreenState(); } class _PatientAddressScreenState extends State { late PatientController _controller; late TextEditingController _houseNoController; late TextEditingController _lineController; late TextEditingController _townController; late TextEditingController _pincodeController; late TextEditingController _otherLabelController; final String country = 'India'; String? state; String? city; String? addressType; final Map _errors = {}; bool _hasErrors = false; @override void initState() { super.initState(); _controller = widget.controller ?? PatientController(); _loadSavedData(); } void _loadSavedData() { final address = _controller.model.address; _houseNoController = TextEditingController(text: address.houseNo ?? ''); _lineController = TextEditingController(text: address.line ?? ''); _townController = TextEditingController(text: address.town ?? ''); _pincodeController = TextEditingController(text: address.pincode ?? ''); _otherLabelController = TextEditingController(text: address.otherLabel ?? ''); state = address.state; city = address.city; addressType = address.addressType; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Address'), actions: [ TextButton( onPressed: _saveAndExit, child: const Text('Done', style: TextStyle(color: Colors.blue)), ), ], ), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionContainer( 'Address Information', Column( children: [ _buildTextField( 'House No.', _houseNoController, (value) => widget.controller!.updateHouseNo(value), icon: Icons.home_outlined, errorKey: 'houseNo', ), _buildTextField( 'Address Line', _lineController, (value) => widget.controller!.updateLine(value), icon: Icons.location_on_outlined, errorKey: 'line', ), _buildTextField( 'Town (Optional)', _townController, (value) => widget.controller!.updateTown(value), icon: Icons.location_city_outlined, ), _buildTextField( 'Pincode', _pincodeController, (value) => widget.controller!.updatePincode(value), icon: Icons.pin_drop_outlined, errorKey: 'pincode', ), ], ), ), const SizedBox(height: 20), _buildSectionContainer( 'Location', Column( children: [ _buildCountrySelection(), const SizedBox(height: 10), SelectState( onCountryChanged: (value) { setState(() {}); widget.controller!.updateCountry('India'); }, onStateChanged: (value) { setState(() { state = value; }); widget.controller!.updateState(value); }, onCityChanged: (value) { setState(() { city = value; }); widget.controller!.updateCity(value); }, ), const SizedBox(height: 20), if (state != null) Padding( padding: const EdgeInsets.only(bottom: 10), child: Text('State: $state', style: const TextStyle( fontSize: 14, color: Colors.black87)), ), if (city != null) Padding( padding: const EdgeInsets.only(bottom: 10), child: Text('City: $city', style: const TextStyle( fontSize: 14, color: Colors.black87)), ), ], ), ), const SizedBox(height: 20), _buildSectionContainer( 'Address Type', Column( children: [ _buildAddressTypeChips(), if (addressType == 'Other') _buildTextField( 'Other Label', _otherLabelController, (value) => widget.controller!.updateOtherLabel(value), icon: Icons.label_outline, ), ], ), ), ], ), ), ); } bool _validateFields() { setState(() { _errors.clear(); _hasErrors = false; if (_houseNoController.text.trim().isEmpty) { _errors['houseNo'] = 'House No. is required'; _hasErrors = true; } if (_lineController.text.trim().isEmpty) { _errors['line'] = 'Address Line is required'; _hasErrors = true; } final pincode = _pincodeController.text.trim(); if (pincode.isEmpty) { _errors['pincode'] = 'Pincode is required'; _hasErrors = true; } else if (!RegExp(r'^\d{6}$').hasMatch(pincode)) { _errors['pincode'] = 'Enter a valid 6-digit pincode'; _hasErrors = true; } if (state == null || state!.isEmpty) { _errors['state'] = 'State is required'; _hasErrors = true; } if (city == null || city!.isEmpty) { _errors['city'] = 'City is required'; _hasErrors = true; } if (addressType == null || addressType!.isEmpty) { _errors['addressType'] = 'Please select an address type'; _hasErrors = true; } if (addressType == 'Other' && _otherLabelController.text.trim().isEmpty) { _errors['otherLabel'] = 'Please specify other label'; _hasErrors = true; } }); return !_hasErrors; } Widget _buildSectionContainer(String title, Widget content) { return Container( padding: const EdgeInsets.all(16), margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), boxShadow: [ BoxShadow( color: Colors.blueGrey.withOpacity(0.5), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), content, ], ), ); } Widget _buildTextField( String label, TextEditingController controller, Function(String) onChanged, { required IconData icon, String? errorKey, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextField( controller: controller, decoration: InputDecoration( labelText: label, prefixIcon: Icon(icon, color: _errors.containsKey(errorKey) ? Colors.red : Colors.blueAccent), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( color: _errors.containsKey(errorKey) ? Colors.red : Colors.grey, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( color: _errors.containsKey(errorKey) ? Colors.red : Colors.grey, ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( color: _errors.containsKey(errorKey) ? Colors.red : Colors.blueAccent, ), ), errorText: _errors[errorKey], ), onChanged: onChanged, ), const SizedBox(height: 20), ], ); } Widget _buildCountrySelection() { return Container( padding: const EdgeInsets.symmetric(vertical: 8.0), child: const Row( children: [ Text( 'Country:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), SizedBox(width: 8), Text('India', style: TextStyle(fontSize: 16)), ], ), ); } Widget _buildAddressTypeChips() { return Wrap( spacing: 8.0, children: ['Home', 'Office', 'Other'].map((String type) { return ChoiceChip( label: Text(type), selected: addressType == type, onSelected: (bool selected) { setState(() { addressType = selected ? type : addressType; }); widget.controller!.updateAddressType(addressType!); }, ); }).toList(), ); } void _saveAndExit() { if (_validateFields()) { widget.controller!.updateHouseNo(_houseNoController.text); widget.controller!.updateLine(_lineController.text); widget.controller!.updateTown(_townController.text); widget.controller!.updatePincode(_pincodeController.text); widget.controller!.updateCountry(country); widget.controller!.updateState(state ?? ''); widget.controller!.updateCity(city ?? ''); widget.controller!.updateAddressType(addressType ?? ''); widget.controller!.updateOtherLabel(_otherLabelController.text); widget.controller!.updatePatientData(); Navigator.pop(context, true); } else { showDialog( context: context, builder: (context) => AlertDialog( title: const Row( children: [ Icon(Icons.error_outline, color: Colors.red), SizedBox(width: 8), Text('Validation Errors'), ], ), content: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: _errors.entries .map((error) => Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Text( '• ${error.value}', style: const TextStyle(color: Colors.red), ), )) .toList(), ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('OK'), ), ], ), ); } } @override void dispose() { _houseNoController.dispose(); _lineController.dispose(); _townController.dispose(); _pincodeController.dispose(); _otherLabelController.dispose(); super.dispose(); } }