393 lines
14 KiB
Dart
Executable File
393 lines
14 KiB
Dart
Executable File
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:jwt_decode/jwt_decode.dart';
|
|
import 'package:nhance_app_pwa/pages/postEnrollment/service/api_service.dart';
|
|
|
|
import '../../customAppBar/customAppBar.dart';
|
|
import '../../customAppBar/customFooter.dart';
|
|
import '../../customAppBar/responsive.dart';
|
|
import '../../customAppBar/tabs.dart';
|
|
import '../../customAppBar/toastHelper.dart';
|
|
import '../service/SessionManager.dart';
|
|
import '../service/TokenService.dart';
|
|
|
|
import 'package:nhance_app_pwa/logger.dart';
|
|
|
|
class AddPolicyScreen extends StatefulWidget {
|
|
const AddPolicyScreen({super.key});
|
|
|
|
@override
|
|
State<AddPolicyScreen> createState() => _AddPolicyScreenState();
|
|
}
|
|
|
|
class _AddPolicyScreenState extends State<AddPolicyScreen> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
bool isLoading = false;
|
|
|
|
dynamic _token;
|
|
final session = SessionManager();
|
|
late ApiService apiService;
|
|
|
|
dynamic empCodeString;
|
|
dynamic empPrimaryId;
|
|
dynamic client_id;
|
|
dynamic mobileNo;
|
|
dynamic client_branch_id;
|
|
dynamic decodedToken;
|
|
|
|
// Form controllers
|
|
final TextEditingController policyNoController = TextEditingController();
|
|
final TextEditingController expDateController = TextEditingController();
|
|
|
|
String? selectedPolicyType;
|
|
String? selectedInsurer;
|
|
|
|
List<Map<String, dynamic>> policyTypeData = [];
|
|
List<Map<String, dynamic>> insurerData = [];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
apiService = ApiService(context);
|
|
_loadToken();
|
|
}
|
|
|
|
Future<void> _loadToken() async {
|
|
final String? token = await TokenService.getPostToken();
|
|
if (token != null && token.isNotEmpty) {
|
|
setState(() => _token = token);
|
|
|
|
decodedToken = Jwt.parseJwt(token);
|
|
mobileNo = session.mobileNo;
|
|
client_branch_id = session.empClientBranchId;
|
|
empCodeString = session.empCodeString;
|
|
empPrimaryId = session.empPrimaryId;
|
|
client_id = session.client_id;
|
|
|
|
getPolicyTypeAndInsurerMaster();
|
|
}
|
|
}
|
|
|
|
Future<void> pickExpiryDate() async {
|
|
DateTime today = DateTime.now();
|
|
|
|
DateTime? picked = await showDatePicker(
|
|
context: context,
|
|
initialDate: today.add(const Duration(days: 1)), // default tomorrow
|
|
firstDate: DateTime(today.year, today.month, today.day), // no past
|
|
lastDate: DateTime(2100),
|
|
);
|
|
|
|
if (picked != null) {
|
|
expDateController.text = DateFormat("dd MMM yyyy").format(picked);
|
|
setState(() {});
|
|
}
|
|
}
|
|
|
|
Future<void> getPolicyTypeAndInsurerMaster() async {
|
|
setState(() => isLoading = true);
|
|
|
|
try {
|
|
final response = await apiService.fetchPolicyTypeAndInsurer();
|
|
if (response['status'] == 'success') {
|
|
policyTypeData =
|
|
List<Map<String, dynamic>>.from(response['data']['policy_type']);
|
|
insurerData =
|
|
List<Map<String, dynamic>>.from(response['data']['insurer']);
|
|
|
|
setState(() => isLoading = false);
|
|
} else {
|
|
throw Exception('Failed to fetch master data');
|
|
}
|
|
} catch (error) {
|
|
logDebug('Error fetching list: $error');
|
|
}
|
|
}
|
|
|
|
Future<void> submitForm() async {
|
|
try {
|
|
if (_formKey.currentState!.validate()) {
|
|
setState(() => isLoading = true);
|
|
Map<String, dynamic> formData = {
|
|
'emp_id': empPrimaryId,
|
|
'policy_type_id': selectedPolicyType,
|
|
'insurer_id': selectedInsurer,
|
|
'policy_no': policyNoController.text,
|
|
'policy_end_date': expDateController.text,
|
|
'policy_start_date': '',
|
|
};
|
|
|
|
final response = await apiService.sendRetailPolicyDetails(formData);
|
|
|
|
if (response['status'] == 'success') {
|
|
ToastHelper.showSuccessToast(context, response['message']);
|
|
|
|
selectedPolicyType = null;
|
|
selectedInsurer = null;
|
|
policyNoController.clear();
|
|
expDateController.clear();
|
|
|
|
context.go('/home');
|
|
}
|
|
}
|
|
} catch (e) {
|
|
logDebug('Submit error: $e');
|
|
} finally {
|
|
if (mounted) {
|
|
setState(() => isLoading = false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// WIDGETS
|
|
// ------------------------------------------------------
|
|
|
|
Widget dropdownFieldMap({
|
|
required String? value,
|
|
required String hint,
|
|
required List<Map<String, dynamic>> items,
|
|
required String validatorMsg,
|
|
bool isMandatory = true,
|
|
required Function(String?) onChanged,
|
|
required String labelKey,
|
|
required String valueKey,
|
|
}) {
|
|
return DropdownButtonFormField<String>(
|
|
value: value,
|
|
decoration: inputDecoration(hint),
|
|
items: items.map((item) {
|
|
return DropdownMenuItem(
|
|
value: item[valueKey].toString(), // send ID
|
|
child: Text(item[labelKey].toString()), // show name
|
|
);
|
|
}).toList(),
|
|
validator: (value) {
|
|
if (!isMandatory) return null;
|
|
return value == null ? validatorMsg : null;
|
|
},
|
|
onChanged: onChanged,
|
|
);
|
|
}
|
|
|
|
TextStyle labelStyle() => GoogleFonts.poppins(
|
|
fontSize: 13,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.black87,
|
|
);
|
|
|
|
InputDecoration inputDecoration(String hint, {Widget? suffix}) {
|
|
return InputDecoration(
|
|
suffixIcon: suffix,
|
|
hintText: hint,
|
|
contentPadding: const EdgeInsets.all(14),
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(10),
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return PopScope(
|
|
canPop: false,
|
|
onPopInvokedWithResult: (didPop, result) {
|
|
if (didPop) return;
|
|
context.go('/home');
|
|
},
|
|
child: Scaffold(
|
|
backgroundColor: Colors.white,
|
|
appBar: CustomAppBar(),
|
|
body: Stack(children: [
|
|
SingleChildScrollView(
|
|
child: Container(
|
|
padding: Responsive.isDesktop(context)
|
|
? EdgeInsets.symmetric(
|
|
horizontal: MediaQuery.of(context).size.width * 0.2,
|
|
vertical: MediaQuery.of(context).size.height * 0.05,
|
|
)
|
|
: const EdgeInsets.all(10),
|
|
color: Colors.white,
|
|
child: Column(children: [
|
|
Card(
|
|
elevation: 5,
|
|
color: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(15)),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(15),
|
|
child: Column(
|
|
children: [
|
|
Row(
|
|
children: [
|
|
InkWell(
|
|
onTap: () => context.go('/home'),
|
|
child: const Icon(Icons.chevron_left, size: 30),
|
|
),
|
|
const SizedBox(width: 10),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text("Add Your Insurance Policy",
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
)),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
'Add and manage all your insurance policies taken anywhere for value added services and renewal reminders',
|
|
maxLines: 3,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: GoogleFonts.poppins(fontSize: 12),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
/// FORM
|
|
Form(
|
|
key: _formKey,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text("Type of Policy", style: labelStyle()),
|
|
const SizedBox(height: 5),
|
|
dropdownFieldMap(
|
|
value: selectedPolicyType,
|
|
hint: "Select policy type",
|
|
items: policyTypeData,
|
|
validatorMsg: "Please select a policy type",
|
|
labelKey: "policy_type",
|
|
valueKey: "policy_type_id",
|
|
onChanged: (val) =>
|
|
setState(() => selectedPolicyType = val),
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
Text("Insurer", style: labelStyle()),
|
|
const SizedBox(height: 5),
|
|
dropdownFieldMap(
|
|
value: selectedInsurer,
|
|
hint: "Select insurer",
|
|
items: insurerData,
|
|
validatorMsg: "Please select an insurer",
|
|
labelKey: "insurer_name",
|
|
valueKey: "insurer_id",
|
|
onChanged: (val) =>
|
|
setState(() => selectedInsurer = val),
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
Text("Policy Number", style: labelStyle()),
|
|
const SizedBox(height: 5),
|
|
TextFormField(
|
|
controller: policyNoController,
|
|
decoration:
|
|
inputDecoration("Enter policy number"),
|
|
validator: (value) => null, // NOT MANDATORY
|
|
),
|
|
const SizedBox(height: 20),
|
|
|
|
Text("Expiry Date", style: labelStyle()),
|
|
const SizedBox(height: 5),
|
|
GestureDetector(
|
|
onTap: pickExpiryDate,
|
|
child: AbsorbPointer(
|
|
child: TextFormField(
|
|
controller: expDateController,
|
|
decoration: inputDecoration(
|
|
"Select expiry date",
|
|
suffix: const Icon(Icons.calendar_month),
|
|
),
|
|
validator: (value) => value == null ||
|
|
value.isEmpty
|
|
? "Expiry date required"
|
|
: null,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 30),
|
|
|
|
SizedBox(
|
|
width: double.infinity,
|
|
height: 50,
|
|
child: ElevatedButton(
|
|
onPressed: submitForm,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: const Color(0xFFE26828),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(10),
|
|
),
|
|
),
|
|
child: Text(
|
|
"Save Policy",
|
|
style: GoogleFonts.poppins(
|
|
fontSize: 16,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 60),
|
|
]),
|
|
),
|
|
),
|
|
|
|
if (isLoading)
|
|
Container(
|
|
color: Colors.white70,
|
|
child: Center(
|
|
child: Image.asset(
|
|
'assets/nhance-loader.gif',
|
|
height: 60,
|
|
width: 60,
|
|
),
|
|
),
|
|
),
|
|
|
|
if (Responsive.isDesktop(context))
|
|
Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: SizedBox(
|
|
width: double.infinity, child: CustomFooter())),
|
|
]),
|
|
bottomNavigationBar: Responsive.isDesktop(context)
|
|
? null
|
|
: CustomBottomNavigationBar(
|
|
icons: [
|
|
Icons.home_outlined,
|
|
Icons.sticky_note_2_outlined,
|
|
Icons.question_answer_outlined,
|
|
Icons.person_outline_outlined,
|
|
Icons.headset_mic_outlined,
|
|
],
|
|
labels: ["Home", "Claims", "FAQs", "Profile", "Help"],
|
|
initialIndex: 0,
|
|
onTabChanged: (index) {
|
|
if (index == 0) context.go('/home');
|
|
if (index == 1) context.go('/claims');
|
|
if (index == 2) context.go('/faqs');
|
|
if (index == 3) context.go('/profile');
|
|
if (index == 4) {context.push('/help');
|
|
}
|
|
},
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|