// ignore_for_file: dead_code import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:telemednet/route_names.dart'; import 'package:image_picker/image_picker.dart'; import 'dart:io'; import '../../../controller/patient_controller.dart'; import '../../../widgets/alert_screen.dart'; class PatientRegistrationScreen extends StatefulWidget { const PatientRegistrationScreen({super.key}); @override State createState() => _PatientRegistrationScreenState(); } class _PatientRegistrationScreenState extends State { final PatientController _controller = PatientController(); final TextEditingController _nameController = TextEditingController(); final TextEditingController _phoneController = TextEditingController(); bool _hasErrors = false; final Map _errors = {}; String? _gender; DateTime? _dateOfBirth; File? _image; final ImagePicker _picker = ImagePicker(); String _selectedCountryCode = '+1'; final List _countryCodes = ['+1', '+91', '+44', '+61', '+81']; @override void initState() { super.initState(); _nameController.text = _controller.model.name ?? ''; if (_controller.model.phoneNumber != null) { String phoneNumber = _controller.model.phoneNumber!; if (phoneNumber.startsWith('+')) { for (String code in _countryCodes) { if (phoneNumber.startsWith(code)) { _selectedCountryCode = code; _phoneController.text = phoneNumber.substring(code.length); break; } } } else { _phoneController.text = phoneNumber; } } _gender = _controller.model.gender; _dateOfBirth = _controller.model.dateOfBirth; if (_controller.model.profileImagePath != null) { _image = File(_controller.model.profileImagePath!); } _updateCombinedPhoneNumber(_phoneController.text); } Future _getImage(ImageSource source) async { final XFile? pickedFile = await _picker.pickImage(source: source); if (pickedFile != null) { setState(() { _image = File(pickedFile.path); }); _controller.updateProfileImage(pickedFile.path); } } void _updateCombinedPhoneNumber(String phoneNumber) { String cleanPhoneNumber = phoneNumber.replaceAll(RegExp(r'^\+\d{1,3}'), ''); String fullPhoneNumber = '$_selectedCountryCode$cleanPhoneNumber'; _controller.updatePhoneNumber(fullPhoneNumber); } void _showImageSourceActionSheet(BuildContext context) { showModalBottomSheet( context: context, backgroundColor: Colors.transparent, builder: (BuildContext context) { return Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), child: SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Padding( padding: EdgeInsets.symmetric(vertical: 16), child: Text( 'Select Image Source', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), ), ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: const Icon(Icons.photo_library, color: Colors.blue), ), title: const Text('Choose from Gallery'), onTap: () { _getImage(ImageSource.gallery); Navigator.pop(context); }, ), ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: const Icon(Icons.photo_camera, color: Colors.blue), ), title: const Text('Take a Photo'), onTap: () { _getImage(ImageSource.camera); Navigator.pop(context); }, ), const SizedBox(height: 16), ], ), ), ); }, ); } void _showResultDialog(bool isSuccess) { Navigator.push( context, MaterialPageRoute( builder: (context) => AlertScreen( arguments: AlertArguments( title: isSuccess ? 'Thank You' : 'Oops!', message: isSuccess ? 'Profile created successfully!' : 'Failed to create profile. Please try again.', actionTitle: isSuccess ? 'Go to Dashboard' : 'Try Again', type: isSuccess ? AlertType.success : AlertType.error, onActionPressed: () { Navigator.pop(context); if (isSuccess) { Navigator.pushReplacementNamed( context, RouteNames.patientDashboardScreen, ); } }, ), ), ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[50], appBar: AppBar( elevation: 0, backgroundColor: Colors.white, title: const Text( 'Create Profile', style: TextStyle(color: Colors.black), ), actions: [ Padding( padding: const EdgeInsets.all(8.0), child: IconButton( onPressed: () { if (_validateAllFields()) { _controller.savePatientData(); _showResultDialog(true); } else { _showValidationErrors(); } }, icon: const Icon(Icons.check, color: Colors.blue, weight: 50), ), ), ], ), body: SingleChildScrollView( child: Column( children: [ Container( color: Colors.white, padding: const EdgeInsets.all(16.0), child: Column( children: [ GestureDetector( onTap: () => _showImageSourceActionSheet(context), child: Stack( alignment: Alignment.bottomRight, children: [ Container( decoration: BoxDecoration( boxShadow: [ BoxShadow( color: Colors.blueGrey.withOpacity(0.5), blurRadius: 5, offset: const Offset(0, 2), ), ], shape: BoxShape.circle, border: Border.all(color: Colors.blue, width: 2), ), child: CircleAvatar( radius: 75, backgroundImage: _image != null ? FileImage(_image!) : null, child: _image == null ? const Icon(Icons.person, size: 50, color: Colors.blue) : null, ), ), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( boxShadow: [ BoxShadow( color: Colors.blueGrey.withOpacity(0.5), blurRadius: 5, offset: const Offset(0, 2), ), ], color: Colors.blue, shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 2), ), child: const Icon(Icons.camera_alt, size: 20, color: Colors.white), ), ], ), ), ], ), ), const SizedBox(height: 8), Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.blueGrey.withOpacity(0.5), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ _buildUniformField( label: 'Name', icon: Icons.person_outline, child: TextField( controller: _nameController, onChanged: (value) => _controller.updateName(value), decoration: const InputDecoration( border: InputBorder.none, hintText: 'Enter your name', ), ), ), _buildUniformField( label: 'Phone Number', icon: Icons.phone_outlined, child: Row( children: [ DropdownButtonHideUnderline( child: DropdownButton( value: _selectedCountryCode, onChanged: (String? newValue) { if (newValue != null) { setState(() { _selectedCountryCode = newValue; }); _updateCombinedPhoneNumber( _phoneController.text); } }, items: _countryCodes.map>( (String code) { return DropdownMenuItem( value: code, child: Text(code), ); }, ).toList(), ), ), const SizedBox(width: 12), Expanded( child: TextField( controller: _phoneController, onChanged: (value) { _updateCombinedPhoneNumber(value); }, keyboardType: TextInputType.phone, decoration: const InputDecoration( border: InputBorder.none, hintText: 'Enter your phone number', ), ), ), ], ), ), _buildUniformField( label: 'Gender', icon: Icons.people_outline, child: DropdownButtonHideUnderline( child: DropdownButton( value: _gender, isExpanded: true, hint: const Text('Select gender'), onChanged: (value) { setState(() => _gender = value); _controller.updateGender(value!); }, items: ['Male', 'Female', 'Other'] .map>((String value) { return DropdownMenuItem( value: value, child: Text(value), ); }).toList(), ), ), ), _buildUniformField( label: 'Date of Birth', icon: Icons.calendar_today_outlined, child: InkWell( onTap: () async { final DateTime? picked = await showDatePicker( context: context, initialDate: _dateOfBirth ?? DateTime.now() .subtract(const Duration(days: 365 * 18)), firstDate: DateTime(1900), lastDate: DateTime.now() .subtract(const Duration(days: 365 * 18)), builder: (context, child) { return Theme( data: Theme.of(context).copyWith( colorScheme: const ColorScheme.light( primary: Colors.blue), ), child: child!, ); }, ); if (picked != null && picked != _dateOfBirth) { setState(() => _dateOfBirth = picked); _controller.updateDateOfBirth(picked); } }, child: Container( padding: const EdgeInsets.symmetric(vertical: 12), child: Text( _dateOfBirth != null ? DateFormat('dd/MM/yyyy').format(_dateOfBirth!) : 'Select date of birth', style: TextStyle( color: _dateOfBirth != null ? Colors.black87 : Colors.grey, ), ), ), ), ), ], ), ), ), Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.blueGrey.withOpacity(0.5), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( children: [ _buildNavigationField( 'Address', Icons.location_on, () async { final result = await Navigator.pushNamed( context, RouteNames.patientAdressScreen, arguments: _controller, ); if (result == true) { setState(() {}); } }, ), const Divider(height: 1), _buildNavigationField( 'Family Members', Icons.family_restroom_outlined, () => Navigator.pushNamed( context, RouteNames.patientFamilyMembersScreen, arguments: _controller, ), ), ], )), ], ), ), ); } Widget _buildUniformField({ required String label, required IconData icon, required Widget child, String? errorKey, }) { return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.grey[50], borderRadius: BorderRadius.circular(12), border: Border.all( color: _errors.containsKey(errorKey ?? '') ? Colors.red : Colors.grey.shade200, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 16, top: 8), child: Text( label, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: _errors.containsKey(errorKey ?? '') ? Colors.red : Colors.grey[600], ), ), ), Padding( padding: const EdgeInsets.only(left: 16, right: 16, bottom: 8), child: Row( children: [ Icon( icon, size: 20, color: _errors.containsKey(errorKey ?? '') ? Colors.red : Colors.blue, ), const SizedBox(width: 12), Expanded(child: child), ], ), ), if (_errors.containsKey(errorKey ?? '')) Padding( padding: const EdgeInsets.only(left: 16, right: 16, bottom: 8), child: Text( _errors[errorKey]!, style: const TextStyle( color: Colors.red, fontSize: 12, ), ), ), ], ), ); } bool _validateAllFields() { setState(() { _errors.clear(); _hasErrors = false; final name = _nameController.text.trim(); if (name.isEmpty) { _errors['name'] = 'Name is required'; _hasErrors = true; } else if (name.length < 2 && RegExp(r'^[A-Za-z]+([.\s]?[A-Za-z]+)*$').hasMatch(name)) { _errors['name'] = 'Name must be at least 2 characters'; _hasErrors = true; } final phoneNumber = _phoneController.text.trim(); if (phoneNumber.isEmpty) { _errors['phone'] = 'Phone number is required'; _hasErrors = true; } else if (!RegExp(r'^\d{10}$').hasMatch(phoneNumber)) { _errors['phone'] = 'Enter a valid 10-digit phone number'; _hasErrors = true; } if (_gender == null) { _errors['gender'] = 'Please select a gender'; _hasErrors = true; } if (_dateOfBirth == null) { _errors['dob'] = 'Date of Birth is required'; _hasErrors = true; } else { final age = DateTime.now().difference(_dateOfBirth!).inDays ~/ 365; if (age < 18) { _errors['dob'] = 'User must be at least 18 years old'; _hasErrors = true; } } if (_image == null) { _errors['image'] = 'Profile picture is required'; _hasErrors = true; } // Validate required address fields final address = _controller.model.address; if (address.houseNo?.isEmpty ?? true) { _errors['address'] = 'Please complete all required address fields'; _hasErrors = true; } // Validate address type and other label if (address.addressType == 'Other' && (address.otherLabel?.isEmpty ?? true)) { _errors['address'] = 'Please specify other address label'; _hasErrors = true; } }); return !_hasErrors; } void _showValidationErrors() { 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'), ), ], ), ); } Widget _buildNavigationField( String label, IconData icon, VoidCallback onTap) { bool isAddressField = label == 'Address'; bool hasAddressError = _errors.containsKey('address'); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: (isAddressField && hasAddressError) ? Colors.red.withOpacity(0.1) : Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, color: (isAddressField && hasAddressError) ? Colors.red : Colors.blue, size: 24), ), title: Text( label, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: (isAddressField && hasAddressError) ? Colors.red : Colors.black, ), ), subtitle: isAddressField ? _buildAddressSubtitle() : null, trailing: Icon( Icons.chevron_right, color: (isAddressField && hasAddressError) ? Colors.red : Colors.blue, ), onTap: onTap, ), if (isAddressField && hasAddressError) Padding( padding: const EdgeInsets.only(left: 16, right: 16, bottom: 8), child: Text( _errors['address']!, style: const TextStyle( color: Colors.red, fontSize: 12, ), ), ), ], ); } Widget _buildAddressSubtitle() { final address = _controller.model.address; if (address.houseNo == null || address.line == null || address.city == null) { return const Text( 'No address added', style: TextStyle(color: Colors.grey), ); } return Text( '${address.houseNo}, ${address.line}\n' '${address.city}, ${address.state} ${address.pincode}\n' '${address.addressType}${address.addressType == "Other" ? ": ${address.otherLabel}" : ""}', style: const TextStyle(color: Colors.black87), ); } }