560 lines
21 KiB
Dart
Executable File
560 lines
21 KiB
Dart
Executable File
import 'package:flutter/foundation.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_svg/svg.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/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:shared_preferences/shared_preferences.dart';
|
||
import 'package:url_launcher/url_launcher.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 wellness extends StatefulWidget {
|
||
const wellness({Key? key}) : super(key: key);
|
||
|
||
@override
|
||
State<wellness> createState() => _wellnessState();
|
||
}
|
||
|
||
class _wellnessState extends State<wellness> {
|
||
late ApiService apiService;
|
||
bool isLoadingGif = false;
|
||
dynamic wellnessURL;
|
||
dynamic wellnessMessage;
|
||
dynamic empCodeString;
|
||
dynamic empName;
|
||
dynamic empPrimaryId;
|
||
dynamic client_id;
|
||
dynamic client_branch_id;
|
||
dynamic mobileNo;
|
||
dynamic policyList;
|
||
dynamic employeeDetailsList;
|
||
dynamic emailId;
|
||
final session = SessionManager();
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
apiService = ApiService(context);
|
||
// getWellnessLink();
|
||
_loadToken();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _loadToken() async {
|
||
logDebug('_loadToken');
|
||
final String? token = await TokenService.getPostToken();
|
||
if (token != null && token.isNotEmpty) {
|
||
// Decode the JWT token received from the API response
|
||
Map<String, dynamic>? decodedToken = Jwt.parseJwt(token);
|
||
logDebug(decodedToken);
|
||
mobileNo = session.mobileNo;
|
||
client_branch_id = session.empClientBranchId;
|
||
empCodeString = session.empCodeString;
|
||
empName = session.gpaEmpName;
|
||
logDebug(empCodeString); // Check if emp_code is correct
|
||
empPrimaryId = session.empPrimaryId;
|
||
client_id = session.client_id;
|
||
emailId = session.empEmailCorporate;
|
||
logDebug(client_id);
|
||
// getAdvertisementSliderImage();
|
||
getActiveAndInactivePolicyDetails('Active');
|
||
}
|
||
}
|
||
|
||
Future<void> getActiveAndInactivePolicyDetails(String status) async {
|
||
logDebug(getActiveAndInactivePolicyDetails);
|
||
if (client_id == null || empCodeString == null) {
|
||
return;
|
||
}
|
||
setState(() {
|
||
isLoadingGif = true;
|
||
});
|
||
logDebug('check 1');
|
||
final response = await apiService.getActiveAndInactivePolicyDetails(
|
||
client_id!, empCodeString!, status, client_branch_id, mobileNo,emailId);
|
||
logDebug('check 1');
|
||
if (response['status'] == 'success') {
|
||
policyList = response['data'];
|
||
logDebug('policyList $policyList');
|
||
|
||
// -------------------------------------------
|
||
// 1️⃣ CHECK FOR GMC OR GMC-PARENT
|
||
// -------------------------------------------
|
||
final gmcPolicies = policyList.where((item) {
|
||
final type = (item['policy_type'] ?? '').toString();
|
||
return type == 'GMC' || type == 'GMC - Parents';
|
||
}).toList();
|
||
|
||
logDebug('gmcPolicies $gmcPolicies');
|
||
|
||
if (gmcPolicies.isNotEmpty) {
|
||
final mergedEmployeeDetails = getMergedEmployeeDetails(gmcPolicies);
|
||
|
||
logDebug("🟢 Merged Employee Details: $mergedEmployeeDetails");
|
||
|
||
setState(() {
|
||
employeeDetailsList = mergedEmployeeDetails;
|
||
});
|
||
|
||
logDebug('mergedEmployeeDetails $employeeDetailsList');
|
||
|
||
setState(() => isLoadingGif = false);
|
||
|
||
// continue your logic here…
|
||
return;
|
||
}
|
||
|
||
// -------------------------------------------
|
||
// 2️⃣ IF NO GMC, CHECK FOR GPA
|
||
// -------------------------------------------
|
||
final gpaPolicies = policyList.where((item) {
|
||
final type = (item['policy_type'] ?? '').toString();
|
||
return type == 'GPA';
|
||
}).toList();
|
||
|
||
if (gpaPolicies.isNotEmpty) {
|
||
logDebug("🟠 GPA FOUND — calling Wellness API directly");
|
||
|
||
final firstPolicy = gpaPolicies[0];
|
||
|
||
final empID = firstPolicy['EmployeePolicy'][0]['employee_id'];
|
||
final clientPolicyId = firstPolicy['client_policy_id'];
|
||
|
||
logDebug("EMPLOYEE ID: $empID");
|
||
logDebug("CLIENT POLICY ID: $clientPolicyId");
|
||
|
||
setState(() => isLoadingGif = false);
|
||
|
||
await getWellnessLink(empID, clientPolicyId);
|
||
|
||
return;
|
||
}
|
||
|
||
// -------------------------------------------
|
||
// 3️⃣ NO GMC, NO GPA
|
||
// -------------------------------------------
|
||
logDebug("❌ No valid policy found");
|
||
ToastHelper.showErrorToast(context, "No valid policies found.");
|
||
setState(() => isLoadingGif = false);
|
||
|
||
|
||
} else {
|
||
setState(() {
|
||
isLoadingGif = false;
|
||
});
|
||
logDebug('API request failed with status: ${response['status']}');
|
||
}
|
||
}
|
||
|
||
List<dynamic> getMergedEmployeeDetails(List<dynamic>? gmcPolicies) {
|
||
logDebug('123');
|
||
if (gmcPolicies == null || gmcPolicies.isEmpty) return [];
|
||
logDebug('getMergedEmployeeDetails $gmcPolicies');
|
||
|
||
List<dynamic> finalList = [];
|
||
|
||
for (var policy in gmcPolicies) {
|
||
final details = policy['EmployeePolicy'];
|
||
final clientPolicyId = policy['client_policy_id'];
|
||
|
||
if (details != null) {
|
||
if (details is List) {
|
||
// Add client_policy_id to each employee
|
||
for (var emp in details) {
|
||
finalList.add({
|
||
...emp, // existing employee fields
|
||
"client_policy_id": clientPolicyId
|
||
});
|
||
}
|
||
} else if (details is Map) {
|
||
// Single employee object
|
||
finalList.add({
|
||
...details,
|
||
"client_policy_id": clientPolicyId
|
||
});
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
return finalList;
|
||
}
|
||
|
||
|
||
Future<void> getWellnessLink(employee_id,client_policy_id) async {
|
||
|
||
final response = await apiService.getWellnessLink(employee_id,client_policy_id);
|
||
logDebug('check 1');
|
||
if (response['status'] == 'success') {
|
||
wellnessURL = response['data'];
|
||
logDebug('✅ Link: $wellnessURL');
|
||
openInWebView(context,wellnessURL);
|
||
// await _launchURL(wellnessURL); // Only launch if status is success
|
||
} else if (response['status'] == 'failed') {
|
||
wellnessMessage = response['message'];
|
||
logDebug('❌ Error: $wellnessMessage');
|
||
ToastHelper.showErrorToast(context, wellnessMessage);
|
||
} else {
|
||
ToastHelper.showErrorToast(context, '⚠️ Unknown response format');
|
||
logDebug('⚠️ Unknown response format');
|
||
}
|
||
}
|
||
|
||
Future<void> _launchURL(String url, BuildContext context) async {
|
||
logDebug('url $url');
|
||
try {
|
||
final Uri uri = Uri.parse(url);
|
||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||
} catch (e) {
|
||
logDebug('Could not launch URL: $e');
|
||
}
|
||
}
|
||
|
||
void openInWebView(BuildContext context, String url) {
|
||
if (kIsWeb) {
|
||
// 🌐 Open in new browser tab (web)
|
||
_launchURL(url,context);
|
||
} else {
|
||
// 📱 Open in platform WebView
|
||
context.push('/wellnessWebView', extra: wellnessURL);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
|
||
return PopScope(
|
||
canPop: false,
|
||
onPopInvokedWithResult: (didPop, result) {
|
||
if (didPop) return;
|
||
context.pop();
|
||
},
|
||
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, // 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: () {
|
||
context.pop();
|
||
},
|
||
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(
|
||
'Wellness',
|
||
textAlign: TextAlign.start,
|
||
style: GoogleFonts.poppins(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: Color(0xFF000000),
|
||
),
|
||
),
|
||
Text(
|
||
'Select your family member to avail the wellness benefits.',
|
||
textAlign: TextAlign.start,
|
||
style: GoogleFonts.poppins(
|
||
fontSize:
|
||
11, // Adjust the font size as needed
|
||
fontWeight: FontWeight.w400,
|
||
color: Color(0xFF000000),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
// Add more rows as needed
|
||
],
|
||
),
|
||
),
|
||
SizedBox(height: 15),
|
||
if (employeeDetailsList != null && employeeDetailsList.length > 0)
|
||
SingleChildScrollView(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
children: generateFamilyMembers(employeeDetailsList),
|
||
),
|
||
),
|
||
SizedBox(height: Responsive.isDesktop(context) ? 40 : 70),
|
||
]),
|
||
)),
|
||
if (isLoadingGif)
|
||
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
|
||
// repositionBotman();
|
||
if (index == 0) {
|
||
context.push('/home');
|
||
} else if (index == 1) {
|
||
context.push('/claims');
|
||
} else if (index == 2) {
|
||
context.push('/faqs');
|
||
} else if (index == 3) {
|
||
context.push('/profile');
|
||
} else if (index == 4) {
|
||
context.push('/help');
|
||
}
|
||
// else if (index == 4) {
|
||
// // context.push('/wellness');
|
||
// // Wellness tab clicked → show popup
|
||
// if(!isRetailLoggedIn)
|
||
// PopupHelper.showRedirectPopup(
|
||
// context: context,
|
||
// apiService: apiService,
|
||
// empPrimaryId: session.empPrimaryId,
|
||
// );
|
||
// }
|
||
},
|
||
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, // Initial index of the bottom navigation bar
|
||
),
|
||
)
|
||
);
|
||
}
|
||
|
||
|
||
List<Widget> generateFamilyMembers(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 gender = item['gender'] ?? '';
|
||
String dob = item['dob'] ?? '';
|
||
String name = item['name'] ?? '';
|
||
String relationship = item['relationship'] ?? '';
|
||
String employee_id = item['employee_id'] ?? '';
|
||
String client_policy_id = item['client_policy_id'] ?? '';
|
||
|
||
logDebug('${name} - ${employee_id}--${client_policy_id}');
|
||
|
||
return GestureDetector(
|
||
onTap: () {
|
||
getWellnessLink(employee_id,client_policy_id);
|
||
},
|
||
child: MouseRegion(
|
||
cursor: SystemMouseCursors.click,
|
||
child: Card(
|
||
elevation: 5,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(15.0),
|
||
),
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(15.0),
|
||
),
|
||
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||
child: Row(
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Expanded(
|
||
flex: 8,
|
||
child: Container(
|
||
alignment: Alignment.centerLeft,
|
||
padding: Responsive.isDesktop(context)
|
||
? EdgeInsets.only(
|
||
top: 10,
|
||
bottom: 10,
|
||
left: 10,
|
||
right: 10)
|
||
: EdgeInsets.only(
|
||
top: 15,
|
||
bottom: 15,
|
||
left: 7,
|
||
right: 7),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
// 👇 SVG icon based on gender
|
||
if (gender == 'M')
|
||
SvgPicture.string(
|
||
SvgService.getSvg('personMale'),
|
||
width: 25,
|
||
height: 25,
|
||
)
|
||
else if (gender == 'F')
|
||
SvgPicture.string(
|
||
SvgService.getSvg('personFemale'),
|
||
width: 25,
|
||
height: 25,
|
||
),
|
||
|
||
const SizedBox(width: 6),
|
||
|
||
// Name text
|
||
Text(
|
||
name ?? '',
|
||
textAlign: TextAlign.start,
|
||
style: GoogleFonts.poppins(
|
||
fontSize: Responsive.isDesktop(context) ? 16 : 14,
|
||
color: const Color(0xFF000000),
|
||
fontWeight: FontWeight.w400,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
|
||
const SizedBox(height: 4),
|
||
|
||
// DOB text
|
||
Text(
|
||
"DOB: ${formatDob(dob!) ?? '-'}",
|
||
style: GoogleFonts.poppins(
|
||
fontSize: Responsive.isDesktop(context) ? 14 : 12,
|
||
color: const Color(0xFF606060),
|
||
fontWeight: FontWeight.w300,
|
||
),
|
||
),
|
||
],
|
||
)
|
||
),
|
||
),
|
||
Expanded(
|
||
flex: 4,
|
||
child: Container(
|
||
alignment: Alignment.centerRight,
|
||
padding: Responsive.isDesktop(context)
|
||
? EdgeInsets.only(
|
||
top: 10,
|
||
bottom: 10,
|
||
left: 10,
|
||
right: 10)
|
||
: EdgeInsets.only(
|
||
top: 15,
|
||
bottom: 15,
|
||
left: 7,
|
||
right: 7),
|
||
child: Text(
|
||
relationship!,
|
||
textAlign: TextAlign.end,
|
||
style: GoogleFonts.poppins(
|
||
fontSize:
|
||
Responsive.isDesktop(context)
|
||
? 16
|
||
: 14,
|
||
color: Color(0xFF404040),
|
||
fontWeight: FontWeight.w400,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
];
|
||
}
|
||
String formatDob(String dob) {
|
||
try {
|
||
final date = DateTime.parse(dob); // input format: yyyy-MM-dd
|
||
return DateFormat("d MMM yyyy").format(date); // output: 18 Jul 1988
|
||
} catch (e) {
|
||
return dob; // fallback in case of error
|
||
}
|
||
}
|
||
|
||
} |