import 'package:flutter/material.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; class OrganizationFormBottomSheet { static void show(BuildContext context) { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (_) => DraggableScrollableSheet( expand: false, initialChildSize: 0.85, minChildSize: 0.5, maxChildSize: 0.95, builder: (context, scrollController) { return _OrganizationForm(scrollController: scrollController); }, ), ); } } class _OrganizationForm extends StatefulWidget { final ScrollController scrollController; const _OrganizationForm({required this.scrollController}); @override State<_OrganizationForm> createState() => _OrganizationFormState(); } class _OrganizationFormState extends State<_OrganizationForm> { final MyFormValidator validator = MyFormValidator(); List> _industries = []; String? _selectedIndustryId; final List _sizes = [ '1-10', '11-50', '51-200', '201-1000', '1000+', ]; final Map _sizeApiMap = { '1-10': 'less than 10', '11-50': '11 to 50', '51-200': '51 to 200', '201-1000': 'more than 200', '1000+': 'more than 1000', }; String? _selectedSize; bool _agreed = false; @override void initState() { super.initState(); _loadIndustries(); validator.addField('organizationName', required: true, controller: TextEditingController()); validator.addField('email', required: true, controller: TextEditingController()); validator.addField('contactPerson', required: true, controller: TextEditingController()); validator.addField('contactNumber', required: true, controller: TextEditingController()); validator.addField('about', controller: TextEditingController()); validator.addField('address', required: true, controller: TextEditingController()); } Future _loadIndustries() async { final industries = await AuthService.getIndustries(); if (industries != null) { setState(() { _industries = industries; }); } } @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), padding: const EdgeInsets.all(20), child: SingleChildScrollView( controller: widget.scrollController, child: Form( key: validator.formKey, child: Column( children: [ Container( width: 40, height: 5, margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(10), ), ), Text( 'Adventure starts here 🚀', style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 4), const Text("Make your app management easy and fun!"), const SizedBox(height: 20), _buildTextField('organizationName', 'Organization Name'), _buildTextField('email', 'Email', keyboardType: TextInputType.emailAddress), _buildTextField('contactPerson', 'Contact Person'), _buildTextField('contactNumber', 'Contact Number', keyboardType: TextInputType.phone), _buildTextField('about', 'About Organization'), _buildTextField('address', 'Current Address'), const SizedBox(height: 10), _buildPopupMenuField( 'Organization Size', _sizes, _selectedSize, (val) => setState(() => _selectedSize = val), 'Please select organization size', ), _buildPopupMenuField( 'Industry', _industries.map((e) => e['name'] as String).toList(), _selectedIndustryId != null ? _industries.firstWhere( (e) => e['id'] == _selectedIndustryId)['name'] : null, (val) { setState(() { final selectedIndustry = _industries.firstWhere( (element) => element['name'] == val, orElse: () => {}); _selectedIndustryId = selectedIndustry['id']; }); }, 'Please select industry', ), const SizedBox(height: 10), Row( children: [ Checkbox( value: _agreed, onChanged: (val) => setState(() => _agreed = val ?? false), fillColor: MaterialStateProperty.all(Colors.white), checkColor: Colors.white, side: MaterialStateBorderSide.resolveWith( (states) => BorderSide(color: Colors.blueAccent, width: 2), ), ), const Expanded( child: Text('I agree to privacy policy & terms')), ], ), const SizedBox(height: 10), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.blueAccent, ), onPressed: _submitForm, child: const Text("Submit"), ), TextButton( onPressed: () => Navigator.pop(context), child: const Text("Back to login"), ), ], ), ), ), ); } Widget _buildPopupMenuField( String label, List items, String? selectedValue, ValueChanged onSelected, String errorText, ) { final bool hasError = selectedValue == null; final GlobalKey _key = GlobalKey(); return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: FormField( validator: (value) => hasError ? errorText : null, builder: (fieldState) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: TextStyle(fontSize: 12, color: Colors.grey[700])), const SizedBox(height: 6), GestureDetector( key: _key, onTap: () async { final RenderBox renderBox = _key.currentContext!.findRenderObject() as RenderBox; final Offset offset = renderBox.localToGlobal(Offset.zero); final Size size = renderBox.size; final selected = await showMenu( context: fieldState.context, position: RelativeRect.fromLTRB( offset.dx, offset.dy + size.height, offset.dx + size.width, offset.dy, ), items: items .map((item) => PopupMenuItem( value: item, child: Text(item), )) .toList(), ); if (selected != null) { onSelected(selected); fieldState.didChange(selected); } }, child: InputDecorator( decoration: InputDecoration( border: const OutlineInputBorder(), errorText: fieldState.errorText, contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 14), ), child: Text( selectedValue ?? 'Select $label', style: TextStyle( color: selectedValue == null ? Colors.grey : Colors.black, fontSize: 16, ), ), ), ), ], ); }, ), ); } Widget _buildTextField(String fieldName, String label, {TextInputType keyboardType = TextInputType.text}) { final controller = validator.getController(fieldName); final validatorFunc = validator.getValidation(fieldName); return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: TextFormField( controller: controller, keyboardType: keyboardType, decoration: InputDecoration( labelText: label, border: const OutlineInputBorder(), ), validator: validatorFunc, ), ); } void _submitForm() async { bool isValid = validator.validateForm(); if (_selectedSize == null || _selectedIndustryId == null) { isValid = false; setState(() {}); } if (!_agreed) { isValid = false; ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Please agree to the privacy policy & terms')), ); } if (isValid) { final formData = validator.getData(); final Map requestBody = { 'organizatioinName': formData['organizationName'], 'email': formData['email'], 'about': formData['about'], 'contactNumber': formData['contactNumber'], 'contactPerson': formData['contactPerson'], 'industryId': _selectedIndustryId ?? '', 'oragnizationSize': _sizeApiMap[_selectedSize] ?? '', 'terms': _agreed, 'address': formData['address'], }; final error = await AuthService.requestDemo(requestBody); if (error == null) { showAppSnackbar( title: "Success", message: "Demo request submitted successfully!.", type: SnackbarType.success, ); Navigator.pop(context); } else { showAppSnackbar( title: "Success", message: (error['error'] ?? 'Unknown error'), type: SnackbarType.success, ); } } } }