username and upload file changes

This commit is contained in:
Surendiran 2025-11-27 11:32:19 +05:30
parent 521bd49a17
commit 45eb1d4c36
17 changed files with 2323 additions and 838 deletions

View File

@ -8,13 +8,25 @@ import 'package:nhance_app_pwa/customAppBar/responsive.dart';
import '../pages/postEnrollment/service/api_service.dart'; import '../pages/postEnrollment/service/api_service.dart';
import '../pages/service/SessionManager.dart'; import '../pages/service/SessionManager.dart';
import '../pages/service/popup_helper.dart'; import '../pages/service/popup_helper.dart';
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
@override
_CustomAppBarState createState() => _CustomAppBarState();
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { @override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
}
class _CustomAppBarState extends State<CustomAppBar> {
@override @override
Size get preferredSize => Size.fromHeight(kToolbarHeight); Size get preferredSize => Size.fromHeight(kToolbarHeight);
late ApiService apiService; late ApiService apiService;
final session = SessionManager(); final session = SessionManager();
@override
void initState() {
super.initState();
apiService = ApiService(context);
}
Future<void> logout(BuildContext context) async { Future<void> logout(BuildContext context) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('_postToken'); final String? token = prefs.getString('_postToken');
@ -28,107 +40,179 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
apiService = ApiService(context);
final sw = MediaQuery.of(context).size.width; final sw = MediaQuery.of(context).size.width;
final isPoliciesPage = Uri.base.fragment == 'policies'; return Scaffold(
return ClipRRect( backgroundColor: Color(0xFFFFFCE5), // Set background color for AppBar
borderRadius: Responsive.isDesktop(context) || isPoliciesPage appBar: PreferredSize(
? BorderRadius.zero preferredSize: widget.preferredSize,
: BorderRadius.only( child: SafeArea(
bottomLeft: Radius.circular(32.0), child: Container(
bottomRight: Radius.circular(32.0), // padding: Responsive.isDesktop(context)
// ? EdgeInsets.symmetric(horizontal: 46.0)
// : EdgeInsets.symmetric(horizontal: 0),
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
(Responsive.isDesktop(context) ? 0.03 : 0.02),
), ),
child: AppBar( child: Row(
backgroundColor: const Color(0xFFFFFBDE), mainAxisAlignment: MainAxisAlignment.spaceBetween,
elevation: 0, // Set background color for AppBar children: [
toolbarHeight: kToolbarHeight, // Logo Column
titleSpacing: 0.0, // Expanded(
automaticallyImplyLeading: false, // // flex: Responsive.isDesktop(context) ? 1 : 9,
title: Padding( // child:
padding: Responsive.isDesktop(context) Row(
? EdgeInsets.symmetric(horizontal: 16.0)
: EdgeInsets.symmetric(horizontal: 10),
child: Row(
children: [
// Logo Column
Expanded(
flex: Responsive.isDesktop(context) ? 3 : 9,
child: Row(
mainAxisAlignment: Responsive.isDesktop(context) mainAxisAlignment: Responsive.isDesktop(context)
? MainAxisAlignment.spaceEvenly ? MainAxisAlignment.spaceEvenly
: MainAxisAlignment : MainAxisAlignment.start,
.start, // Adjust the alignment as needed
children: [ children: [
Container( Container(
// margin: EdgeInsets.only( margin: EdgeInsets.only(top: 10, bottom: 10),
// top: 10, bottom: 10, left: 10, right: 10), width: 150,
// width: Responsive.isDesktop(context) ? 150 : 130, height: 150,
// height: Responsive.isDesktop(context) ? 31 : 130, child: Image.asset(
child: SvgPicture.asset( 'assets/nhance_client_logo.png',
'assets/nhance_client_logo.svg', fit: BoxFit.contain,
width: 150,
), ),
// child: Image.asset(
// 'assets/nhance_logo.png',
// width: 250,
// ),
), ),
], ],
), ),
), // ),
// AdaptiveNavBar Column // AdaptiveNavBar Column
if (Responsive.isDesktop(context))
Expanded( // Expanded(
flex: Responsive.isDesktop(context) ? 9 : 3, // // flex: Responsive.isDesktop(context) ? 1 : 9,
child: AdaptiveNavBar( // child:
screenWidth: sw, if(Responsive.isDesktop(context))
backgroundColor: const Color(0xFFFFFBDE), Row(
leading: mainAxisSize: MainAxisSize.min,
Container(), // Set an empty container as we have the logo separately children: [
title: Text(''), NavBarItem(
navBarItems: [ text: "Home",
NavBarItem( onTap: () {
text: "Home", context.push('/home');
onTap: () { },
context.push('/home'); ),
}, NavBarItem(
), text: "Claims",
NavBarItem( onTap: () {
text: "Claims", context.push('/claims');
onTap: () { },
context.push('/claims'); ),
}, NavBarItem(
), text: "Help",
NavBarItem( onTap: () {
text: "Help", context.push('/help');
onTap: () { },
context.push('/help'); ),
}, NavBarItem(
), text: "Wellness",
NavBarItem( onTap: () {
text: "Wellness", // context.push('/wellness');
onTap: () { // Wellness tab clicked show popup
// Wellness tab clicked show popup PopupHelper.showRedirectPopup(
PopupHelper.showRedirectPopup( context: context,
context: context, apiService: apiService,
apiService: apiService, empPrimaryId: session.empPrimaryId,
empPrimaryId: session.empPrimaryId, );
); },
}, ),
), NavBarItem(
NavBarItem( text: "Profile",
text: "Profile", onTap: () {
onTap: () { context.push('/profile');
context.push('/profile'); },
}, ),
), ],
],
),
), ),
], // )
// Expanded(
// flex: Responsive.isDesktop(context) ? 9 : 3,
// child: AdaptiveNavBar(
// screenWidth: sw,
// backgroundColor: Color(0xFFFFFCE5),
// leading:
// Container(), // Set an empty container as we have the logo separately
// title: Text(''),
// navBarItems: [
// // if (Responsive.isDesktop(context))
// // if (hideInactiveStatus)
// // NavBarItem(
// // text: "Inactive Policy",
// // onTap: () {
// // Navigator.pushNamed(context, 'oldPolicy');
// // },
// // ),
// // if (showBackToHR)
// NavBarItem(
// text: "Change Branch",
// onTap: () async {
// final prefs = await SharedPreferences.getInstance();
// await prefs.remove('selected_branch');
// await prefs.remove('decoded_token');
// await prefs.remove('clientLogo');
// await prefs.remove('clientName');
// await prefs.remove('empAllowed_modules');
// await prefs.remove('empClientBranchId');
// await prefs.remove('empClientId');
// await prefs.remove('empEmail');
// await prefs.remove('empHrId');
// await prefs.remove('empPrimaryId');
// await prefs.remove('enrollmentAllowed_modules');
// await prefs.remove('enrollmentClient_id');
// await prefs.remove('enrollmentEmpClientBranchId');
// await prefs.remove('enrollmentEmpPrimaryId');
// await prefs.remove('enrollmentHrId');
// await prefs.remove('token');
// Navigator.pushNamed(context, 'branchSelection');
// },
// ),
// NavBarItem(
// text: "Logout",
// onTap: () async {
// logout(context);
// },
// ),
// ],
// ),
// ),
],
),
), ),
), ),
), ),
); );
} }
} }
class NavBarItem extends StatelessWidget {
final String text;
final VoidCallback? onTap;
const NavBarItem({
Key? key,
required this.text,
this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
borderRadius: BorderRadius.circular(6),
onTap: onTap,
hoverColor: const Color(0xFFF4F3E7), // subtle hover background
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
child: Text(
text,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
),
);
}
}

View File

@ -41,12 +41,25 @@ class _changesPasswordState extends State<changesPassword> {
bool _obscureNewPassword = true; bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true; bool _obscureConfirmPassword = true;
late SessionManager session; late SessionManager session;
bool hasMinLength = false;
bool hasUpperLower = false;
bool hasNumber = false;
bool hasSpecialChar = false;
bool get isPasswordValid => hasMinLength && hasUpperLower && hasNumber && hasSpecialChar;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
} }
void validatePassword(String password) {
setState(() {
hasMinLength = password.length >= 8;
hasUpperLower = RegExp(r'(?=.*[A-Za-z])').hasMatch(password);
hasNumber = RegExp(r'(?=.*\d)').hasMatch(password);
hasSpecialChar = RegExp(r'(?=.*[@$!%*#?&])').hasMatch(password);
});
}
Future<void> resetYourPassword() async { Future<void> resetYourPassword() async {
final oldpassword = oldPasswordController.text.trim(); final oldpassword = oldPasswordController.text.trim();
@ -354,7 +367,7 @@ class _changesPasswordState extends State<changesPassword> {
MainAxisAlignment.center, MainAxisAlignment.center,
children: [ children: [
Text( Text(
"Welcome to Nhance", "Change Password",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -378,7 +391,7 @@ class _changesPasswordState extends State<changesPassword> {
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"Login with your to review and enroll for exciting health benefits for you and your family", "To change your password, please fill in the fields below.",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Color(0xFF000000)), color: Color(0xFF000000)),
@ -466,70 +479,58 @@ class _changesPasswordState extends State<changesPassword> {
const SizedBox(height: 10), const SizedBox(height: 10),
Container( Container(
height: 55, height: 55,
margin: Responsive.isDesktop( margin: Responsive.isDesktop(context)
context) ? const EdgeInsets.symmetric(horizontal: 150)
? const EdgeInsets : const EdgeInsets.symmetric(horizontal: 0),
.symmetric(
horizontal: 150)
: const EdgeInsets
.symmetric(
horizontal: 0),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(width: 1, color: Colors.grey),
width: 1, borderRadius: BorderRadius.circular(10),
color: Colors.grey),
borderRadius:
BorderRadius.circular(
10),
), ),
child: TextFormField( child: TextFormField(
controller: controller: newPasswordController,
newPasswordController, obscureText: _obscureNewPassword,
obscureText: onChanged: validatePassword,
_obscureNewPassword, textAlignVertical: TextAlignVertical.center,
textAlignVertical:
TextAlignVertical
.center,
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
hintText: hintText: "New Password",
"New Password", contentPadding: const EdgeInsets.symmetric(horizontal: 10),
contentPadding:
const EdgeInsets
.symmetric(
horizontal: 10),
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscureNewPassword _obscureNewPassword ? Icons.visibility_off : Icons.visibility,
? Icons
.visibility_off
: Icons
.visibility,
color: Colors.grey, color: Colors.grey,
), ),
onPressed: () { onPressed: () {
setState(() { setState(() {
_obscureNewPassword = _obscureNewPassword = !_obscureNewPassword;
!_obscureNewPassword;
}); });
}, },
), ),
), ),
validator: (value) { ),
if (value == null || ),
value.isEmpty) { const SizedBox(height: 8),
return 'Please enter your new password'; // 🔹 VALIDATION LIST
} Padding(
if (value.length < 6) { padding: Responsive.isDesktop(context)
return 'Password must be at least 6 characters'; ? const EdgeInsets.symmetric(horizontal: 150)
} : const EdgeInsets.symmetric(horizontal: 5),
if (!RegExp( child: Column(
r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$') crossAxisAlignment: CrossAxisAlignment.start,
.hasMatch(value)) { children: [
return 'Include at least 1 uppercase letter and 1 number'; Row(
} children: [
return null; Expanded(child: _buildCheckItem(hasMinLength, "Minimum 8 characters")),
}, Expanded(child: _buildCheckItem(hasSpecialChar, "1 special character")),
],
),
Row(
children: [
Expanded(child: _buildCheckItem(hasUpperLower, "1 UPPER or lower case")),
Expanded(child: _buildCheckItem(hasNumber, "1 numerical")),
],
),
],
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
@ -767,4 +768,28 @@ class _changesPasswordState extends State<changesPassword> {
)), )),
))); )));
} }
Widget _buildCheckItem(bool status, String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
children: [
Icon(
status ? Icons.check : Icons.close,
color: status ? Colors.green : Colors.red,
size: 18,
),
const SizedBox(width: 6),
Text(
text,
style: TextStyle(
color: status ? Colors.green : Colors.red,
fontSize: 14,
),
),
],
),
);
}
} }

View File

@ -442,9 +442,9 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
// final SharedPreferences prefs = await SharedPreferences.getInstance(); // final SharedPreferences prefs = await SharedPreferences.getInstance();
// prefs.setString('empEmailid', widget.email); // prefs.setString('empEmailid', widget.email);
ToastHelper.showSuccessToast(context, 'Successfully Login'); ToastHelper.showSuccessToast(context, 'Successfully Login');
// checkPassword(context,session.empEmailCorporate,session.client_id,'home'); checkPassword(context,session.empEmailCorporate,session.client_id,'home');
// if (emp_status == 'enrolled' || emp_status == 'active') { // if (emp_status == 'enrolled' || emp_status == 'active') {
context.go('/home'); // context.go('/home');
// Navigator.pushReplacementNamed(context, 'home'); // Navigator.pushReplacementNamed(context, 'home');
// } else { // } else {
// Navigator.pushReplacementNamed(context, 'empDetails'); // Navigator.pushReplacementNamed(context, 'empDetails');
@ -499,11 +499,11 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
} else { } else {
if (_preToken != null && _preToken.isNotEmpty) { if (_preToken != null && _preToken.isNotEmpty) {
ToastHelper.showSuccessToast(context, 'Successfully Login'); ToastHelper.showSuccessToast(context, 'Successfully Login');
// checkPassword(context,session.enrollmentEmailCorporate,session.enrollmentClient_id,'empDetails'); checkPassword(context,session.enrollmentEmailCorporate,session.enrollmentClient_id,'empDetails');
// if (emp_status == 'enrolled' || emp_status == 'active') { // if (emp_status == 'enrolled' || emp_status == 'active') {
// Navigator.pushReplacementNamed(context, 'home'); // Navigator.pushReplacementNamed(context, 'home');
// } else { // } else {
context.go('/empDetails'); // context.go('/empDetails');
// Navigator.pushReplacementNamed(context, 'empDetails'); // Navigator.pushReplacementNamed(context, 'empDetails');
// } // }
} }

File diff suppressed because it is too large Load Diff

View File

@ -960,15 +960,25 @@ class _claimsState extends State<claims> {
print(claimStatus); print(claimStatus);
print(claimsDepartmentName); print(claimsDepartmentName);
final Map<String, Color> statusColors = { final Map<String, Color> statusColors = {
'Received': Colors.blueGrey, // New / Received 'Claim Received': Colors.blueGrey,
'Under Process': Colors.orangeAccent, // Work in progress 'Under Process' : Colors.orangeAccent,
'Approved': Colors.green, // Approved 'Information Required': Colors.deepOrange,
'Settled': Colors.teal, // Completed successfully 'Approved': Colors.green,
'Returned': Colors.deepOrange, // Sent back for correction 'Settled': Colors.teal,
'Rejected': Colors.red, // Rejected 'Denial Review Awaited':Colors.redAccent,
'Cancelled': Colors.redAccent, // Cancelled 'Rejected': Colors.red,
'Closed': Colors.grey, // Closed
// 'Received': Colors.blueGrey, // New / Received
// 'Under Process': Colors.orangeAccent, // Work in progress
// 'Approved': Colors.green, // Approved
// 'Settled': Colors.teal, // Completed successfully
// 'Returned': Colors.deepOrange, // Sent back for correction
// 'Rejected': Colors.red, // Rejected
// 'Cancelled': Colors.redAccent, // Cancelled
// 'Closed': Colors.grey, // Closed
}; };
// Determine the color based on the claimStatus // Determine the color based on the claimStatus

View File

@ -601,6 +601,7 @@ class _ClaimHistoryPopupState extends State<ClaimHistoryPopup> {
Widget _getStepTitleFromApi(String status, Map<String, dynamic> data) { Widget _getStepTitleFromApi(String status, Map<String, dynamic> data) {
final modifiedBy = data['modified_by'] ?? ''; final modifiedBy = data['modified_by'] ?? '';
final modifiedAt = data['modified_at'] ?? ''; final modifiedAt = data['modified_at'] ?? '';
final symbol = (data['modified_by'] != null && data['modified_by'] != '') ? ' - ' : '';
final isDesktop = Responsive.isDesktop(context); final isDesktop = Responsive.isDesktop(context);
return RichText( return RichText(
@ -615,7 +616,7 @@ class _ClaimHistoryPopupState extends State<ClaimHistoryPopup> {
), ),
), ),
TextSpan( TextSpan(
text: ' ($modifiedBy $modifiedAt)', text: ' ($modifiedBy$symbol$modifiedAt)',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: Responsive.isDesktop(context) ? 14 : 11, fontSize: Responsive.isDesktop(context) ? 14 : 11,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,

View File

@ -1053,13 +1053,23 @@ class _HomeState extends State<Home> {
crossAxisCount: Responsive.isDesktop(context) ? 2 : 1, crossAxisCount: Responsive.isDesktop(context) ? 2 : 1,
crossAxisSpacing: 20.0, crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0, mainAxisSpacing: 20.0,
childAspectRatio: Responsive.isDesktop(context) ? 3.2 : 2.8), childAspectRatio: Responsive.isDesktop(context) ? 2.2 : 2.6),
itemCount: data.length, itemCount: data.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
var item = data[index]; var item = data[index];
String policyHeading = item['heading']; String policyHeading = item['heading'];
String policyName = item['policy_name']; String policyName = item['policy_name'];
String si_value = item['si_value']; // String si_value = item['si_value'];
String siValueStr = item['si_value'] ?? '0';
String settledStr = item['total_settled_amount']?.toString() ?? '0';
double siValue = double.tryParse(siValueStr) ?? 0;
double settled = double.tryParse(settledStr) ?? 0;
// Main logic
double finalValue = (settled == 0) ? siValue : (siValue - settled);
print("Final Value: $finalValue");
String policyEndDate = item['policy_end_date']; String policyEndDate = item['policy_end_date'];
List<dynamic> employeePolicy = item['EmployeePolicy']; List<dynamic> employeePolicy = item['EmployeePolicy'];
String memberNames = getMemberNames(employeePolicy); String memberNames = getMemberNames(employeePolicy);
@ -1188,7 +1198,7 @@ class _HomeState extends State<Home> {
children: [ children: [
Text( Text(
formatToCroresLakhsAndThousands( formatToCroresLakhsAndThousands(
si_value), siValueStr),
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: fontSize:
@ -1247,7 +1257,34 @@ class _HomeState extends State<Home> {
), ),
], ],
), ),
SizedBox(height: 7), SizedBox(height: 20),
Row(
children: [
Expanded(
flex: 12,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
Text(
'Remaining Amount: ${finalValue}',
textAlign: TextAlign.right,
style: GoogleFonts.poppins(
fontSize:
Responsive.isDesktop(
context)
? 10
: 10,
fontWeight: FontWeight.w400,
color: Color(0xFF747474),
),
),
],
),
),
],
),
// SizedBox(height: 7),
], ],
))), ))),
], ],

View File

@ -24,6 +24,8 @@ import 'package:file_picker/file_picker.dart';
import '../service/SessionManager.dart'; import '../service/SessionManager.dart';
import '../service/TokenService.dart'; import '../service/TokenService.dart';
import '../service/popup_helper.dart'; import '../service/popup_helper.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
class planclaimsform extends StatefulWidget { class planclaimsform extends StatefulWidget {
final Map<String, dynamic>? details; final Map<String, dynamic>? details;
@ -634,29 +636,73 @@ class _planclaimsformState extends State<planclaimsform> {
} }
// NEW VALIDATION: At least one PDF must be uploaded // NEW VALIDATION: At least one PDF must be uploaded
bool hasPdf = uploadedFiles.any((uf) { // bool hasPdf = uploadedFiles.any((uf) {
final ext = uf.file.extension?.toLowerCase() ?? ''; // final ext = uf.file.extension?.toLowerCase() ?? '';
return ext == 'pdf'; // return ext == 'pdf';
}); // });
//
if (!hasPdf) { // if (!hasPdf) {
ToastHelper.showErrorToast(context, 'Please upload at least one PDF document'); // ToastHelper.showErrorToast(context, 'Please upload at least one PDF document');
setState(() => isLoading = false); // setState(() => isLoading = false);
return; // return;
} // }
// Add files // Add files
// for (var uf in uploadedFiles) {
// final pf = uf.file;
// if (pf.bytes != null) {
// request.files.add(http.MultipartFile.fromBytes(
// 'claim_docs[]',
// pf.bytes!,
// filename: pf.name,
// ));
// }
// }
// Add files convert images to PDF if needed
for (var uf in uploadedFiles) { for (var uf in uploadedFiles) {
final pf = uf.file; final pf = uf.file;
final ext = pf.extension?.toLowerCase() ?? '';
if (pf.bytes != null) { if (pf.bytes != null) {
request.files.add(http.MultipartFile.fromBytes( Uint8List fileBytes = pf.bytes!;
'claim_docs[]',
pf.bytes!, if (['jpg', 'jpeg', 'png', 'heic'].contains(ext)) {
filename: pf.name, // Convert image PDF
)); final pdf = pw.Document();
final image = pw.MemoryImage(fileBytes);
pdf.addPage(
pw.Page(
build: (pw.Context context) => pw.Center(
child: pw.Image(image, fit: pw.BoxFit.contain),
),
),
);
fileBytes = await pdf.save(); // converted PDF bytes
// replace file name with .pdf extension
final pdfFileName = pf.name.replaceAll(RegExp(r'\.\w+$'), '.pdf');
print('📄 Converted image ${pf.name} → PDF ($pdfFileName)');
request.files.add(http.MultipartFile.fromBytes(
'claim_docs[]',
fileBytes,
filename: pdfFileName,
));
} else {
// Already a PDF
request.files.add(http.MultipartFile.fromBytes(
'claim_docs[]',
fileBytes,
filename: pf.name,
));
}
} }
} }
// Combine all names into a JSON array string // Combine all names into a JSON array string
final claimDocNames = uploadedFiles.map((uf) => uf.label.trim()).toList(); final claimDocNames = uploadedFiles.map((uf) => uf.label.trim()).toList();
final encodedNames = jsonEncode(claimDocNames); final encodedNames = jsonEncode(claimDocNames);

View File

@ -787,10 +787,10 @@ class _profileState extends State<profile> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// Change Password Button // Change Password Button
// if(Responsive.isDesktop(context)) if(Responsive.isDesktop(context))
// _buildChangePasswordButton(context), _buildChangePasswordButton(context),
// const SizedBox(width: 10), const SizedBox(width: 10),
// Logout Button // Logout Button
Responsive.isDesktop(context) Responsive.isDesktop(context)

View File

@ -146,6 +146,7 @@ class ApiService {
await _initializeToken(); await _initializeToken();
} }
final url = Uri.parse('${Environment.apiUrl}getWellnessURL?emp_id=$empPrimaryId'); final url = Uri.parse('${Environment.apiUrl}getWellnessURL?emp_id=$empPrimaryId');
// final url = Uri.parse('${Environment.apiUrl}getWellnessURL?emp_id=$empPrimaryId&client_policy_id=$client_policy_id');
final headers = { final headers = {
'Authorization': 'Bearer $_postToken' ?? '', 'Authorization': 'Bearer $_postToken' ?? '',
}; };

View File

@ -41,12 +41,25 @@ class _setPasswordState extends State<setPassword> {
bool _obscureNewPassword = true; bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true; bool _obscureConfirmPassword = true;
late SessionManager session; late SessionManager session;
bool hasMinLength = false;
bool hasUpperLower = false;
bool hasNumber = false;
bool hasSpecialChar = false;
bool get isPasswordValid => hasMinLength && hasUpperLower && hasNumber && hasSpecialChar;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
} }
void validatePassword(String password) {
setState(() {
hasMinLength = password.length >= 8;
hasUpperLower = RegExp(r'(?=.*[A-Za-z])').hasMatch(password);
hasNumber = RegExp(r'(?=.*\d)').hasMatch(password);
hasSpecialChar = RegExp(r'(?=.*[@$!%*#?&])').hasMatch(password);
});
}
Future<void> resetYourPassword() async { Future<void> resetYourPassword() async {
final newPassword = newPasswordController.text.trim(); final newPassword = newPasswordController.text.trim();
@ -348,7 +361,7 @@ class _setPasswordState extends State<setPassword> {
MainAxisAlignment.center, MainAxisAlignment.center,
children: [ children: [
Text( Text(
"Welcome to Nhance", "Set a new password",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -372,7 +385,7 @@ class _setPasswordState extends State<setPassword> {
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"Login with your to review and enroll for exciting health benefits for you and your family", "Create a new password. Ensure it differs from previous ones for security",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
color: Color(0xFF000000)), color: Color(0xFF000000)),
@ -391,70 +404,58 @@ class _setPasswordState extends State<setPassword> {
// 🔹 Password Field // 🔹 Password Field
Container( Container(
height: 55, height: 55,
margin: Responsive.isDesktop( margin: Responsive.isDesktop(context)
context) ? const EdgeInsets.symmetric(horizontal: 150)
? const EdgeInsets : const EdgeInsets.symmetric(horizontal: 0),
.symmetric(
horizontal: 150)
: const EdgeInsets
.symmetric(
horizontal: 0),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(width: 1, color: Colors.grey),
width: 1, borderRadius: BorderRadius.circular(10),
color: Colors.grey),
borderRadius:
BorderRadius.circular(
10),
), ),
child: TextFormField( child: TextFormField(
controller: controller: newPasswordController,
newPasswordController, obscureText: _obscureNewPassword,
obscureText: onChanged: validatePassword,
_obscureNewPassword, textAlignVertical: TextAlignVertical.center,
textAlignVertical:
TextAlignVertical
.center,
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
hintText: hintText: "New Password",
"New Password", contentPadding: const EdgeInsets.symmetric(horizontal: 10),
contentPadding:
const EdgeInsets
.symmetric(
horizontal: 10),
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
_obscureNewPassword _obscureNewPassword ? Icons.visibility_off : Icons.visibility,
? Icons
.visibility_off
: Icons
.visibility,
color: Colors.grey, color: Colors.grey,
), ),
onPressed: () { onPressed: () {
setState(() { setState(() {
_obscureNewPassword = _obscureNewPassword = !_obscureNewPassword;
!_obscureNewPassword;
}); });
}, },
), ),
), ),
validator: (value) { ),
if (value == null || ),
value.isEmpty) { const SizedBox(height: 8),
return 'Please enter your new password'; // 🔹 VALIDATION LIST
} Padding(
if (value.length < 6) { padding: Responsive.isDesktop(context)
return 'Password must be at least 6 characters'; ? const EdgeInsets.symmetric(horizontal: 150)
} : const EdgeInsets.symmetric(horizontal: 5),
if (!RegExp( child: Column(
r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$') crossAxisAlignment: CrossAxisAlignment.start,
.hasMatch(value)) { children: [
return 'Include at least 1 uppercase letter and 1 number'; Row(
} children: [
return null; Expanded(child: _buildCheckItem(hasMinLength, "Minimum 8 characters")),
}, Expanded(child: _buildCheckItem(hasSpecialChar, "1 special character")),
],
),
Row(
children: [
Expanded(child: _buildCheckItem(hasUpperLower, "1 UPPER or lower case")),
Expanded(child: _buildCheckItem(hasNumber, "1 numerical")),
],
),
],
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
@ -561,7 +562,7 @@ class _setPasswordState extends State<setPassword> {
), ),
) )
: Text( : Text(
"Reset Password", "Update Password",
style: GoogleFonts style: GoogleFonts
.poppins( .poppins(
color: Color( color: Color(
@ -692,4 +693,28 @@ class _setPasswordState extends State<setPassword> {
)), )),
))); )));
} }
Widget _buildCheckItem(bool status, String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
children: [
Icon(
status ? Icons.check : Icons.close,
color: status ? Colors.green : Colors.red,
size: 18,
),
const SizedBox(width: 6),
Text(
text,
style: TextStyle(
color: status ? Colors.green : Colors.red,
fontSize: 14,
),
),
],
),
);
}
} }

View File

@ -8,6 +8,7 @@
#include <file_selector_linux/file_selector_plugin.h> #include <file_selector_linux/file_selector_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h> #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <printing/printing_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
@ -17,6 +18,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
g_autoptr(FlPluginRegistrar) printing_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "PrintingPlugin");
printing_plugin_register_with_registrar(printing_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux file_selector_linux
flutter_secure_storage_linux flutter_secure_storage_linux
printing
url_launcher_linux url_launcher_linux
) )

View File

@ -13,6 +13,7 @@ import google_sign_in_ios
import local_auth_darwin import local_auth_darwin
import package_info_plus import package_info_plus
import path_provider_foundation import path_provider_foundation
import printing
import shared_preferences_foundation import shared_preferences_foundation
import sqflite_darwin import sqflite_darwin
import url_launcher_macos import url_launcher_macos
@ -28,6 +29,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin")) LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))

View File

@ -67,6 +67,7 @@ dependencies:
universal_html: ^2.2.4 universal_html: ^2.2.4
go_router: ^16.2.2 go_router: ^16.2.2
flutter_secure_storage: ^9.2.4 flutter_secure_storage: ^9.2.4
printing: ^5.14.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -10,6 +10,7 @@
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h> #include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h> #include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <local_auth_windows/local_auth_plugin.h> #include <local_auth_windows/local_auth_plugin.h>
#include <printing/printing_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
@ -21,6 +22,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
LocalAuthPluginRegisterWithRegistrar( LocalAuthPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("LocalAuthPlugin")); registry->GetRegistrarForPlugin("LocalAuthPlugin"));
PrintingPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PrintingPlugin"));
UrlLauncherWindowsRegisterWithRegistrar( UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows")); registry->GetRegistrarForPlugin("UrlLauncherWindows"));
} }

View File

@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
flutter_inappwebview_windows flutter_inappwebview_windows
flutter_secure_storage_windows flutter_secure_storage_windows
local_auth_windows local_auth_windows
printing
url_launcher_windows url_launcher_windows
) )