You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudsolutions-atoms/lib/modules/applicationDemo/screens/demo_request_form_screen.dart

310 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/validator/validator.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/applicationDemo/enums/otp_method.dart';
import 'package:test_sa/modules/applicationDemo/models/application_demo_request_model.dart';
import 'package:test_sa/modules/applicationDemo/models/role_model.dart';
import 'package:test_sa/modules/applicationDemo/providers/application_demo_request_provider.dart';
import 'package:test_sa/modules/applicationDemo/widgets/otp_method_selection_dialog.dart';
import 'package:test_sa/modules/applicationDemo/widgets/otp_verification_bottom_sheet.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/custom_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
class DemoRequestFormScreen extends StatefulWidget {
static const String routeName = '/demo_request_form';
const DemoRequestFormScreen({Key? key}) : super(key: key);
@override
State<DemoRequestFormScreen> createState() => _DemoRequestFormScreenState();
}
class _DemoRequestFormScreenState extends State<DemoRequestFormScreen> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _fullNameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _mobileController = TextEditingController();
final TextEditingController _companyNameController = TextEditingController();
List<ApplicationDemoRoleModel> _selectedRoles = [];
bool _isSubmitting = false;
@override
void initState() {
super.initState();
// Fetch roles when the screen initializes
WidgetsBinding.instance.addPostFrameCallback((_) {
final provider = Provider.of<ApplicationDemoRequestProvider>(context, listen: false);
provider.fetchRoles();
});
}
@override
void dispose() {
_fullNameController.dispose();
_emailController.dispose();
_mobileController.dispose();
_companyNameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final provider = Provider.of<ApplicationDemoRequestProvider>(context);
return Scaffold(
backgroundColor: AppColor.background(context),
appBar: const CustomAppBar(
title: 'Demo Request',
),
body: Form(
key: _formKey,
child: Column(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppTextFormField(
controller: _fullNameController,
labelText: 'Full Name',
hintText: 'Enter your full name',
textInputType: TextInputType.name,
validator: (value) {
if (value == null || value.isEmpty) return 'Full Name is required';
return null;
},
),
16.height,
AppTextFormField(
controller: _emailController,
labelText: 'Email Address',
hintText: 'Enter your email address',
textInputType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) return 'Email is required';
if (!Validator.isEmail(value)) return 'Invalid email format';
return null;
},
),
16.height,
AppTextFormField(
controller: _mobileController,
labelText: 'Mobile Number',
hintText: 'Enter your mobile number',
textInputType: TextInputType.phone,
validator: (value) {
if (value == null || value.isEmpty) return 'Mobile Number is required';
if (!Validator.isPhoneNumber(value)) return 'Invalid mobile number';
return null;
},
),
16.height,
AppTextFormField(
controller: _companyNameController,
labelText: 'Company Name',
hintText: 'Enter your company name',
textInputType: TextInputType.text,
validator: (value) {
if (value == null || value.isEmpty) return 'Company Name is required';
return null;
},
),
16.height,
MultipleItemDropDownMenu<ApplicationDemoRoleModel, NullableLoadingProvider>(
context: context,
title: 'Select Roles',
initialValue: _selectedRoles,
staticData: provider.roles,
loading: provider.roleLoading,
showAsFullScreenDialog: true,
onSelect: (selectedRoles) {
setState(() {
_selectedRoles = selectedRoles ?? [];
});
},
),
],
).paddingAll(16).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
label: 'Submit',
buttonColor: AppColor.primary10,
maxWidth: true,
loading: _isSubmitting,
onPressed: _isSubmitting ? null : _submitRequest,
),
),
],
),
),
);
}
Future<void> _submitRequest() async {
// Validate form fields
if (!_formKey.currentState!.validate()) {
return;
}
if (_selectedRoles.isEmpty) {
context.showConfirmDialog('Please select at least one role');
return;
}
showDialog(
context: context,
builder: (BuildContext context) {
return OtpMethodSelectionDialog(
onMethodSelected: (OtpMethod method) {
_submitRequestWithOtpMethod(method);
},
);
},
);
}
Future<void> _submitRequestWithOtpMethod(OtpMethod otpMethod) async {
setState(() {
_isSubmitting = true;
});
try {
final provider = Provider.of<ApplicationDemoRequestProvider>(context, listen: false);
final otpSent = await provider.sendOtp(
fullName: _fullNameController.text.trim(),
phoneNumber: _mobileController.text.trim(),
email: _emailController.text.trim(),
typeSend: otpMethod.value,
);
if (otpSent) {
if (mounted) {
setState(() {
_isSubmitting = false;
});
await context.showBottomSheet(
OtpVerificationBottomSheet(
otpMethod: otpMethod.value,
onOtpVerified: (String otp) async {
await _verifyOtpAndComplete(otp, otpMethod);
},
onResend: () async {
await provider.sendOtp(
fullName: _fullNameController.text.trim(),
phoneNumber: _mobileController.text.trim(),
email: _emailController.text.trim(),
typeSend: otpMethod.value,
);
},
onChangeMethod: () {
_submitRequest();
},
),
isDismissible: false,
title: 'Verify OTP',
showCancelButton: true,
);
}
} else {
if (mounted) {
setState(() {
_isSubmitting = false;
});
context.showConfirmDialog(
provider.errorMessage ?? 'Failed to send OTP. Please try again.',
);
}
}
} catch (e) {
if (mounted) {
setState(() {
_isSubmitting = false;
});
context.showConfirmDialog('An error occurred: $e');
}
}
}
Future<void> _verifyOtpAndComplete(String otp, OtpMethod otpMethod) async {
// Close the bottom sheet
Navigator.pop(context);
// Show loading
setState(() {
_isSubmitting = true;
});
try {
final provider = Provider.of<ApplicationDemoRequestProvider>(context, listen: false);
// Verify OTP - pass email or phoneNumber based on selected method
final otpVerified = await provider.verifyOtp(
email: otpMethod == OtpMethod.email ? _emailController.text.trim() : null,
phoneNumber: otpMethod == OtpMethod.sms ? _mobileController.text.trim() : null,
otpCode: otp,
);
if (otpVerified) {
// OTP verified, now submit the demo request
final request = ApplicationDemoRequestModel(
fullName: _fullNameController.text.trim(),
emailAddress: _emailController.text.trim(),
mobileNumber: _mobileController.text.trim(),
companyId: 0,
roleIds: _selectedRoles.map((role) => role.identifier ?? '').toList(),
roleNames: _selectedRoles.map((role) => role.name ?? '').toList(),
status: 'Pending',
requestDate: DateTime.now(),
);
final success = await provider.submitApplicationDemoRequest(request);
if (mounted) {
setState(() {
_isSubmitting = false;
});
if (success) {
context.showConfirmDialog(
provider.successMessage ?? 'Your demo request has been verified and submitted successfully. We will contact you soon!',
onTap: () {
Navigator.of(context).pop(); // Close dialog
Navigator.of(context).pop(); // Go back to login
},
);
} else {
context.showConfirmDialog(
provider.errorMessage ?? 'Failed to submit demo request. Please try again.',
);
}
}
} else {
// OTP verification failed
if (mounted) {
setState(() {
_isSubmitting = false;
});
context.showConfirmDialog(
provider.errorMessage ?? 'Invalid OTP code. Please try again.',
);
}
}
} catch (e) {
if (mounted) {
setState(() {
_isSubmitting = false;
});
context.showConfirmDialog('OTP verification failed: $e');
}
}
}
}