new requirement
This commit is contained in:
parent
fbcfe20b9b
commit
3abde687ca
@ -2,10 +2,12 @@ import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:nhancepolicy/service/api_service.dart';
|
||||
import 'package:nhancepolicy/service/svg_service.dart';
|
||||
import 'package:nhancepolicy/service/token_storage_service.dart';
|
||||
import 'package:nhancepolicy/logger.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class NhanceSideBar extends StatefulWidget {
|
||||
const NhanceSideBar({super.key});
|
||||
@ -211,6 +213,19 @@ class _NhanceSideBarState extends State<NhanceSideBar> {
|
||||
_isHoveringClaimsMenu = false;
|
||||
}
|
||||
|
||||
Future<void> _openHelpDialog() async {
|
||||
final isPostUser = postModules.isNotEmpty;
|
||||
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) => _HelpContactDialog(
|
||||
isPostUser: isPostUser,
|
||||
apiService: apiService,
|
||||
tokenService: tokenService,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
@ -355,6 +370,17 @@ class _NhanceSideBarState extends State<NhanceSideBar> {
|
||||
|
||||
const Spacer(),
|
||||
|
||||
if (enrollmentModules.isNotEmpty || postModules.isNotEmpty)
|
||||
_SideItem(
|
||||
icon: const Icon(
|
||||
Icons.help_outline,
|
||||
color: Colors.white,
|
||||
size: 30,
|
||||
),
|
||||
label: 'Help',
|
||||
onTap: _openHelpDialog,
|
||||
),
|
||||
|
||||
_SideItem(
|
||||
icon: SvgPicture.string(
|
||||
SvgService.getSvg('logout'),
|
||||
@ -376,6 +402,380 @@ class _NhanceSideBarState extends State<NhanceSideBar> {
|
||||
}
|
||||
}
|
||||
|
||||
class _HelpContactDialog extends StatefulWidget {
|
||||
final bool isPostUser;
|
||||
final ApiService apiService;
|
||||
final TokenStorageService tokenService;
|
||||
|
||||
const _HelpContactDialog({
|
||||
required this.isPostUser,
|
||||
required this.apiService,
|
||||
required this.tokenService,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_HelpContactDialog> createState() => _HelpContactDialogState();
|
||||
}
|
||||
|
||||
class _HelpContactDialogState extends State<_HelpContactDialog> {
|
||||
bool _isLoading = false;
|
||||
List<Map<String, dynamic>> _level1Contacts = [];
|
||||
List<Map<String, dynamic>> _level2Contacts = [];
|
||||
Map<String, String> _hospitalLinks = {};
|
||||
String? _errorMessage;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.isPostUser) {
|
||||
_loadClientRM();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadClientRM() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_errorMessage = null;
|
||||
});
|
||||
|
||||
try {
|
||||
final clientId = await widget.tokenService.readValue('empClientId');
|
||||
final token = widget.tokenService.getCurrentToken();
|
||||
|
||||
if (clientId == null ||
|
||||
clientId.toString().isEmpty ||
|
||||
token == null ||
|
||||
token.isEmpty) {
|
||||
setState(() {
|
||||
_errorMessage = 'Client details not found';
|
||||
_isLoading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final response = await widget.apiService.getClientRMApi(
|
||||
clientId.toString(),
|
||||
token,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (response['status'] == 'success' && response['data'] is Map) {
|
||||
final data = Map<String, dynamic>.from(response['data'] as Map);
|
||||
setState(() {
|
||||
_level1Contacts = _parseContacts(data['level_1']);
|
||||
_level2Contacts = _parseContacts(data['level_2']);
|
||||
_hospitalLinks = _parseHospitalLinks(data['tpa_network_hospitals']);
|
||||
_isLoading = false;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_errorMessage =
|
||||
response['message']?.toString() ?? 'Failed to load contacts';
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
logDebug('getClientRM failed: $e');
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_errorMessage = 'Failed to load contacts';
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _parseContacts(dynamic raw) {
|
||||
if (raw is! List) return [];
|
||||
return raw
|
||||
.whereType<Map>()
|
||||
.map((item) => Map<String, dynamic>.from(item))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Map<String, String> _parseHospitalLinks(dynamic raw) {
|
||||
if (raw is! Map) return {};
|
||||
final parsed = <String, String>{};
|
||||
raw.forEach((key, value) {
|
||||
final name = key.toString().trim();
|
||||
final url = value?.toString().trim() ?? '';
|
||||
if (name.isNotEmpty && url.isNotEmpty) {
|
||||
parsed[name] = url;
|
||||
}
|
||||
});
|
||||
return parsed;
|
||||
}
|
||||
|
||||
Future<void> _openHospitalUrl(String url) async {
|
||||
final uri = Uri.tryParse(url);
|
||||
if (uri == null) return;
|
||||
await launchUrl(uri, webOnlyWindowName: '_blank');
|
||||
}
|
||||
|
||||
Widget _buildContactCard(Map<String, dynamic> contact) {
|
||||
final name = contact['first_name']?.toString() ?? '-';
|
||||
final email = contact['email']?.toString() ?? '-';
|
||||
final mobile = contact['mobile']?.toString() ?? '-';
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.only(bottom: 10),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF5F5F5),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE8E8E8)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
name,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: const Color(0xFF009195),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
email,
|
||||
style: GoogleFonts.poppins(fontSize: 13, color: Colors.black87),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
mobile,
|
||||
style: GoogleFonts.poppins(fontSize: 13, color: Colors.black87),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLevelSection({
|
||||
required String title,
|
||||
required List<Map<String, dynamic>> contacts,
|
||||
}) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (contacts.isEmpty)
|
||||
Text(
|
||||
'No contact assigned',
|
||||
style: GoogleFonts.poppins(fontSize: 13, color: Colors.black54),
|
||||
)
|
||||
else
|
||||
...contacts.map(_buildContactCard),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildContent() {
|
||||
if (!widget.isPostUser) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'No Level Contact',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black54,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (_isLoading) {
|
||||
return const SizedBox(
|
||||
height: 180,
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
|
||||
if (_errorMessage != null) {
|
||||
return Center(
|
||||
child: Text(
|
||||
_errorMessage!,
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.poppins(fontSize: 14, color: Colors.red),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildLevelSection(
|
||||
title: 'Level 1 - Account Manager',
|
||||
contacts: _level1Contacts,
|
||||
),
|
||||
_buildLevelSection(
|
||||
title: 'Level 2 - Head',
|
||||
contacts: _level2Contacts,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHospitalListContent() {
|
||||
if (!widget.isPostUser) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'No Network Hospital List',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black54,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (_isLoading) {
|
||||
return const SizedBox(
|
||||
height: 180,
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
|
||||
if (_errorMessage != null) {
|
||||
return Center(
|
||||
child: Text(
|
||||
_errorMessage!,
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.poppins(fontSize: 14, color: Colors.red),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (_hospitalLinks.isEmpty) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'No Network Hospital List',
|
||||
style: GoogleFonts.poppins(fontSize: 14, color: Colors.black54),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: _hospitalLinks.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(height: 10),
|
||||
itemBuilder: (context, index) {
|
||||
final entry = _hospitalLinks.entries.elementAt(index);
|
||||
return InkWell(
|
||||
onTap: () => _openHospitalUrl(entry.value),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF5F5F5),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE8E8E8)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
entry.key,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: const Color(0xFF009195),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Icon(
|
||||
Icons.open_in_new,
|
||||
size: 16,
|
||||
color: Color(0xFF009195),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final maxHeight = MediaQuery.of(context).size.height * 0.65;
|
||||
final cappedMaxHeight = maxHeight.clamp(280.0, 520.0);
|
||||
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Help',
|
||||
style:
|
||||
GoogleFonts.poppins(fontWeight: FontWeight.w600, fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TabBar(
|
||||
labelColor: const Color(0xFF009195),
|
||||
unselectedLabelColor: Colors.black54,
|
||||
indicatorColor: const Color(0xFF009195),
|
||||
labelStyle: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
tabs: const [
|
||||
Tab(text: 'Contacts'),
|
||||
Tab(text: 'Network Hospital List'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
content: SizedBox(
|
||||
width: 560,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: cappedMaxHeight),
|
||||
child: TabBarView(
|
||||
children: [
|
||||
Scrollbar(
|
||||
child: SingleChildScrollView(child: _buildContent()),
|
||||
),
|
||||
Scrollbar(
|
||||
child: SingleChildScrollView(
|
||||
child: _buildHospitalListContent(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF009195),
|
||||
),
|
||||
child: Text('Close', style: GoogleFonts.poppins(color: Colors.white)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SideItem extends StatelessWidget {
|
||||
// final IconData icon;
|
||||
final Widget icon; // 👈 changed
|
||||
|
||||
@ -102,6 +102,7 @@ class _HrPolicyDetailsState extends State<hrPolicyDetails>
|
||||
bool isLoading = false;
|
||||
bool _isLoading = false;
|
||||
bool _isSendingReminder = false;
|
||||
bool _isLoadingPolicyTerms = false;
|
||||
// dynamic clintID;
|
||||
late TabController _tabController;
|
||||
// List<dynamic> dataPolicy = [];
|
||||
@ -652,6 +653,105 @@ class _HrPolicyDetailsState extends State<hrPolicyDetails>
|
||||
return _capitalize(status);
|
||||
}
|
||||
|
||||
Future<void> _openPolicyTermsDialog() async {
|
||||
setState(() => _isLoadingPolicyTerms = true);
|
||||
|
||||
try {
|
||||
final clientId = localClientId ?? widget.ClientId;
|
||||
final branchId = localClientBranchId ?? widget.clientBranchId;
|
||||
final clientPolicyId = localClientPolicyId ?? widget.ClientPoliyId;
|
||||
final token = localToken ?? widget.Token;
|
||||
final hrId = await tokenService.readValue('empHrId');
|
||||
|
||||
if (hrId == null || hrId.toString().isEmpty) {
|
||||
if (mounted) {
|
||||
ToastHelper.showErrorToast(context, 'HR ID not found');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final response = await apiService.getActiveCashDepositDetailsToApi(
|
||||
clientId,
|
||||
branchId,
|
||||
hrId.toString(),
|
||||
token,
|
||||
1,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (response['status'] != 'success') {
|
||||
ToastHelper.showErrorToast(
|
||||
context,
|
||||
response['message']?.toString() ?? 'Failed to load policy terms',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final policies = List<Map<String, dynamic>>.from(response['data'] ?? []);
|
||||
Map<String, dynamic>? matchedPolicy;
|
||||
for (final policy in policies) {
|
||||
if (policy['client_policy_id'].toString() == clientPolicyId) {
|
||||
matchedPolicy = policy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedPolicy == null) {
|
||||
ToastHelper.showErrorToast(context, 'Policy not found');
|
||||
return;
|
||||
}
|
||||
|
||||
final rawTerms =
|
||||
matchedPolicy['policy_terms'] ?? matchedPolicy['Policy_Terms'];
|
||||
final terms = <String, String>{};
|
||||
|
||||
if (rawTerms is Map) {
|
||||
rawTerms.forEach((key, value) {
|
||||
if (value != null && value.toString().trim().isNotEmpty) {
|
||||
terms[key.toString()] = value.toString();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (terms.isEmpty) {
|
||||
ToastHelper.showWarningToast(context, 'No policy terms available');
|
||||
return;
|
||||
}
|
||||
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) => _PolicyTermsDialog(terms: terms),
|
||||
);
|
||||
} catch (e) {
|
||||
logDebug('Policy terms load failed: $e');
|
||||
if (mounted) {
|
||||
ToastHelper.showErrorToast(context, 'Failed to load policy terms');
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() => _isLoadingPolicyTerms = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _openReminderConfigDialog() async {
|
||||
final clientPolicyId = localClientPolicyId ?? widget.ClientPoliyId;
|
||||
final token = localToken ?? widget.Token;
|
||||
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (dialogContext) {
|
||||
return _ReminderMailConfigDialog(
|
||||
clientPolicyId: clientPolicyId,
|
||||
token: token,
|
||||
apiService: apiService,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String _defaultReminderSubject() {
|
||||
final policyName = localCardPolicyName ?? widget.cardPolicy_name;
|
||||
return 'Reminder: Complete Your Enrollment - $policyName';
|
||||
@ -706,7 +806,7 @@ HR Team''';
|
||||
return (subject: subject, body: body);
|
||||
}
|
||||
|
||||
Future<void> _confirmAndSendReminder() async {
|
||||
Future<void> _openReminderTemplateDialog() async {
|
||||
final template = await _loadReminderEmailTemplate();
|
||||
if (!mounted) return;
|
||||
|
||||
@ -866,8 +966,8 @@ HR Team''';
|
||||
|
||||
final ok = response['status'] == 'success' || response['status'] == true;
|
||||
if (ok) {
|
||||
final message = response['message']?.toString() ??
|
||||
'Reminder sent successfully';
|
||||
final message =
|
||||
response['message']?.toString() ?? 'Reminder sent successfully';
|
||||
ToastHelper.showSuccessToast(context, message);
|
||||
await _logReminderActivity();
|
||||
} else {
|
||||
@ -1112,13 +1212,40 @@ HR Team''';
|
||||
const SizedBox(width: 12),
|
||||
|
||||
if (localTokenType == 'pre') ...[
|
||||
SizedBox(
|
||||
width: 150,
|
||||
height: 37,
|
||||
child: ElevatedButton(
|
||||
onPressed: _openReminderConfigDialog,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF009195),
|
||||
elevation: 0,
|
||||
padding: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Reminder Config',
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
SizedBox(
|
||||
width: 142,
|
||||
height: 37,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isSendingReminder
|
||||
? null
|
||||
: _confirmAndSendReminder,
|
||||
: _openReminderTemplateDialog,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFFE26728),
|
||||
elevation: 0,
|
||||
@ -1153,6 +1280,49 @@ HR Team''';
|
||||
const SizedBox(width: 12),
|
||||
],
|
||||
|
||||
if (localTokenType == 'post') ...[
|
||||
SizedBox(
|
||||
width: 130,
|
||||
height: 37,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isLoadingPolicyTerms
|
||||
? null
|
||||
: _openPolicyTermsDialog,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF009195),
|
||||
elevation: 0,
|
||||
padding: EdgeInsets.zero,
|
||||
disabledBackgroundColor:
|
||||
const Color(0xFF009195).withValues(alpha: 0.6),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: _isLoadingPolicyTerms
|
||||
? const SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
'Policy Terms',
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
],
|
||||
|
||||
SizedBox(
|
||||
width: 116,
|
||||
height: 37,
|
||||
@ -1777,7 +1947,7 @@ HR Team''';
|
||||
Widget _buildStatusSummary() {
|
||||
if (originalData.isEmpty) {
|
||||
return const SizedBox();
|
||||
}
|
||||
}
|
||||
|
||||
final statusCounts = getPreStatusCounts();
|
||||
const filters = <Map<String, String>>[
|
||||
@ -2883,3 +3053,573 @@ class _CDHeaderDelegate extends SliverPersistentHeaderDelegate {
|
||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
|
||||
true;
|
||||
}
|
||||
|
||||
class _PolicyTermsDialog extends StatelessWidget {
|
||||
final Map<String, String> terms;
|
||||
|
||||
const _PolicyTermsDialog({required this.terms});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final entries = terms.entries.toList();
|
||||
final maxHeight = MediaQuery.of(context).size.height * 0.65;
|
||||
final cappedMaxHeight = maxHeight.clamp(320.0, 560.0);
|
||||
final contentHeight =
|
||||
(entries.length * 88.0).clamp(120.0, cappedMaxHeight);
|
||||
|
||||
return AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
title: Text(
|
||||
'Policy Terms',
|
||||
style: GoogleFonts.poppins(fontWeight: FontWeight.w600, fontSize: 18),
|
||||
),
|
||||
content: SizedBox(
|
||||
width: 640,
|
||||
height: contentHeight,
|
||||
child: Scrollbar(
|
||||
thumbVisibility: entries.length > 4,
|
||||
child: ListView.separated(
|
||||
itemCount: entries.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(height: 10),
|
||||
itemBuilder: (context, index) {
|
||||
final entry = entries[index];
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF5F5F5),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFE8E8E8)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
entry.key,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: const Color(0xFF009195),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
entry.value,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF009195),
|
||||
),
|
||||
child: Text('Close', style: GoogleFonts.poppins(color: Colors.white)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ReminderMailConfigDialog extends StatefulWidget {
|
||||
final String clientPolicyId;
|
||||
final String token;
|
||||
final ApiService apiService;
|
||||
|
||||
const _ReminderMailConfigDialog({
|
||||
required this.clientPolicyId,
|
||||
required this.token,
|
||||
required this.apiService,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_ReminderMailConfigDialog> createState() =>
|
||||
_ReminderMailConfigDialogState();
|
||||
}
|
||||
|
||||
class _ReminderMailConfigDialogState extends State<_ReminderMailConfigDialog> {
|
||||
static const _frequencies = <String, String>{
|
||||
'daily': 'Daily',
|
||||
'weekly': 'Weekly',
|
||||
'monthly': 'Monthly',
|
||||
'custom': 'Custom',
|
||||
'working_days': 'Working Days',
|
||||
};
|
||||
|
||||
bool _isLoadingConfig = true;
|
||||
bool _isSaving = false;
|
||||
int? _configId;
|
||||
String _frequency = 'daily';
|
||||
bool _isEnabled = true;
|
||||
String _reminderDaysText = '';
|
||||
final Set<String> _selectedWorkingDays = {};
|
||||
List<Map<String, dynamic>> _workingDayOptions = [];
|
||||
late final TextEditingController _reminderDaysController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_reminderDaysController = TextEditingController();
|
||||
_loadConfig();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_reminderDaysController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _loadConfig() async {
|
||||
setState(() => _isLoadingConfig = true);
|
||||
try {
|
||||
final response = await widget.apiService.getReminderMailConfigApi(
|
||||
widget.clientPolicyId,
|
||||
widget.token,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
final ok = response['status'] == true || response['status'] == 'success';
|
||||
if (ok) {
|
||||
_workingDayOptions = _parseWorkingDayOptions(
|
||||
response['working_day_options'],
|
||||
);
|
||||
_applyConfig(response['data']);
|
||||
} else {
|
||||
ToastHelper.showErrorToast(
|
||||
context,
|
||||
response['message']?.toString() ?? 'Failed to load reminder config',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logDebug('Reminder config load failed: $e');
|
||||
if (mounted) {
|
||||
ToastHelper.showErrorToast(
|
||||
context,
|
||||
'Failed to load reminder configuration',
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() => _isLoadingConfig = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _parseWorkingDayOptions(dynamic raw) {
|
||||
if (raw is! List) return _defaultWorkingDayOptions();
|
||||
return raw
|
||||
.whereType<Map>()
|
||||
.map((item) => Map<String, dynamic>.from(item))
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _defaultWorkingDayOptions() {
|
||||
return [
|
||||
{'value': 1, 'label': 'Mon', 'key': 'mon'},
|
||||
{'value': 2, 'label': 'Tue', 'key': 'tue'},
|
||||
{'value': 3, 'label': 'Wed', 'key': 'wed'},
|
||||
{'value': 4, 'label': 'Thu', 'key': 'thu'},
|
||||
{'value': 5, 'label': 'Fri', 'key': 'fri'},
|
||||
{'value': 6, 'label': 'Sat', 'key': 'sat'},
|
||||
{'value': 7, 'label': 'Sun', 'key': 'sun'},
|
||||
];
|
||||
}
|
||||
|
||||
void _applyConfig(dynamic data) {
|
||||
_configId = null;
|
||||
_frequency = 'daily';
|
||||
_isEnabled = true;
|
||||
_reminderDaysText = '';
|
||||
_reminderDaysController.clear();
|
||||
_selectedWorkingDays.clear();
|
||||
|
||||
if (data is! Map) return;
|
||||
|
||||
final config = Map<String, dynamic>.from(data);
|
||||
_configId = int.tryParse(config['id']?.toString() ?? '');
|
||||
_frequency = config['frequency']?.toString() ?? 'daily';
|
||||
_isEnabled = config['is_enabled']?.toString() != '0';
|
||||
|
||||
if (_frequency == 'working_days') {
|
||||
final labels = config['working_day_labels'];
|
||||
if (labels is List && labels.isNotEmpty) {
|
||||
_selectedWorkingDays.addAll(labels.map((e) => e.toString()));
|
||||
} else {
|
||||
_applyWorkingDaysFromReminderDays(
|
||||
config['reminder_days']?.toString() ?? '',
|
||||
);
|
||||
}
|
||||
} else if (_frequency != 'daily') {
|
||||
_reminderDaysText = config['reminder_days']?.toString() ?? '';
|
||||
_reminderDaysController.text = _reminderDaysText;
|
||||
}
|
||||
}
|
||||
|
||||
void _applyWorkingDaysFromReminderDays(String reminderDays) {
|
||||
if (reminderDays.isEmpty) return;
|
||||
|
||||
final options = _workingDayOptions.isNotEmpty
|
||||
? _workingDayOptions
|
||||
: _defaultWorkingDayOptions();
|
||||
final valueToLabel = <String, String>{
|
||||
for (final option in options)
|
||||
option['value'].toString(): option['label'].toString(),
|
||||
};
|
||||
|
||||
for (final part in reminderDays.split(',')) {
|
||||
final token = part.trim();
|
||||
if (token.isEmpty) continue;
|
||||
|
||||
if (RegExp(r'^\d+$').hasMatch(token)) {
|
||||
final normalized = token == '0' ? '7' : token;
|
||||
final label = valueToLabel[normalized];
|
||||
if (label != null) {
|
||||
_selectedWorkingDays.add(label);
|
||||
}
|
||||
} else {
|
||||
final match = options.firstWhere(
|
||||
(option) =>
|
||||
option['label'].toString().toLowerCase() == token.toLowerCase() ||
|
||||
option['key'].toString().toLowerCase() == token.toLowerCase(),
|
||||
orElse: () => {},
|
||||
);
|
||||
if (match.isNotEmpty) {
|
||||
_selectedWorkingDays.add(match['label'].toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String? _buildReminderDays() {
|
||||
switch (_frequency) {
|
||||
case 'daily':
|
||||
return null;
|
||||
case 'working_days':
|
||||
if (_selectedWorkingDays.isEmpty) return null;
|
||||
return _selectedWorkingDays.join(',');
|
||||
default:
|
||||
final value = _reminderDaysText.trim();
|
||||
return value.isEmpty ? null : value;
|
||||
}
|
||||
}
|
||||
|
||||
String? _validateBeforeSave() {
|
||||
if (_frequency == 'working_days' && _selectedWorkingDays.isEmpty) {
|
||||
return 'Select at least one working day';
|
||||
}
|
||||
if (_frequency != 'daily' &&
|
||||
_frequency != 'working_days' &&
|
||||
_reminderDaysText.trim().isEmpty) {
|
||||
return 'Reminder days are required for $_frequency frequency';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<int?> _resolveHrId() async {
|
||||
final tokenService = TokenStorageService();
|
||||
final hrId = await tokenService.readValue('enrollmentHrId') ??
|
||||
await tokenService.readValue('empHrId');
|
||||
return int.tryParse(hrId?.toString() ?? '');
|
||||
}
|
||||
|
||||
Future<void> _saveConfig() async {
|
||||
final validationError = _validateBeforeSave();
|
||||
if (validationError != null) {
|
||||
ToastHelper.showWarningToast(context, validationError);
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _isSaving = true);
|
||||
try {
|
||||
final policyId = int.tryParse(widget.clientPolicyId);
|
||||
if (policyId == null) {
|
||||
ToastHelper.showErrorToast(context, 'Invalid client policy id');
|
||||
return;
|
||||
}
|
||||
|
||||
final payload = <String, dynamic>{
|
||||
'client_policy_id': policyId,
|
||||
'frequency': _frequency,
|
||||
'is_enabled': _isEnabled ? 1 : 0,
|
||||
};
|
||||
|
||||
final reminderDays = _buildReminderDays();
|
||||
if (reminderDays != null) {
|
||||
payload['reminder_days'] = reminderDays;
|
||||
}
|
||||
|
||||
final hrId = await _resolveHrId();
|
||||
if (hrId != null) {
|
||||
payload['hr_id'] = hrId;
|
||||
}
|
||||
|
||||
if (_configId != null) {
|
||||
payload['id'] = _configId;
|
||||
}
|
||||
|
||||
final response = await widget.apiService.saveReminderMailConfigApi(
|
||||
widget.token,
|
||||
payload,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
final ok = response['status'] == true || response['status'] == 'success';
|
||||
if (ok) {
|
||||
final data = response['data'];
|
||||
if (data is Map) {
|
||||
_applyConfig(data);
|
||||
}
|
||||
ToastHelper.showSuccessToast(
|
||||
context,
|
||||
response['message']?.toString() ??
|
||||
'Reminder mail configuration saved successfully',
|
||||
);
|
||||
} else {
|
||||
ToastHelper.showErrorToast(
|
||||
context,
|
||||
response['message']?.toString() ?? 'Failed to save configuration',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logDebug('Reminder config save failed: $e');
|
||||
if (mounted) {
|
||||
ToastHelper.showErrorToast(
|
||||
context,
|
||||
'Failed to save reminder configuration',
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() => _isSaving = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildDaysField() {
|
||||
if (_frequency == 'daily') {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
if (_frequency == 'working_days') {
|
||||
final options = _workingDayOptions.isNotEmpty
|
||||
? _workingDayOptions
|
||||
: _defaultWorkingDayOptions();
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Working Days',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: options.map((option) {
|
||||
final label = option['label'].toString();
|
||||
final selected = _selectedWorkingDays.contains(label);
|
||||
return FilterChip(
|
||||
label: Text(label, style: GoogleFonts.poppins(fontSize: 12)),
|
||||
selected: selected,
|
||||
onSelected: (value) {
|
||||
setState(() {
|
||||
if (value) {
|
||||
_selectedWorkingDays.add(label);
|
||||
} else {
|
||||
_selectedWorkingDays.remove(label);
|
||||
}
|
||||
});
|
||||
},
|
||||
selectedColor: const Color(0xFFC5F2F4),
|
||||
checkmarkColor: const Color(0xFF009195),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
final helperText = switch (_frequency) {
|
||||
'weekly' => 'Weekday numbers 0-6 (Sun-Sat), comma-separated. Example: 1,3,5',
|
||||
'monthly' => 'Days of month 1-31, comma-separated. Example: 1,15,28',
|
||||
'custom' => 'Custom days of month 1-31, comma-separated. Example: 5,10,20',
|
||||
_ => '',
|
||||
};
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Reminder Days',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
TextField(
|
||||
controller: _reminderDaysController,
|
||||
onChanged: (value) => _reminderDaysText = value,
|
||||
style: GoogleFonts.poppins(fontSize: 14),
|
||||
decoration: InputDecoration(
|
||||
hintText: helperText,
|
||||
filled: true,
|
||||
fillColor: const Color(0xFFF5F5F5),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
helperText,
|
||||
style: GoogleFonts.poppins(fontSize: 11, color: Colors.black45),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isBusy = _isSaving;
|
||||
|
||||
return AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
title: Text(
|
||||
'Email Reminder Config',
|
||||
style: GoogleFonts.poppins(fontWeight: FontWeight.w600, fontSize: 18),
|
||||
),
|
||||
content: SizedBox(
|
||||
width: 560,
|
||||
child: _isLoadingConfig
|
||||
? const SizedBox(
|
||||
height: 180,
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Configure the schedule for automated enrollment reminder emails.',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
color: Colors.black54,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text(
|
||||
'Enable scheduled reminders',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
value: _isEnabled,
|
||||
activeColor: const Color(0xFF009195),
|
||||
onChanged: isBusy
|
||||
? null
|
||||
: (value) => setState(() => _isEnabled = value),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Frequency',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
DropdownButtonFormField<String>(
|
||||
value: _frequency,
|
||||
isExpanded: true,
|
||||
decoration: InputDecoration(
|
||||
filled: true,
|
||||
fillColor: const Color(0xFFF5F5F5),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 10,
|
||||
),
|
||||
),
|
||||
items: _frequencies.entries
|
||||
.map(
|
||||
(entry) => DropdownMenuItem(
|
||||
value: entry.key,
|
||||
child: Text(
|
||||
entry.value,
|
||||
style: GoogleFonts.poppins(fontSize: 14),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: isBusy
|
||||
? null
|
||||
: (value) {
|
||||
if (value == null) return;
|
||||
setState(() {
|
||||
_frequency = value;
|
||||
_reminderDaysText = '';
|
||||
_reminderDaysController.clear();
|
||||
_selectedWorkingDays.clear();
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
_buildDaysField(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: isBusy ? null : () => Navigator.pop(context),
|
||||
child: Text('Cancel', style: GoogleFonts.poppins(color: Colors.black54)),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: isBusy || _isLoadingConfig ? null : _saveConfig,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF009195),
|
||||
),
|
||||
child: _isSaving
|
||||
? const SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: Text('Save', style: GoogleFonts.poppins(color: Colors.white)),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,6 +579,7 @@ class _PolicyGrid extends StatelessWidget {
|
||||
final Function(String clientPolicyId)? onBulkDownload;
|
||||
|
||||
static const double _enrollmentCardHeight = 156;
|
||||
static const double _activePolicyCardHeight = 170;
|
||||
|
||||
const _PolicyGrid({
|
||||
super.key,
|
||||
@ -699,7 +700,7 @@ class _PolicyGrid extends StatelessWidget {
|
||||
if (isEnrollment) {
|
||||
cardHeight = _enrollmentCardHeight;
|
||||
} else {
|
||||
cardHeight = 170;
|
||||
cardHeight = _activePolicyCardHeight;
|
||||
}
|
||||
|
||||
final double totalHeight = rowCount * cardHeight + ((rowCount - 1) * 16);
|
||||
@ -714,7 +715,8 @@ class _PolicyGrid extends StatelessWidget {
|
||||
childAspectRatio: config.childAspectRatio,
|
||||
crossAxisSpacing: 16,
|
||||
mainAxisSpacing: 16,
|
||||
mainAxisExtent: isEnrollment ? _enrollmentCardHeight : 150,
|
||||
mainAxisExtent:
|
||||
isEnrollment ? _enrollmentCardHeight : _activePolicyCardHeight,
|
||||
),
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) {
|
||||
@ -1085,6 +1087,19 @@ class _EnrollmentPolicyCardNew extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
String? _formatTpaDisplayName(Map<String, dynamic> data) {
|
||||
final tpaName = data['tpa_name']?.toString().trim() ?? '';
|
||||
final tpaShortName = data['tpa_short_name']?.toString().trim() ?? '';
|
||||
final raw = tpaName.isNotEmpty ? tpaName : tpaShortName;
|
||||
if (raw.isEmpty) return null;
|
||||
|
||||
final normalized = raw.toLowerCase().replaceAll(RegExp(r'[\s_-]+'), '');
|
||||
if (normalized == 'inhouse') {
|
||||
return 'In-house';
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
class _ActivePolicyCardNew extends StatelessWidget {
|
||||
final Map<String, dynamic> data;
|
||||
final VoidCallback? onTap;
|
||||
@ -1100,6 +1115,8 @@ class _ActivePolicyCardNew extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final tpaLabel = _formatTpaDisplayName(data);
|
||||
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click, // 👈 pointer on hover
|
||||
child: InkWell(
|
||||
@ -1197,6 +1214,24 @@ class _ActivePolicyCardNew extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
|
||||
if (tpaLabel != null) ...[
|
||||
const SizedBox(height: 2),
|
||||
Tooltip(
|
||||
message: tpaLabel,
|
||||
waitDuration: const Duration(milliseconds: 300),
|
||||
child: Text(
|
||||
tpaLabel,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: false,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
const SizedBox(height: 4),
|
||||
|
||||
/// DATE RANGE
|
||||
|
||||
@ -1088,6 +1088,62 @@ class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getReminderMailConfigApi(
|
||||
String clientPolicyId,
|
||||
String token,
|
||||
) async {
|
||||
final url = Uri.parse(
|
||||
'${Environment.apiUrl}getReminderMailConfig'
|
||||
'?client_policy_id=$clientPolicyId',
|
||||
);
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
};
|
||||
return _makeGetRequest(url, headers);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> saveReminderMailConfigApi(
|
||||
String token,
|
||||
Map<String, dynamic> payload,
|
||||
) async {
|
||||
final url = Uri.parse('${Environment.apiUrl}saveReminderMailConfig');
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
return _makePostRequest(url, jsonEncode(payload), headers);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> sendReminderMailApi(
|
||||
String clientPolicyId,
|
||||
String token,
|
||||
) async {
|
||||
final url = Uri.parse('${Environment.apiUrl}sendReminderMail');
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
final policyId = int.tryParse(clientPolicyId) ?? clientPolicyId;
|
||||
return _makePostRequest(
|
||||
url,
|
||||
jsonEncode({'client_policy_id': policyId}),
|
||||
headers,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getClientRMApi(
|
||||
String postClientId,
|
||||
String token,
|
||||
) async {
|
||||
final url = Uri.parse(
|
||||
'${Environment.apiUrlPost}getClientRM?client_id=$postClientId',
|
||||
);
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
};
|
||||
return _makeGetRequest(url, headers);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getEmployeeAndDependenceToApiPre(
|
||||
String clintID, String getPolicyNo, String empRefId, String token) async {
|
||||
logDebug(_hrtoken);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user