416 lines
12 KiB
Dart
416 lines
12 KiB
Dart
import 'dart:convert';
|
|
// import 'dart:io' as html;
|
|
import 'dart:typed_data'; // Import for Uint8List
|
|
import 'package:dropdown_search/dropdown_search.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:nhance_partner/core/routing/routes.dart';
|
|
import 'package:nhance_partner/data/utils/toastNotification.dart';
|
|
import 'package:nhance_partner/presentation/themes/indicators/text_field_theme.dart';
|
|
import 'package:nhance_partner/presentation/themes/indicators/text_field_theme_inline_editor.dart';
|
|
|
|
import '../../../../core/config/env.dart';
|
|
import '../../../../core/services/api_service.dart';
|
|
import '../../../../data/services/auth_service.dart';
|
|
import '../../../../data/utils/validators.dart';
|
|
import '../../../layouts/main_layout.dart';
|
|
import '../../../layouts/responsive_layout.dart';
|
|
import '../../../providers/manager_provider.dart';
|
|
|
|
import 'package:universal_html/html.dart' as html;
|
|
|
|
import '../../../themes/indicators/input_field_decoration.dart';
|
|
|
|
class Broker extends ConsumerStatefulWidget {
|
|
final String? id;
|
|
final Map<String, dynamic>? data;
|
|
final VoidCallback onSubmit;
|
|
const Broker({super.key, this.id, this.data, required this.onSubmit});
|
|
@override
|
|
ConsumerState<Broker> createState() => BrokerState();
|
|
}
|
|
|
|
class BrokerState extends ConsumerState<Broker> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
late ApiService apiService;
|
|
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
|
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
|
dropDownKeyHandler = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
|
|
List<String> tabHeader = ['name', 'email', 'mobile', 'code'];
|
|
late String isActive = "1";
|
|
html.File? passportFile;
|
|
String? selectedFileNames;
|
|
String? passportFileUrlFromApi;
|
|
dynamic selectedId;
|
|
String? _token;
|
|
bool isLoading = false;
|
|
bool showHandler = false;
|
|
|
|
String? selectedRole;
|
|
List<Map<String, dynamic>> filteredRolesData = [];
|
|
List<Map<String, dynamic>> getRolesData = [];
|
|
|
|
List<dynamic>? selectedHandlerIds = [];
|
|
String? selectedHandler;
|
|
List<Map<String, dynamic>> filteredHandlersData = [];
|
|
List<Map<String, dynamic>> getHandlersData = [];
|
|
|
|
Map<String, TextEditingController> controllers = {};
|
|
|
|
dynamic userId;
|
|
dynamic managerId;
|
|
|
|
Map<String, dynamic> dataDetails() {
|
|
final data = {
|
|
"name": controllers["name"]?.text,
|
|
"short_name": controllers["code"]?.text,
|
|
"is_active": isActive,
|
|
};
|
|
return data;
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
apiService = ApiService();
|
|
for (String field in tabHeader) {
|
|
controllers[field] = TextEditingController();
|
|
}
|
|
|
|
_initializeToken();
|
|
updateData();
|
|
|
|
Future.microtask(() {
|
|
managerId = ref.watch(managerIdProvider);
|
|
userId = ref.watch(userIdProvider);
|
|
if (managerId != null) {
|
|
print('hansles');
|
|
// getHandlers(managerId);
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<void> _initializeToken() async {
|
|
_token = await AuthService.getToken();
|
|
print("APISERTOKEN - $_token");
|
|
}
|
|
|
|
void updateData() async {
|
|
if (widget.data == null) return;
|
|
|
|
final data = widget.data!;
|
|
dynamic id = data['id'];
|
|
|
|
setState(() {
|
|
selectedId = id;
|
|
controllers['name']?.text = data['name'] ?? '';
|
|
controllers['code']?.text = data['short_name'] ?? '';
|
|
controllers["is_active"]?.text = data['is_active']?.toString() ?? '';
|
|
});
|
|
|
|
|
|
}
|
|
|
|
// void updateData() async {
|
|
// if (widget.data != null) {
|
|
// dynamic id = widget.data?['id'];
|
|
// final data = widget.data;
|
|
//
|
|
// if (data == null) return;
|
|
// setState(() {
|
|
// selectedId = id;
|
|
// controllers['name']?.text = data['name'] ?? '';
|
|
// controllers['code']?.text = data['short_name'] ?? '';
|
|
// controllers["is_active"]?.text = data['is_active'].toString();
|
|
// });
|
|
// }
|
|
// }
|
|
|
|
Future<void> handleSave() async {
|
|
final nameEmpty = controllers['name'] == null ||
|
|
controllers['name']!.text.trim().isEmpty;
|
|
|
|
final codeEmpty = controllers['code'] == null ||
|
|
controllers['code']!.text.trim().isEmpty;
|
|
|
|
// 🔥 Both empty
|
|
if (nameEmpty && codeEmpty) {
|
|
ToastHelper.showWarningToast(
|
|
context,
|
|
"Broker and Broker Code is required",
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Broker Name only
|
|
if (nameEmpty) {
|
|
ToastHelper.showWarningToast(
|
|
context,
|
|
"Broker is required",
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Broker Code only
|
|
if (codeEmpty) {
|
|
ToastHelper.showWarningToast(
|
|
context,
|
|
"Broker Code is required",
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (!_formKey.currentState!.validate()) return;
|
|
setState(() {
|
|
if (_formKey.currentState!.validate()) {
|
|
dataDetails();
|
|
final dataSet = dataDetails();
|
|
print("dataSetAgent - $dataSet");
|
|
|
|
print("TYPE of is_active → ${dataSet['is_active'].runtimeType}");
|
|
print("TYPE of value → ${dataSet['value'].runtimeType}");
|
|
createUserData(dataSet);
|
|
} else {
|
|
// isDisable = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
|
|
// Future<void> handleSave() async {
|
|
// // if (controllers['name'] != null && controllers['name'] != '') {
|
|
// // return;
|
|
// // }
|
|
// if (!_formKey.currentState!.validate()) return;
|
|
// setState(() {
|
|
// if (_formKey.currentState!.validate()) {
|
|
// dataDetails();
|
|
// final dataSet = dataDetails();
|
|
// print("dataSetAgent - $dataSet");
|
|
//
|
|
// print("TYPE of is_active → ${dataSet['is_active'].runtimeType}");
|
|
// print("TYPE of name → ${dataSet['name'].runtimeType}");
|
|
// createUserData(dataSet);
|
|
// } else {
|
|
// // isDisable = false;
|
|
// }
|
|
// });
|
|
// }
|
|
|
|
void refresh() {
|
|
print('REfresj');
|
|
widget.onSubmit();
|
|
setState(() {
|
|
// clear all text controllers
|
|
for (var controller in controllers.values) {
|
|
controller.clear();
|
|
} // 👈 clear selected agent
|
|
controllers['name']?.clear();
|
|
});
|
|
}
|
|
|
|
Future<void> createUserData(data) async {
|
|
final bool isUpdating = selectedId != null;
|
|
final dynamic id = isUpdating ? int.tryParse(selectedId.toString()) : 0;
|
|
final String apiUrldata;
|
|
|
|
print("TYPE of id → $id - ${id.runtimeType}");
|
|
print("TYPE of id → $userId - ${userId.runtimeType}");
|
|
|
|
apiUrldata = isUpdating
|
|
? '${Env.apiUrl}/master/updateBroker/$selectedId'
|
|
: '${Env.apiUrl}/master/createBroker';
|
|
|
|
// final token = await getToken(); // Fetch token
|
|
|
|
if (_token == null) {
|
|
throw Exception('Token not found. Please log in.');
|
|
}
|
|
|
|
if (isUpdating) {
|
|
data['updated_by'] = userId.toString();
|
|
} else {
|
|
data['created_by'] = userId.toString();
|
|
}
|
|
|
|
print("data------- $data}");
|
|
|
|
try {
|
|
final response = await http.post(
|
|
Uri.parse(apiUrldata),
|
|
headers: {
|
|
'Authorization': 'Bearer $_token',
|
|
'Content-Type': 'application/json',
|
|
'app-signature': Env.App_Signature,
|
|
},
|
|
body: jsonEncode(data), // Convert map to JSON
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final responseBody = jsonDecode(response.body);
|
|
final message = responseBody['message'];
|
|
print("Broker submitted successfully!");
|
|
print("Response: ${response.body}");
|
|
|
|
if (responseBody['status'] == 200) {
|
|
refresh();
|
|
isUpdating
|
|
? ToastHelper.showSuccessToast(context, message)
|
|
: ToastHelper.showSuccessToast(context, message);
|
|
} else {
|
|
print("Failed to submit plan. Status: ${response.statusCode}");
|
|
print("Error: ${response.body}");
|
|
|
|
showDialog(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return AlertDialog(
|
|
title: Text("Broker Creation Failed"),
|
|
content: Text(message),
|
|
actions: [
|
|
TextButton(
|
|
child: Text("OK"),
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
},
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
} else if (response.statusCode == 403) {
|
|
await apiService.clearLocalStorageAndRedirect();
|
|
}
|
|
} catch (e) {
|
|
print(" Error submitting Staff: $e");
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
for (var controller in controllers.values) {
|
|
controller.dispose();
|
|
}
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SelectionArea(
|
|
child: Container(
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
children: [
|
|
buildFormFields(),
|
|
SizedBox(width: 5),
|
|
InkWell(
|
|
onTap: () {
|
|
handleSave();
|
|
},
|
|
child: Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 6),
|
|
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(8.0),
|
|
color: Color(0xFF2E7D6E),
|
|
),
|
|
child: Text(
|
|
'Save',
|
|
style: GoogleFonts.inter(color: Colors.white, fontSize: 10),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 5),
|
|
InkWell(
|
|
onTap: () {
|
|
refresh();
|
|
},
|
|
child: Container(
|
|
padding: EdgeInsets.all(6.0),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF2E7D6E),
|
|
borderRadius: BorderRadius.circular(5.0),
|
|
),
|
|
child: Icon(Icons.refresh, size: 13, color: Colors.white),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
) );
|
|
}
|
|
|
|
Widget buildFormFields() {
|
|
return Form(
|
|
key: _formKey,
|
|
child: Row(
|
|
children: [buildName(), SizedBox(width: 10), buildShortName()],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget buildName() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text("Broker *", style: _textStyle),
|
|
SizedBox(width: 10),
|
|
SizedBox(
|
|
child: ThemedFormInlineField(
|
|
controller: controllers['name']!,
|
|
validator: (value) => Validators.requiredField(value, "name"),
|
|
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
|
borderColor: Color(0xFFE2E8F0),
|
|
highlightColor: Color(0xFF50A398),
|
|
// txtheight: 30,
|
|
isdense: true,
|
|
errFieldHgt: 0,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget buildShortName() {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text("Broker Code *", style: _textStyle),
|
|
SizedBox(width: 10),
|
|
SizedBox(
|
|
child: ThemedFormInlineField(
|
|
controller: controllers['code']!,
|
|
validator: (value) => Validators.requiredField(value, "code"),
|
|
inputFormatters: [
|
|
// This line now allows letters, numbers, hyphens, and underscores
|
|
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9\-_ ]')),
|
|
],
|
|
txtwidth: MediaQuery.of(context).size.width * 0.15,
|
|
borderColor: Color(0xFFE2E8F0),
|
|
highlightColor: Color(0xFF50A398),
|
|
// txtheight: 30,
|
|
isdense: true,
|
|
errFieldHgt: 0,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
static final _textStyle = GoogleFonts.inter(
|
|
fontSize: 11,
|
|
fontWeight: FontWeight.w600,
|
|
);
|
|
}
|