import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import '../../config/apiUrl.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../widgets/custom_text_forex.dart'; import 'purpose_of_travel_list.dart'; class PurposeOfTravelData extends StatefulWidget { final Future> Function() fetchGetPurposeOfTravel; final bool isDesktop; final Color? layoutColor; final int? purposeOfTravelId; // <-- Add this final Map? purposeOfTravelData; const PurposeOfTravelData({ super.key, required this.isDesktop, this.layoutColor, required this.fetchGetPurposeOfTravel, this.purposeOfTravelId, this.purposeOfTravelData, }); @override PurposeOfTravelDataState createState() => PurposeOfTravelDataState(); } class PurposeOfTravelDataState extends State { final ApiService apiService = ApiService(); Map? apiData; // final Map focusNodes = { // "name": FocusNode(), // "description": FocusNode(), // }; final Map controllers = {}; Map errorMessages = {}; Map focusNodes = {}; Map focusStates = {}; String? selectedName; String? selectedDescription; String? userId; int? purposeOfTravelDataId; late String isActive = "1"; bool isDisable = false; List dataHeader = ["dropdown_value", "description"]; Map purposeOfTravelDetails() { final data = { // "purposeOfTravel_id": int.parse(purposeOfTravelId), "dropdown_value": controllers["dropdown_value"]?.text, "description": controllers["description"]?.text, "created_by": userId, "is_active": isActive, }; return data; } @override void initState() { super.initState(); apiData = null; for (var field in dataHeader) { controllers[field] = TextEditingController(); focusNodes["${field}FocusNode"] = FocusNode(); focusStates["${field}Focused"] = false; } for (var key in focusNodes.keys) { _addFocusListener(focusNodes[key]!, (focus) { setState(() { focusStates[key.replaceFirst("FocusNode", "Focused")] = focus; }); }); } if (widget.purposeOfTravelId != null) { print('Editing D ID: ${widget.purposeOfTravelId}'); updateDepartmentDetails(); } } void _clearError() { setState(() { errorMessages.clear(); }); } @override void dispose() { for (var controller in controllers.values) { controller.dispose(); } for (var node in focusNodes.values) { node.dispose(); } super.dispose(); } void _addFocusListener(FocusNode node, Function(bool) updateState) { node.addListener(() { setState(() { updateState(node.hasFocus); }); }); } void updateDepartmentDetails() { print("Inside Update Function - ${widget.purposeOfTravelData}"); final data = widget.purposeOfTravelData; if (data == null) return; setState(() { controllers['dropdown_value']?.text = data['dropdown_value'] ?? ''; // controllers['description']?.text = data['description'].toString(); isActive = data["is_active"]; final purposeOfTravelId = int.tryParse(data['id'].toString()); purposeOfTravelDataId = purposeOfTravelId; }); } void toggleStatus() { setState(() { isActive = isActive == "1" ? "0" : "1"; }); } bool validateData() { errorMessages.clear(); final data = { "dropdown_value": controllers["dropdown_value"]?.text, // "description": controllers["description"]?.text, }; final requiredFields = ["dropdown_value"]; bool hasFocused = false; // Check validation for each field for (String field in requiredFields) { if (data[field] == null || data[field]!.trim().isEmpty) { errorMessages[field] = "Required"; // if (!hasFocused) { // focusNodes[field]?.requestFocus(); // hasFocused = true; // } } } return errorMessages.isEmpty; } Future handleSubmit() async { userId = await getUserId(); setState(() { isDisable = true; // This triggers UI rebuild with error messages if (validateData()) { postPurposeOfTravelData(); }else{ isDisable = false; } }); final purposeOfTravelData1 = purposeOfTravelDetails(); print("submit data - $purposeOfTravelData1"); } Future postPurposeOfTravelData({int isActive = 1}) async { // final remarksData = getData(); final purposeOfTravelData = purposeOfTravelDetails(); print("initially value of the Department - $purposeOfTravelData"); final String apiUrldata; if (purposeOfTravelDataId != null) { print("for edit purposeOfTravel id - $purposeOfTravelDataId"); apiUrldata = '$apiUrl/api/updatePurposeOfTravel/$purposeOfTravelDataId'; purposeOfTravelData["id"] = purposeOfTravelDataId.toString(); purposeOfTravelData["updated_by"] = userId; (purposeOfTravelData.containsKey("created_by")) ? purposeOfTravelData.remove("created_by") : ''; } else { print("for add PurposeOfTravel id - null"); apiUrldata = '$apiUrl/api/createPurposeOfTravel'; print("called apiUrl - $apiUrldata"); purposeOfTravelData["created_by"] = userId; } print("recently PurposeOfTravel data - $purposeOfTravelData"); final token = await getToken(); // Fetch token if (token == null) { throw Exception('Token not found. Please log in.'); } try { final uri = Uri.parse(apiUrldata); final headers = { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', }; final body = jsonEncode(purposeOfTravelData); final response = purposeOfTravelDataId != null ? await http.put(uri, headers: headers, body: body) : await http.post(uri, headers: headers, body: body); if (response.statusCode == 200 || response.statusCode == 201) { print("successfully!"); print("Response: ${response.body}"); _clearError(); widget.fetchGetPurposeOfTravel(); // dispose(); if (context.mounted) { Navigator.of(context).pop(); // Close modal only if mounted } setState(() { isDisable = false; }); } else if (response.statusCode == 404) { if (context.mounted) { Navigator.of(context).pop(); // Close modal only if mounted } setState(() { isDisable = false; }); final message = jsonDecode(response.body)['message'] ?? 'Unknown error'; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: Colors.redAccent, behavior: SnackBarBehavior.floating, ), ); } else { print("Failed to submit. Status: ${response.statusCode}"); print("Error: ${response.body}"); setState(() { isDisable = false; }); } } catch (e) { print(" Error submitting plan: $e"); setState(() { isDisable = false; }); } } @override Widget build(BuildContext context) { return AlertDialog( backgroundColor: Colors.white, contentPadding: const EdgeInsets.fromLTRB(34, 30, 34, 30), // contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 10), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), content: Column( mainAxisSize: MainAxisSize.min, children: [ // Row 1: Title + Edit + Delete buttons Row( children: [ Text( (purposeOfTravelDataId != null) ? 'Edit Purpose Of Travel' : 'Create Purpose Of Travel', style: GoogleFonts.poppins(fontSize: 15, color: Colors.black), ), const Spacer(), ], ), const SizedBox(height: 2), Divider(thickness: 0.2, color: Colors.blueGrey.shade100), const SizedBox(height: 5), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Name *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldForexWrapper( isFocused: focusStates["dropdown_valueFocused"] ?? false, isDesktop: widget.isDesktop, color: Colors.transparent, child: SizedBox( height: 40, child: TextField( controller: controllers["dropdown_value"], focusNode: focusNodes["dropdown_valueFocusNode"], style: const TextStyle(fontSize: 12), decoration: const InputDecoration( labelText: "Name", labelStyle: TextStyle(fontSize: 11, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), ), ), ), ), if (errorMessages["dropdown_value"] != null) ...[ SizedBox(height: 5), // Space before error message Text( errorMessages["dropdown_value"]!, style: TextStyle(color: Colors.red, fontSize: 12), ), ], ], ), SizedBox(height: 15), // Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text( // "Description *", // style: GoogleFonts.poppins( // fontSize: 12, // fontWeight: FontWeight.w600, // color: Color(0xFF575A74), // ), // ), // SizedBox(height: 5), // CustomTextFieldForexWrapper( // isFocused: focusStates["descriptionFocused"] ?? false, // isDesktop: widget.isDesktop, // color: Colors.transparent, // child: SizedBox( // height: 100, // child: TextField( // controller: controllers["description"], // focusNode: focusNodes["descriptionFocusNode"], // style: const TextStyle(fontSize: 12), // maxLines: null, // expands: true, // decoration: const InputDecoration( // labelText: "Description", // labelStyle: TextStyle(fontSize: 11, color: Colors.grey), // floatingLabelBehavior: FloatingLabelBehavior.never, // border: InputBorder.none, // contentPadding: EdgeInsets.symmetric(vertical: 16), // ), // ), // ), // ), // if (errorMessages["description"] != null) ...[ // SizedBox(height: 5), // Space before error message // Text( // errorMessages["description"]!, // style: TextStyle(color: Colors.red, fontSize: 12), // ), // ], // ], // ), // SizedBox(height: 15), if (purposeOfTravelDataId != null) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Change Status ", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), Tooltip( message: isActive == "1" ? "Tap to deactivate" : "Tap to activate", child: GestureDetector( onTap: toggleStatus, child: Text( isActive == "1" ? "Active" : "Inactive", style: TextStyle( fontSize: 13, fontFamily: "Inter", color: isActive == "1" ? Colors.green : Colors.red, ), ), ), ), ], ), if (purposeOfTravelDataId != null) SizedBox(height: 15), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ // SizedBox( // child: ElevatedButton( // onPressed: () { // // You can get text from commentController.text // Navigator.of(context).pop(); // Close the modal // }, // style: ElevatedButton.styleFrom( // backgroundColor: widget.layoutColor, // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(8), // ), // ), // child: Text('Cancel', // style: GoogleFonts.poppins( // fontSize: 13, color: Colors.white)), // ), // ), // SizedBox( // width: 10, // ), SizedBox( child: ElevatedButton( onPressed: isDisable ? null : () async { setState(() { isDisable = true; }); await handleSubmit(); // You can get text from commentController.text // Navigator.of(context).pop(); // Close the modal // Optional: re-enable only on error // setState(() { // isDisable = false; // }); }, style: ElevatedButton.styleFrom( backgroundColor: widget.layoutColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Text( 'Save', style: GoogleFonts.poppins( fontSize: 11, color: Colors.white, ), ), ), ), ], ), // : SizedBox.shrink(), ], ), ); } }