import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:wanisdriver/Screen/LoginScreen.dart'; import 'package:wanisdriver/config/AppSnackbar.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../Screen/OtpVerificationScreen.dart'; import '../config/language/language_enum.dart'; import '../models/OTPMessages.dart'; import '../models/TaxiOptionsModel.dart'; import '../services/signUpDriverService.dart'; import '../utils/connection.dart'; import 'language_provider.dart'; class SignUpProvider extends ChangeNotifier { static final SignUpProvider _instance = SignUpProvider._internal(); factory SignUpProvider() { return _instance; } SignUpProvider._internal(); bool _loader = false; // Driver Info - Private variables File? _profileImage; String _email = ''; String _city = ''; String _phone = ''; String _firstName = ''; String _lastName = ''; String _gender = ''; String _carbrand = ''; String _carmodel = ''; String _licencecard = ''; String _password = ''; String _idCard = ''; String _expirationDate = ''; String _patentNumber = ''; String _taxiId = ''; String _taxiIdFirst = ''; String _taxiIdLast = ''; // Vehicle Info - Private variables List _vehicleImages = [null, null, null, null]; File? _insuranceFile; String? _plateNumber; String? _plateNumberfirstPart; String? _plateNumberLastPart; File? _idCardFile; File? _taxiIdpictureFile; File? _carLicenseFile; File? _licenceFile; File? _idTaxiFile; int? _selectedTaxiType; List _selectedAllowedItems = []; // Commercial Info - Private variables File? _patentFile; String? _vehicleModel; String? _vehicleYear; String? _vehicleType; String deviceId = ""; String deviceModel = ""; String ipAddress = ""; String deviceType = ""; String dToken = ""; bool get loader => _loader; // Getters for Driver Info File? get profileImage => _profileImage; String get email => _email; String get carbrand => _carbrand; String get carmodel => _carmodel; String get licencecard => _licencecard; String get city => _city; String get phone => _phone; String get taxiId => _taxiId; String get taxiIdFirst => _taxiIdFirst; String get taxiIdLast => _taxiIdLast; File? get licenceFile => _licenceFile; String get firstName => _firstName; String get lastName => _lastName; String get gender => _gender; String get password => _password; File? get carLicenseFile => _carLicenseFile; File? get taxiIdpictureFile => _taxiIdpictureFile; String get idCard => _idCard; String get expirationDate => _expirationDate; String get patentNumber => _patentNumber; // Getters for Vehicle Info List get vehicleImages => _vehicleImages; File? get insuranceFile => _insuranceFile; String? get plateNumber => _plateNumber; String? get plateNumberfirstPart => _plateNumberfirstPart; String? get plateNumberLastPart => _plateNumberLastPart; File? get idCardFile => _idCardFile; File? get idTaxiFile => _idTaxiFile; int? get selectedTaxiType => _selectedTaxiType; List get selectedAllowedItems => _selectedAllowedItems; // Getters for Commercial Info File? get patentFile => _patentFile; String? get vehicleModel=> _vehicleModel; String? get vehicleYear=> _vehicleYear; String? get vehicleType=> _vehicleType; void setTaxiType(int id) { _selectedTaxiType = id; notifyListeners(); } // Setters void setProfileImage(File file) { _profileImage = file; notifyListeners(); } void setDriverInfo({ required String email, required String phone, required String firstName, required String lastName, required String carbrand, required String carmodel, required String idCard, required String licencecard, required String city, required String gender, }) { _email = email; _phone = phone; _firstName = firstName; _lastName = lastName; _city = city; _carbrand = carbrand; _carmodel = carmodel; _licencecard = licencecard; _idCard = idCard; _gender = gender; notifyListeners(); } void setCity(String text) { _city = text; notifyListeners(); } void setPassword(String password) { _password = password; notifyListeners(); } void setVehicleImage(int index, File? file) { if (index >= 0 && index < _vehicleImages.length) { _vehicleImages[index] = file; notifyListeners(); } } void removeVehicleImage(int index) { if (index >= 0 && index < _vehicleImages.length) { _vehicleImages[index] = null; notifyListeners(); } } void setInsuranceFile(File file) { _insuranceFile = file; notifyListeners(); } void setPlateNumber(String text) { _plateNumber= text; notifyListeners(); } void setPlateNumberLastPart(String text) { _plateNumberLastPart= text; notifyListeners(); } void setPlateNumberfirstPart(String text) { _plateNumberfirstPart= text; notifyListeners(); } void setIdPictureFile(File file) { _taxiIdpictureFile = file; notifyListeners(); } void setTaxiId(String text) { _taxiId = text; notifyListeners(); } void setTaxiIdFirst(String text) { _taxiIdFirst = text; notifyListeners(); } void setTaxiIdLast(String text) { _taxiIdLast = text; notifyListeners(); } void setIdTaxiFile(File file) { _idTaxiFile = file; notifyListeners(); } void setCarLicenseFile(File file) { _carLicenseFile = file; notifyListeners(); } void setLicenceFile(File file) { _licenceFile = file; notifyListeners(); } void setIdCardFile(File file) { _idCardFile = file; notifyListeners(); } void toggleAllowedItem(int item) { if (_selectedAllowedItems.contains(item)) { _selectedAllowedItems.remove(item); } else { _selectedAllowedItems.add(item); } notifyListeners(); } void setPatentFile(File file) { _patentFile = file; notifyListeners(); } void setVehicleModel(String vehicleModel ) { _vehicleModel = vehicleModel; notifyListeners(); } void setVehicleYear(String year) { _vehicleYear = year; notifyListeners(); } void setVehicleType(String type) { _vehicleType = type; notifyListeners(); } void reset() { _loader = false; // Driver Info _profileImage = null; _email = ''; _licencecard = ''; _phone = ''; _firstName = ''; _lastName = ''; _gender = ''; _password = ''; _idCard = ''; _expirationDate = ''; _taxiId = ''; _city = ''; _patentNumber = ''; // Vehicle Info _vehicleImages = [null, null, null, null]; _insuranceFile = null; _plateNumber = ''; _plateNumberfirstPart = ''; _plateNumberLastPart = ''; _idCardFile = null; _idTaxiFile = null; _taxiIdpictureFile = null; _carLicenseFile = null; _licenceFile = null; _selectedTaxiType = null; _selectedAllowedItems = []; // Commercial Info _patentFile = null; _vehicleModel = null; _vehicleYear = null; _vehicleType = null; notifyListeners(); } String formatDateRFC1123(DateTime date) { final DateFormat formatter = DateFormat('EEE, dd MMM yyyy HH:mm:ss', 'en_US'); return '${formatter.format(date.toUtc())} GMT'; } Future phoneSignUp() async { log("phoneNumber: $_phone"); if (!await Connection.checkConnection()) { AppSnackbar.showError("Error", 'No Internet Connection'); log("-----> No Internet Connection"); } _loader= true; notifyListeners(); try { final sendCodeResult = await SignUpDriverService().phoneSignUP(_phone); log("Status Code: ${sendCodeResult.statusCode}"); log("data: ${sendCodeResult.data}"); log("error Message: ${sendCodeResult.errorMessage}"); if (sendCodeResult.statusCode == 200 || sendCodeResult.statusCode == 201) { Get.offAll(() => const OtpVerificationScreen()); // signUpDriver(); }else if (sendCodeResult.statusCode == 226){ AppSnackbar.showError("Error", "The phone number is already used !"); } else { AppSnackbar.showError("Error", "Error happen with OTP please try again later"); } } catch (e, stackTrace) { log("Error: $e"); log("StackTrace: $stackTrace"); AppSnackbar.showError("Error", 'Error happen with OTP please try again later'); } finally { _loader= false; notifyListeners(); } } Future getIpAddress() async { try { final response = await http.get(Uri.parse('https://api.ipify.org?format=json')); if (response.statusCode == 200) { final jsonResponse = json.decode(response.body); ipAddress = jsonResponse['ip']; return jsonResponse['ip']; // IP Address } } catch (e) { print('Failed to get IP address: $e'); } return ''; } Future> getDeviceInfo() async { DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); if (Platform.isAndroid) { AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; deviceId = androidInfo.id ?? ""; // Device ID deviceType = "Android"; // Device Type } else if (Platform.isIOS) { IosDeviceInfo iosInfo = await deviceInfo.iosInfo; deviceId = iosInfo.identifierForVendor ?? ""; // Device ID deviceType = "iOS"; // Device Type } return { 'deviceId': deviceId, 'deviceType': deviceType, }; } Future getDeviceToken() async { FirebaseMessaging messaging = FirebaseMessaging.instance; String? token = await messaging.getToken(); dToken = token ?? ""; return token ?? ""; } Future validateResetPasswordOTP(String phoneNum, String code, BuildContext context) async { final languageProvider = Provider.of(context, listen: false); // Convert enum to string for translation String langCode; switch (languageProvider.currentLangCode) { case Language.en: langCode = 'en'; break; case Language.fr: langCode = 'fr'; break; case Language.ar: langCode = 'ar'; break; default: langCode = 'en'; } if (!await Connection.checkConnection()) { AppSnackbar.showError("Error", 'No Internet Connection'); _loader=false; return false; } _loader=true; ChangeNotifier(); try { await Future.wait([ getDeviceToken(), getDeviceInfo(), getIpAddress(), ]); final verifyResult = await SignUpDriverService().validateResetPasswordOTP(phoneNum, code); _loader=false; final statusCode = verifyResult.statusCode ?? 500; final backendData = verifyResult.data; log('================+++>>>> $statusCode'); log('================+++>>>> ${verifyResult.data}'); String message; // Handle 200/201 = success if (statusCode == 200 || statusCode == 201) { message = OTPMessages.get("", langCode); // null = "code correct" AppSnackbar.showSuccess("Success", message); return true; } // Handle error codes like 406 if (statusCode == 406) { // backendData could be "expired", "invalidToken", or other string message = OTPMessages.get(backendData??"", langCode); AppSnackbar.showError("Error", message); return false; } // Other unexpected errors message = OTPMessages.get(backendData ?? 'this code is wrong', langCode); AppSnackbar.showError("Error", message); return false; } catch (e, stackTrace) { _loader=false; log("-----> Verify OTP Caught Error: $e"); log("-----> Verify OTP Caught Error StackTrace: $stackTrace"); AppSnackbar.showError("Error", 'Unexpected error occurred'); return false; } } Future VerifyOtp(String otp) async { log("phoneNumber:VerifyOtp $_phone"); log("phoneNumber:VerifyOtp $otp"); if (!await Connection.checkConnection()) { AppSnackbar.showError("Error", 'No Internet Connection'); log("-----> No Internet Connection"); } _loader= true; notifyListeners(); try { final sendCodeResult = await SignUpDriverService().verifyphonenumber(_phone,otp); log("Status Code: ${sendCodeResult.statusCode}"); log("data: ${sendCodeResult.data}"); log("error Message: ${sendCodeResult.errorMessage}"); if (sendCodeResult.statusCode == 200 || sendCodeResult.statusCode == 201) { AppSnackbar.showSuccess("Success", "Phone number verified successfully!"); signUpDriver(); } else { AppSnackbar.showError("Error", "Error happen with OTP please try again later"); } } catch (e, stackTrace) { log("Error: $e"); log("StackTrace: $stackTrace"); AppSnackbar.showError("Error", 'Error happen with OTP please try again later'); } // finally { // _loader= false; // notifyListeners(); // } } Future signUpDriver() async { log("signUpDriver ========> "); // _loader= true; // notifyListeners(); try { // Validate required fields before sending if ( _phone.isEmpty || _firstName.isEmpty) { print('Error: Missing required fields $_phone | $_firstName | $_lastName'); return; } // Prepare text fields EXACTLY as in working Postman request final Map textFields = { 'city': _city.isNotEmpty ?city.toUpperCase().replaceAll(' ', '_') : 'SOUSSE', // Match Postman 'email': _email.toLowerCase().trim(), 'firstName': _firstName.trim(), 'lastName': _lastName.trim(), 'password': _password, 'gender': _gender, 'phoneNumber': _phone.trim(), 'idnumber': _idCard.trim(), 'licencecard': _licencecard.trim(), 'vehiclemodel': _vehicleModel?.trim() ?? 'model', 'vehicletype': _vehicleType?.toUpperCase() ?? 'SEDAN', }; // // Handle taxi type ID // if (_selectedTaxiType != null) { // textFields['taxiTypeId'] = _selectedTaxiType.toString(); // } else { // textFields['taxiTypeId'] = '935'; // Default from Postman // } // // // Handle license expiry date - use RFC1123 format like Postman // if (_expirationDate.isNotEmpty) { // try { // final parsedDate = DateTime.parse(_expirationDate); // textFields['licenseexpirydate'] = formatDateRFC1123(parsedDate); // } catch (e) { // print('Error parsing expiration date: $e'); // // Use default date like Postman // textFields['licenseexpirydate'] = 'Tue, 31 Dec 2025 23:59:59 GMT'; // } // } else { // // Default date from Postman // textFields['licenseexpirydate'] = 'Tue, 31 Dec 2025 23:59:59 GMT'; // } // // // Handle taxiAllowedItems as comma-separated string (like Postman: '121,213') // if (_selectedAllowedItems.isNotEmpty) { // textFields['taxiAllowedItems'] = _selectedAllowedItems.join(','); // } // Prepare file fields with EXACT field names from Postman final Map fileFields = { // 'patentPicture': _patentFile, // 'IdPicture': _idCardFile, // Capital I - matches Postman 'profilePicture': _profileImage, // 'carlicence': _carLicenseFile, // 'TaxiIdPicture': _taxiIdpictureFile, // Capital T and I - matches Postman // 'taxiInsurancePicture': _insuranceFile, // 'driverlicence': _licenceFile, }; // Filter out null files final validFileFields = {}; for (final entry in fileFields.entries) { if (entry.value != null && entry.value!.existsSync()) { validFileFields[entry.key] = entry.value; } } // Filter valid vehicle images for taxPicture field // final validVehicleImages = []; // for (final image in _vehicleImages) { // if (image != null && image.existsSync()) { // validVehicleImages.add(image); // } // } print('=== Debug Info ==='); print('Text fields: $textFields'); print('File fields: ${validFileFields.keys.toList()}'); // print('Vehicle images count: ${validVehicleImages.length}'); print('=================='); // Call service final response = await SignUpDriverService().signUpDriver( textFields: textFields, fileFields: validFileFields, taxPictures: [], ); print('=== Response ==='); print('Status Code: ${response.statusCode}'); print('Response Body: ${response.body}'); print('==============='); if (response.statusCode == 200 ||response.statusCode == 201) { print("SUCCESS: Driver registration completed successfully"); AppSnackbar.showSuccess("SUCCESS", "Driver registration completed successfully"); final prefs = await SharedPreferences.getInstance(); await prefs.setString('Email',email); await prefs.setString('Password',password); reset(); Get.offNamed('/login'); } else { print("ERROR ${response.statusCode}: ${response.body}"); AppSnackbar.showError("ERROR", "${response.statusCode} ${response.body}"); _handleErrorResponse(response); } } catch (e) { print('Exception during signup: $e'); }finally{ _loader= false; notifyListeners(); } } // Future signUpDriverNew() async { // log("signUpDriver ========> "); // // _loader= true; // // notifyListeners(); // try { // // Validate required fields before sending // if ( _phone.isEmpty || _firstName.isEmpty || _lastName.isEmpty) { // print('Error: Missing required fields'); // return; // } // // // Prepare text fields EXACTLY as in working Postman request // final Map textFields = { // 'city': _city.isNotEmpty ?city.toUpperCase().replaceAll(' ', '_') : 'SOUSSE', // 'email': _email.toLowerCase().trim(), // 'firstName': _firstName.trim(), // 'gender': _gender.toUpperCase(), // MALE/FEMALE // 'idnumber': _idCard.trim(), // 'licencecard': _licencecard.trim(), // 'lastName': _lastName.trim(), // 'password': _password, // 'phoneNumber': _phone.trim(), // 'taxId': _taxiId.trim(), // 'taxiPlateNumber': _plateNumber?.trim() ?? '', // 'vehiclemodel': _vehicleModel?.trim() ?? 'model', // Default from Postman // 'vehicletype': _vehicleType?.toUpperCase() ?? 'SEDAN', // Default from Postman // 'vehicleyear': _vehicleYear?.trim() ?? '2015', // Default from Postman // }; // // // Handle taxi type ID // if (_selectedTaxiType != null) { // textFields['taxiTypeId'] = _selectedTaxiType.toString(); // } else { // textFields['taxiTypeId'] = '935'; // Default from Postman // } // // // Handle license expiry date - use RFC1123 format like Postman // if (_expirationDate.isNotEmpty) { // try { // final parsedDate = DateTime.parse(_expirationDate); // textFields['licenseexpirydate'] = formatDateRFC1123(parsedDate); // } catch (e) { // print('Error parsing expiration date: $e'); // // textFields['licenseexpirydate'] = 'Tue, 31 Dec 2026 23:59:59 GMT'; // } // } else { // // textFields['licenseexpirydate'] = 'Tue, 31 Dec 2026 23:59:59 GMT'; // } // // // Handle taxiAllowedItems as comma-separated string (like Postman: '121,213') // if (_selectedAllowedItems.isNotEmpty) { // textFields['taxiAllowedItems'] = _selectedAllowedItems.join(','); // } // // // Prepare file fields with EXACT field names from Postman // final Map fileFields = { // 'patentPicture': _patentFile, // 'IdPicture': _idCardFile, // Capital I - matches Postman // 'profilePicture': _profileImage, // 'carlicence': _carLicenseFile, // 'TaxiIdPicture': _taxiIdpictureFile, // Capital T and I - matches Postman // 'taxiInsurancePicture': _insuranceFile, // 'driverlicence': _licenceFile, // }; // // // Filter out null files // final validFileFields = {}; // for (final entry in fileFields.entries) { // if (entry.value != null && entry.value!.existsSync()) { // validFileFields[entry.key] = entry.value; // } // } // // // Filter valid vehicle images for taxPicture field // final validVehicleImages = []; // for (final image in _vehicleImages) { // if (image != null && image.existsSync()) { // validVehicleImages.add(image); // } // } // // print('=== Debug Info ==='); // print('Text fields: $textFields'); // print('File fields: ${validFileFields.keys.toList()}'); // print('Vehicle images count: ${validVehicleImages.length}'); // print('=================='); // // // Call service // final response = await SignUpDriverService().signUpDriver( // textFields: textFields, // fileFields: validFileFields, // taxPictures: validVehicleImages, // ); // // print('=== Response ==='); // print('Status Code: ${response.statusCode}'); // print('Response Body: ${response.body}'); // print('==============='); // // if (response.statusCode == 200 ||response.statusCode == 201) { // print("SUCCESS: Driver registration completed successfully"); // AppSnackbar.showSuccess("SUCCESS", "Driver registration completed successfully"); // reset(); // Get.offNamed('/login'); // } else { // print("ERROR ${response.statusCode}: ${response.body}"); // AppSnackbar.showError("ERROR", "${response.statusCode} ${response.body}"); // _handleErrorResponse(response); // } // } catch (e) { // print('Exception during signup: $e'); // }finally{ // _loader= false; // notifyListeners(); // } // } void _handleErrorResponse(response) { switch (response.statusCode) { case 400: print('Bad Request - Check your input data format'); break; case 404: print('User already exists or endpoint not found'); break; case 500: print('Server error - Please try again later'); break; default: print('Unexpected error: ${response.statusCode}'); } } void showData() { print("------ Profile Image: $_profileImage"); print("------ Email: $_email"); print("------ Phone: $_phone"); print("------ First Name: $_firstName"); print("------ Last Name: $_lastName"); print("------ Gender: $_gender"); print("------ Password: $_password"); print("------ ID Card: $_idCard"); print("------ Expiration Date: $_expirationDate"); print("------ Taxi ID: $_taxiId"); print("------ Taxi ID Picture File: $_taxiIdpictureFile"); print("------ Vehicle Images: $_vehicleImages"); print("------ Insurance File: $_insuranceFile"); print("------ Plate Number: $_plateNumber"); print("------ Plate Number: $_plateNumberfirstPart"); print("------ Plate Number: $_plateNumberLastPart"); print("------ ID Card File: $_idCardFile"); print("------ ID Taxi File: $_idTaxiFile"); print("------ Car License File: $_carLicenseFile"); print("------ Licence File: $_licenceFile"); print("------ Selected Taxi Type: $_selectedTaxiType"); print("------ Selected Allowed Items: $_selectedAllowedItems"); print("------ Patent File: $_patentFile"); print("------ Patent Number: $_patentNumber"); print("------ Vehicle Model: $_vehicleModel"); print("------ Vehicle Year: $_vehicleYear"); } Future ResetPassword(String newPassword,String phonenumber,String code) async { log("password: $newPassword"); log("phonenumber: $phonenumber"); log("code: $code"); if (!await Connection.checkConnection()) { AppSnackbar.showError("Error", 'No Internet Connection'); log("-----> No Internet Connection"); return false; } _loader= true; ChangeNotifier(); try { final sendCodeResult = await SignUpDriverService().resetPassword(newPassword,phonenumber,code); log("Status Code: ${sendCodeResult.statusCode}"); log("data: ${sendCodeResult.data}"); log("error Message: ${sendCodeResult.errorMessage}"); if (sendCodeResult.statusCode == 200 || sendCodeResult.statusCode == 201) { final responseBody = sendCodeResult.data; if (responseBody != null && responseBody.isNotEmpty) { final String token = responseBody; log("Token: $token"); Get.offAll(() => LoginScreen()); } return true; } else { AppSnackbar.showError("Error", 'Unexpected error occurred'); return false; } } catch (e, stackTrace) { log("Error: $e"); log("StackTrace: $stackTrace"); AppSnackbar.showError("Error", 'Unexpected error occurred'); return false; } finally { _loader= false; ChangeNotifier(); } } } final signUpProviderSingletone = SignUpProvider();