claims and chatbot changes done

This commit is contained in:
Surendiran 2025-09-12 15:59:43 +05:30
parent 22b6b6750c
commit 6641314af0
32 changed files with 1642 additions and 733 deletions

11
.env
View File

@ -1,7 +1,6 @@
API_URL=https://venbait.in/nhance/dev/employeeRest/
#CHAT_BOT_URL=https://venbait.in/nhance/dev
API_URL_Enrollment=https://venbait.in/enrollment/employeeRest/
TICKET_API_URL=https://venbait.in/nhance/dev/api
API_URL=https://app.nhanceindia.in/zenith/employeeRest/
API_URL_Enrollment=https://app.nhanceindia.in/enrolment/employeeRest/
TICKET_API_URL=https://app.nhanceindia.in/zenith/api
ticketToken=3YTSia2mRoZ7A4zvBgkqbGPrCd6Ewp8IDOuyjXhVFsl1nxWNcQJ95MeUftKH
BASE_HREF=/nhance/app/dev/
ENV=development
BASE_HREF=/app/
ENV=production

View File

@ -1,7 +1,6 @@
API_URL=https://venbait.in/nhance/dev/employeeRest/
#CHAT_BOT_URL=https://venbait.in/nhance/dev
API_URL_Enrollment=https://venbait.in/enrollment/employeeRest/
TICKET_API_URL=https://venbait.in/nhance/dev/api
API_URL=https://app.nhanceindia.in/zenith/employeeRest/
API_URL_Enrollment=https://app.nhanceindia.in/enrolment/employeeRest/
TICKET_API_URL=https://app.nhanceindia.in/zenith/api
ticketToken=3YTSia2mRoZ7A4zvBgkqbGPrCd6Ewp8IDOuyjXhVFsl1nxWNcQJ95MeUftKH
BASE_HREF=/nhance/app/dev/
ENV=development
BASE_HREF=/app/
ENV=production

View File

@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
revision: "300451adae589accbece3490f4396f10bdf15e6e"
revision: "05db9689081f091050f01aed79f04dce0c750154"
channel: "stable"
project_type: app
@ -13,26 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 300451adae589accbece3490f4396f10bdf15e6e
base_revision: 300451adae589accbece3490f4396f10bdf15e6e
- platform: android
create_revision: 300451adae589accbece3490f4396f10bdf15e6e
base_revision: 300451adae589accbece3490f4396f10bdf15e6e
- platform: ios
create_revision: 300451adae589accbece3490f4396f10bdf15e6e
base_revision: 300451adae589accbece3490f4396f10bdf15e6e
- platform: linux
create_revision: 300451adae589accbece3490f4396f10bdf15e6e
base_revision: 300451adae589accbece3490f4396f10bdf15e6e
- platform: macos
create_revision: 300451adae589accbece3490f4396f10bdf15e6e
base_revision: 300451adae589accbece3490f4396f10bdf15e6e
create_revision: 05db9689081f091050f01aed79f04dce0c750154
base_revision: 05db9689081f091050f01aed79f04dce0c750154
- platform: web
create_revision: 300451adae589accbece3490f4396f10bdf15e6e
base_revision: 300451adae589accbece3490f4396f10bdf15e6e
- platform: windows
create_revision: 300451adae589accbece3490f4396f10bdf15e6e
base_revision: 300451adae589accbece3490f4396f10bdf15e6e
create_revision: 05db9689081f091050f01aed79f04dce0c750154
base_revision: 05db9689081f091050f01aed79f04dce0c750154
# User provided section

View File

@ -64,7 +64,7 @@ android {
applicationId "nh.ind.nhance.benefits"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 23
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

View File

@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
<string>13.0</string>
</dict>
</plist>

View File

@ -13,7 +13,6 @@ import 'package:nhance_app_pwa/pages/postEnrollment/botman_widget.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/chatbot.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/claimprocess.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/claims.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/claimtracklist.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/generalexclusionsdeductibles.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/help.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/home.dart';
@ -21,8 +20,10 @@ import 'package:nhance_app_pwa/pages/postEnrollment/planclaimsform.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/policies.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/privacypolicy.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/profile.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/raisedTicketList.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/termsofuse.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/tickets.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/tickettracklist.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/wellness.dart';
import 'package:nhance_app_pwa/pages/session/SetPinBiometric.dart';
import 'package:nhance_app_pwa/pages/session/changePin.dart';
@ -99,14 +100,33 @@ Future<void> main() async {
await dotenv.load(fileName: Environment.fileName);
runApp(MyApp());
// Get prefs
final prefs = await SharedPreferences.getInstance();
// Decide initialRoute
String initialRoute = 'login';
if (!kIsWeb) {
if (prefs.containsKey('is_mpin_skipped')) {
final isMpinSkipped = prefs.getString('is_mpin_skipped');
if (isMpinSkipped == '0') {
initialRoute = 'pinPage';
}
}
}
runApp(MyApp(initialRoute: initialRoute));
}
class MyApp extends StatelessWidget {
final String initialRoute;
const MyApp({super.key, required this.initialRoute});
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: 'login',
// initialRoute: 'login',
initialRoute: initialRoute,
debugShowCheckedModeBanner: false,
routes: {
'splash': (context) => SplashScreen(),
@ -131,7 +151,7 @@ class MyApp extends StatelessWidget {
'profile': (context) => profile(),
'wellness': (context) => wellness(),
'planclaimsform': (context) => planclaimsform(),
'claimtracklist': (context) => claimtracklist(
'tickettracklist': (context) => tickettracklist(
ticketID: "",
),
'privacypolicy': (context) => privacypolicy(),
@ -155,6 +175,7 @@ class MyApp extends StatelessWidget {
'addOnsDetails': (context) => addOnsDetails(),
'empReviewDetails': (context) => empReviewDetails(),
'tickets': (context) => tickets(),
'raisedTicketHistory': (context) => raisedTicketHistory(),
},
);
}

View File

@ -1875,7 +1875,7 @@ class _addOnsDetailsState extends State<addOnsDetails> {
color: Colors.white,
child: Container(
width: double.infinity,
height: 75,
height: 80,
padding: Responsive.isDesktop(context)
? EdgeInsets.only(
top: 20, bottom: 20, left: 30, right: 30)
@ -1889,13 +1889,13 @@ class _addOnsDetailsState extends State<addOnsDetails> {
Expanded(
flex: 6,
child: Container(
width: 150,
height: 150,
width: 200,
height: 200,
alignment: Alignment.centerLeft,
child: Image.network(
clientLogo ?? '',
width: 80, // Set the width here
height: 80, // Set the height here
// width: 200, // Set the width here
// height: 200, // Set the height here
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent? loadingProgress) {
@ -1903,13 +1903,13 @@ class _addOnsDetailsState extends State<addOnsDetails> {
return Center(
child: CircularProgressIndicator(
value:
loadingProgress.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
loadingProgress
.expectedTotalBytes!
: null,
loadingProgress.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
loadingProgress
.expectedTotalBytes!
: null,
),
);
},

View File

@ -680,7 +680,7 @@ class _empDetailsState extends State<empDetails> {
color: Colors.white,
child: Container(
width: double.infinity,
height: 75,
height: 80,
padding: Responsive.isDesktop(context)
? EdgeInsets.only(
top: 20, bottom: 20, left: 30, right: 30)
@ -694,13 +694,13 @@ class _empDetailsState extends State<empDetails> {
Expanded(
flex: 6,
child: Container(
width: 150,
height: 150,
width: 200,
height: 200,
alignment: Alignment.centerLeft,
child: Image.network(
clientLogo ?? '',
width: 80, // Set the width here
height: 80, // Set the height here
// width: 200, // Set the width here
// height: 200, // Set the height here
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent? loadingProgress) {

View File

@ -1395,7 +1395,7 @@ class _empReviewDetailsState extends State<empReviewDetails> {
color: Colors.white,
child: Container(
width: double.infinity,
height: 75,
height: 80,
padding: Responsive.isDesktop(context)
? EdgeInsets.only(
top: 20, bottom: 20, left: 30, right: 30)
@ -1409,13 +1409,13 @@ class _empReviewDetailsState extends State<empReviewDetails> {
Expanded(
flex: 6,
child: Container(
width: 150,
height: 150,
width: 200,
height: 200,
alignment: Alignment.centerLeft,
child: Image.network(
clientLogo ?? '',
width: 80, // Set the width here
height: 80, // Set the height here
// width: 200, // Set the width here
// height: 200, // Set the height here
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent? loadingProgress) {
@ -1423,13 +1423,13 @@ class _empReviewDetailsState extends State<empReviewDetails> {
return Center(
child: CircularProgressIndicator(
value:
loadingProgress.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
loadingProgress
.expectedTotalBytes!
: null,
loadingProgress.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
loadingProgress
.expectedTotalBytes!
: null,
),
);
},

View File

@ -43,7 +43,7 @@ class _loginState extends State<login> {
void initState() {
countryController.text = "+91";
super.initState();
checkLoginPinOnMobile();
// checkLoginPinOnMobile();
}
Future<void> checkLoginPinOnMobile() async {

View File

@ -1,83 +1,6 @@
// import 'package:flutter/material.dart';
// import 'package:webview_flutter/webview_flutter.dart';
//
// class BotmanChatPage extends StatefulWidget {
// const BotmanChatPage({super.key});
//
// @override
// State<BotmanChatPage> createState() => _BotmanChatPageState();
// }
//
// class _BotmanChatPageState extends State<BotmanChatPage> {
// late final WebViewController _controller;
//
// @override
// void initState() {
// super.initState();
//
// _controller = WebViewController()
// ..setJavaScriptMode(JavaScriptMode.unrestricted)
// ..loadHtmlString(_htmlContent);
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: AppBar(title: const Text('Ask ILA')),
// body: WebViewWidget(controller: _controller),
// );
// }
// }
//
// const String _htmlContent = '''
// <!DOCTYPE html>
// <html lang="en">
// <head>
// <meta charset="UTF-8" />
// <meta name="viewport" content="width=device-width, initial-scale=1.0" />
// <style>
// html, body {
// margin: 0;
// padding: 0;
// height: 100%;
// }
// #botmanWidgetRoot svg {
// display: none !important;
// }
// </style>
// <script>
// const APIENDPOINT = 'https://venbait.in/nhance/chatbot';
// const APIAPIENDPOINT = 'https://venbait.in/nhance/chatbot';
//
// window.botmanWidget = {
// chatServer: APIENDPOINT + '/chat',
// frameEndpoint: APIAPIENDPOINT + '/widget',
// title: 'Ask ILA',
// introMessage: 'Hai Suren',
// bubbleBackground: '#007bff',
// mainColor: '#007bff',
// placeholderText: 'Type your message here...',
// aboutText: 'Insurance Assistant ILA',
// enableAttachments: false,
// parameters: {
// employee_id: '12288',
// session_id: 'XYZ789',
// origin: 'mobile',
// emp_code: 'HTL-007',
// client_id: 159,
// client_branch_id: 125,
// },
// };
// </script>
// <script src="https://cdn.jsdelivr.net/npm/botman-web-widget@0/build/js/widget.js"></script>
// </head>
// <body>
// </body>
// </html>
// ''';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
class ChatbotWebViewPage extends StatefulWidget {
final String client_branch_id;
@ -105,11 +28,42 @@ class _ChatbotWebViewPageState extends State<ChatbotWebViewPage> {
@override
void initState() {
super.initState();
final url = Uri.parse(
'https://venbait.in/nhance/dev/chatbot'
'?employee_id=${widget.empPrimaryId}'
'&emp_code=${widget.empCodeString}'
'&origin=mob'
'&name=${widget.empName}'
'&client_id=${widget.client_id}'
'&client_branch_id=${widget.client_branch_id}',
);
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadRequest(
Uri.parse('https://venbait.in/nhance/dev/chatbot?employee_id=${widget.empPrimaryId}&emp_code=${widget.empCodeString}&origin=mob&name=${widget.empName}&client_id=${widget.client_id}&client_branch_id=${widget.client_branch_id}'),
);
..setBackgroundColor(Colors.transparent)
..setNavigationDelegate(
NavigationDelegate(
onNavigationRequest: (NavigationRequest request) {
debugPrint("Clicked URL: ${request.url}");
_launchInExternalBrowser(Uri.parse(request.url));
return NavigationDecision.prevent; // prevent WebView navigation
},
onWebResourceError: (error) {
debugPrint("WebView error: ${error.description}");
},
),
)
..loadRequest(url);
}
/// Launch URL in external browser (Chrome or default)
Future<void> _launchInExternalBrowser(Uri url) async {
if (await canLaunchUrl(url)) {
await launchUrl(url, mode: LaunchMode.externalApplication);
} else {
debugPrint("Could not launch $url");
}
}
@override

View File

@ -733,6 +733,7 @@ class _claimsState extends State<claims> {
String policyEndDate = item['policy_end_date'];
String policyNo = item['policy_no'];
String clientPolicyId = item['client_policy_id'];
String sumInsuredLabel = item['sum_insured_label'];
List<dynamic> employeePolicy = item['EmployeePolicy'];
return GestureDetector(
@ -835,7 +836,7 @@ class _claimsState extends State<claims> {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'Cover Amount',
sumInsuredLabel ?? '',
textAlign: TextAlign.end,
style: GoogleFonts.poppins(
fontSize:
@ -1098,7 +1099,7 @@ class _claimsState extends State<claims> {
DateTime date = DateTime.parse(timestamp);
// Format the DateTime object with date and time
String formattedDate = DateFormat('d MMM, y HH:mm a').format(date);
String formattedDate = DateFormat('d MMM y hh:mm a').format(date);
return formattedDate;
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/service/api_service.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../customAppBar/responsive.dart';
@ -37,6 +38,29 @@ class _ClaimHistoryPopupState extends State<ClaimHistoryPopup> {
late Map<String, dynamic> stepMap;
int _index = 4;
bool isLoading = false;
List<dynamic> claimFiles = [];
// final List<Map<String, dynamic>> claimFiles = [
// {
// "claim_file_id": "23",
// "claim_file_name": "1757420176_c2c92a7393b75677a5bb.png",
// "url": "https://venbait.in/nhance/dev/downloadClaimFile/23"
// },
// {
// "claim_file_id": "24",
// "claim_file_name": "1757420176_7ff43ded77125ae390d0.png",
// "url": "https://venbait.in/nhance/dev/downloadClaimFile/24"
// },
// {
// "claim_file_id": "25",
// "claim_file_name": "1757420176_193139b931f3bbf792f2.png",
// "url": "https://venbait.in/nhance/dev/downloadClaimFile/25"
// },
// {
// "claim_file_id": "26",
// "claim_file_name": "1757420176_f66188d9ebf2580ed0f1.png",
// "url": "https://venbait.in/nhance/dev/downloadClaimFile/26"
// }
// ];
@override
void initState() {
@ -73,6 +97,11 @@ class _ClaimHistoryPopupState extends State<ClaimHistoryPopup> {
setState(() {
isLoading = false;
print('Claims History List1');
final claimsDocs = response['data']['claim_files'];
print("TC1 - $claimsDocs");
claimFiles = List<Map<String, dynamic>>.from(claimsDocs);
print('claimFiles $claimFiles');
// final List<dynamic> ticketDataList = response['data']['ticket_data'];
// final Map<String, dynamic> ticketDataMap =
// response['data']['ticket_data'];
@ -136,6 +165,18 @@ class _ClaimHistoryPopupState extends State<ClaimHistoryPopup> {
}
}
Future<void> _launchURL(String url) async {
final Uri uri = Uri.parse(url); // Parse the URL properly
print('_launchURL $uri');
if (uri != null) {
print('If $uri');
await launchUrl(uri, mode: LaunchMode.externalApplication);
} else {
print('else $uri');
throw 'Could not launch $url';
}
}
@override
Widget build(BuildContext context) {
// if (getClaimsHistoryList.isEmpty) {
@ -428,6 +469,30 @@ class _ClaimHistoryPopupState extends State<ClaimHistoryPopup> {
)),
),
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: claimFiles.isEmpty
? const Center(child: Text("No files available"))
: SizedBox( // Give ListView a fixed height
height: 300,
child: ListView.builder(
itemCount: claimFiles.length,
itemBuilder: (context, index) {
final file = claimFiles[index];
return Card(
child: ListTile(
leading: const Icon(Icons.insert_drive_file, color: Colors.blue),
title: Text(file['claim_file_name']),
trailing: const Icon(Icons.download, color: Colors.green),
onTap: () => _launchURL(file['url']),
),
);
},
),
),
)
],
),
),

File diff suppressed because it is too large Load Diff

View File

@ -83,9 +83,9 @@ class _HomeState extends State<Home> {
if (kIsWeb) {
openBotmanChat();
setupBackButtonHandler(() {
if (!_dialogShown) _showBackConfirmationDialog();
});
// setupBackButtonHandler(() {
// if (!_dialogShown) _showBackConfirmationDialog();
// });
// Push a dummy state so back button triggers popstate instead of navigating
// html.window.history.pushState(null, 'home', html.window.location.href);
@ -922,7 +922,7 @@ class _HomeState extends State<Home> {
String memberNames = getMemberNames(employeePolicy);
DateTime parsedDate = DateFormat('dd-MMM-yyyy').parse(policyEndDate);
String formattedDate = DateFormat('d MMM, yyyy').format(parsedDate);
String formattedDate = DateFormat('d MMM yyyy').format(parsedDate);
return GestureDetector(
onTap: () {

View File

@ -1,17 +1,24 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.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/customAppBar/customAppBar.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/claimtracklist.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/service/api_service.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/service/file_upload_service.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/service/multi_file_upload_widget.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../customAppBar/customFooter.dart';
import '../../customAppBar/responsive.dart';
import '../../customAppBar/tabs.dart';
import '../../customAppBar/toastHelper.dart';
import 'package:http/http.dart' as http;
// import 'package:universal_html/html.dart' as html;
import '../../models/environment.dart';
import 'package:file_picker/file_picker.dart';
class planclaimsform extends StatefulWidget {
const planclaimsform({Key? key}) : super(key: key);
@ -46,6 +53,7 @@ class _planclaimsformState extends State<planclaimsform> {
String? selectedServiceName;
String? selectedPolicyNo;
dynamic claimsDepartmentId;
dynamic claimSubject;
dynamic rawPolicyStartDate;
dynamic rawPolicyEndDate;
dynamic claimsPolicyNo;
@ -55,6 +63,12 @@ class _planclaimsformState extends State<planclaimsform> {
dynamic client_policy_id;
dynamic selfDetails;
List<Map<String, dynamic>> employeePolicyList = [];
String? selectedFileNames;
// html.File? uploadedFile;
// List<html.File> uploadedFiles = [];
List<PlatformFile> uploadedFiles = [];
final fileService = FileUploadService();
// Declare subjectController and bodyController as instance variables
late TextEditingController subjectController;
@ -100,6 +114,7 @@ class _planclaimsformState extends State<planclaimsform> {
@override
void initState() {
super.initState();
fileService.clearAll();
subjectController = TextEditingController();
messageController = TextEditingController();
accidentDetailsController = TextEditingController();
@ -118,6 +133,7 @@ class _planclaimsformState extends State<planclaimsform> {
@override
void dispose() {
// Dispose the controllers to avoid memory leaks
subjectController.dispose();
messageController.dispose();
@ -151,6 +167,8 @@ class _planclaimsformState extends State<planclaimsform> {
print('fromClaimsPage $fromClaimsPage');
}
if (fromClaimsPage == 0) {
claimSubject = claimsDetails['claim_subject'];
print('claimSubject $claimSubject');
claimsDepartmentId = claimsDetails['ticket_type_id'];
rawPolicyStartDate = claimsDetails['policy_start_date'];
print('rawPolicyStartDate $rawPolicyStartDate');
@ -163,6 +181,7 @@ class _planclaimsformState extends State<planclaimsform> {
// print('employeePolicyList : $employeePolicyList');
List<dynamic> empList = claimsDetails['EmployeePolicy'];
setState(() {
subjectController.text = claimSubject;
employeePolicyList = empList.map((memberList) {
return {
'id': int.parse(memberList['id']),
@ -303,7 +322,7 @@ class _planclaimsformState extends State<planclaimsform> {
isLoading = true;
});
try {
final response = await apiService.fetchDepartmentList();
final response = await apiService.fetchDepartmentList(client_id!, empCodeString!);
print(response);
if (response['ticket_type'] != null) {
print(response['ticket_type']);
@ -364,6 +383,7 @@ class _planclaimsformState extends State<planclaimsform> {
'id': index + 1, // Use index + 1 as a unique ID
'policy_start_date' : policy['policy_start_date'],
'claims_grace_date' : policy['claims_grace_date'],
'claim_subject' : policy['claim_subject'],
};
}).toList();
@ -445,6 +465,8 @@ class _planclaimsformState extends State<planclaimsform> {
print('Filtered matching policy_no: $filteredPoliciesList');
client_policy_id = filteredPoliciesList[0]['client_policy_id'];
subjectController.text = filteredPoliciesList[0]['claim_subject'];
if (filteredPoliciesList.isNotEmpty) {
// Assuming you need to access the first matched policy
@ -525,7 +547,7 @@ class _planclaimsformState extends State<planclaimsform> {
// print('Help $filteredPoliciesList');
try {
print('Check One');
Map<String, dynamic> formData = {
Map<String, dynamic> fields = {
// 'opener': 'user',
'emp_id': emp_id,
'client_policy_id': client_policy_id,
@ -578,13 +600,13 @@ class _planclaimsformState extends State<planclaimsform> {
// formData['emp_policy_id'] = selectedMemberId;
// } else
if (policyTypeCondition == 1) {
formData['hospital_name'] = hospitalNameController.text;
formData['doa'] = admitDateController.text;
formData['dod'] = dischargeDateController.text;
formData['claim_amount'] = claimAmountController.text;
formData['policyholder_name'] = employeePolicyList[0]['name'];
formData['member_name'] = selectedMemberName;
formData['insured_emp_id'] = selectedMemberId;
fields['hospital_name'] = hospitalNameController.text;
fields['doa'] = admitDateController.text;
fields['dod'] = dischargeDateController.text;
fields['claim_amount'] = claimAmountController.text;
fields['policyholder_name'] = employeePolicyList[0]['name'];
fields['member_name'] = selectedMemberName;
fields['insured_emp_id'] = selectedMemberId;
} else {
String formattedAccidentDate =
DateFormat('yyyy-MM-dd').format(accidentDate!);
@ -594,23 +616,73 @@ class _planclaimsformState extends State<planclaimsform> {
DateFormat('yyyy-MM-dd').format(intimationDate!);
// formData['accident_details'] = accidentDetailsController.text;
// formData['accident_details'] = messageController.text;
formData['date_of_accident'] = formattedAccidentDate;
formData['dob'] = formattedBirthDate;
formData['date_of_intimat'] = formattedIntimationDate;
formData['date_of_death'] = formattedDeathDate;
formData['si_amt'] = sumInsuredController.text;
formData['policyholder_name'] = employeePolicyList[0]['name'];
formData['member_name'] = selectedMemberName;
formData['insured_emp_id'] = selectedMemberId;
fields['date_of_accident'] = formattedAccidentDate;
fields['dob'] = formattedBirthDate;
fields['date_of_intimat'] = formattedIntimationDate;
fields['date_of_death'] = formattedDeathDate;
fields['si_amt'] = sumInsuredController.text;
fields['policyholder_name'] = employeePolicyList[0]['name'];
fields['member_name'] = selectedMemberName;
fields['insured_emp_id'] = selectedMemberId;
}
// Convert integer values to strings
formData = formData.map((key, value) => MapEntry(key, value.toString()));
// Multipart request
final response = await apiService.sendFormDataToApi(formData);
// final request = http.MultipartRequest('POST', Uri.parse('${Environment.apiUrl}/initiateClaim'));
// request.headers['Authorization'] = 'Bearer $_token';
// final stringFields = fields.map((key, value) => MapEntry(key, value?.toString() ?? ''));
// request.fields.addAll(stringFields);
//
// if (uploadedFile != null) {
// final reader = html.FileReader();
// reader.readAsArrayBuffer(uploadedFile!);
// await reader.onLoad.first;
//
// final data = reader.result as Uint8List;
//
// request.files.add(http.MultipartFile.fromBytes(
// 'claim_docs',
// data,
// filename: uploadedFile!.name,
// ));
// }
if (response['status'] == true) {
ToastHelper.showSuccessToast(context, response['message']);
final request = http.MultipartRequest('POST', Uri.parse('${Environment.apiUrl}/initiateClaim'));
request.headers['Authorization'] = 'Bearer $_token';
final stringFields = fields.map((key, value) => MapEntry(key, value?.toString() ?? ''));
request.fields.addAll(stringFields);
// 🔥 Loop through multiple files
// for (var file in uploadedFiles) {
// final reader = html.FileReader();
// reader.readAsArrayBuffer(file);
// await reader.onLoad.first;
// final data = reader.result as Uint8List;
//
// request.files.add(http.MultipartFile.fromBytes(
// 'claim_docs[]', // 👈 if backend expects array
// data,
// filename: file.name,
// ));
// }
uploadedFiles = FileUploadService().files;
print("Files available globally: ${uploadedFiles.map((f) => f.name).toList()}");
for (var file in uploadedFiles) {
if (file.bytes != null) {
request.files.add(http.MultipartFile.fromBytes(
'claim_docs[]',
file.bytes!,
filename: file.name,
));
}
}
final response = await request.send();
final responseBody = await response.stream.bytesToString();
final decoded = jsonDecode(responseBody);
if (decoded['status'] == true) {
ToastHelper.showSuccessToast(context, decoded['message']);
serviceId = null;
departmentList.clear();
setState(() {
@ -618,14 +690,18 @@ class _planclaimsformState extends State<planclaimsform> {
});
Navigator.pushNamed(context, 'claims');
print('Form data submitted successfully');
fileService.clearAll();
} else {
print('Failed to submit form data: ${response['status']}');
ToastHelper.showErrorToast(context, "Failed: ${decoded['message']}");
}
} catch (e) {
print('Error submitting form data: $e');
}
}
Future<void> _pickDate(BuildContext context, String label) async {
final DateTime? pickedDate = await showDatePicker(
context: context,
@ -661,14 +737,15 @@ class _planclaimsformState extends State<planclaimsform> {
setState(() {
admitDate = pickedDateRange.start;
dischargeDate = pickedDateRange.end;
admitDateController.text = DateFormat('yyyy-MM-dd').format(admitDate!);
admitDateController.text = DateFormat('dd-MM-yyyy').format(admitDate!);
dischargeDateController.text =
DateFormat('yyyy-MM-dd').format(dischargeDate!);
DateFormat('dd-MM-yyyy').format(dischargeDate!);
});
}
}
// Future<void> _pickFromToDate(BuildContext context) async {
// final DateTimeRange? pickedDateRange = await showDateRangePicker(
// context: context,
@ -1026,10 +1103,10 @@ SizedBox(height: 15),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildTextField('Subject',
subjectController),
if (!isSubjectValid)
Text('Please enter the Subject', style: TextStyle(color: Colors.red)),
// buildTextField('Subject',
// subjectController),
// if (!isSubjectValid)
// Text('Please enter the Subject', style: TextStyle(color: Colors.red)),
SizedBox(height: 15),
buildTextAreaField(
'Message',
@ -1157,7 +1234,28 @@ SizedBox(height: 15),
),
]
),
SizedBox(height: 15),
// ThemedUploadField(
// hintText: "Upload Documents",
// txtwidth: MediaQuery.of(context).size.width < 600
// ? MediaQuery.of(context).size.width // Full width on mobile
// : MediaQuery.of(context).size.width * 0.26, // 26% on desktop
// txtheight: 45,
// onFilesSelected: (files) {
// print("Picked files: ${files.map((f) => f.name).toList()}");
// setState(() {
// uploadedFiles = files; // store all selected files
// });
// },
// ),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const MultiFileUploadWidget(),
],
),
),
],
),
),
@ -1270,7 +1368,8 @@ SizedBox(height: 15),
"Profile",
"Help",
"Wellness",
], // Initial index of the bottom navigation bar
],
initialIndex: 1,// Initial index of the bottom navigation bar
),
);
}
@ -1336,7 +1435,7 @@ SizedBox(height: 15),
),
child: Text(
selectedDate != null
? DateFormat('yyyy-MM-dd').format(selectedDate)
? DateFormat('dd-MM-yyyy').format(selectedDate)
: 'Select $label',
style: TextStyle(color: Colors.black),
),

View File

@ -92,7 +92,7 @@ class _policiesState extends State<policies> {
String convertDateFormat(String date) {
// Define input and output date formats
DateFormat inputFormat = DateFormat('dd-MMM-yyyy');
DateFormat outputFormat = DateFormat('d MMM, yyyy');
DateFormat outputFormat = DateFormat('d MMM yyyy');
// Parse the input date string
DateTime parsedDate = inputFormat.parse(date);
@ -1034,7 +1034,7 @@ class _policiesState extends State<policies> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
buildExpandedColumn(
context, 'Cover Amount', '${argumentsData['si_value']}'),
context, argumentsData['sum_insured_label'], '${argumentsData['si_value']}'),
buildExpandedColumn(context, 'Policy No', argumentsData['policy_no']),
buildExpandedColumn(context, 'Policy Expiry',
convertDateFormat(argumentsData['policy_end_date'])),
@ -1058,7 +1058,7 @@ class _policiesState extends State<policies> {
mainAxisAlignment: MainAxisAlignment.start,
children: [
buildExpandedColumn(
context, 'Cover Amount', '${argumentsData['si_value']}'),
context, argumentsData['sum_insured_label'], '${argumentsData['si_value']}'),
buildExpandedColumn(context, 'Policy Expiry',
convertDateFormat(argumentsData['policy_end_date'])),
],

View File

@ -115,7 +115,7 @@ class _profileState extends State<profile> {
String convertDate(String dateString) {
DateTime date = DateTime.parse(dateString);
DateFormat formatter = DateFormat('dd MMMM, yyyy');
DateFormat formatter = DateFormat('dd MMM yyyy');
return formatter.format(date);
}
@ -169,15 +169,17 @@ class _profileState extends State<profile> {
final SharedPreferences prefs = await SharedPreferences.getInstance();
// Get the value of the mobile_number key
String? mobileNumber = prefs.getString('empMobileNo');
String? mailID = prefs.getString('empEmailid');
final isMpinSkipped = prefs.getString('is_mpin_skipped');
// bool? biometricStatus = prefs.getBool('biometricStatus') ?? false;
// int? skipStatus = prefs.getInt('skipStatus') ?? 1;
// Clear all keys
await prefs.clear();
print('Local Storage Clear');
print('Local Storage Clear');
// html.window.localStorage.clear();
// Re-set the mobile_number key
@ -192,10 +194,20 @@ class _profileState extends State<profile> {
// await prefs.setBool('biometricStatus', biometricStatus!);
// await prefs.setInt('skipStatus', skipStatus!);
}
await prefs.setString('is_mpin_skipped', isMpinSkipped!);
print('isMpinSkipped $isMpinSkipped');
if (isMpinSkipped != null && isMpinSkipped == '0') {
Navigator.pushReplacementNamed(context, 'pinPage');
} else {
Navigator.pushReplacementNamed(context, 'login');
}
} else {
ToastHelper.showSuccessToast(context, 'logout');
// Navigate to login page
Navigator.pushNamed(context, 'login');
}
ToastHelper.showSuccessToast(context, 'logout');
// Navigate to login page
Navigator.pushNamed(context, 'login');
// } else {
// final prefs = await SharedPreferences.getInstance();
// await prefs.clear();
@ -594,6 +606,7 @@ class _profileState extends State<profile> {
)
])),
SizedBox(height: 12),
if(Responsive.isMobile(context))
Container(
child: Row(
children: [

View File

@ -0,0 +1,586 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.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/customAppBar/customAppBar.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/service/api_service.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/service/svg_service.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/tickettracklist.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import '../../customAppBar/customFooter.dart';
import '../../customAppBar/responsive.dart';
import '../../customAppBar/tabs.dart';
import '../../customAppBar/toastHelper.dart';
class raisedTicketHistory extends StatefulWidget {
const raisedTicketHistory({Key? key}) : super(key: key);
@override
State<raisedTicketHistory> createState() => _raisedTicketHistoryState();
}
class _raisedTicketHistoryState extends State<raisedTicketHistory> {
bool isLoading = false;
late ApiService apiService;
int _currentIndex = 0;
dynamic _token;
dynamic decodedToken;
dynamic empCodeString;
dynamic empPrimaryId;
dynamic client_id;
dynamic empName;
dynamic policyList;
dynamic policyDataIsEmpty = 1;
dynamic trackClaimsIsEmpty = 1;
dynamic policyHeading;
dynamic policyName;
dynamic EmployeePolicy;
List<Map<String, String>> employeeDetails = [];
dynamic argumentsData;
dynamic empMobileNo;
List<dynamic> reversedClaimsList = [];
List<dynamic> trackClaimsList = [];
int trackClaimsActive = 1;
int yourPlanActive = 0;
int? serviceId;
dynamic client_branch_id;
dynamic mobileNo;
List<dynamic> reversedTicketList = [];
List<dynamic> ticketList = [];
final Map<String, Color> statusColors = {
'Open': Colors.green,
'In Progress': Colors.blue,
// 'Awaiting Reply': Colors.orange,
'Resolved': Colors.yellow,
'Closed': Colors.red,
};
@override
void initState() {
super.initState();
apiService = ApiService(context);
_loadToken();
}
@override
void dispose() {
super.dispose();
}
Future<void> _loadToken() async {
print('_loadToken');
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('_postToken');
if (token != null && token.isNotEmpty) {
setState(() {
_token = token;
});
// Decode the JWT token received from the API response
decodedToken = Jwt.parseJwt(token);
print(decodedToken);
mobileNo = decodedToken['mobile'];
client_branch_id = decodedToken['client_branch_id'];
empMobileNo = decodedToken['mobile'];
empName = decodedToken['name'];
empCodeString = prefs.getString('empCode');
print(empCodeString); // Check if emp_code is correct
empPrimaryId = prefs.getString('empPrimaryId');
client_id = prefs.getString('client_id');
print(client_id);
getTicketList();
} else {
// Token is empty or null, handle accordingly (e.g., navigate to login screen)
// For now, let's navigate to the login screen
ToastHelper.showErrorToast(context, 'Session Out');
Navigator.pushReplacementNamed(context, 'login');
}
}
Future<void> getTicketList() async {
if (client_id == null || empCodeString == null) {
return;
}
setState(() {
isLoading = true;
});
try {
print('check getTicketList 1');
final response = await apiService.getTicketListByMobile(empMobileNo!);
print('check getTicketList 2');
setState(() {
isLoading = false;
});
// if (response['success'] == true && response['data'] is List) {
setState(() {
ticketList = response['data'].toList();
print("TC1 - $ticketList");
reversedTicketList = List<Map<String, dynamic>>.from(ticketList);
reversedTicketList = List<Map<String, dynamic>>.from(ticketList);
print("TC2 - $ticketList");
// ticketList = reversedTicketList.reversed.toList();
ticketList = reversedTicketList.toList();
print("TC3 - $ticketList");
});
// }
// else if (response['status'] == "error" &&
// response['message'] == "No tickets found") {
// setState(() {
// ticketList = [];
// trackClaimsList = [];
// trackClaimsClosedList = [];
// });
// ToastHelper.showErrorToast(context, 'No tickets found');
// } else {
// setState(() {
// isLoading = false;
// });
// ToastHelper.showErrorToast(context, 'Something went wrong');
// print('API request failed with status: ${response['status']}');
// }
} catch (e) {
// ToastHelper.showErrorToast(context, 'Failed to load data');
print('Error in getTicketList: $e');
} finally {
if (mounted) {
setState(() {
isLoading = false;
});
}
}
}
String formatDate(String timestamp) {
// Convert the timestamp string to milliseconds
int milliseconds = int.parse(timestamp) * 1000;
// Create a DateTime object from milliseconds
DateTime date = DateTime.fromMillisecondsSinceEpoch(milliseconds);
// Format the DateTime object
String formattedDate = DateFormat('d MMM, y').format(date);
return formattedDate;
}
Color getStatusColor(String? policyStatus) {
if (policyStatus != null && statusColors.containsKey(policyStatus)) {
return statusColors[policyStatus]!;
} else {
return Color(0xFF000000); // Default color for policyStatus text
}
}
@override
Widget build(BuildContext context) {
return 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, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height *
0.03, // 5% of screen height as vertical padding
)
: EdgeInsets.all(10),
color: Colors.white,
child: Column(children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
flex: 12,
child: InkWell(
onTap: () {
Navigator.pushNamed(context, 'help');
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
Icons
.chevron_left, // Replace with your desired icon
color: Color(0xFF000000),
size: 30,
),
SizedBox(
width:
5), // Adjust space between icon and text
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Track Queries',
textAlign: TextAlign.start,
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color(0xFF000000),
),
),
Text(
'Manage your Queries',
textAlign: TextAlign.start,
style: GoogleFonts.poppins(
fontSize:
12, // Adjust the font size as needed
fontWeight: FontWeight.w400,
color: Color(0xFF000000),
),
),
],
),
],
),
),
),
],
),
// Add more rows as needed
],
),
),
SizedBox(height: 15),
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: generateClaimsTicketList(
ticketList), // Replace 'yourDataList' with your actual data list
),
),
SizedBox(height: Responsive.isDesktop(context) ? 40 : 70),
]),
)),
if (isLoading)
Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Center(
child: // Your GIF loader widget
Image.asset(
height: 60,
width: 60,
'assets/nhance-loader.gif'), // Adjust path to your GIF loader
),
),
if (Responsive.isDesktop(context))
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity, // Make the footer full width
child: CustomFooter(),
),
),
]),
// floatingActionButton: Responsive.isDesktop(context)
// ? null
// : FloatingActionButton(
// onPressed: () {
// Navigator.pushNamed(context, 'chatbot');
// },
// child: Icon(Icons.chat),
// ),
floatingActionButtonLocation: Responsive.isDesktop(context)
? null
: FloatingActionButtonLocation.miniEndFloat,
bottomNavigationBar: Responsive.isDesktop(context)
? null
: CustomBottomNavigationBar(
onTabChanged: (index) {
// Add your navigation logic here
// For example:
if (index == 0) {
Navigator.pushNamed(context, 'home');
} else if (index == 1) {
Navigator.pushNamed(context, 'claims');
} else if (index == 2) {
Navigator.pushNamed(context, 'profile');
} else if (index == 3) {
Navigator.pushNamed(context, 'help');
} else if (index == 4) {
Navigator.pushNamed(context, 'wellness');
}
},
icons: [
Icons.home_outlined,
Icons.sticky_note_2_outlined,
Icons.person_outline_outlined,
Icons.headset_mic_outlined,
Icons.health_and_safety_outlined,
],
labels: [
"Home",
"Claim",
"Profile",
"Help",
"Wellness",
],
initialIndex: 3, // Initial index of the bottom navigation bar
),
);
}
List<Widget> generateClaimsTicketList(List<dynamic> data) {
return [
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
var item = data[index];
// String claimsName = item['user_name'];
String claimsticket = item['thz_id'] ?? '';
String claimsSubject = item['subject'] ?? '';
String claimsDate = item['created_at'] ?? '';
String claimStatus = item['status'] ?? '';
String claimsDepartmentName = item['ticket_type'] ?? '';
// String claimsReplies = item['replies'];
// List<dynamic> messageList = item['message_list'];
print("item - $item");
print('generateTrackList');
print(claimsSubject);
print(claimsDate);
print(claimStatus);
print(claimsDepartmentName);
final Map<String, Color> statusColors = {
'Received': Colors.amber,
'Rejected': Colors.red,
'Cancelled': Colors.red,
'Returned': Colors.deepOrange,
'Closed': Colors.grey,
'Approved': Colors.green,
'Settled': Colors.lightBlueAccent,
'Under Process': Colors.brown,
};
// Determine the color based on the claimStatus
Color statusColor;
if (claimStatus != null) {
statusColor = statusColors[claimStatus!] ?? Color(0xFF979797);
} else {
statusColor = Color(0xFF979797); // Default color if status is null
}
final truncatedSubject = Responsive.isDesktop(context)
? (claimsSubject.length > 30
? '${claimsSubject.substring(0, 30)}...'
: claimsSubject)
: (claimsSubject.length > 15
? '${claimsSubject.substring(0, 10)}...'
: claimsSubject);
return GestureDetector(
onTap: () {
print("Navigating with thz_id: ${item['thz_id']}");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
tickettracklist(ticketID: item['thz_id']),
),
);
// Navigator.pushNamed(
// context,
// 'claimtracklist',
// arguments: item['thz_id'],
// );
},
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Card(
elevation: 0,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Color(0xFFD9D9D9), // Set the border color here
width: 1.0, // Set the border width here
),
borderRadius: BorderRadius.circular(
8.0), // Set the border radius here
),
child: Column(children: [
Container(
decoration: BoxDecoration(
color: Colors
.white, // Set background color for the container
),
padding: EdgeInsets.only(
top: 10, bottom: 10, left: 10, right: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 7,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.string(
SvgService.getSvg('tickets'),
width: 40,
height: 40,
),
SizedBox(
width:
10), // Adjust space between icon and text
Container(
alignment: Alignment.centerLeft,
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'$claimsDepartmentName' ?? '',
textAlign: TextAlign.left,
style: GoogleFonts.poppins(
fontSize: Responsive.isDesktop(
context)
? 16
: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF000000),
),
),
Text(
Responsive.isDesktop(context)
? ' (Ticket Id #$claimsticket)'
: ' (Tkt #$claimsticket)' ??
'',
textAlign: TextAlign.left,
style: GoogleFonts.poppins(
fontSize: Responsive.isDesktop(
context)
? 14
: 10,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
],
),
SizedBox(height: 5),
Container(
alignment: Alignment
.centerLeft, // Set a fixed width or adjust based on your layout
child: Tooltip(
message: claimsSubject,
child: Text(
truncatedSubject,
textAlign: TextAlign.left,
style: GoogleFonts.poppins(
fontSize:
Responsive.isDesktop(
context)
? 14
: 12,
fontWeight: FontWeight.w400,
color: Color(0xFF777777),
),
),
))
],
))
],
),
),
Expanded(
flex: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// Adjust space between icon and text
Container(
alignment: Alignment.centerRight,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
Container(
width: 100,
decoration: BoxDecoration(
// color: statusColor,
color: getStatusColor(claimStatus),
borderRadius: BorderRadius.circular(
50), // Border radius set to 50
),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Text(
claimStatus,
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: Responsive.isDesktop(
context)
? 12
: 10,
fontWeight: FontWeight.w400,
color: Colors
.white, // Text color against the background
),
),
),
),
SizedBox(height: 5),
Text(
formatDateWithTime(claimsDate),
textAlign: TextAlign.right,
style: GoogleFonts.poppins(
fontSize:
Responsive.isDesktop(context)
? 14
: 12,
fontWeight: FontWeight.w400,
color: Color(0xFF777777),
), // Ensure text automatically wraps
),
],
))
],
),
),
],
),
),
])),
),
);
},
),
];
}
String formatDateWithTime(String timestamp) {
// Parse the timestamp string to DateTime
DateTime date = DateTime.parse(timestamp);
// Format the DateTime object with date and time
String formattedDate = DateFormat('d MMM y hh:mm a').format(date);
return formattedDate;
}
}

View File

@ -97,7 +97,7 @@ class ApiService {
await _initializeToken();
}
final url = Uri.parse(
'${Environment.apiUrlTicket}/get_ticket_data?emp_id=$empPrimaryId');
'${Environment.apiUrl}/get_ticket_data?emp_id=$empPrimaryId');
final headers = {
'Authorization': 'Bearer $_token' ?? '',
};
@ -152,12 +152,12 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> fetchDepartmentList() async {
Future<Map<String, dynamic>> fetchDepartmentList(String clientId, String empCode) async {
print(_token);
if (_token == null) {
await _initializeToken();
}
final url = Uri.parse('${Environment.apiUrlTicket}/get_ticket_type');
final url = Uri.parse('${Environment.apiUrl}/get_ticket_type?client_id=$clientId&emp_code=$empCode');
final headers = {
'Authorization': 'Bearer $_token' ?? '',
};
@ -165,7 +165,7 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> sendFormDataToApi(
Future<Map<String, dynamic>> sendTicketFormDataToApi(
Map<String, dynamic> formData) async {
print(_token);
if (_token == null) {
@ -182,6 +182,23 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> sendClaimsFormDataToApi(
Map<String, dynamic> formData) async {
print(_token);
if (_token == null) {
await _initializeToken();
}
final url = Uri.parse('${Environment.apiUrl}/initiateClaim');
// Convert formData to Map<String, String>
Map<String, String> stringFormData =
formData.map((key, value) => MapEntry(key, value.toString()));
final response = await _makePostRequest(url, stringFormData, {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer $_token' ?? '',
});
return response;
}
Future<Map<String, dynamic>> sendClaimsMessageToApi(
Map<String, dynamic> formData) async {
print("sendClaimsMessageToApi");

View File

@ -0,0 +1,46 @@
import 'package:file_picker/file_picker.dart';
class FileUploadService {
FileUploadService._();
static final FileUploadService _instance = FileUploadService._();
factory FileUploadService() => _instance;
final List<PlatformFile> _files = [];
List<PlatformFile> get files => List.unmodifiable(_files);
// Allowed extensions
static const allowedExtensions = ['pdf', 'png', 'jpg', 'jpeg','heic'];
Future<String?> pickFiles({int maxFileSizeInMB = 3}) async {
final result = await FilePicker.platform.pickFiles(
allowMultiple: true,
withData: true,
type: FileType.custom,
allowedExtensions: allowedExtensions,
);
if (result != null) {
for (final file in result.files) {
final ext = file.extension?.toLowerCase() ?? '';
final sizeInMB = (file.size / (1024 * 1024));
if (!allowedExtensions.contains(ext)) {
return "Unsupported file format: ${file.name}";
}
if (sizeInMB > maxFileSizeInMB) {
return "File too large (${file.name}). Max $maxFileSizeInMB MB allowed.";
}
}
_files.addAll(result.files);
}
return null; // success
}
void removeFileAt(int index) {
if (index >= 0 && index < _files.length) _files.removeAt(index);
}
void clearAll() => _files.clear();
}

View File

@ -0,0 +1,137 @@
import 'package:flutter/material.dart';
import 'package:nhance_app_pwa/customAppBar/responsive.dart';
import 'file_upload_service.dart';
class MultiFileUploadWidget extends StatefulWidget {
const MultiFileUploadWidget({super.key});
@override
State<MultiFileUploadWidget> createState() => _MultiFileUploadWidgetState();
}
class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
final fileService = FileUploadService();
String? errorMessage;
void _pickFiles() async {
final error = await fileService.pickFiles(maxFileSizeInMB: 10); // 5 MB limit
if (error != null) {
if (mounted) {
setState(() {
errorMessage = error;
});
// also show alert dialog for big error messages
// showDialog(
// context: context,
// builder: (ctx) => AlertDialog(
// title: const Text("File Upload Error"),
// content: Text(error),
// actions: [
// TextButton(
// onPressed: () => Navigator.pop(ctx),
// child: const Text("OK"),
// ),
// ],
// ),
// );
}
} else {
setState(() {
errorMessage = null;
});
}
}
void _removeFile(int index) {
fileService.removeFileAt(index);
setState(() {});
}
@override
Widget build(BuildContext context) {
final files = fileService.files;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (Responsive.isMobile(context)) ...[
OutlinedButton.icon(
onPressed: _pickFiles,
icon: const Icon(Icons.file_upload_outlined,
color: Color(0xFFE26728), size: 24),
label: const Text(
"Upload Documents",
style: TextStyle(
fontSize: 14,
color: Colors.black,
),
overflow: TextOverflow.ellipsis,
),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Color(0xFFE26728)),
),
),
const SizedBox(height: 6),
const Text(
"Supports only PDF, PNG, JPG, JPEG,HEIC formats (max 10 MB each)",
style: TextStyle(fontSize: 12, color: Colors.grey),
),
] else ...[
Row(
children: [
OutlinedButton.icon(
onPressed: _pickFiles,
icon: const Icon(Icons.file_upload_outlined,
color: Color(0xFFE26728), size: 24),
label: const Text(
"Upload Documents",
style: TextStyle(
fontSize: 14,
color: Colors.black,
),
overflow: TextOverflow.ellipsis,
),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Color(0xFFE26728)),
),
),
const SizedBox(width: 12),
const Expanded(
child: Text(
"Supports only PDF, PNG, JPG, JPEG,HEIC formats (max 10 MB each)",
style: TextStyle(fontSize: 12, color: Colors.grey),
overflow: TextOverflow.ellipsis,
),
),
],
),
],
if (errorMessage != null) ...[
const SizedBox(height: 4),
Text(
errorMessage!,
style: const TextStyle(color: Colors.red, fontSize: 12),
),
],
const SizedBox(height: 8),
...files.asMap().entries.map((entry) {
final index = entry.key;
final file = entry.value;
return ListTile(
dense: true,
contentPadding: EdgeInsets.zero,
title: Text(file.name, style: const TextStyle(fontSize: 14)),
trailing: IconButton(
icon: const Icon(Icons.close, color: Colors.red),
onPressed: () => _removeFile(index),
),
);
}),
],
);
}
}

View File

@ -4,7 +4,6 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:jwt_decode/jwt_decode.dart';
import 'package:nhance_app_pwa/customAppBar/customAppBar.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/claimtracklist.dart';
import 'package:nhance_app_pwa/pages/postEnrollment/service/api_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../customAppBar/customFooter.dart';
@ -238,7 +237,7 @@ class _ticketsState extends State<tickets> {
// Convert integer values to strings
formData = formData.map((key, value) => MapEntry(key, value.toString()));
final response = await apiService.sendFormDataToApi(formData);
final response = await apiService.sendTicketFormDataToApi(formData);
if (response['status'] == 'success') {
ToastHelper.showSuccessToast(context, response['message']);
@ -252,7 +251,7 @@ class _ticketsState extends State<tickets> {
// Navigator.pushNamed(context, 'help');
Navigator.pushNamed(
context,
'help',
'raisedTicketHistory',
arguments: {'ticketTabSelected': 0},
);
print('Form data submitted successfully');

View File

@ -14,15 +14,15 @@ import '../../customAppBar/responsive.dart';
import '../../customAppBar/tabs.dart';
import '../../customAppBar/toastHelper.dart';
class claimtracklist extends StatefulWidget {
class tickettracklist extends StatefulWidget {
final String ticketID;
const claimtracklist({Key? key, required this.ticketID}) : super(key: key);
const tickettracklist({Key? key, required this.ticketID}) : super(key: key);
@override
State<claimtracklist> createState() => _claimtracklistformState();
State<tickettracklist> createState() => _tickettracklistState();
}
class _claimtracklistformState extends State<claimtracklist> {
class _tickettracklistState extends State<tickettracklist> {
late ApiService apiService;
late String ticketID;
dynamic _token;
@ -308,14 +308,10 @@ class _claimtracklistformState extends State<claimtracklist> {
flex: 1,
child: InkWell(
onTap: () {
// Navigator.pushNamed(
// context, 'claims');
Navigator.pushNamed(
context,
'help',
arguments: {
'ticketTabSelected': 0
},
'raisedTicketHistory',
);
},
child: Icon(
@ -713,11 +709,11 @@ class _claimtracklistformState extends State<claimtracklist> {
}
String formatDateWithTime(String timestamp) {
// Parse the input string to DateTime
DateTime date = DateFormat("yyyy-MM-dd HH:mm:ss").parse(timestamp);
// Parse the timestamp string to DateTime
DateTime date = DateTime.parse(timestamp);
// Format to your desired output
String formattedDate = DateFormat("dd, MMM yy h:mm a").format(date);
// Format the DateTime object with date and time
String formattedDate = DateFormat('d MMM y hh:mm a').format(date);
return formattedDate;
}

View File

@ -6,9 +6,13 @@
#include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
url_launcher_linux
)

View File

@ -5,6 +5,8 @@
import FlutterMacOS
import Foundation
import file_picker
import file_selector_macos
import firebase_app_check
import firebase_auth
import firebase_core
@ -21,13 +23,15 @@ import video_player_avfoundation
import webview_flutter_wkwebview
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FLTFirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAppCheckPlugin"))
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin"))
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

View File

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
#version: 1.0.24+24
version: 1.0.12+13
version: 1.0.13+14
environment:
sdk: '>=3.3.3 <4.0.0'
@ -61,6 +61,9 @@ dependencies:
webview_flutter: ^4.13.0
webview_flutter_android: ^4.7.0
flutter_inappwebview: ^6.1.5
file_picker: ^10.3.2
file_selector: ^1.0.3
universal_html: ^2.2.4
dev_dependencies:
flutter_test:

View File

@ -1,56 +0,0 @@
(function() {
var botmanCDN = document.createElement("script");
botmanCDN.src = "https://cdn.jsdelivr.net/npm/botman-web-widget@0/build/js/widget.js";
botmanCDN.defer = true;
document.head.appendChild(botmanCDN);
botmanCDN.onload = function() {
var botmanWidget = {
// chatServer: 'https://appstage.nhanceindia.in/arena/crm/chat',
// frameEndpoint: 'https://appstage.nhanceindia.in/arena/crm/widget',
// chatServer: 'https://app.nhanceindia.in/zenith/chat ',
//frameEndpoint: 'https://app.nhanceindia.in/zenith/widget',
chatServer: 'https://venbait.in/nhance/dev/chat',
frameEndpoint: 'https://venbait.in/nhance/dev/widget',
title: "Ask ILA",
introMessage: "",
bubbleBackground: "#007bff",
mainColor: "#007bff",
placeholderText: "Type your message here...",
aboutText: "Insurance Assistant ILA",
enableAttachments: false,
parameters: {
employee_id: localStorage.getItem('empPrimaryId') || '',
session_id: generateSessionId(15),
origin: "mobile",
emp_code: localStorage.getItem('empCode') || '',
client_id: localStorage.getItem('client_id') || '',
client_branch_id: localStorage.getItem('empClientBranchId') || ''
}
};
function generateSessionId(length = 15) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let sessionId = '';
for (let i = 0; i < length; i++) {
sessionId += characters.charAt(Math.floor(Math.random() * characters.length));
}
return sessionId;
}
function openBotmanChat() {
var checkBotman = setInterval(function () {
if (typeof botmanChatWidget !== "undefined" && botmanChatWidget.open) {
clearInterval(checkBotman);
botmanChatWidget.open();
setTimeout(function () {
botmanChatWidget.sayAsBot('Hi ' + (localStorage.getItem('gpaEmpName') || '') +
', This is ILA, your Insurance Assistant. Please choose an option.');
}, 2000);
}
}, 500);
}
window.openBotmanChat = openBotmanChat;
};
})();

View File

@ -171,8 +171,9 @@ body.show-botman #botmanWidgetRoot {
introMessage: "",
bubbleBackground: "#179a9f",
mainColor: "#179a9f",
bubbleAvatarUrl:"https://botman.io/img/logo.png",
placeholderText: "Type your message here...",
aboutText: "Insurance Assistant ILA",
aboutText: "Press Enter to send the message",
enableAttachments: false,
parameters: getUpdatedParameters()
};

View File

@ -6,6 +6,7 @@
#include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <firebase_auth/firebase_auth_plugin_c_api.h>
#include <firebase_core/firebase_core_plugin_c_api.h>
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
@ -13,6 +14,8 @@
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
FirebaseAuthPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi"));
FirebaseCorePluginCApiRegisterWithRegistrar(

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
firebase_auth
firebase_core
flutter_inappwebview_windows