import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:geolocator/geolocator.dart' as LocationAccuracy; import 'package:flutter/cupertino.dart'; import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'package:minio/io.dart'; import 'package:minio/minio.dart'; import 'package:path/path.dart' as path; import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'dart:io'; import 'package:rounded_loading_button_plus/rounded_loading_button.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../Data/Provider/Appcategory/Appcategoryprovider.dart'; import '../../Data/Repository/Appcategory/Appcategoryrepository.dart'; import '../../Data/Repository/Applocation/Applocationrepository.dart'; import '../../Data/Repository/Authentication/Createtenantuser/Createtenantuserrepository.dart'; import '../../Data/Repository/TenantPartner/Tenantpartnerrepository.dart'; import '../../Helper/Logger.dart'; import '../../Helper/location_service.dart'; import '../../Helper/toast.dart'; import '../../Model/Request/Authentication/Createuser/Createuserresponse.dart'; import '../../Model/Response/Appcategory/app_category_response.dart'; import '../../Model/Response/Applocations/Applocationresponse.dart'; import '../../Model/Response/Authentication/Createtenantuser/Createtenantuserresponse.dart'; import '../../Model/Response/Partners/Getpartnerinforequest.dart'; import '../../View/Success/Successview.dart'; class CreateUserController extends GetxController { String appLocationName = ''; String appCategoryName = ''; String partnerName = ''; String? latitude; String? longitude; String? catName; int? moduleIdByCategory = 0; String? subCatName; String? fcmEntryToken; String? todayDate; String? validityDate; String? url; // This will hold the uploaded image URL int selectedIndex = 0; int? catId; int? subCatId; String? deviceId; int appLocationId = 0; int partnerSelectedIndex = -1; int? partnerId; List locations = []; List getPartners = []; List appCategory = []; Position? resultPosition; List subCategories = []; Future getFcmToken() async { try { await FirebaseMessaging.instance.requestPermission(); fcmEntryToken = await FirebaseMessaging.instance.getToken(); print('FCM Token: $fcmEntryToken'); FirebaseMessaging.instance.onTokenRefresh.listen((newToken) { fcmEntryToken = newToken; print('FCM Token Refreshed: $fcmEntryToken'); }); } catch (e) { print('Error getting FCM token: $e'); } } Future getSubCategories() async { final provider = SubCategoryProvider(); final List fetched = await provider.fetchSubCategories(); subCategories.assignAll(fetched); update(); } final String apiUrl = "https://fiesta.nearle.app/live/api/v1/mob/utils/getsubcategories"; Future fetchSubCategories() async { try { final response = await http.get(Uri.parse(apiUrl)); if (response.statusCode == 200) { final jsonData = json.decode(response.body); return GetSubCategoriesResponse.fromJson(jsonData); } else { print("Failed to load subcategories: ${response.statusCode}"); } } catch (e) { print("Error fetching subcategories: $e"); } return null; } bool shimmer = true; bool categoryShimmer = true; bool isEnterAddress = false; String selectedCategoryName = ''; var currentLat; var currentLong; TextEditingController firstnameController = TextEditingController(); TextEditingController lastnameController = TextEditingController(); TextEditingController companyNameController = TextEditingController(); TextEditingController emailController = TextEditingController(); TextEditingController gstinNumberController = TextEditingController(); TextEditingController contactNoController = TextEditingController(); TextEditingController addressController = TextEditingController(); TextEditingController stateController = TextEditingController(); TextEditingController cityController = TextEditingController(); TextEditingController suburbController = TextEditingController(); TextEditingController postcodeController = TextEditingController(); final searchText = ''.obs; final predictions = >[].obs; final selectedPlace = {}.obs; final RoundedLoadingButtonController btnController = RoundedLoadingButtonController(); AppLocationRepository appLocationRepository = AppLocationRepository(); GetPartnersRepository getPartnersRepository = GetPartnersRepository(); AppCategoryRepository appCategoryRepository = AppCategoryRepository(); CreateTenantUserRepository createTenantUserRepository = CreateTenantUserRepository(); final GooglePlacesService placesService = GooglePlacesService(); getAppLocations() async { GetAppLocations? result = await appLocationRepository.getAppLocations(); if (result?.code == 200) { locations = result?.details ?? []; shimmer = false; update(); } else { Toast.showToast("${result?.message}"); } } getCurrentLocation() async { resultPosition = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.LocationAccuracy.high); currentLat = resultPosition?.latitude.toString(); currentLong = resultPosition?.longitude.toString(); print('currentLatinlocation $currentLat'); print('currentLonglocation $currentLong'); getAddressFromLatLongs(double.parse(currentLat), double.parse(currentLong)); } getAppCategory() async { categoryShimmer = true; update(); try { final provider = SubCategoryProvider(); final List subCats = await provider.fetchSubCategories(); final Map uniqueCats = {}; for (var sub in subCats) { if (sub.categoryid != null && sub.catgeoryname != null) { uniqueCats[sub.categoryid!] = AppCategoryDetails( categoryid: sub.categoryid, categoryname: sub.catgeoryname, moduleid: sub.moduleid, ); } } appCategory = uniqueCats.values.toList(); logger.i('Loaded ${appCategory.length} categories'); if (appCategory.isNotEmpty) { catId = appCategory[0].categoryid; catName = appCategory[0].categoryname; moduleIdByCategory = appCategory[0].moduleid; } } catch (e) { logger.e('Error loading categories: $e'); Toast.showToast("Failed to load categories"); } categoryShimmer = false; update(); } Future getAddressFromLatLongs(double latitudes, double longitudes) async { await placemarkFromCoordinates(latitudes, longitudes).then((List placemarks) { Placemark place = placemarks[0]; cityController.text = place.locality ?? ''; stateController.text = place.administrativeArea ?? ''; suburbController.text = '${place.subLocality ?? place.street}'; postcodeController.text = place.postalCode ?? ''; latitude = latitudes.toString(); longitude = longitudes.toString(); addressController.text = '${place.street}, ${place.subLocality}, ${place.locality}, ${place.administrativeArea} ${place.subAdministrativeArea}, ${place.country}, ${place.postalCode}.'; update(); }).catchError((e) { debugPrint(e); }); } getPartnersInfo(locationId) async { GetPartnersInfo? result = await getPartnersRepository.getPartners(locationId); getPartners = result?.details ?? []; partnerId = getPartners.isNotEmpty ? getPartners[0].partnerid : null; print('getPartnerslengthss${getPartners.length}'); print('getpartnerId$partnerId'); } onSearchTextChanged(String text) async { searchText.value = text; if (text.length > 2) { try { final places = await placesService.getPlacesPredictions(text); predictions.assignAll(places); update(); } catch (e) { print('Error fetching predictions: $e'); } } else { predictions.clear(); update(); } } getPlaceDetails(String placeId, locationAddress) async { try { final details = await placesService.getPlaceDetails(placeId); selectedPlace.value = details; getAddressFromLatLng( selectedPlace['geometry']['location']['lat'], selectedPlace['geometry']['location']['lng'], locationAddress, ); } catch (e) { print('Error fetching place details: $e'); } } getAddressFromLatLng(double latitudes, double longitudes, locationAddress) async { await placemarkFromCoordinates(latitudes, longitudes).then((List placemarks) { Placemark place = placemarks[0]; cityController.text = place.locality ?? ''; stateController.text = place.administrativeArea ?? ''; suburbController.text = (place.subLocality?.isNotEmpty == true) ? place.subLocality! : place.street!; postcodeController.text = place.postalCode ?? ''; addressController.text = locationAddress; latitude = latitudes.toString(); longitude = longitudes.toString(); predictions.clear(); update(); }).catchError((e) { debugPrint(e); }); } void doSomething() async { Timer(const Duration(seconds: 1), () { profileValidation(); }); } profileValidation() async { if (firstnameController.text.isEmpty) { btnController.reset(); Toast.showToast("Please Enter Firstname"); return; } if (companyNameController.text.isEmpty) { btnController.reset(); Toast.showToast("Please Enter Companyname"); return; } if (emailController.text.isEmpty) { btnController.reset(); Toast.showToast("Please Enter Email"); return; } if (addressController.text.isEmpty) { btnController.reset(); Toast.showToast("Please Enter Address"); return; } if (suburbController.text.isEmpty) { btnController.reset(); Toast.showToast("Please Enter Suburb"); return; } if (cityController.text.isEmpty) { btnController.reset(); Toast.showToast("Please Enter City"); return; } if (stateController.text.isEmpty) { btnController.reset(); Toast.showToast("Please Enter State"); return; } if (postcodeController.text.isEmpty) { btnController.reset(); Toast.showToast("Please Enter Postcode"); return; } // Handle image upload if selected if (profileImage != null) { btnController.start(); final uploadedUrl = await uploadImageAndSave(File(profileImage!.path)); if (uploadedUrl == null) { btnController.reset(); Toast.showToast("Image upload failed. Please try again."); return; } url = uploadedUrl; } else { url = null; // Optional: send empty or placeholder } // Now safe to create tenant createTenantUser(); } createTenantUser() async { SharedPreferences prefs = await SharedPreferences.getInstance(); DateTime now = DateTime.now(); todayDate = DateFormat("yyyy-MM-dd").format(now); validityDate = DateTime(now.year + 1, now.month, now.day).toString(); deviceId = prefs.getString('deviceId'); final request = CreateTenantUser( tenantimage: url, // Now correctly set configid: 1, allocationid: 2, roleid: 1, tenantname: companyNameController.text, tenanttype: "D", registrationno: gstinNumberController.text, devicetype: Platform.isAndroid ? "android" : "ios", deviceid: deviceId ?? '', tenanttoken: fcmEntryToken ?? '', companyname: companyNameController.text, firstname: firstnameController.text, primaryemail: emailController.text, primarycontact: contactNoController.text, categoryid: catId, subcategoryid: subCatId, moduleid: 2, address: addressController.text, suburb: suburbController.text, state: stateController.text, city: cityController.text, postcode: postcodeController.text, latitude: latitude, longitude: longitude, applocationid: 1, approved: 0, tenantlocations: Tenantlocations( locationid: 0, applocationid: appLocationId, tenantid: 0, moduleid: 2, locationname: companyNameController.text, email: emailController.text, contactno: contactNoController.text, address: addressController.text, suburb: suburbController.text, state: stateController.text, city: cityController.text, postcode: postcodeController.text, latitude: latitude, longitude: longitude, partnerid: partnerId, opentime: "09:00", closetime: "21:00", deliverytype: 0, deliverymins: 60, cancelsecs: 20, ), tenantsubscriptions: Tenantsubscriptions( subscriptionid: 0, tenantid: 0, transactiondate: todayDate, moduleid: 2, applocationid: appLocationId, categoryid: catId, subcategoryid: subCatId, validitydate: validityDate?.split(' ')[0] ?? '', subscriptionprice: 300.00, quantity: 1, taxamount: 0.00, taxpercent: 18, totalamount: 300.00, paymentstatus: 1, ), ); createTenantUserResult(request); } createTenantUserResult(CreateTenantUser data) async { SharedPreferences prefs = await SharedPreferences.getInstance(); CreateTenantUserResponse? result = await createTenantUserRepository.createTenantUser(data); if (result?.status == true) { await Future.wait([ prefs.setInt('userId', result?.details?.userid ?? 0), prefs.setInt('configId', result?.details?.configid ?? 0), prefs.setString('userEmail', result?.details?.authname ?? ''), prefs.setInt('authMode', result?.details?.authmode ?? 0), prefs.setInt('roleId', result?.details?.roleid ?? 0), prefs.setString('userFirstname', result?.details?.firstname ?? ''), prefs.setString('userLastname', result?.details?.lastname ?? ''), prefs.setString('userName', result?.details?.fullname ?? ''), prefs.setString('password', result?.details?.password ?? ''), prefs.setString('userEmail', result?.details?.email ?? ''), prefs.setString('tenantContactNo', result?.details?.contactno ?? ''), prefs.setString('userAddress', result?.details?.address ?? ''), prefs.setString('userSuburb', result?.details?.suburb ?? ''), prefs.setString('userCity', result?.details?.city ?? ''), prefs.setString('userState', result?.details?.state ?? ''), prefs.setString('userPostcode', result?.details?.postcode ?? ''), prefs.setString('userFcmToken', result?.details?.userfcmtoken ?? ''), prefs.setInt('userPin', result?.details?.pin ?? 0), prefs.setInt('partnerId', result?.details?.partnerid ?? 0), prefs.setInt('locationId', result?.details?.locationid ?? 0), prefs.setInt('tenantId', result?.details?.tenantid ?? 0), prefs.setString('tenantName', result?.details?.tenantname ?? ''), prefs.setString('tenantAddress', result?.details?.address ?? ''), prefs.setString('tenantSuburb', result?.details?.suburb ?? ''), prefs.setString('tenantCity', result?.details?.city ?? ''), prefs.setString('tenantState', result?.details?.state ?? ''), prefs.setString('tenantPostcode', result?.details?.postcode ?? ''), prefs.setInt('moduleId', result?.details?.moduleid ?? 0), prefs.setString('locationName', result?.details?.locationname ?? ''), prefs.setInt('categoryId', result?.details?.categoryid ?? 0), prefs.setInt('subcategoryId', result?.details?.subcategoryid ?? 0), prefs.setInt('appLocationId', result?.details?.applocationid ?? 0), ]); logger.i('TenantId From Create Tenant Response: ${prefs.getInt('tenantId')}'); // Clear fields firstnameController.clear(); companyNameController.clear(); emailController.clear(); addressController.clear(); suburbController.clear(); cityController.clear(); stateController.clear(); postcodeController.clear(); profileImage = null; url = null; btnController.reset(); update(); await Future.delayed(Duration(milliseconds: 100)); Get.to(() => AccountCreatedScreen()); } else { btnController.reset(); Toast.showToast("${result?.message}"); } } Future getLocation() async { LocationPermission permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { return Future.error('Location permissions are denied'); } } if (permission == LocationPermission.deniedForever) { await Geolocator.openLocationSettings(); return Future.error('Location permissions are permanently denied'); } Position position = await Geolocator.getCurrentPosition(); await getAddressFromLatLongs(position.latitude, position.longitude); logger.i(position); return position; } XFile? profileImage; final _picker = ImagePicker(); RxString uploadedFileUrl = ''.obs; // Only pick image — upload later Future getProfileImage() async { final XFile? selectedImage = await _picker.pickImage(source: ImageSource.gallery); if (selectedImage != null) { profileImage = selectedImage; update(); } else { Toast.showToast('Image Not Selected'); } } // Upload image and return public URL Future uploadImageAndSave(File selectedImage) async { try { var rng = Random(); const String region = "sgp1"; const String accessKey = "DO00NQER7N2FRYZAB2HR"; const String secretKey = "nMDewX25IBEu1FM5dakK+v28/WbW3TzBAwq913+dxP0"; const String bucketName = "nearle"; const String folderName = "deals"; String fileName = 'profile-${rng.nextInt(1000)}-1234.jpg'; String endpointUrl = "https://$bucketName.$region.digitaloceanspaces.com/$folderName/$fileName"; final minio = Minio( endPoint: '$region.digitaloceanspaces.com', // ✅ FIXED HERE accessKey: accessKey, secretKey: secretKey, region: region, useSSL: true, ); await minio.fPutObject( bucketName, '$folderName/$fileName', selectedImage.path, metadata: { 'Content-Type': 'image/jpeg', 'x-amz-acl': 'public-read', }, ); print("File uploaded successfully: $endpointUrl"); return endpointUrl; } catch (e) { Get.snackbar("Error", "Image upload failed: $e"); print("Upload error: $e"); return null; } } @override void onInit() { getFcmToken(); getLocation(); getSubCategories(); getAppCategory(); super.onInit(); } @override void dispose() { firstnameController.dispose(); lastnameController.dispose(); companyNameController.dispose(); emailController.dispose(); gstinNumberController.dispose(); contactNoController.dispose(); addressController.dispose(); stateController.dispose(); cityController.dispose(); suburbController.dispose(); postcodeController.dispose(); super.dispose(); } } class SubCategoryService { final String apiUrl = "https://fiesta.nearle.app/live/api/v1/mob/utils/getsubcategories"; Future fetchSubCategories() async { try { final response = await http.get(Uri.parse(apiUrl)); if (response.statusCode == 200) { final jsonData = json.decode(response.body); print(response.body); return GetSubCategoriesResponse.fromJson(jsonData); } else { print("Failed to load subcategories: ${response.statusCode}"); } } catch (e) { print("Error fetching subcategories: $e"); } return null; } }