post_enrollment_app/lib/pages/postEnrollment/AddPolicyScreen.dart
2026-04-08 09:11:24 +05:30

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');
}
},
),
),
);
}
}