import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_places_flutter/google_places_flutter.dart'; import 'package:google_places_flutter/model/prediction.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import '../../constants/color_constants.dart'; import '../../constants/font_constants.dart'; import '../../controllers/tenant_controller /tenant_list.dart'; import '../../widgets/text_widget.dart'; import '../home_view.dart'; class CustomerCreateView extends StatefulWidget { final String mobileNumber; const CustomerCreateView({super.key,required this.mobileNumber}); @override State createState() => _CustomerCreateViewState(); } class _CustomerCreateViewState extends State { Map? selectedLocationData; bool isFetching = false; final TenantController tenantController = Get.put(TenantController()); final TextEditingController nameController = TextEditingController(); final TextEditingController landmarkController = TextEditingController(); Future createCustomer(Map locationData) async { try { SharedPreferences prefs = await SharedPreferences.getInstance(); String? fcmToken = prefs.getString('fcmToken') ?? ''; String deviceId = prefs.getString('currentDeviceId') ?? ''; String deviceType = Platform.isAndroid ? "android" : "ios"; final url = Uri.parse('https://fiesta.nearle.app/live/api/v1/mob/customers/create'); final Map body = { "configid": 2, "firstname": nameController.text.trim(), "applocationid": 1, "profileimage": "", "dialcode": "+91", "contactno": widget.mobileNumber, "devicetype": deviceType, "deviceid": deviceId, "customertoken": fcmToken, "address": locationData["address"] ?? "", "suburb": locationData["suburb"] ?? "", "city": locationData["city"] ?? "", "state": locationData["state"] ?? "", "postcode": locationData["postcode"] ?? "", "landmark": landmarkController.text.isEmpty ? "near" : landmarkController.text.trim(), "doorno": locationData["doorno"] ?? "", "latitude": locationData["latitude"] ?? "", "longitude": locationData["longitude"] ?? "", "tenantid": 630, "email": "", "primaryaddress": 1, "gender": "Male", "dob": "2025-06-30" }; Fluttertoast.showToast( msg: "Creating customer...", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.TOP, backgroundColor: Colors.black.withOpacity(0.8), textColor: Colors.white, fontSize: 15, ); final response = await http.post( url, headers: {"Content-Type": "application/json"}, body: jsonEncode(body), ); final data = jsonDecode(response.body); final bool status = data['status'] ?? false; final String message = data['message'] ?? 'Unknown response'; if (status) { final details = data['details']; if (details != null) { // ✅ Save important details to SharedPreferences final customerIdStr = details['customerid']?.toString() ?? '0'; await prefs.setInt('customerId', int.tryParse(customerIdStr) ?? 0); await prefs.setString('customerFirstname', details['firstname'] ?? ''); await prefs.setString('customertoken', details['customertoken'] ?? ''); await prefs.setInt('deliverylocationid', details['deliverylocationid'] ?? 0); await prefs.setInt('contactno', int.tryParse(details['contactno'] ?? '0') ?? 0); await prefs.setString('customerAddress', details['address'] ?? ''); await prefs.setString('customerSuburb', details['suburb'] ?? ''); await prefs.setString('customerCity', details['city'] ?? ''); await prefs.setString('customerState', details['state'] ?? ''); await prefs.setString('customerLandmark', details['landmark'] ?? ''); await prefs.setString('customerDoorNo', details['doorno'] ?? ''); debugPrint("✅ Customer info saved to SharedPreferences."); } tenantController.loadTenants(); print(data); // Get.put(TenantController()); Get.offAll(() => BottomNavigation()); // ✅ Use message from API Fluttertoast.showToast( msg: "Customer created successfully!", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.TOP, backgroundColor: Colors.green.withOpacity(0.8), textColor: Colors.white, fontSize: 15, ); } else { // ❌ Handle failure message from API debugPrint("❌ API returned failure: $message"); Fluttertoast.showToast( msg: "Customer already available", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.TOP, backgroundColor: Colors.black.withOpacity(0.8), textColor: Colors.white, fontSize: 15, ); } } catch (e, stacktrace) { debugPrint(" Something went wrong"); debugPrint("Stacktrace: $stacktrace"); Fluttertoast.showToast( msg: "Something went wrong", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.TOP, backgroundColor: Colors.black.withOpacity(0.8), textColor: Colors.white, fontSize: 15, ); } } @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final width = size.width; final height = size.height; double scaleFont(double size) { if (width > 800) return size * 1.5; if (width > 600) return size * 1.3; return size; } return SafeArea( top: false, child: Scaffold( backgroundColor: Colors.grey.shade100, appBar: AppBar( backgroundColor: Colors.white, elevation: 0, centerTitle: true, leadingWidth: 300, leading: Row( children: [ IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black87), onPressed: () => Navigator.pop(context), ), ReusableTextWidget( text: "Create Account", color: ColorConstants.blackColor, fontWeight: FontWeight.w700, fontSize: scaleFont(17), fontFamily: FontConstants.fontFamily, ) ], ), ), body: SingleChildScrollView( padding: EdgeInsets.symmetric(horizontal: width * 0.06, vertical: height * 0.02), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.only(bottom: height * 0.02), child: ReusableTextWidget( text: "Welcome 👋\nPlease enter your details below", color: Colors.black87, fontWeight: FontWeight.w600, fontSize: scaleFont(13), fontFamily: FontConstants.fontFamily, ), ), _buildLabel("Full Name", scaleFont), _buildTextField("Enter your name", Icons.person, width, controller: nameController), SizedBox(height: height * 0.03), _buildLabel("Location", scaleFont), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), border: Border.all(color: Colors.black54, width: 0.40), ), child: ListTile( leading: Icon(Icons.location_on, color: ColorConstants.primaryColor), title: ReusableTextWidget( text: selectedLocationData == null ? "Use my current location" : selectedLocationData!["address"], color: selectedLocationData == null ? ColorConstants.primaryColor : Colors.black, fontWeight: FontWeight.w600, fontSize: 12, fontFamily: FontConstants.fontFamily, maxLines: 2, overflow: TextOverflow.ellipsis, ), subtitle: selectedLocationData == null ? ReusableTextWidget( text: "Fetching current location...", color: Colors.grey, fontWeight: FontWeight.w400, fontSize: 9, fontFamily: FontConstants.fontFamily, ) : null, trailing: isFetching ? const SizedBox( width: 22, height: 22, child: CircularProgressIndicator(strokeWidth: 2), ) : const Icon(Icons.arrow_forward_ios_rounded, color: Colors.grey, size: 18), onTap: () async { setState(() => isFetching = true); final result = await Get.to(() => const MapPickerPage1()); if (result != null) { setState(() { selectedLocationData = result; }); } setState(() => isFetching = false); }, ), ), SizedBox(height: height * 0.03), _buildLabel("Door No / Landmark", scaleFont), _buildTextField("Enter door no / landmark", Icons.home_filled, width, controller: landmarkController), SizedBox(height: height * 0.05), ], ), ), bottomNavigationBar: Container( padding: EdgeInsets.symmetric(horizontal: width * 0.06, vertical: height * 0.02), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.grey.shade300, blurRadius: 10, offset: const Offset(0, -2), ) ], ), child: SizedBox( height: height * 0.065, width: double.infinity, child: ElevatedButton( onPressed: selectedLocationData == null ? null : () { if (nameController.text.isEmpty) { Get.snackbar("Error", "Please enter your name"); return; } createCustomer(selectedLocationData!); }, style: ElevatedButton.styleFrom( backgroundColor: ColorConstants.primaryColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 2, ), child: Text( "Submit", style: TextStyle( fontFamily: FontConstants.fontFamily, fontSize: scaleFont(17), fontWeight: FontWeight.w700, color: Colors.white, ), ), ), ), ), ), ); } Widget _buildLabel(String text, double Function(double) scaleFont) { return Padding( padding: const EdgeInsets.only(bottom: 6), child: ReusableTextWidget( text: text, color: Colors.black87, fontWeight: FontWeight.w700, fontSize: scaleFont(15), fontFamily: FontConstants.fontFamily, ), ); } Widget _buildTextField(String hint, IconData icon, double width, {TextEditingController? controller}) { return TextFormField( controller: controller, style: const TextStyle(fontSize: 14), decoration: InputDecoration( hintText: hint, hintStyle: TextStyle( fontFamily: FontConstants.fontFamily, fontWeight: FontWeight.w400, color: Colors.grey, ), prefixIcon: Icon(icon, color: Colors.grey[700]), filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.symmetric(vertical: 14, horizontal: 12), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.black54, width: 0.40), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: ColorConstants.primaryColor, width: 1.3), ), ), ); } } class MapPickerPage1 extends StatefulWidget { const MapPickerPage1({super.key}); @override State createState() => _MapPickerPage1State(); } class _MapPickerPage1State extends State { GoogleMapController? mapController; LatLng? selectedLatLng; final TextEditingController searchController = TextEditingController(); @override void initState() { super.initState(); _getCurrentLocation(); } void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { // App came back from background, retry location _getCurrentLocation(); } } Future _getCurrentLocation() async { try { bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { // Get.snackbar("Location Disabled", "Please enable GPS to continue"); await Geolocator.openLocationSettings(); _getCurrentLocation(); serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) return _getCurrentLocation(); } LocationPermission permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) return; } if (permission == LocationPermission.deniedForever) { Get.snackbar("Permission Denied Forever", "Please enable location in app settings."); await Geolocator.openAppSettings(); return; } Position position = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.high, ); setState(() { selectedLatLng = LatLng(position.latitude, position.longitude); }); mapController?.animateCamera(CameraUpdate.newLatLngZoom(selectedLatLng!, 16)); } catch (e) { Get.snackbar("Error", "Failed to get location: $e"); } } Future _goToSearchedPlace(double lat, double lng) async { setState(() { selectedLatLng = LatLng(lat, lng); }); mapController?.animateCamera( CameraUpdate.newCameraPosition( CameraPosition(target: selectedLatLng!, zoom: 16), ), ); } @override Widget build(BuildContext context) { return SafeArea( top: false, child: Scaffold( backgroundColor: Colors.white, appBar: AppBar( backgroundColor: Colors.white, title: const Text("Pick Location"), ), body: Stack( children: [ selectedLatLng == null ? const Center(child: CircularProgressIndicator()) : GoogleMap( initialCameraPosition: CameraPosition(target: selectedLatLng!, zoom: 16), onMapCreated: (controller) => mapController = controller, onTap: (latLng) { setState(() => selectedLatLng = latLng); }, markers: selectedLatLng != null ? { Marker( markerId: const MarkerId("selected"), position: selectedLatLng!, draggable: true, onDragEnd: (newPos) => setState(() => selectedLatLng = newPos), ), } : {}, ), Positioned( top: 10, left: 15, right: 15, child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 5, ), ], ), child: GooglePlaceAutoCompleteTextField( textEditingController: searchController, googleAPIKey: "AIzaSyBhkGfnq27sN0wV5y_S-M2KojpFTk_by-Q", inputDecoration: const InputDecoration( hintText: "Search location...", border: InputBorder.none, contentPadding: EdgeInsets.all(12), ), debounceTime: 400, countries: ["in"], isLatLngRequired: true, getPlaceDetailWithLatLng: (Prediction prediction) { double lat = double.parse(prediction.lat!); double lng = double.parse(prediction.lng!); _goToSearchedPlace(lat, lng); }, itemClick: (Prediction prediction) { searchController.text = prediction.description!; FocusScope.of(context).unfocus(); }, ), ), ), Positioned( bottom: 30, left: 20, right: 20, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: ColorConstants.primaryColor, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), ), onPressed: selectedLatLng == null ? null : () async { try { List placemarks = await placemarkFromCoordinates( selectedLatLng!.latitude, selectedLatLng!.longitude, ); if (placemarks.isNotEmpty) { final place = placemarks.first; String address = "${place.name}, ${place.locality}, ${place.administrativeArea}, ${place.postalCode}, ${place.country}"; Map selectedLocation = { "address": address, "suburb": place.subLocality ?? "", "city": place.locality ?? "", "state": place.administrativeArea ?? "", "postcode": place.postalCode ?? "", "doorno": place.name ?? "", "landmark": "near", "latitude": selectedLatLng!.latitude.toString(), "longitude": selectedLatLng!.longitude.toString(), }; Navigator.of(Get.context!).pop(selectedLocation); } } catch (e) { Get.snackbar("Error", "Failed to get location: $e"); } }, child: const Text( "Confirm Location", style: TextStyle(color: Colors.white, fontSize: 16), ), ), ), ], ), ), ); } }