merged
This commit is contained in:
commit
f1f3bcd1b6
@ -90,7 +90,7 @@ class _SplashScreenState extends State<SplashScreen> {
|
|||||||
Future<String?> tokenRedirectLogic(
|
Future<String?> tokenRedirectLogic(
|
||||||
BuildContext context, GoRouterState state) async {
|
BuildContext context, GoRouterState state) async {
|
||||||
print('ABCDEFGH');
|
print('ABCDEFGH');
|
||||||
const allowedWithoutToken = [
|
const guestRoutes = [
|
||||||
'/login',
|
'/login',
|
||||||
'/verify',
|
'/verify',
|
||||||
'/mailVerify',
|
'/mailVerify',
|
||||||
@ -98,17 +98,17 @@ Future<String?> tokenRedirectLogic(
|
|||||||
'/splash',
|
'/splash',
|
||||||
];
|
];
|
||||||
|
|
||||||
final location = state.uri.toString();
|
|
||||||
|
|
||||||
// ✅ Allow login, verify, splash without token
|
|
||||||
if (allowedWithoutToken.contains(location)) return null;
|
|
||||||
|
|
||||||
// ✅ Check if token exists
|
|
||||||
// final hasToken = await TokenService.hasValidToken();
|
|
||||||
// if (!hasToken) return '/login';
|
|
||||||
final hasToken = await TokenService.hasValidToken();
|
final hasToken = await TokenService.hasValidToken();
|
||||||
print('hasToken : $hasToken');
|
print('hasToken : $hasToken');
|
||||||
if (!hasToken) {
|
final location = state.matchedLocation;
|
||||||
|
|
||||||
|
// ✅ If user is already logged in, never allow returning to OTP/login screens.
|
||||||
|
if (hasToken && guestRoutes.contains(location)) {
|
||||||
|
return '/home';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ If not logged in and trying to access a protected route, force login.
|
||||||
|
if (!hasToken && !guestRoutes.contains(location)) {
|
||||||
print('!!!!hasToken : $hasToken');
|
print('!!!!hasToken : $hasToken');
|
||||||
await SessionManager().clear();
|
await SessionManager().clear();
|
||||||
// Show toast once
|
// Show toast once
|
||||||
|
|||||||
@ -28,72 +28,84 @@ class changesPassword extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _changesPasswordState extends State<changesPassword> {
|
class _changesPasswordState extends State<changesPassword> {
|
||||||
final TextEditingController oldPasswordController = TextEditingController();
|
final TextEditingController oldPasswordController = TextEditingController();
|
||||||
final TextEditingController newPasswordController = TextEditingController();
|
final TextEditingController newPasswordController = TextEditingController();
|
||||||
final TextEditingController confirmPasswordController = TextEditingController();
|
final TextEditingController confirmPasswordController = TextEditingController();
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
dynamic _preToken;
|
dynamic _preToken;
|
||||||
dynamic _postToken;
|
dynamic _postToken;
|
||||||
dynamic clientName;
|
dynamic clientName;
|
||||||
dynamic clientLogo;
|
dynamic clientLogo;
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
bool _obscureOldPassword = true;
|
bool _obscureOldPassword = true;
|
||||||
bool _obscureNewPassword = true;
|
bool _obscureNewPassword = true;
|
||||||
bool _obscureConfirmPassword = true;
|
bool _obscureConfirmPassword = true;
|
||||||
late SessionManager session;
|
late SessionManager session;
|
||||||
bool hasMinLength = false;
|
bool hasMinLength = false;
|
||||||
bool hasUpperLower = false;
|
bool hasUpperLower = false;
|
||||||
bool hasNumber = false;
|
bool hasNumber = false;
|
||||||
bool hasSpecialChar = false;
|
bool hasSpecialChar = false;
|
||||||
bool get isPasswordValid => hasMinLength && hasUpperLower && hasNumber && hasSpecialChar;
|
bool get isPasswordValid => hasMinLength && hasUpperLower && hasNumber && hasSpecialChar;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void validatePassword(String password) {
|
void validatePassword(String password) {
|
||||||
setState(() {
|
setState(() {
|
||||||
hasMinLength = password.length >= 8;
|
hasMinLength = password.length >= 8;
|
||||||
hasUpperLower = RegExp(r'(?=.*[A-Za-z])').hasMatch(password);
|
hasUpperLower = RegExp(r'(?=.*[A-Za-z])').hasMatch(password);
|
||||||
hasNumber = RegExp(r'(?=.*\d)').hasMatch(password);
|
hasNumber = RegExp(r'(?=.*\d)').hasMatch(password);
|
||||||
hasSpecialChar = RegExp(r'(?=.*[@$!%*#?&])').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();
|
||||||
final newPassword = newPasswordController.text.trim();
|
final newPassword = newPasswordController.text.trim();
|
||||||
final confirmPassword = confirmPasswordController.text.trim();
|
final confirmPassword = confirmPasswordController.text.trim();
|
||||||
try {
|
try {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
if (confirmPassword != newPassword) {
|
// Extra safety checks before calling the API
|
||||||
ToastHelper.showErrorToast(context, 'Passwords do not match');
|
if (oldpassword == newPassword) {
|
||||||
return;
|
ToastHelper.showErrorToast(
|
||||||
}
|
context, 'New password cannot be same as old password');
|
||||||
setState(() {
|
return;
|
||||||
_isLoading = true;
|
}
|
||||||
});
|
if (!isPasswordValid) {
|
||||||
|
ToastHelper.showErrorToast(
|
||||||
|
context,
|
||||||
|
'Password must be 8+ characters with 1 letter, 1 number, and 1 special character');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (confirmPassword != newPassword) {
|
||||||
|
ToastHelper.showErrorToast(context, 'Passwords do not match');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
_isLoading = true;
|
||||||
|
});
|
||||||
|
|
||||||
// Determine the API and the payload based on the visible field
|
// Determine the API and the payload based on the visible field
|
||||||
String apiEndpoint = Environment.apiUrlEnrollment + 'changePassword';
|
String apiEndpoint = Environment.apiUrlEnrollment + 'changePassword';
|
||||||
Map<String, dynamic> payload = {
|
Map<String, dynamic> payload = {
|
||||||
'email_id': widget.email,
|
'email_id': widget.email,
|
||||||
'client_id': widget.client_id,
|
'client_id': widget.client_id,
|
||||||
'old_password': oldpassword,
|
'old_password': oldpassword,
|
||||||
'new_password': newPassword,
|
'new_password': newPassword,
|
||||||
'confirm_password': confirmPassword
|
'confirm_password': confirmPassword
|
||||||
};
|
};
|
||||||
|
|
||||||
// var enteredMobileNumber = mobileController.text;
|
// var enteredMobileNumber = mobileController.text;
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse(apiEndpoint),
|
Uri.parse(apiEndpoint),
|
||||||
body: json.encode(payload),
|
body: json.encode(payload),
|
||||||
headers: {
|
headers: {
|
||||||
HttpHeaders.contentTypeHeader: 'application/json',
|
HttpHeaders.contentTypeHeader: 'application/json',
|
||||||
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
|
'APP-SIGNATURE': 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
Map<String, dynamic> data = json.decode(response.body);
|
Map<String, dynamic> data = json.decode(response.body);
|
||||||
@ -163,26 +175,26 @@ class _changesPasswordState extends State<changesPassword> {
|
|||||||
print('Error: $e');
|
print('Error: $e');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔹 Password validation
|
// 🔹 Password validation
|
||||||
// if (password.isEmpty) {
|
// if (password.isEmpty) {
|
||||||
// ToastHelper.showErrorToast(context, 'Please enter your password');
|
// ToastHelper.showErrorToast(context, 'Please enter your password');
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// if (password.length < 6) {
|
// if (password.length < 6) {
|
||||||
// ToastHelper.showErrorToast(context, 'Password must be at least 6 characters');
|
// ToastHelper.showErrorToast(context, 'Password must be at least 6 characters');
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// if (!RegExp(r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$').hasMatch(password)) {
|
// if (!RegExp(r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$').hasMatch(password)) {
|
||||||
// ToastHelper.showErrorToast(context, 'Include at least 1 uppercase letter and 1 number');
|
// ToastHelper.showErrorToast(context, 'Include at least 1 uppercase letter and 1 number');
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // 🔹 Confirm password validation
|
// // 🔹 Confirm password validation
|
||||||
// if (confirmPassword.isEmpty) {
|
// if (confirmPassword.isEmpty) {
|
||||||
// ToastHelper.showErrorToast(context, 'Please confirm your password');
|
// ToastHelper.showErrorToast(context, 'Please confirm your password');
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
//Ends Login with UserName and Password
|
//Ends Login with UserName and Password
|
||||||
|
|
||||||
@ -227,7 +239,7 @@ class _changesPasswordState extends State<changesPassword> {
|
|||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: _size.height,
|
constraints: BoxConstraints(minHeight: _size.height),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
@ -314,7 +326,7 @@ class _changesPasswordState extends State<changesPassword> {
|
|||||||
// ),
|
// ),
|
||||||
Container(
|
Container(
|
||||||
margin: marginInsets,
|
margin: marginInsets,
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
@ -332,62 +344,37 @@ class _changesPasswordState extends State<changesPassword> {
|
|||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.center,
|
MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (!Responsive.isMobile(context) &&
|
// Desktop-only: center "<" and logo in one row
|
||||||
!Responsive.isTablet(context))
|
if (Responsive.isDesktop(context))
|
||||||
Row(
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.go('/home');
|
context.go('/home');
|
||||||
},
|
},
|
||||||
child: Row(
|
child: const Icon(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
Icons.chevron_left,
|
||||||
children: [
|
color: Color(0xFF000000),
|
||||||
// if (!Responsive.isDesktop(context))
|
size: 30,
|
||||||
Icon(
|
|
||||||
Icons.chevron_left,
|
|
||||||
color: Color(0xFF000000),
|
|
||||||
size: 30,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: Responsive.isDesktop(context)
|
|
||||||
? 0
|
|
||||||
: 5),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 12,
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment
|
|
||||||
.topLeft, // ✅ Always top-left
|
|
||||||
child: _size.width <= 1100
|
|
||||||
? Image.asset(
|
|
||||||
'assets/nhance_app_logo.png',
|
|
||||||
width: 150,
|
|
||||||
height: 150,
|
|
||||||
)
|
|
||||||
: _size.width > 1100
|
|
||||||
? Image.asset(
|
|
||||||
'assets/nhance_app_logo.png',
|
|
||||||
width: 150,
|
|
||||||
height: 150,
|
|
||||||
)
|
|
||||||
: Image.asset(
|
|
||||||
'assets/nhance_app_logo.png',
|
|
||||||
width: 150,
|
|
||||||
height: 150,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Image.asset(
|
||||||
|
'assets/nhance_app_logo.png',
|
||||||
|
width: 150,
|
||||||
|
height: 150,
|
||||||
|
// color: Colors.green,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: Responsive.isDesktop(context)
|
height: Responsive.isDesktop(context)
|
||||||
? _size.height * 0.1
|
? null
|
||||||
: 10,
|
: 10,
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
// SizedBox(height: 10),
|
||||||
Container(
|
Container(
|
||||||
margin: Responsive.isDesktop(context)
|
margin: Responsive.isDesktop(context)
|
||||||
? EdgeInsets.symmetric(
|
? EdgeInsets.symmetric(
|
||||||
@ -437,259 +424,278 @@ class _changesPasswordState extends State<changesPassword> {
|
|||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
// 🔹 Password Field
|
// 🔹 Password Field
|
||||||
Container(
|
Container(
|
||||||
height: 55,
|
height: 55,
|
||||||
margin: Responsive.isDesktop(
|
margin: Responsive.isDesktop(
|
||||||
context)
|
context)
|
||||||
? const EdgeInsets
|
? const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal: 150)
|
||||||
|
: const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal: 0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
width: 1,
|
||||||
|
color: Colors.grey),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
10),
|
||||||
|
),
|
||||||
|
child: TextFormField(
|
||||||
|
controller:
|
||||||
|
oldPasswordController,
|
||||||
|
obscureText:
|
||||||
|
_obscureOldPassword,
|
||||||
|
textAlignVertical:
|
||||||
|
TextAlignVertical
|
||||||
|
.center,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
hintText:
|
||||||
|
"Old Password",
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets
|
||||||
.symmetric(
|
.symmetric(
|
||||||
horizontal: 150)
|
horizontal: 10),
|
||||||
: const EdgeInsets
|
suffixIcon: IconButton(
|
||||||
.symmetric(
|
icon: Icon(
|
||||||
horizontal: 0),
|
_obscureOldPassword
|
||||||
decoration: BoxDecoration(
|
? Icons
|
||||||
border: Border.all(
|
.visibility_off
|
||||||
width: 1,
|
: Icons
|
||||||
color: Colors.grey),
|
.visibility,
|
||||||
borderRadius:
|
color: Colors.grey,
|
||||||
BorderRadius.circular(
|
|
||||||
10),
|
|
||||||
),
|
|
||||||
child: TextFormField(
|
|
||||||
controller:
|
|
||||||
oldPasswordController,
|
|
||||||
obscureText:
|
|
||||||
_obscureOldPassword,
|
|
||||||
textAlignVertical:
|
|
||||||
TextAlignVertical
|
|
||||||
.center,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
border: InputBorder.none,
|
|
||||||
hintText:
|
|
||||||
"Old Password",
|
|
||||||
contentPadding:
|
|
||||||
const EdgeInsets
|
|
||||||
.symmetric(
|
|
||||||
horizontal: 10),
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
_obscureOldPassword
|
|
||||||
? Icons
|
|
||||||
.visibility_off
|
|
||||||
: Icons
|
|
||||||
.visibility,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
_obscureOldPassword =
|
|
||||||
!_obscureOldPassword;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
validator: (value) {
|
onPressed: () {
|
||||||
if (value == null ||
|
setState(() {
|
||||||
value.isEmpty) {
|
_obscureOldPassword =
|
||||||
return 'Please enter your old password';
|
!_obscureOldPassword;
|
||||||
}
|
});
|
||||||
if (value.length < 6) {
|
|
||||||
return 'Password must be at least 6 characters';
|
|
||||||
}
|
|
||||||
if (!RegExp(
|
|
||||||
r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$')
|
|
||||||
.hasMatch(value)) {
|
|
||||||
return 'Include at least 1 uppercase letter and 1 number';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
validator: (value) {
|
||||||
Container(
|
if (value == null ||
|
||||||
height: 55,
|
value.isEmpty) {
|
||||||
margin: Responsive.isDesktop(context)
|
return 'Please enter your old password';
|
||||||
? const EdgeInsets.symmetric(horizontal: 150)
|
}
|
||||||
: const EdgeInsets.symmetric(horizontal: 0),
|
if (value.length < 8) {
|
||||||
decoration: BoxDecoration(
|
return 'Password must be at least 8 characters';
|
||||||
border: Border.all(width: 1, color: Colors.grey),
|
}
|
||||||
borderRadius: BorderRadius.circular(10),
|
if (!RegExp(
|
||||||
),
|
r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$')
|
||||||
child: TextFormField(
|
.hasMatch(value)) {
|
||||||
controller: newPasswordController,
|
return 'Include at least 1 uppercase letter and 1 number';
|
||||||
obscureText: _obscureNewPassword,
|
}
|
||||||
onChanged: validatePassword,
|
return null;
|
||||||
textAlignVertical: TextAlignVertical.center,
|
},
|
||||||
decoration: InputDecoration(
|
),
|
||||||
border: InputBorder.none,
|
),
|
||||||
hintText: "New Password",
|
const SizedBox(height: 10),
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
|
Container(
|
||||||
suffixIcon: IconButton(
|
height: 55,
|
||||||
icon: Icon(
|
margin: Responsive.isDesktop(context)
|
||||||
_obscureNewPassword ? Icons.visibility_off : Icons.visibility,
|
? const EdgeInsets.symmetric(horizontal: 150)
|
||||||
color: Colors.grey,
|
: const EdgeInsets.symmetric(horizontal: 0),
|
||||||
),
|
decoration: BoxDecoration(
|
||||||
onPressed: () {
|
border: Border.all(width: 1, color: Colors.grey),
|
||||||
setState(() {
|
borderRadius: BorderRadius.circular(10),
|
||||||
_obscureNewPassword = !_obscureNewPassword;
|
),
|
||||||
});
|
child: TextFormField(
|
||||||
},
|
controller: newPasswordController,
|
||||||
),
|
obscureText: _obscureNewPassword,
|
||||||
|
onChanged: validatePassword,
|
||||||
|
textAlignVertical: TextAlignVertical.center,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
hintText: "New Password",
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
_obscureNewPassword ? Icons.visibility_off : Icons.visibility,
|
||||||
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
_obscureNewPassword = !_obscureNewPassword;
|
||||||
|
});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
validator: (value) {
|
||||||
// 🔹 VALIDATION LIST
|
final password = value ?? '';
|
||||||
Padding(
|
if (password.isEmpty) {
|
||||||
padding: Responsive.isDesktop(context)
|
return 'Please enter your new password';
|
||||||
? const EdgeInsets.symmetric(horizontal: 150)
|
}
|
||||||
: const EdgeInsets.symmetric(horizontal: 5),
|
if (password.length < 8) {
|
||||||
child: Column(
|
return 'Password must be at least 8 characters';
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
}
|
||||||
|
if (!RegExp(r'[A-Za-z]').hasMatch(password)) {
|
||||||
|
return 'Password must include at least 1 letter';
|
||||||
|
}
|
||||||
|
if (!RegExp(r'\d').hasMatch(password)) {
|
||||||
|
return 'Password must include at least 1 number';
|
||||||
|
}
|
||||||
|
if (!RegExp(r'[@$!%*#?&]').hasMatch(password)) {
|
||||||
|
return 'Password must include at least 1 special character';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
// 🔹 VALIDATION LIST
|
||||||
|
Padding(
|
||||||
|
padding: Responsive.isDesktop(context)
|
||||||
|
? const EdgeInsets.symmetric(horizontal: 150)
|
||||||
|
: const EdgeInsets.symmetric(horizontal: 5),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Expanded(child: _buildCheckItem(hasMinLength, "Minimum 8 characters")),
|
||||||
children: [
|
Expanded(child: _buildCheckItem(hasSpecialChar, "1 special character")),
|
||||||
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")),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
Row(
|
||||||
const SizedBox(height: 10),
|
children: [
|
||||||
Container(
|
Expanded(child: _buildCheckItem(hasUpperLower, "1 UPPER or lower case")),
|
||||||
height: 55,
|
Expanded(child: _buildCheckItem(hasNumber, "1 numerical")),
|
||||||
margin: Responsive.isDesktop(
|
],
|
||||||
context)
|
|
||||||
? const EdgeInsets
|
|
||||||
.symmetric(
|
|
||||||
horizontal: 150)
|
|
||||||
: const EdgeInsets
|
|
||||||
.symmetric(
|
|
||||||
horizontal: 0),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
width: 1,
|
|
||||||
color: Colors.grey),
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(
|
|
||||||
10),
|
|
||||||
),
|
),
|
||||||
child: TextFormField(
|
],
|
||||||
controller:
|
),
|
||||||
confirmPasswordController,
|
),
|
||||||
obscureText:
|
const SizedBox(height: 10),
|
||||||
_obscureConfirmPassword,
|
Container(
|
||||||
textAlignVertical:
|
height: 55,
|
||||||
TextAlignVertical
|
margin: Responsive.isDesktop(
|
||||||
.center,
|
context)
|
||||||
decoration: InputDecoration(
|
? const EdgeInsets
|
||||||
border: InputBorder.none,
|
.symmetric(
|
||||||
hintText:
|
horizontal: 150)
|
||||||
"Confirm Password",
|
: const EdgeInsets
|
||||||
contentPadding:
|
.symmetric(
|
||||||
const EdgeInsets
|
horizontal: 0),
|
||||||
.symmetric(
|
decoration: BoxDecoration(
|
||||||
horizontal: 10),
|
border: Border.all(
|
||||||
suffixIcon: IconButton(
|
width: 1,
|
||||||
icon: Icon(
|
color: Colors.grey),
|
||||||
_obscureConfirmPassword
|
borderRadius:
|
||||||
? Icons
|
BorderRadius.circular(
|
||||||
.visibility_off
|
10),
|
||||||
: Icons
|
),
|
||||||
.visibility,
|
child: TextFormField(
|
||||||
color: Colors.grey,
|
controller:
|
||||||
),
|
confirmPasswordController,
|
||||||
onPressed: () {
|
obscureText:
|
||||||
setState(() {
|
_obscureConfirmPassword,
|
||||||
_obscureConfirmPassword =
|
textAlignVertical:
|
||||||
!_obscureConfirmPassword;
|
TextAlignVertical
|
||||||
});
|
.center,
|
||||||
},
|
decoration: InputDecoration(
|
||||||
),
|
border: InputBorder.none,
|
||||||
|
hintText:
|
||||||
|
"Confirm Password",
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal: 10),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
_obscureConfirmPassword
|
||||||
|
? Icons
|
||||||
|
.visibility_off
|
||||||
|
: Icons
|
||||||
|
.visibility,
|
||||||
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
validator: (value) {
|
onPressed: () {
|
||||||
if (value == null ||
|
setState(() {
|
||||||
value.isEmpty) {
|
_obscureConfirmPassword =
|
||||||
return 'Please confirm your password';
|
!_obscureConfirmPassword;
|
||||||
}
|
});
|
||||||
if (value !=
|
|
||||||
newPasswordController
|
|
||||||
.text) {
|
|
||||||
return 'Passwords do not match';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
validator: (value) {
|
||||||
|
if (value == null ||
|
||||||
|
value.isEmpty) {
|
||||||
|
return 'Please confirm your password';
|
||||||
|
}
|
||||||
|
if (value !=
|
||||||
|
newPasswordController
|
||||||
|
.text) {
|
||||||
|
return 'Passwords do not match';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 15),
|
],
|
||||||
Container(
|
),
|
||||||
margin:
|
SizedBox(height: 15),
|
||||||
Responsive.isDesktop(context)
|
Container(
|
||||||
? EdgeInsets.symmetric(
|
margin:
|
||||||
horizontal: 150)
|
Responsive.isDesktop(context)
|
||||||
: EdgeInsets.symmetric(
|
? EdgeInsets.symmetric(
|
||||||
horizontal: 0),
|
horizontal: 150)
|
||||||
child: SizedBox(
|
: EdgeInsets.symmetric(
|
||||||
width: double.infinity,
|
horizontal: 0),
|
||||||
height: 40,
|
child: SizedBox(
|
||||||
child: ElevatedButton(
|
width: double.infinity,
|
||||||
style:
|
height: 40,
|
||||||
ElevatedButton.styleFrom(
|
child: ElevatedButton(
|
||||||
backgroundColor:
|
style:
|
||||||
Color(0xFF00989E),
|
ElevatedButton.styleFrom(
|
||||||
shape:
|
backgroundColor:
|
||||||
RoundedRectangleBorder(
|
Color(0xFF00989E),
|
||||||
borderRadius:
|
shape:
|
||||||
BorderRadius.circular(
|
RoundedRectangleBorder(
|
||||||
10),
|
borderRadius:
|
||||||
),
|
BorderRadius.circular(
|
||||||
),
|
10),
|
||||||
onPressed: _isLoading
|
),
|
||||||
? null
|
),
|
||||||
: resetYourPassword,
|
onPressed: _isLoading
|
||||||
|
? null
|
||||||
|
: resetYourPassword,
|
||||||
|
|
||||||
child: _isLoading
|
child: _isLoading
|
||||||
? CircularProgressIndicator(
|
? CircularProgressIndicator(
|
||||||
valueColor:
|
valueColor:
|
||||||
AlwaysStoppedAnimation<
|
AlwaysStoppedAnimation<
|
||||||
Color>(
|
Color>(
|
||||||
Color(0xFF00989E),
|
Color(0xFF00989E),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Text(
|
: Text(
|
||||||
"Reset Password",
|
"Reset Password",
|
||||||
style: GoogleFonts
|
style: GoogleFonts
|
||||||
.poppins(
|
.poppins(
|
||||||
color: Color(
|
color: Color(
|
||||||
0xFFFFFFFF),
|
0xFFFFFFFF),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: Responsive.isDesktop(context)
|
height: Responsive.isDesktop(context)
|
||||||
? _size.height * 0.3
|
? null
|
||||||
: _size.height * 0.2,
|
: _size.height * 0.2,
|
||||||
),
|
),
|
||||||
// SizedBox(
|
// SizedBox(
|
||||||
// height: _size.height * 0.1,
|
// height: _size.height * 0.1,
|
||||||
// ),
|
// ),
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.center,
|
||||||
padding:
|
padding:
|
||||||
EdgeInsets.symmetric(vertical: 8),
|
EdgeInsets.symmetric(vertical: 8),
|
||||||
child: RichText(
|
child: RichText(
|
||||||
@ -801,27 +807,27 @@ class _changesPasswordState extends State<changesPassword> {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCheckItem(bool status, String text) {
|
Widget _buildCheckItem(bool status, String text) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
status ? Icons.check : Icons.close,
|
status ? Icons.check : Icons.close,
|
||||||
color: status ? Colors.green : Colors.red,
|
color: status ? Colors.green : Colors.red,
|
||||||
size: 18,
|
size: 18,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
text,
|
text,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: status ? Colors.green : Colors.red,
|
color: status ? Colors.green : Colors.red,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,171 +32,216 @@
|
|||||||
// import '../session/settingUpPinAndBiometric.dart';
|
// import '../session/settingUpPinAndBiometric.dart';
|
||||||
// import '../verify.dart';
|
// import '../verify.dart';
|
||||||
//
|
//
|
||||||
// class AppRouter {
|
// import 'package:flutter/foundation.dart';
|
||||||
// // static final SessionNotifier sessionNotifier = SessionNotifier();
|
import 'package:flutter/material.dart';
|
||||||
// static GoRouter createRouter() {
|
import 'package:go_router/go_router.dart';
|
||||||
// return GoRouter(
|
import 'package:flutter/foundation.dart';
|
||||||
// initialLocation: kIsWeb ? '/login' : '/splash',
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
// debugLogDiagnostics: true,
|
import '../../main.dart';
|
||||||
// // refreshListenable: sessionNotifier,
|
import '../email_verify.dart';
|
||||||
// redirect: (BuildContext context, GoRouterState state) {
|
import '../enrollment/addons.dart';
|
||||||
// const allowedWithoutToken = [
|
import '../enrollment/empDetails.dart';
|
||||||
// '/login',
|
import '../enrollment/empReview.dart';
|
||||||
// '/verify',
|
import '../login.dart';
|
||||||
// '/mailVerify',
|
import '../postEnrollment/chatbot.dart';
|
||||||
// '/pinPage',
|
import '../postEnrollment/claimprocess.dart';
|
||||||
// '/splash',
|
import '../postEnrollment/claims.dart';
|
||||||
// ];
|
import '../postEnrollment/faqs.dart';
|
||||||
//
|
import '../postEnrollment/generalexclusionsdeductibles.dart';
|
||||||
// final location = state.uri.toString();
|
import '../postEnrollment/help.dart';
|
||||||
// if (allowedWithoutToken.contains(location)) return null;
|
import '../postEnrollment/home.dart';
|
||||||
//
|
import '../postEnrollment/planclaimsform.dart';
|
||||||
// // final hasToken = TokenService.hasValidTokenSync();
|
import '../postEnrollment/policies.dart';
|
||||||
// // if (!hasToken) return '/login';
|
import '../postEnrollment/privacypolicy.dart';
|
||||||
//
|
import '../postEnrollment/profile.dart';
|
||||||
// // if (!kIsWeb &&
|
import '../postEnrollment/raisedTicketList.dart';
|
||||||
// // SessionManager().prefs?.getString('is_mpin_skipped') == '0' &&
|
import '../postEnrollment/retailClaimForm.dart';
|
||||||
// // location != '/pinPage') {
|
import '../postEnrollment/termsofuse.dart';
|
||||||
// // return '/pinPage';
|
import '../postEnrollment/tickets.dart';
|
||||||
// // }
|
import '../postEnrollment/tickettracklist.dart';
|
||||||
//
|
import '../postEnrollment/wellness.dart';
|
||||||
// return null;
|
import '../postEnrollment/wellness_web_view.dart';
|
||||||
// },
|
import '../service/SessionManager.dart';
|
||||||
//
|
import '../service/TokenService.dart';
|
||||||
//
|
import '../session/SetPinBiometric.dart';
|
||||||
//
|
import '../session/changePin.dart';
|
||||||
// routes: [
|
import '../session/settingUpPinAndBiometric.dart';
|
||||||
// // if (!kIsWeb)
|
import '../verify.dart';
|
||||||
// // GoRoute(
|
|
||||||
// // path: '/splash',
|
class AppRouter {
|
||||||
// // builder: (context, state) => SplashScreen(),
|
// static final SessionNotifier sessionNotifier = SessionNotifier();
|
||||||
// // ),
|
static GoRouter createRouter() {
|
||||||
// GoRoute(
|
return GoRouter(
|
||||||
// path: '/login',
|
// On web, respect the browser URL if present; otherwise fall back to login.
|
||||||
// builder: (context, state) => login(),
|
initialLocation: kIsWeb ? '/login' : '/splash',
|
||||||
// ),
|
debugLogDiagnostics: true,
|
||||||
// GoRoute(
|
redirect: (BuildContext context, GoRouterState state) async {
|
||||||
// path: '/mailVerify',
|
const allowedWithoutToken = [
|
||||||
// builder: (context, state) {
|
'/login',
|
||||||
// final email = state.extra as String;
|
'/verify',
|
||||||
// return MyEmailVerify(email: email);
|
'/mailVerify',
|
||||||
// },
|
'/pinPage',
|
||||||
// ),
|
'/splash',
|
||||||
// GoRoute(
|
];
|
||||||
// path: '/verify',
|
|
||||||
// builder: (context, state) {
|
// Always work with the matched path (ignores query params).
|
||||||
// final args = state.extra as Map<String, dynamic>;
|
final location = state.matchedLocation;
|
||||||
// return MyVerify(
|
final hasToken = await TokenService.hasValidToken();
|
||||||
// verificationId: args['verificationId'] as String,
|
|
||||||
// mobileNumber: args['mobileNumber'] as String,
|
final isGuestRoute = allowedWithoutToken.contains(location);
|
||||||
// resendToken: args['resendToken'],
|
|
||||||
// onResendCode: args['onResendCode'] as Function(String, int?),
|
if (hasToken && isGuestRoute) {
|
||||||
// );
|
// If a logged-in user tries to access a guest route, redirect to home
|
||||||
// },
|
return '/home';
|
||||||
// ),
|
}
|
||||||
// GoRoute(
|
|
||||||
// path: '/mailVerify',
|
if (!hasToken && !isGuestRoute) {
|
||||||
// builder: (context, state) => MyVerify(
|
// If a guest user tries to access a protected route, redirect to login
|
||||||
// verificationId: '',
|
return '/login';
|
||||||
// mobileNumber: '',
|
}
|
||||||
// resendToken: null,
|
|
||||||
// onResendCode: (String, int) {},
|
return null; // No redirect needed
|
||||||
// ),
|
},
|
||||||
// ),
|
routes: [
|
||||||
// GoRoute(
|
if (!kIsWeb)
|
||||||
// path: '/home',
|
GoRoute(
|
||||||
// builder: (context, state) => Home(),
|
path: '/splash',
|
||||||
// ),
|
builder: (context, state) => const SplashScreen(),
|
||||||
// GoRoute(
|
),
|
||||||
// path: '/pinSettingPage',
|
GoRoute(
|
||||||
// builder: (context, state) => pinSettingPage(),
|
path: '/login',
|
||||||
// ),
|
builder: (context, state) => const login(),
|
||||||
// GoRoute(
|
),
|
||||||
// path: '/pinPage',
|
GoRoute(
|
||||||
// builder: (context, state) => pinPage(),
|
path: '/mailVerify',
|
||||||
// ),
|
builder: (context, state) {
|
||||||
// GoRoute(
|
final data = state.extra as Map<String, dynamic>;
|
||||||
// path: '/changePin',
|
final type = data['type'] as String;
|
||||||
// builder: (context, state) => changePin(),
|
final value = data['value'] as String;
|
||||||
// ),
|
return MyEmailVerify(type: type, value: value);
|
||||||
// GoRoute(
|
},
|
||||||
// path: '/claimprocess',
|
),
|
||||||
// builder: (context, state) => claimprocess(),
|
// Legacy Firebase-phone OTP route is commented out in verify.dart,
|
||||||
// ),
|
// so we do not expose /verify from GoRouter anymore.
|
||||||
// GoRoute(
|
GoRoute(
|
||||||
// path: '/policies',
|
path: '/home',
|
||||||
// builder: (context, state) => policies(),
|
builder: (context, state) => Home(),
|
||||||
// ),
|
),
|
||||||
// GoRoute(
|
GoRoute(
|
||||||
// path: '/claims',
|
path: '/pinSettingPage',
|
||||||
// builder: (context, state) => claims(),
|
builder: (context, state) => pinSettingPage(),
|
||||||
// ),
|
),
|
||||||
// GoRoute(
|
GoRoute(
|
||||||
// path: '/profile',
|
path: '/pinPage',
|
||||||
// builder: (context, state) => profile(),
|
builder: (context, state) => pinPage(),
|
||||||
// ),
|
),
|
||||||
// GoRoute(
|
GoRoute(
|
||||||
// path: '/help',
|
path: '/changePin',
|
||||||
// builder: (context, state) => help(),
|
builder: (context, state) => changePin(),
|
||||||
// ),
|
),
|
||||||
// GoRoute(
|
GoRoute(
|
||||||
// path: '/wellness',
|
path: '/claimprocess',
|
||||||
// builder: (context, state) => wellness(),
|
builder: (context, state) => claimprocess(),
|
||||||
// ),
|
),
|
||||||
// GoRoute(
|
GoRoute(
|
||||||
// path: '/planclaimsform',
|
path: '/policies',
|
||||||
// builder: (context, state) => planclaimsform(),
|
builder: (context, state) {
|
||||||
// ),
|
final arguments =
|
||||||
// GoRoute(
|
state.extra as Map<String, dynamic>?; // optional args
|
||||||
// path: '/privacypolicy',
|
return policies(arguments: arguments);
|
||||||
// builder: (context, state) => privacypolicy(),
|
},
|
||||||
// ),
|
),
|
||||||
// GoRoute(
|
GoRoute(
|
||||||
// path: '/termsofuse',
|
path: '/claims',
|
||||||
// builder: (context, state) => termsofuse(),
|
builder: (context, state) {
|
||||||
// ),
|
final int tabIndex = state.extra as int? ?? 0;
|
||||||
// GoRoute(
|
return claims(initialTab: tabIndex);
|
||||||
// path: '/generalExclusionsDeductibles',
|
},
|
||||||
// builder: (context, state) => generalExclusionsDeductibles(),
|
),
|
||||||
// ),
|
GoRoute(
|
||||||
// GoRoute(
|
path: '/profile',
|
||||||
// path: '/chatbot()',
|
builder: (context, state) => profile(),
|
||||||
// builder: (context, state) => chatbot(),
|
),
|
||||||
// ),
|
GoRoute(
|
||||||
// GoRoute(
|
path: '/help',
|
||||||
// path: '/chatbot()',
|
builder: (context, state) => help(),
|
||||||
// builder: (context, state) => chatbot(),
|
),
|
||||||
// ),
|
GoRoute(
|
||||||
// GoRoute(
|
path: '/wellness',
|
||||||
// path: '/tickettracklist',
|
builder: (context, state) => wellness(),
|
||||||
// builder: (context, state) => tickettracklist(
|
),
|
||||||
// ticketID: "",
|
GoRoute(
|
||||||
// ),
|
path: '/privacypolicy',
|
||||||
// ),
|
builder: (context, state) => privacypolicy(),
|
||||||
// GoRoute(
|
),
|
||||||
// path: '/empDetails()',
|
GoRoute(
|
||||||
// builder: (context, state) => empDetails(),
|
path: '/termsofuse',
|
||||||
// ),
|
builder: (context, state) => termsofuse(),
|
||||||
// GoRoute(
|
),
|
||||||
// path: '/addOnsDetails()',
|
GoRoute(
|
||||||
// builder: (context, state) => addOnsDetails(),
|
path: '/generalExclusionsDeductibles',
|
||||||
// ),
|
builder: (context, state) => generalExclusionsDeductibles(),
|
||||||
// GoRoute(
|
),
|
||||||
// path: '/empReviewDetails()',
|
GoRoute(
|
||||||
// builder: (context, state) => empReviewDetails(),
|
path: '/planclaimsform',
|
||||||
// ),
|
builder: (context, state) {
|
||||||
// GoRoute(
|
final details = state.extra as Map<String, dynamic>?;
|
||||||
// path: '/tickets()',
|
return planclaimsform(details: details);
|
||||||
// builder: (context, state) => tickets(),
|
},
|
||||||
// ),
|
),
|
||||||
// GoRoute(
|
GoRoute(
|
||||||
// path: '/raisedTicketHistory()',
|
path: '/retailClaimForm',
|
||||||
// builder: (context, state) => raisedTicketHistory(),
|
builder: (context, state) {
|
||||||
// ),
|
final details = state.extra as Map<String, dynamic>?;
|
||||||
// ],
|
return retailClaimForm(details: details);
|
||||||
// );
|
},
|
||||||
// }
|
),
|
||||||
// }
|
GoRoute(
|
||||||
|
path: '/raisedTicketHistory',
|
||||||
|
builder: (context, state) => raisedTicketHistory(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/tickettracklist/:ticketID',
|
||||||
|
builder: (context, state) {
|
||||||
|
final ticketID = state.pathParameters['ticketID']!;
|
||||||
|
return tickettracklist(ticketID: ticketID);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/empDetails',
|
||||||
|
builder: (context, state) => empDetails(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/faqs',
|
||||||
|
builder: (context, state) => faqs(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/addOnsDetails',
|
||||||
|
builder: (context, state) => addOnsDetails(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/empReviewDetails',
|
||||||
|
builder: (context, state) => empReviewDetails(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/tickets',
|
||||||
|
builder: (context, state) => tickets(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/chatbot',
|
||||||
|
builder: (context, state) => chatbot(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/wellnessWebView',
|
||||||
|
builder: (context, state) {
|
||||||
|
final url = state.extra as String;
|
||||||
|
return WellnessWebView(url: url);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// //
|
// //
|
||||||
// // class AppRouter {
|
// // class AppRouter {
|
||||||
|
|||||||
@ -511,7 +511,8 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
|
|||||||
session.empClientBranchId == null || session.empClientBranchId!.isEmpty) {
|
session.empClientBranchId == null || session.empClientBranchId!.isEmpty) {
|
||||||
prefs.setBool('isRetailLoggedIn', true);
|
prefs.setBool('isRetailLoggedIn', true);
|
||||||
}
|
}
|
||||||
context.go('/home');
|
// context.go('/home');
|
||||||
|
context.replace('/home');
|
||||||
}
|
}
|
||||||
// if (emp_status == 'enrolled' || emp_status == 'active') {
|
// if (emp_status == 'enrolled' || emp_status == 'active') {
|
||||||
// context.go('/home');
|
// context.go('/home');
|
||||||
@ -686,10 +687,12 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
|
|||||||
|
|
||||||
if (_postToken != null && _postToken.isNotEmpty) {
|
if (_postToken != null && _postToken.isNotEmpty) {
|
||||||
ToastHelper.showSuccessToast(context, 'Successfully Logged In');
|
ToastHelper.showSuccessToast(context, 'Successfully Logged In');
|
||||||
context.go('/home');
|
context.replace('/home');
|
||||||
|
// context.go('/home');
|
||||||
// Navigator.pushReplacementNamed(context, 'home');
|
// Navigator.pushReplacementNamed(context, 'home');
|
||||||
} else {
|
} else {
|
||||||
context.go('/empDetails');
|
context.replace('/empDetails');
|
||||||
|
// context.go('/empDetails');
|
||||||
// Navigator.pushReplacementNamed(context, 'empDetails');
|
// Navigator.pushReplacementNamed(context, 'empDetails');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,10 +743,12 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
|
|||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
Map<String, dynamic> data = json.decode(response.body);
|
Map<String, dynamic> data = json.decode(response.body);
|
||||||
if(data['status'] == 'success') {
|
if(data['status'] == 'success') {
|
||||||
context.go('/${route}');
|
context.replace('/${route}');
|
||||||
|
// context.go('/${route}');
|
||||||
} else if(data['status'] == 'failed'){
|
} else if(data['status'] == 'failed'){
|
||||||
print('setPassword');
|
print('setPassword');
|
||||||
context.goNamed(
|
// goNamed
|
||||||
|
context.replaceNamed(
|
||||||
'setPassword',
|
'setPassword',
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'email': email_id,
|
'email': email_id,
|
||||||
@ -930,7 +935,7 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
|
|||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
margin: marginInsets,
|
margin: marginInsets,
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.center,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
@ -1272,14 +1277,14 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
|
|||||||
// ),
|
// ),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: Responsive.isDesktop(context)
|
height: Responsive.isDesktop(context)
|
||||||
? _size.height * 0.3
|
? _size.height * 0.2
|
||||||
: _size.height * 0.2,
|
: _size.height * 0.15,
|
||||||
),
|
),
|
||||||
// SizedBox(
|
// SizedBox(
|
||||||
// height: _size.height * 0.1,
|
// height: _size.height * 0.1,
|
||||||
// ),
|
// ),
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.center,
|
||||||
padding:
|
padding:
|
||||||
EdgeInsets.symmetric(vertical: 8),
|
EdgeInsets.symmetric(vertical: 8),
|
||||||
child: RichText(
|
child: RichText(
|
||||||
|
|||||||
@ -1428,15 +1428,14 @@ class _addOnsDetailsState extends State<addOnsDetails> {
|
|||||||
|
|
||||||
Future<void> backFunction() async {
|
Future<void> backFunction() async {
|
||||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
if (prefs.containsKey('hrtoken')) {
|
if (prefs.containsKey('hrtoken')) {
|
||||||
String? mobileNo = prefs.getString('fromHrLoginMobileNo');
|
String? mobileNo = prefs.getString('fromHrLoginMobileNo');
|
||||||
Navigator.pushNamed(context, 'empDetails',
|
Navigator.pushNamed(context, 'empDetails',
|
||||||
arguments: {'mobile': mobileNo});
|
arguments: {'mobile': mobileNo});
|
||||||
} else {
|
} else {
|
||||||
context.go('/empDetails');
|
context.pop();
|
||||||
// Navigator.pushNamed(context, 'empDetails');
|
// Navigator.pushNamed(context, 'empDetails');
|
||||||
}
|
} }
|
||||||
}
|
|
||||||
|
|
||||||
void checkSiTopUp() async {
|
void checkSiTopUp() async {
|
||||||
List<Map<String, dynamic>> siData = [
|
List<Map<String, dynamic>> siData = [
|
||||||
@ -1936,6 +1935,14 @@ class _addOnsDetailsState extends State<addOnsDetails> {
|
|||||||
Image.network(
|
Image.network(
|
||||||
clientLogo ?? '', // Nhance logo
|
clientLogo ?? '', // Nhance logo
|
||||||
height: 40,
|
height: 40,
|
||||||
|
errorBuilder: (BuildContext context, Object error,
|
||||||
|
StackTrace? stackTrace) {
|
||||||
|
return Image.asset(
|
||||||
|
'assets/Solid_gray.png',
|
||||||
|
height: 40,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
// Image.network(
|
// Image.network(
|
||||||
// 'https://i.imgur.com/qOihOvk.png', // Prodapt logo
|
// 'https://i.imgur.com/qOihOvk.png', // Prodapt logo
|
||||||
@ -4520,8 +4527,7 @@ class _addOnsDetailsState extends State<addOnsDetails> {
|
|||||||
checkDependentTopUp();
|
checkDependentTopUp();
|
||||||
sendAddonsGmcDependentToAPI();
|
sendAddonsGmcDependentToAPI();
|
||||||
}
|
}
|
||||||
context.go('/empReviewDetails');
|
context.push('/empReviewDetails'); // Navigator.pushNamed(context,
|
||||||
// Navigator.pushNamed(context,
|
|
||||||
// 'empReviewDetails');
|
// 'empReviewDetails');
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
|||||||
@ -760,15 +760,15 @@ class _empDetailsState extends State<empDetails> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
// errorBuilder: (BuildContext context,
|
errorBuilder: (BuildContext context,
|
||||||
// Object error, StackTrace? stackTrace) {
|
Object error, StackTrace? stackTrace) {
|
||||||
// return Image.asset(
|
return Image.asset(
|
||||||
// 'assets/Solid_gray.png', // Replace 'default_image.png' with your default image asset path
|
'assets/Solid_gray.png',
|
||||||
// width: 80,
|
width: 80,
|
||||||
// height: 80,
|
height: 80,
|
||||||
// fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
// );
|
);
|
||||||
// },
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -976,7 +976,7 @@ class _empDetailsState extends State<empDetails> {
|
|||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go('/addOnsDetails');
|
context.push('/addOnsDetails');
|
||||||
// Navigator.pushNamed(
|
// Navigator.pushNamed(
|
||||||
// context, 'addOnsDetails');
|
// context, 'addOnsDetails');
|
||||||
},
|
},
|
||||||
@ -2240,6 +2240,8 @@ class _empDetailsState extends State<empDetails> {
|
|||||||
print('gmcFloaterTextDescription $gmcFloaterTextDescription');
|
print('gmcFloaterTextDescription $gmcFloaterTextDescription');
|
||||||
String gmcNotes = item['notes'];
|
String gmcNotes = item['notes'];
|
||||||
print('gmcNotes $gmcNotes');
|
print('gmcNotes $gmcNotes');
|
||||||
|
String cleanedNotes = gmcNotes?.toString().toLowerCase().replaceAll(' ', '') ?? '';
|
||||||
|
print('gmcNotes cleaned: $cleanedNotes');
|
||||||
dynamic gmcECardDownload = item['eCardDownload'];
|
dynamic gmcECardDownload = item['eCardDownload'];
|
||||||
print('gmcECardDownload $gmcECardDownload');
|
print('gmcECardDownload $gmcECardDownload');
|
||||||
bool gmcCopyDependenceDataEnable = item['copy_dependence_data_enable'];
|
bool gmcCopyDependenceDataEnable = item['copy_dependence_data_enable'];
|
||||||
@ -2635,46 +2637,134 @@ class _empDetailsState extends State<empDetails> {
|
|||||||
Column(
|
Column(
|
||||||
children: familyFloaterContainers,
|
children: familyFloaterContainers,
|
||||||
),
|
),
|
||||||
// Add Family Member Button HERE
|
// Add Family Member Button:
|
||||||
if (gmcOpenForEnrollment != 0 && gmcECardDownload == null)...[
|
// Show only when:
|
||||||
GestureDetector(
|
// - enrollment is open
|
||||||
onTap: () {
|
// - e-card not generated
|
||||||
if (getFalseObjects.length == 0) {
|
// - there are still dependants left to add
|
||||||
ToastHelper.showWarningToast(context, "No family member to add");
|
// - and the policy allows relationships beyond just "Self"
|
||||||
return;
|
// if (gmcOpenForEnrollment != 0 &&
|
||||||
}
|
// gmcECardDownload == null &&
|
||||||
openAddFamilyMemberPopup(
|
// getFalseObjects.isNotEmpty &&
|
||||||
"Add",
|
// gmcRelationShip.any((rel) =>
|
||||||
null,
|
// (rel?.toString().toLowerCase() ?? '') != 'self')) ...[
|
||||||
gmcClientPolicyId,
|
// Builder(builder: (context) {
|
||||||
gmcRelationShip,
|
// print("*** Condition is TRUE");
|
||||||
gmcSumInsured,
|
// GestureDetector(
|
||||||
);
|
// onTap: () {
|
||||||
},
|
// if (getFalseObjects.length == 0) {
|
||||||
child: Container(
|
// ToastHelper.showWarningToast(context, "No family member to add");
|
||||||
margin: EdgeInsets.only(top: 10),
|
// return;
|
||||||
padding: EdgeInsets.all(15),
|
// }
|
||||||
decoration: BoxDecoration(
|
// openAddFamilyMemberPopup(
|
||||||
border: Border.all(color: Colors.black, width: 1),
|
// "Add",
|
||||||
borderRadius: BorderRadius.circular(8),
|
// null,
|
||||||
),
|
// gmcClientPolicyId,
|
||||||
child: Row(
|
// gmcRelationShip,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// gmcSumInsured,
|
||||||
children: [
|
// );
|
||||||
Icon(Icons.person_add, color: Colors.black),
|
// },
|
||||||
SizedBox(width: 10),
|
// child: Container(
|
||||||
Text(
|
// margin: EdgeInsets.only(top: 10),
|
||||||
"Add Family Member",
|
// padding: EdgeInsets.all(15),
|
||||||
style: GoogleFonts.poppins(
|
// decoration: BoxDecoration(
|
||||||
fontSize: Responsive.isDesktop(context) ? 20 : 16,
|
// border: Border.all(color: Colors.black, width: 1),
|
||||||
fontWeight: FontWeight.w500,
|
// borderRadius: BorderRadius.circular(8),
|
||||||
|
// ),
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
// children: [
|
||||||
|
// Icon(Icons.person_add, color: Colors.black),
|
||||||
|
// SizedBox(width: 10),
|
||||||
|
// Text(
|
||||||
|
// "Add Family Member",
|
||||||
|
// style: GoogleFonts.poppins(
|
||||||
|
// fontSize: Responsive.isDesktop(context) ? 20 : 16,
|
||||||
|
// fontWeight: FontWeight.w500,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
if (cleanedNotes != 'allowedmembersself') ...<Widget>[
|
||||||
|
if (gmcOpenForEnrollment != 0 &&
|
||||||
|
gmcECardDownload == null &&
|
||||||
|
getFalseObjects.isNotEmpty &&
|
||||||
|
gmcRelationShip.any((rel) =>
|
||||||
|
(rel is Map
|
||||||
|
? rel['relationship']?.toString().toLowerCase()
|
||||||
|
: rel?.toString().toLowerCase() ?? '') != 'self')) ...<Widget>[
|
||||||
|
Builder(builder: (context) {
|
||||||
|
print("*** IF - Condition is TRUE");
|
||||||
|
print("*** gmcOpenForEnrollment: $gmcOpenForEnrollment");
|
||||||
|
print("*** gmcECardDownload: $gmcECardDownload");
|
||||||
|
print("*** getFalseObjects length: ${getFalseObjects.length}");
|
||||||
|
print("*** gmcRelationShip full: $gmcRelationShip");
|
||||||
|
print("*** gmcNotes original: $gmcNotes");
|
||||||
|
print("*** gmcNotes cleaned: $cleanedNotes");
|
||||||
|
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (getFalseObjects.length == 0) {
|
||||||
|
ToastHelper.showWarningToast(context, "No family member to add");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openAddFamilyMemberPopup(
|
||||||
|
"Add",
|
||||||
|
null,
|
||||||
|
gmcClientPolicyId,
|
||||||
|
gmcRelationShip,
|
||||||
|
gmcSumInsured,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(top: 10),
|
||||||
|
padding: EdgeInsets.all(15),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: Colors.black, width: 1),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.person_add, color: Colors.black),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
"Add Family Member",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: Responsive.isDesktop(context) ? 20 : 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
}),
|
||||||
|
] else ...<Widget>[
|
||||||
|
Builder(builder: (context) {
|
||||||
|
print("*** ELSE - Condition is FALSE");
|
||||||
|
print("*** gmcOpenForEnrollment: $gmcOpenForEnrollment → pass: ${gmcOpenForEnrollment != 0}");
|
||||||
|
print("*** gmcECardDownload: $gmcECardDownload → pass: ${gmcECardDownload == null}");
|
||||||
|
print("*** getFalseObjects length: ${getFalseObjects.length} → pass: ${getFalseObjects.isNotEmpty}");
|
||||||
|
print("*** gmcRelationShip full list: $gmcRelationShip");
|
||||||
|
print("*** gmcNotes original: $gmcNotes");
|
||||||
|
print("*** gmcNotes cleaned: $cleanedNotes");
|
||||||
|
return SizedBox.shrink(); // no widget shown in else
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
|
]else ...<Widget>[
|
||||||
|
Builder(builder: (context) {
|
||||||
|
print("*** OUTER ELSE - Condition is FALSE");
|
||||||
|
print("*** gmcNotes original: $gmcNotes");
|
||||||
|
print("*** gmcNotes cleaned: $cleanedNotes");
|
||||||
|
return SizedBox.shrink();
|
||||||
|
}),
|
||||||
|
|
||||||
|
],
|
||||||
SizedBox(height: 15),
|
SizedBox(height: 15),
|
||||||
if (Responsive.isDesktop(context) && gmcIsValueValid)
|
if (Responsive.isDesktop(context) && gmcIsValueValid)
|
||||||
Row(
|
Row(
|
||||||
|
|||||||
@ -1413,6 +1413,14 @@ setState(() {
|
|||||||
Image.network(
|
Image.network(
|
||||||
clientLogo ?? '', // Nhance logo
|
clientLogo ?? '', // Nhance logo
|
||||||
height: 40,
|
height: 40,
|
||||||
|
errorBuilder: (BuildContext context, Object error,
|
||||||
|
StackTrace? stackTrace) {
|
||||||
|
return Image.asset(
|
||||||
|
'assets/Solid_gray.png',
|
||||||
|
height: 40,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
// Image.network(
|
// Image.network(
|
||||||
// 'https://i.imgur.com/qOihOvk.png', // Prodapt logo
|
// 'https://i.imgur.com/qOihOvk.png', // Prodapt logo
|
||||||
|
|||||||
@ -278,7 +278,7 @@ class _loginState extends State<login> {
|
|||||||
print('isEmailFieldVisible $isEmailFieldVisible');
|
print('isEmailFieldVisible $isEmailFieldVisible');
|
||||||
// prefs.setString('empEmail', emailController.text);
|
// prefs.setString('empEmail', emailController.text);
|
||||||
print('${emailMobileController.text}');
|
print('${emailMobileController.text}');
|
||||||
context.push(
|
context.go(
|
||||||
'/mailVerify',
|
'/mailVerify',
|
||||||
extra: {
|
extra: {
|
||||||
'type': 'email',
|
'type': 'email',
|
||||||
@ -287,7 +287,7 @@ class _loginState extends State<login> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// _verifyPhoneNumber();
|
// _verifyPhoneNumber();
|
||||||
context.push(
|
context.go(
|
||||||
'/mailVerify',
|
'/mailVerify',
|
||||||
extra: {
|
extra: {
|
||||||
'type': 'mobile',
|
'type': 'mobile',
|
||||||
@ -690,6 +690,14 @@ class _loginState extends State<login> {
|
|||||||
clickedForgotPassword = true;
|
clickedForgotPassword = true;
|
||||||
passwordController.text = '';
|
passwordController.text = '';
|
||||||
passwordController.clear();
|
passwordController.clear();
|
||||||
|
|
||||||
|
// ✅ Clear everything so the flow starts fresh
|
||||||
|
emailController.clear();
|
||||||
|
_otpController.clear();
|
||||||
|
resetPasswordController.clear();
|
||||||
|
confirmPasswordController.clear();
|
||||||
|
|
||||||
|
_formKey.currentState?.reset();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,8 +808,17 @@ class _loginState extends State<login> {
|
|||||||
otpValueStatus = false;
|
otpValueStatus = false;
|
||||||
otpFieldShow = false;
|
otpFieldShow = false;
|
||||||
clickedForgotPassword = false;
|
clickedForgotPassword = false;
|
||||||
resetPasswordEnable = true;
|
resetPasswordEnable = true; // This shows the reset fields
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
|
hasMinLength = false;
|
||||||
|
hasUpperLower = false;
|
||||||
|
hasNumber = false;
|
||||||
|
hasSpecialChar = false;
|
||||||
|
|
||||||
|
// ✅ ADD THESE LINES TO CLEAR CACHED DATA
|
||||||
|
resetPasswordController.clear();
|
||||||
|
confirmPasswordController.clear();
|
||||||
|
_formKey.currentState?.reset();
|
||||||
});
|
});
|
||||||
// ToastHelper.showSuccessToast(context, message);
|
// ToastHelper.showSuccessToast(context, message);
|
||||||
} else {
|
} else {
|
||||||
@ -871,6 +888,17 @@ class _loginState extends State<login> {
|
|||||||
resetPasswordEnable = false;
|
resetPasswordEnable = false;
|
||||||
clickedForgotPassword = false;
|
clickedForgotPassword = false;
|
||||||
otpFieldShow = false;
|
otpFieldShow = false;
|
||||||
|
|
||||||
|
// ✅ CLEAR THE CONTROLLERS HERE
|
||||||
|
resetPasswordController.clear();
|
||||||
|
confirmPasswordController.clear();
|
||||||
|
_otpController.clear();
|
||||||
|
// emailController.clear(); // Uncomment if you want the email cleared too
|
||||||
|
|
||||||
|
// Reset the form state to clear validation error messages
|
||||||
|
_formKey.currentState?.reset();
|
||||||
|
emailController.text = '';
|
||||||
|
emailController.clear();
|
||||||
});
|
});
|
||||||
// ToastHelper.showSuccessToast(context, message);
|
// ToastHelper.showSuccessToast(context, message);
|
||||||
} else {
|
} else {
|
||||||
@ -1095,7 +1123,7 @@ class _loginState extends State<login> {
|
|||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/nhance_app_logo.png',
|
'assets/nhance_app_logo.png',
|
||||||
width: 150,
|
width: 150,
|
||||||
height: 100,
|
height: 150,
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -1109,7 +1137,7 @@ class _loginState extends State<login> {
|
|||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
margin: marginInsets,
|
margin: marginInsets,
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.center,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
@ -1120,9 +1148,7 @@ class _loginState extends State<login> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: _size.width < 1100 ? 6 : 12,
|
flex: _size.width < 1100 ? 6 : 12,
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: _size.width > 1100
|
margin: EdgeInsets.symmetric(horizontal: 20),
|
||||||
? EdgeInsets.only(left: 20, right: 20)
|
|
||||||
: EdgeInsets.only(left: 0, right: 0),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.center,
|
MainAxisAlignment.center,
|
||||||
@ -1638,152 +1664,114 @@ class _loginState extends State<login> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (otpFieldShow) ...[
|
if (otpFieldShow &&
|
||||||
SizedBox(height: 10),
|
clickedForgotPassword) ...[
|
||||||
AnimatedSwitcher(
|
const SizedBox(height: 10),
|
||||||
duration: const Duration(
|
Column(
|
||||||
milliseconds: 500,
|
crossAxisAlignment:
|
||||||
), // animation speed
|
CrossAxisAlignment.start,
|
||||||
switchInCurve:
|
children: [
|
||||||
Curves.easeInOutCirc,
|
Center(
|
||||||
switchOutCurve:
|
child: Text(
|
||||||
Curves.easeOutCirc,
|
'OTP',
|
||||||
child:
|
style: TextStyle(
|
||||||
clickedForgotPassword
|
fontSize: Responsive
|
||||||
? Column(
|
.isMobile(
|
||||||
key: const ValueKey(
|
context)
|
||||||
'otp_block'),
|
? 14
|
||||||
crossAxisAlignment:
|
: 18,
|
||||||
CrossAxisAlignment
|
fontWeight:
|
||||||
.start,
|
FontWeight
|
||||||
children: [
|
.w600,
|
||||||
Container(
|
color:
|
||||||
child: Center(
|
|
||||||
child:
|
|
||||||
Text(
|
|
||||||
'OTP',
|
|
||||||
style:
|
|
||||||
TextStyle(
|
|
||||||
fontSize: Responsive.isMobile(context)
|
|
||||||
? 14
|
|
||||||
: 18,
|
|
||||||
fontWeight:
|
|
||||||
FontWeight.w600,
|
|
||||||
color:
|
|
||||||
Colors.black,
|
Colors.black,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10),
|
||||||
|
Container(
|
||||||
|
alignment:
|
||||||
|
Alignment.center,
|
||||||
|
margin: Responsive
|
||||||
|
.isDesktop(
|
||||||
|
context)
|
||||||
|
? const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal:
|
||||||
|
150)
|
||||||
|
: const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal:
|
||||||
|
0),
|
||||||
|
child: Pinput(
|
||||||
|
length: 6,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter
|
||||||
|
.digitsOnly,
|
||||||
|
],
|
||||||
|
keyboardType:
|
||||||
|
TextInputType
|
||||||
|
.number,
|
||||||
|
showCursor: true,
|
||||||
|
controller:
|
||||||
|
_otpController,
|
||||||
|
validator:
|
||||||
|
(value) {
|
||||||
|
if (value ==
|
||||||
|
null ||
|
||||||
|
value
|
||||||
|
.isEmpty) {
|
||||||
|
return 'Please enter OTP';
|
||||||
|
}
|
||||||
|
if (value
|
||||||
|
.length <
|
||||||
|
6) {
|
||||||
|
return 'OTP must be 6 digits';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10),
|
||||||
|
Container(
|
||||||
|
margin: Responsive
|
||||||
|
.isDesktop(
|
||||||
|
context)
|
||||||
|
? const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal:
|
||||||
|
150)
|
||||||
|
: const EdgeInsets
|
||||||
|
.symmetric(
|
||||||
|
horizontal:
|
||||||
|
0),
|
||||||
|
alignment: Alignment
|
||||||
|
.centerRight,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
otpFieldShow =
|
||||||
|
false;
|
||||||
|
});
|
||||||
|
resendOTP();
|
||||||
|
},
|
||||||
|
mouseCursor:
|
||||||
|
SystemMouseCursors
|
||||||
|
.click,
|
||||||
|
child: Text(
|
||||||
|
'Didn’t Receive Code?',
|
||||||
|
style: GoogleFonts
|
||||||
|
.poppins(
|
||||||
|
color: Colors
|
||||||
|
.blue,
|
||||||
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
),
|
||||||
height:
|
],
|
||||||
10),
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
margin: Responsive.isDesktop(context)
|
|
||||||
? EdgeInsets.symmetric(
|
|
||||||
horizontal: 150)
|
|
||||||
: EdgeInsets.symmetric(
|
|
||||||
horizontal: 0),
|
|
||||||
child: Pinput(
|
|
||||||
length: 6,
|
|
||||||
// defaultPinTheme: defaultPinTheme,
|
|
||||||
// focusedPinTheme: focusedPinTheme,
|
|
||||||
// submittedPinTheme: submittedPinTheme,
|
|
||||||
inputFormatters: [
|
|
||||||
FilteringTextInputFormatter
|
|
||||||
.digitsOnly, // ✅ allows only 0–9
|
|
||||||
],
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
showCursor: true,
|
|
||||||
controller: _otpController,
|
|
||||||
validator:
|
|
||||||
(value) {
|
|
||||||
if (value == null ||
|
|
||||||
value.isEmpty) {
|
|
||||||
return 'Please enter OTP';
|
|
||||||
}
|
|
||||||
if (value.length <
|
|
||||||
6) {
|
|
||||||
return 'OTP must be 6 digits';
|
|
||||||
}
|
|
||||||
// if (otpValueStatus) {
|
|
||||||
// // example
|
|
||||||
// return 'Invalid OTP';
|
|
||||||
// }
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height:
|
|
||||||
10),
|
|
||||||
Container(
|
|
||||||
margin: Responsive.isDesktop(context)
|
|
||||||
? EdgeInsets.symmetric(
|
|
||||||
horizontal:
|
|
||||||
150)
|
|
||||||
: EdgeInsets.symmetric(
|
|
||||||
horizontal:
|
|
||||||
0),
|
|
||||||
alignment:
|
|
||||||
Alignment
|
|
||||||
.centerRight, // center the text
|
|
||||||
child:InkWell(
|
|
||||||
onTap: (){
|
|
||||||
setState(() {
|
|
||||||
otpFieldShow = false;
|
|
||||||
});
|
|
||||||
print('ABCDEF');
|
|
||||||
resendOTP();
|
|
||||||
},
|
|
||||||
mouseCursor: SystemMouseCursors.click,
|
|
||||||
child: Text(
|
|
||||||
'Didn’t Receive Code?',
|
|
||||||
style: GoogleFonts.poppins(
|
|
||||||
color: Colors.blue,
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// RichText(
|
|
||||||
// textAlign:
|
|
||||||
// TextAlign.right,
|
|
||||||
// text:
|
|
||||||
// TextSpan(
|
|
||||||
// text:
|
|
||||||
// 'Didn’t Receive Code? ', // normal text
|
|
||||||
// style:
|
|
||||||
// TextStyle(
|
|
||||||
// fontSize: Responsive.isMobile(context)
|
|
||||||
// ? 12
|
|
||||||
// : 14,
|
|
||||||
// fontWeight:
|
|
||||||
// FontWeight.normal,
|
|
||||||
// color:
|
|
||||||
// Colors.black,
|
|
||||||
// ),
|
|
||||||
// children: [
|
|
||||||
// TextSpan(
|
|
||||||
// text: 'Resend', // bold clickable part
|
|
||||||
// style: TextStyle(
|
|
||||||
// fontWeight: FontWeight.bold,
|
|
||||||
// color: Colors.white,
|
|
||||||
// decoration: TextDecoration.underline, // optional
|
|
||||||
// ),
|
|
||||||
// // recognizer: TapGestureRecognizer()
|
|
||||||
// // ..onTap = () {
|
|
||||||
// //
|
|
||||||
// // },
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: const SizedBox
|
|
||||||
.shrink(), // Empty widget when false
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
@ -1856,6 +1844,7 @@ class _loginState extends State<login> {
|
|||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
|
key: const ValueKey('new_password_field'),
|
||||||
controller: resetPasswordController,
|
controller: resetPasswordController,
|
||||||
obscureText: _resetObscurePassword,
|
obscureText: _resetObscurePassword,
|
||||||
onChanged: validatePassword,
|
onChanged: validatePassword,
|
||||||
@ -1915,6 +1904,7 @@ class _loginState extends State<login> {
|
|||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
|
key: const ValueKey('confirm_password_field'),
|
||||||
controller: confirmPasswordController,
|
controller: confirmPasswordController,
|
||||||
obscureText: _obscureConfirmPassword,
|
obscureText: _obscureConfirmPassword,
|
||||||
textAlignVertical: TextAlignVertical.center,
|
textAlignVertical: TextAlignVertical.center,
|
||||||
|
|||||||
@ -127,13 +127,15 @@ class _AddPolicyScreenState extends State<AddPolicyScreen> {
|
|||||||
policyNoController.clear();
|
policyNoController.clear();
|
||||||
expDateController.clear();
|
expDateController.clear();
|
||||||
|
|
||||||
setState(() => isLoading = false);
|
|
||||||
|
|
||||||
context.go('/home');
|
context.go('/home');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Submit error: $e');
|
print('Submit error: $e');
|
||||||
|
} finally {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() => isLoading = false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -177,7 +177,8 @@ import '../service/popup_helper.dart';
|
|||||||
canPop: false,
|
canPop: false,
|
||||||
onPopInvokedWithResult: (didPop, result) {
|
onPopInvokedWithResult: (didPop, result) {
|
||||||
if (didPop) return;
|
if (didPop) return;
|
||||||
context.go('/claims');
|
// context.go('/claims');
|
||||||
|
context.pop();
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
@ -209,7 +210,7 @@ import '../service/popup_helper.dart';
|
|||||||
flex: 12,
|
flex: 12,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.go('/claims');
|
context.pop(); // context.go('/claims');
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
|
|||||||
@ -311,11 +311,18 @@ class _claimsState extends State<claims> {
|
|||||||
if (widget.initialTab == 2) {
|
if (widget.initialTab == 2) {
|
||||||
context.go('/home');
|
context.go('/home');
|
||||||
}
|
}
|
||||||
if (widget.initialTab == 0) {
|
|
||||||
context.go('/home');
|
if (Navigator.canPop(context)) {
|
||||||
} else {
|
context.pop();
|
||||||
context.pop();
|
} else {
|
||||||
}
|
context.go('/home');
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (widget.initialTab == 0) {
|
||||||
|
// context.pop();
|
||||||
|
// } else {
|
||||||
|
// context.pop();
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
@ -993,14 +1000,14 @@ class _claimsState extends State<claims> {
|
|||||||
var details = {
|
var details = {
|
||||||
"retailDetails": item,
|
"retailDetails": item,
|
||||||
};
|
};
|
||||||
context.go('/retailClaimForm', extra: details);
|
context.push('/retailClaimForm', extra: details);
|
||||||
} else {
|
} else {
|
||||||
// Normal claim policy click
|
// Normal claim policy click
|
||||||
var details = {
|
var details = {
|
||||||
"claimsDetails": item,
|
"claimsDetails": item,
|
||||||
"fromClaimPage": 0,
|
"fromClaimPage": 0,
|
||||||
};
|
};
|
||||||
context.go('/planclaimsform', extra: details);
|
context.push('/planclaimsform', extra: details);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
|
|||||||
@ -192,11 +192,55 @@ class _generalExclusionsDeductiblesState
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Row(
|
||||||
'General Exclusions & Deductibles',
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
style: GoogleFonts.poppins(
|
children: [
|
||||||
fontSize: 18, fontWeight: FontWeight.w600),
|
Expanded(
|
||||||
|
flex: 12,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
context.go('/home');
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.chevron_left,
|
||||||
|
color: Color(0xFF000000),
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: Responsive.isDesktop(context)
|
||||||
|
? 0
|
||||||
|
: 5),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'General Exclusions & Deductibles',
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF000000),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
// Text(
|
||||||
|
// 'General Exclusions & Deductibles',
|
||||||
|
// style: GoogleFonts.poppins(
|
||||||
|
// fontSize: 18, fontWeight: FontWeight.w600),
|
||||||
|
// ),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
if (type3Content.isNotEmpty) ...[
|
if (type3Content.isNotEmpty) ...[
|
||||||
Text(type3SectionName ?? '',
|
Text(type3SectionName ?? '',
|
||||||
|
|||||||
@ -336,31 +336,31 @@ class _helpState extends State<help> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
// Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
// mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
// children: [
|
||||||
Expanded(
|
// Expanded(
|
||||||
flex: 12,
|
// flex: 12,
|
||||||
child: InkWell(
|
// child: InkWell(
|
||||||
onTap: () {
|
// onTap: () {
|
||||||
context.push('/claims');
|
// context.push('/claims');
|
||||||
// Navigator.pushNamed(context, 'home');
|
// // Navigator.pushNamed(context, 'home');
|
||||||
},
|
// },
|
||||||
child: Row(
|
// child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
// mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
// children: [
|
||||||
Icon(
|
// Icon(
|
||||||
Icons
|
// Icons
|
||||||
.chevron_left, // Replace with your desired icon
|
// .chevron_left, // Replace with your desired icon
|
||||||
color: Color(0xFF000000),
|
// color: Color(0xFF000000),
|
||||||
size: 30,
|
// size: 30,
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -1880,10 +1880,44 @@ class _HomeState extends State<Home> {
|
|||||||
cards.add(_buildAddCard()); // <-- always add this card
|
cards.add(_buildAddCard()); // <-- always add this card
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ NEW: Show empty state when inactive tab has no policies
|
||||||
|
if (!isActive && cards.isEmpty) {
|
||||||
|
return _buildEmptyState("No inactive policies available");
|
||||||
|
}
|
||||||
|
|
||||||
return _buildCarouselSlider(cards);
|
return _buildCarouselSlider(cards);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildEmptyState(String message) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFF7F7F7),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: Border.all(color: const Color(0xFFE0E0E0), width: 1.5),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.folder_off_outlined, size: 48, color: Colors.grey[400]),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
message,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildCarouselSlider(List<Widget> cards) {
|
Widget _buildCarouselSlider(List<Widget> cards) {
|
||||||
final int totalCards = cards.length;
|
final int totalCards = cards.length;
|
||||||
final bool hasAddCard = isActive; // because you add AddCard only when isActive
|
final bool hasAddCard = isActive; // because you add AddCard only when isActive
|
||||||
|
|||||||
@ -137,6 +137,7 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
bool isIntimationDateValid = true;
|
bool isIntimationDateValid = true;
|
||||||
bool isAdmitDateValid = true;
|
bool isAdmitDateValid = true;
|
||||||
bool isDischargeDateValid = true;
|
bool isDischargeDateValid = true;
|
||||||
|
bool showFileError = false;
|
||||||
|
|
||||||
final session = SessionManager();
|
final session = SessionManager();
|
||||||
|
|
||||||
@ -591,57 +592,70 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> sendFormDataToApi() async {
|
Future<void> sendFormDataToApi() async {
|
||||||
setState(() => isSubmitting = true); // 🔥 start loader
|
final isServiceValid = serviceId != null;
|
||||||
setState(() {
|
final isPolicyValid = policyNumberId != null;
|
||||||
isServiceValid = serviceId != null;
|
final isMemberValid = selectedMemberId != null;
|
||||||
isPolicyValid = policyNumberId != null;
|
final isSubjectValid = subjectController.text.trim().isNotEmpty;
|
||||||
isMemberValid = selectedMemberId != null;
|
final isHospitalNameValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalNameController.text.trim().isNotEmpty;
|
||||||
isSubjectValid = subjectController.text.trim().isNotEmpty;
|
final isHospitalAddressValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalAddressController.text.trim().isNotEmpty;
|
||||||
isHospitalNameValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalNameController.text.trim().isNotEmpty;
|
final isHospitalStateValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalStateController.text.trim().isNotEmpty;
|
||||||
isHospitalAddressValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalAddressController.text.trim().isNotEmpty;
|
final isHospitalCityValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalCityController.text.trim().isNotEmpty;
|
||||||
isHospitalStateValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalStateController.text.trim().isNotEmpty;
|
final isHospitalPincodeValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalPinCodeController.text.trim().isNotEmpty;
|
||||||
isHospitalCityValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalCityController.text.trim().isNotEmpty;
|
final isHospitalPhoneNoValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || (hospitalPhoneNoController.text.trim().length == 10);
|
||||||
isHospitalPincodeValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalPinCodeController.text.trim().isNotEmpty;
|
final isAdmitDateValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || admitDate != null;
|
||||||
isHospitalPhoneNoValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || hospitalPhoneNoController.text.trim().isNotEmpty;
|
final isDischargeDateValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || dischargeDate != null;
|
||||||
// isAdmitDischargeValid = policyTypeCondition != 1 || (admitDate != null && dischargeDate != null);
|
final isClaimAmountValid = serviceId != 1 || claimAmountController.text.trim().isNotEmpty;
|
||||||
isClaimTypeValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || claimTypeId != null;
|
final isAccidentDateValid = (serviceId == 2 || serviceId == 3 || serviceId == 4) ? accidentDate != null : true;
|
||||||
isAdmitDateValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || admitDate != null;
|
final isIntimationDateValid = (serviceId == 2 || serviceId == 3 || serviceId == 4) ? intimationDate != null : true;
|
||||||
isDischargeDateValid = (policyTypeCondition != 1 && policyTypeCondition != 72) || dischargeDate != null;
|
final areFilesUploaded = FileUploadService().files.isNotEmpty;
|
||||||
isClaimAmountValid = serviceId != 1 || claimAmountController.text.trim().isNotEmpty;
|
|
||||||
isAccidentDateValid = (serviceId == 2 || serviceId == 3 || serviceId == 4) ? accidentDate != null : true;
|
|
||||||
isIntimationDateValid = (serviceId == 2 || serviceId == 3 || serviceId == 4) ? intimationDate != null : true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isServiceValid &&
|
if (!isServiceValid ||
|
||||||
isClaimTypeValid &&
|
!isPolicyValid ||
|
||||||
isPolicyValid &&
|
!isMemberValid ||
|
||||||
isMemberValid &&
|
!isSubjectValid ||
|
||||||
isSubjectValid &&
|
!isHospitalNameValid ||
|
||||||
isHospitalNameValid &&
|
!isHospitalAddressValid ||
|
||||||
isHospitalAddressValid &&
|
!isHospitalStateValid ||
|
||||||
isHospitalStateValid &&
|
!isHospitalCityValid ||
|
||||||
isHospitalCityValid &&
|
!isHospitalPincodeValid ||
|
||||||
isHospitalPincodeValid &&
|
!isHospitalPhoneNoValid ||
|
||||||
isHospitalPhoneNoValid &&
|
!isAdmitDateValid ||
|
||||||
isAdmitDateValid &&
|
!isDischargeDateValid ||
|
||||||
isDischargeDateValid &&
|
!isClaimAmountValid ||
|
||||||
isClaimAmountValid &&
|
!isAccidentDateValid ||
|
||||||
isAccidentDateValid &&
|
!isIntimationDateValid) {
|
||||||
isIntimationDateValid) {
|
setState(() {
|
||||||
if (FileUploadService().files.isEmpty) {
|
this.isServiceValid = isServiceValid;
|
||||||
setState(() {
|
this.isPolicyValid = isPolicyValid;
|
||||||
MultiFileUploadWidget.hasFiles = false;
|
this.isMemberValid = isMemberValid;
|
||||||
});
|
this.isSubjectValid = isSubjectValid;
|
||||||
ToastHelper.showErrorToast(context, 'Please upload at least one document');
|
this.isHospitalNameValid = isHospitalNameValid;
|
||||||
return;
|
this.isHospitalAddressValid = isHospitalAddressValid;
|
||||||
}
|
this.isHospitalStateValid = isHospitalStateValid;
|
||||||
// Proceed to submit
|
this.isHospitalCityValid = isHospitalCityValid;
|
||||||
} else {
|
this.isHospitalPincodeValid = isHospitalPincodeValid;
|
||||||
|
this.isHospitalPhoneNoValid = isHospitalPhoneNoValid;
|
||||||
|
this.isAdmitDateValid = isAdmitDateValid;
|
||||||
|
this.isDischargeDateValid = isDischargeDateValid;
|
||||||
|
this.isClaimAmountValid = isClaimAmountValid;
|
||||||
|
this.isAccidentDateValid = isAccidentDateValid;
|
||||||
|
this.isIntimationDateValid = isIntimationDateValid;
|
||||||
|
showFileError = true; // Also show file error if other fields are invalid
|
||||||
|
});
|
||||||
ToastHelper.showErrorToast(context, 'Please Fill Required Fields');
|
ToastHelper.showErrorToast(context, 'Please Fill Required Fields');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!areFilesUploaded) {
|
||||||
|
setState(() {
|
||||||
|
showFileError = true;
|
||||||
|
});
|
||||||
|
ToastHelper.showErrorToast(context, 'Please upload the document');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
isSubmitting = true;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -711,7 +725,8 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
|
|
||||||
_token = await TokenService.getPostToken();
|
_token = await TokenService.getPostToken();
|
||||||
|
|
||||||
final request = http.MultipartRequest('POST', Uri.parse('${Environment.apiUrl}initiateClaim'));
|
final request = http.MultipartRequest(
|
||||||
|
'POST', Uri.parse('${Environment.apiUrl}initiateClaim'));
|
||||||
request.headers['Authorization'] = 'Bearer $_token';
|
request.headers['Authorization'] = 'Bearer $_token';
|
||||||
request.headers['APP-SIGNATURE'] = 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y';
|
request.headers['APP-SIGNATURE'] = 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y';
|
||||||
final stringFields = fields.map((key, value) => MapEntry(key, value?.toString() ?? ''));
|
final stringFields = fields.map((key, value) => MapEntry(key, value?.toString() ?? ''));
|
||||||
@ -728,7 +743,10 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
print("📝 Checking label for file: ${uf.file.name}, current label: '${uf.label}'");
|
print("📝 Checking label for file: ${uf.file.name}, current label: '${uf.label}'");
|
||||||
if ((uf.label ?? '').trim().isEmpty) {
|
if ((uf.label ?? '').trim().isEmpty) {
|
||||||
ToastHelper.showErrorToast(context, 'Please enter name for all uploaded documents');
|
ToastHelper.showErrorToast(context, 'Please enter name for all uploaded documents');
|
||||||
setState(() => isLoading = false);
|
setState(() {
|
||||||
|
isLoading = false;
|
||||||
|
isSubmitting = false; // ✅ reset loader
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -769,33 +787,20 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
// ✅ Convert image → PDF
|
// ✅ Convert image → PDF
|
||||||
final pdf = pw.Document();
|
final pdf = pw.Document();
|
||||||
final image = pw.MemoryImage(fileBytes);
|
final image = pw.MemoryImage(fileBytes);
|
||||||
|
pdf.addPage(pw.Page(
|
||||||
pdf.addPage(
|
build: (pw.Context context) =>
|
||||||
pw.Page(
|
pw.Center(child: pw.Image(image, fit: pw.BoxFit.contain)),
|
||||||
build: (pw.Context context) => pw.Center(
|
));
|
||||||
child: pw.Image(image, fit: pw.BoxFit.contain),
|
fileBytes = await pdf.save();
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
fileBytes = await pdf.save(); // converted PDF bytes
|
|
||||||
|
|
||||||
// replace file name with .pdf extension
|
|
||||||
final pdfFileName = pf.name.replaceAll(RegExp(r'\.\w+$'), '.pdf');
|
final pdfFileName = pf.name.replaceAll(RegExp(r'\.\w+$'), '.pdf');
|
||||||
|
|
||||||
print('📄 Converted image ${pf.name} → PDF ($pdfFileName)');
|
print('📄 Converted image ${pf.name} → PDF ($pdfFileName)');
|
||||||
request.files.add(http.MultipartFile.fromBytes(
|
request.files.add(http.MultipartFile.fromBytes(
|
||||||
'claim_docs[]',
|
'claim_docs[]', fileBytes, filename: pdfFileName));
|
||||||
fileBytes,
|
|
||||||
filename: pdfFileName,
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
// ✅ Already a PDF
|
// ✅ Already a PDF
|
||||||
request.files.add(http.MultipartFile.fromBytes(
|
request.files.add(http.MultipartFile.fromBytes(
|
||||||
'claim_docs[]',
|
'claim_docs[]', fileBytes, filename: pf.name));
|
||||||
fileBytes,
|
|
||||||
filename: pf.name,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -816,31 +821,25 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
final responseBody = await response.stream.bytesToString();
|
final responseBody = await response.stream.bytesToString();
|
||||||
|
|
||||||
final decoded = jsonDecode(responseBody);
|
final decoded = jsonDecode(responseBody);
|
||||||
|
|
||||||
if (decoded['status'] == true) {
|
if (decoded['status'] == true) {
|
||||||
ToastHelper.showSuccessToast(context, decoded['message']);
|
ToastHelper.showSuccessToast(context, decoded['message']);
|
||||||
serviceId = null;
|
serviceId = null;
|
||||||
departmentList.clear();
|
departmentList.clear();
|
||||||
setState(() {
|
setState(() => isLoading = false);
|
||||||
isLoading = false;
|
|
||||||
});
|
|
||||||
context.go('/claims', extra: 2);
|
context.go('/claims', extra: 2);
|
||||||
print('Form data submitted successfully');
|
print('Form data submitted successfully');
|
||||||
fileService.clearAll();
|
fileService.clearAll();
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() => isLoading = false);
|
||||||
isLoading = false;
|
|
||||||
});
|
|
||||||
ToastHelper.showErrorToast(context, "Failed: ${decoded['message']}");
|
ToastHelper.showErrorToast(context, "Failed: ${decoded['message']}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setState(() {
|
setState(() => isLoading = false);
|
||||||
isLoading = false;
|
|
||||||
});
|
|
||||||
print('Error submitting form data: $e');
|
print('Error submitting form data: $e');
|
||||||
} finally {
|
} finally {
|
||||||
setState(() => isSubmitting = false); // 🔥 stop loader
|
setState(() => isSubmitting = false); // 🔥 always stop loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,60 +931,92 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
canPop: false,
|
canPop: false,
|
||||||
onPopInvokedWithResult: (didPop, result) {
|
onPopInvokedWithResult: (didPop, result) {
|
||||||
if (didPop) return;
|
if (didPop) return;
|
||||||
final route = fromClaimsPage == 0 ? 'claims' : 'help';
|
context.pop();
|
||||||
context.go('/$route');
|
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
appBar: CustomAppBar(),
|
appBar: CustomAppBar(),
|
||||||
body: Stack(children: [
|
body: Stack(children: [
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: Responsive.isDesktop(context)
|
padding: Responsive.isDesktop(context)
|
||||||
? EdgeInsets.symmetric(
|
? EdgeInsets.symmetric(
|
||||||
horizontal: MediaQuery.of(context).size.width *
|
horizontal: MediaQuery.of(context).size.width *
|
||||||
0.2, // 30% of screen width as horizontal padding
|
0.2, // 30% of screen width as horizontal padding
|
||||||
vertical: MediaQuery.of(context).size.height *
|
vertical: MediaQuery.of(context).size.height *
|
||||||
0.05, // 5% of screen height as vertical padding
|
0.05, // 5% of screen height as vertical padding
|
||||||
)
|
)
|
||||||
: EdgeInsets.all(10),
|
: EdgeInsets.all(10),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Card(
|
Card(
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.circular(15.0), // Set border radius here
|
BorderRadius.circular(15.0), // Set border radius here
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white, // Set background color to white
|
color: Colors.white, // Set background color to white
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
15.0), // Set border radius for Container
|
15.0), // Set border radius for Container
|
||||||
),
|
),
|
||||||
padding: Responsive.isDesktop(context)
|
padding: Responsive.isDesktop(context)
|
||||||
? EdgeInsets.only(top: 15, bottom: 15, left: 15, right: 15)
|
? EdgeInsets.only(top: 15, bottom: 15, left: 15, right: 15)
|
||||||
: EdgeInsets.only(
|
: EdgeInsets.only(
|
||||||
top: 10,
|
top: 10,
|
||||||
bottom: 10,
|
bottom: 10,
|
||||||
left: 10,
|
left: 10,
|
||||||
right: 10), // Add padding to the container
|
right: 10), // Add padding to the container
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 12,
|
flex: 12,
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Color(
|
color: Color(
|
||||||
0xFFFFFCE5), // Set background color for the container
|
0xFFFFFCE5), // Set background color for the container
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
10), // Set border radius for the container
|
10), // Set border radius for the container
|
||||||
|
),
|
||||||
|
padding: Responsive.isDesktop(context)
|
||||||
|
? EdgeInsets.only(
|
||||||
|
top: 20,
|
||||||
|
bottom: 20,
|
||||||
|
left: 0,
|
||||||
|
right: 0)
|
||||||
|
: EdgeInsets.only(
|
||||||
|
top: 10,
|
||||||
|
bottom: 10,
|
||||||
|
left: 10,
|
||||||
|
right: 10),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
context.pop();
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons
|
||||||
|
.chevron_left, // Replace with your desired icon
|
||||||
|
color: Color(0xFF000000),
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
padding: Responsive.isDesktop(context)
|
padding: Responsive.isDesktop(context)
|
||||||
? EdgeInsets.only(
|
? EdgeInsets.only(
|
||||||
@ -1039,19 +1070,439 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
fontSize:
|
fontSize:
|
||||||
Responsive.isDesktop(
|
Responsive.isDesktop(
|
||||||
context)
|
context)
|
||||||
? 20
|
? 20
|
||||||
: 16,
|
: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF000000),
|
color: Color(0xFF000000),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
), // Space between rows
|
||||||
|
// Add more rows as needed
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
Container(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Form(
|
||||||
|
key: formKey,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
buildDropdownField(
|
||||||
|
'Service',isRequired: true,
|
||||||
|
(value) {
|
||||||
|
setState(() {
|
||||||
|
serviceId = value;
|
||||||
|
selectedServiceName = departmentList.firstWhere(
|
||||||
|
(serList) => serList['id'] == value,
|
||||||
|
orElse: () => {'name': ''},
|
||||||
|
)['name'];
|
||||||
|
policyNumberId = null;
|
||||||
|
if (fromClaimsPage == 1) {
|
||||||
|
fetchPoliciesBasedOnService(serviceId);
|
||||||
|
}
|
||||||
|
isServiceValid = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fromClaimsPage == 0,
|
||||||
|
departmentList,
|
||||||
|
'name',
|
||||||
|
serviceId,
|
||||||
|
),
|
||||||
|
if (!isServiceValid)
|
||||||
|
Text('Please select a service', style: TextStyle(color: Colors.red)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// buildDropdownField(
|
||||||
|
// 'Service',
|
||||||
|
// (value) {
|
||||||
|
// setState(() {
|
||||||
|
// serviceId = value;
|
||||||
|
// selectedServiceName =
|
||||||
|
// departmentList
|
||||||
|
// .firstWhere(
|
||||||
|
// (serList) =>
|
||||||
|
// serList[
|
||||||
|
// 'id'] ==
|
||||||
|
// value,
|
||||||
|
// orElse: () =>
|
||||||
|
// {'name': ''},
|
||||||
|
// )['name'];
|
||||||
|
// policyNumberId =
|
||||||
|
// null;
|
||||||
|
// if (fromClaimsPage ==
|
||||||
|
// 1) {
|
||||||
|
// fetchPoliciesBasedOnService(
|
||||||
|
// serviceId);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// fromClaimsPage == 0,
|
||||||
|
// departmentList,
|
||||||
|
// 'name',
|
||||||
|
// serviceId, // Pass current serviceId as selectedValue
|
||||||
|
// ),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
buildDropdownField(
|
||||||
|
'Select Policy',isRequired: true,
|
||||||
|
(value) {
|
||||||
|
setState(() {
|
||||||
|
policyNumberId = value;
|
||||||
|
selectedMemberId = null;
|
||||||
|
String? selectedPolicyNo = policyNumberList.firstWhere(
|
||||||
|
(item) => item['id'] == value,
|
||||||
|
orElse: () => {'policy_no': ''},
|
||||||
|
)['policy_no'];
|
||||||
|
if (selectedPolicyNo != null && fromClaimsPage == 1) {
|
||||||
|
fetchMemberBasedOnPolicy(selectedPolicyNo);
|
||||||
|
}
|
||||||
|
isPolicyValid = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fromClaimsPage == 0,
|
||||||
|
policyNumberList,
|
||||||
|
'policy_no',
|
||||||
|
policyNumberId,
|
||||||
|
),
|
||||||
|
if (!isPolicyValid)
|
||||||
|
Text('Please select a policy', style: TextStyle(color: Colors.red)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// // if (fromClaimsPage == 1)
|
||||||
|
// buildDropdownField(
|
||||||
|
// 'Select Policy',
|
||||||
|
// (value) {
|
||||||
|
// setState(() {
|
||||||
|
// policyNumberId =
|
||||||
|
// value;
|
||||||
|
// selectedMemberId =
|
||||||
|
// null;
|
||||||
|
// String?
|
||||||
|
// selectedPolicyNo =
|
||||||
|
// policyNumberList
|
||||||
|
// .firstWhere(
|
||||||
|
// (item) =>
|
||||||
|
// item['id'] ==
|
||||||
|
// value,
|
||||||
|
// orElse: () =>
|
||||||
|
// {
|
||||||
|
// 'policy_no': ''
|
||||||
|
// })['policy_no'];
|
||||||
|
//
|
||||||
|
// if (selectedPolicyNo !=
|
||||||
|
// null &&
|
||||||
|
// fromClaimsPage ==
|
||||||
|
// 1) {
|
||||||
|
// fetchMemberBasedOnPolicy(
|
||||||
|
// selectedPolicyNo);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// fromClaimsPage == 0,
|
||||||
|
// policyNumberList,
|
||||||
|
// 'policy_no',
|
||||||
|
// policyNumberId, // Pass current policyNumberId as selectedValue
|
||||||
|
// ),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
buildDropdownField(
|
||||||
|
'Member Name',isRequired: true,
|
||||||
|
(value) {
|
||||||
|
setState(() {
|
||||||
|
selectedMemberId = value;
|
||||||
|
selectedMemberName = employeePolicyList.firstWhere(
|
||||||
|
(member) => member['id'] == value,
|
||||||
|
orElse: () => {'name': ''},
|
||||||
|
)['name'];
|
||||||
|
isMemberValid = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
employeePolicyList,
|
||||||
|
'name',
|
||||||
|
selectedMemberId,
|
||||||
|
),
|
||||||
|
if (!isMemberValid)
|
||||||
|
Text('Please select a member', style: TextStyle(color: Colors.red)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
// buildDropdownField(
|
||||||
|
// 'Member Name',
|
||||||
|
// (value) {
|
||||||
|
// setState(() {
|
||||||
|
// selectedMemberId =
|
||||||
|
// value;
|
||||||
|
// selectedMemberName =
|
||||||
|
// employeePolicyList
|
||||||
|
// .firstWhere(
|
||||||
|
// (member) =>
|
||||||
|
// member[
|
||||||
|
// 'id'] ==
|
||||||
|
// value,
|
||||||
|
// orElse: () =>
|
||||||
|
// {'name': ''},
|
||||||
|
// )['name'];
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// false,
|
||||||
|
// employeePolicyList,
|
||||||
|
// 'name',
|
||||||
|
// selectedMemberId, // Pass current selectedMemberId as selectedValue
|
||||||
|
// ),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// buildTextField('Subject',
|
||||||
|
// subjectController),
|
||||||
|
// if (!isSubjectValid)
|
||||||
|
// Text('Please enter the Subject', style: TextStyle(color: Colors.red)),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildTextAreaField(
|
||||||
|
'Message',
|
||||||
|
messageController),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
// if (policyTypeCondition ==
|
||||||
|
// 3)
|
||||||
|
// buildTextField(
|
||||||
|
// 'Accident Details',
|
||||||
|
// accidentDetailsController),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
if (policyTypeCondition == 1 || policyTypeCondition == 72) ...[
|
||||||
|
buildTextField('Hospital Name', hospitalNameController, isRequired: true),
|
||||||
|
if (!isHospitalNameValid)
|
||||||
|
Text('Please enter the Hospital Name', style: TextStyle(color: Colors.red)),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildTextAreaField('Hospital Address', hospitalAddressController, isRequired: true),
|
||||||
|
if (!isHospitalAddressValid)
|
||||||
|
Text('Please enter the Hospital Address', style: TextStyle(color: Colors.red)),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildTextField('Hospital City', hospitalCityController,isRequired: true,inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z ]'))]),
|
||||||
|
if (!isHospitalCityValid)
|
||||||
|
Text('Please enter the Hospital City', style: TextStyle(color: Colors.red)),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildTextField('Hospital State', hospitalStateController,isRequired: true,inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z ]'))]),
|
||||||
|
if (!isHospitalStateValid)
|
||||||
|
Text('Please enter the Hospital State', style: TextStyle(color: Colors.red)),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildTextField('Hospital Pincode', hospitalPinCodeController,isRequired: true,keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
LengthLimitingTextInputFormatter(6),
|
||||||
|
]),
|
||||||
|
if (!isHospitalPincodeValid)
|
||||||
|
Text('Please enter the Hospital Pincode', style: TextStyle(color: Colors.red)),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildTextField('Hospital Phone No', hospitalPhoneNoController,
|
||||||
|
isRequired: true,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
LengthLimitingTextInputFormatter(10),
|
||||||
|
],minLength: 10,),
|
||||||
|
if (!isHospitalPhoneNoValid)
|
||||||
|
Text(
|
||||||
|
hospitalPhoneNoController.text.trim().isEmpty
|
||||||
|
? 'Please enter the Hospital Phone No'
|
||||||
|
: 'Hospital Phone No must be 10 digits', // ✅ specific message
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
SizedBox(height: 15),
|
||||||
)
|
if (serviceId == 2 ||
|
||||||
],
|
serviceId == 3 ||
|
||||||
), // Space between rows
|
serviceId == 4) ...[
|
||||||
// Add more rows as needed
|
buildDatePickerField(
|
||||||
],
|
label:
|
||||||
|
'Date of Birth',
|
||||||
|
selectedDate:
|
||||||
|
birthDate,
|
||||||
|
allowFuture: false,
|
||||||
|
onDateSelected:
|
||||||
|
(selectedDate) {
|
||||||
|
setState(() {
|
||||||
|
birthDate =
|
||||||
|
selectedDate;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildDatePickerField(
|
||||||
|
label: 'Accident Date',
|
||||||
|
isRequired: true,
|
||||||
|
selectedDate: accidentDate,
|
||||||
|
allowFuture: false,
|
||||||
|
minDate: parsedPolicyStartDate,
|
||||||
|
maxDate: parsedPolicyEndDate,
|
||||||
|
onDateSelected: (selectedDate) {
|
||||||
|
setState(() {
|
||||||
|
if (deathDate != null) deathDate = null;
|
||||||
|
if (intimationDate != null) intimationDate = null;
|
||||||
|
accidentDate = selectedDate;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (!isAccidentDateValid)
|
||||||
|
Text('Please select the Accident Date', style: TextStyle(color: Colors.red)),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildDatePickerField(
|
||||||
|
label:
|
||||||
|
'Date of Death',
|
||||||
|
selectedDate:
|
||||||
|
deathDate,
|
||||||
|
isRequired: true,
|
||||||
|
allowFuture: false,
|
||||||
|
minDate: accidentDate ?? parsedPolicyStartDate,
|
||||||
|
maxDate: parsedPolicyEndDate,
|
||||||
|
onDateSelected:
|
||||||
|
(selectedDate) {
|
||||||
|
setState(() {
|
||||||
|
deathDate =
|
||||||
|
selectedDate;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
buildDatePickerField(
|
||||||
|
label: 'Date of Intimation',
|
||||||
|
isRequired: true,
|
||||||
|
selectedDate: intimationDate,
|
||||||
|
allowFuture: false,
|
||||||
|
minDate: accidentDate ?? deathDate ?? parsedPolicyStartDate,
|
||||||
|
maxDate: parsedPolicyEndDate,
|
||||||
|
onDateSelected: (selectedDate) {
|
||||||
|
setState(() {
|
||||||
|
intimationDate = selectedDate;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (!isIntimationDateValid)
|
||||||
|
Text('Please select the Intimation Date', style: TextStyle(color: Colors.red)),
|
||||||
|
],
|
||||||
|
SizedBox(height: 15),
|
||||||
|
// buildTextAreaField(
|
||||||
|
// 'Accident Details',
|
||||||
|
// accidentDetailsController),
|
||||||
|
// SizedBox(height: 15),
|
||||||
|
if (policyTypeCondition == 1 || policyTypeCondition == 72) ...[
|
||||||
|
// 🟡 Admit Date — no future allowed
|
||||||
|
buildDatePickerField(
|
||||||
|
label: 'Admit Date',
|
||||||
|
isRequired: true,
|
||||||
|
selectedDate: admitDate,
|
||||||
|
allowFuture: false,
|
||||||
|
onDateSelected: (selectedDate) {
|
||||||
|
setState(() {
|
||||||
|
admitDate = selectedDate;
|
||||||
|
dischargeDate = null; // reset discharge when admit changes
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (!isAdmitDateValid)
|
||||||
|
const Text('Please select the Admit Date', style: TextStyle(color: Colors.red)),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
// 🟢 Discharge Date — must be after Admit Date
|
||||||
|
buildDatePickerField(
|
||||||
|
label: 'Discharge Date',
|
||||||
|
isRequired: true,
|
||||||
|
selectedDate: dischargeDate,
|
||||||
|
allowFuture: true,
|
||||||
|
minDate: admitDate != null
|
||||||
|
? admitDate!.add(const Duration(days: 1))
|
||||||
|
: DateTime.now().add(const Duration(days: 1)),
|
||||||
|
maxDate: null,
|
||||||
|
onDateSelected: (selectedDate) {
|
||||||
|
setState(() {
|
||||||
|
dischargeDate = selectedDate;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (!isDischargeDateValid)
|
||||||
|
const Text('Please select the Discharge Date', style: TextStyle(color: Colors.red)),
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
SizedBox(height: 15),
|
||||||
|
if (serviceId == 1) ...[
|
||||||
|
buildTextField('Claims Amount', claimAmountController, isRequired: true, keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
]),
|
||||||
|
if (!isClaimAmountValid)
|
||||||
|
Text('Please enter the Claims Amount', style: TextStyle(color: Colors.red)),
|
||||||
|
],
|
||||||
|
|
||||||
|
SizedBox(height: 15),
|
||||||
|
if (serviceId == 2 ||
|
||||||
|
serviceId == 3 ||
|
||||||
|
serviceId == 4)
|
||||||
|
buildTextField(
|
||||||
|
'Sum Insured',
|
||||||
|
sumInsuredController,
|
||||||
|
isRequired: true,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
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: [
|
||||||
|
MultiFileUploadWidget(isRequired: true,showError: showFileError),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 15),
|
SizedBox(height: 15),
|
||||||
@ -1615,32 +2066,38 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget buildTextField(
|
Widget buildTextField(
|
||||||
String label,
|
String label,
|
||||||
TextEditingController controller, {
|
TextEditingController controller, {
|
||||||
|
bool isRequired = false, // 👈 ADD THIS
|
||||||
TextInputType keyboardType = TextInputType.text,
|
TextInputType keyboardType = TextInputType.text,
|
||||||
List<TextInputFormatter>? inputFormatters,
|
List<TextInputFormatter>? inputFormatters,
|
||||||
|
int? minLength,
|
||||||
}) {
|
}) {
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
keyboardType: keyboardType,
|
keyboardType: keyboardType,
|
||||||
inputFormatters: inputFormatters,
|
inputFormatters: inputFormatters,
|
||||||
decoration: InputDecoration(labelText: label),
|
decoration: InputDecoration(
|
||||||
|
labelText: isRequired ? '$label *' : label, // 👈 ADD THIS
|
||||||
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'Please enter the $label';
|
return 'Please enter the $label';
|
||||||
}
|
}
|
||||||
|
if (minLength != null && value.trim().length < minLength) { // 👈 ADD this
|
||||||
|
return '$label must be at least $minLength digits';
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget buildTextAreaField(String label, TextEditingController controller) {
|
Widget buildTextAreaField(String label, TextEditingController controller ,{ bool isRequired = false}) {
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
decoration: InputDecoration(labelText: label),
|
decoration: InputDecoration(labelText: isRequired ? '$label *' : label),
|
||||||
maxLines: 5,
|
maxLines: 5,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
@ -1656,6 +2113,7 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
required DateTime? selectedDate,
|
required DateTime? selectedDate,
|
||||||
required bool allowFuture,
|
required bool allowFuture,
|
||||||
required ValueChanged<DateTime?> onDateSelected,
|
required ValueChanged<DateTime?> onDateSelected,
|
||||||
|
bool isRequired = false,
|
||||||
DateTime? minDate,
|
DateTime? minDate,
|
||||||
DateTime? maxDate,
|
DateTime? maxDate,
|
||||||
}) {
|
}) {
|
||||||
@ -1706,7 +2164,7 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
},
|
},
|
||||||
child: InputDecorator(
|
child: InputDecorator(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: label,
|
labelText: isRequired ? '$label *' : label,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -1726,11 +2184,12 @@ class _planclaimsformState extends State<planclaimsform> {
|
|||||||
bool readOnly,
|
bool readOnly,
|
||||||
List<Map<String, dynamic>> itemsList,
|
List<Map<String, dynamic>> itemsList,
|
||||||
String displayField,
|
String displayField,
|
||||||
int? selectedValue // Added selectedValue parameter
|
int? selectedValue, // Added selectedValue parameter
|
||||||
|
{bool isRequired = false,}
|
||||||
) {
|
) {
|
||||||
return DropdownButtonFormField<int>(
|
return DropdownButtonFormField<int>(
|
||||||
value: selectedValue,
|
value: selectedValue,
|
||||||
decoration: InputDecoration(labelText: label),
|
decoration: InputDecoration(labelText: isRequired ? '$label *' : label,),
|
||||||
items: itemsList.map<DropdownMenuItem<int>>((item) {
|
items: itemsList.map<DropdownMenuItem<int>>((item) {
|
||||||
return DropdownMenuItem<int>(
|
return DropdownMenuItem<int>(
|
||||||
value: item['id'], // Ensure 'id' is correctly referenced
|
value: item['id'], // Ensure 'id' is correctly referenced
|
||||||
|
|||||||
@ -330,12 +330,8 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _clearLocalStorageAndRedirect() async {
|
Future<void> _clearLocalStorageAndRedirect() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
if (!context.mounted) return;
|
||||||
await prefs.clear();
|
await TokenService().logout(context);
|
||||||
// Assuming you have access to the context
|
|
||||||
ToastHelper.showErrorToast(context, 'Session Out');
|
|
||||||
context.go('/login');
|
|
||||||
// Navigator.pushNamed(context, 'login');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> getBotDetails(
|
Future<Map<String, dynamic>> getBotDetails(
|
||||||
@ -425,7 +421,12 @@ class ApiService {
|
|||||||
ToastHelper.showWarningToast(context, message);
|
ToastHelper.showWarningToast(context, message);
|
||||||
return {};
|
return {};
|
||||||
} else if (response.statusCode == 429) {
|
} else if (response.statusCode == 429) {
|
||||||
|
<<<<<<< HEAD
|
||||||
final body = jsonDecode(response.body);
|
final body = jsonDecode(response.body);
|
||||||
|
=======
|
||||||
|
if (!context.mounted) return {};
|
||||||
|
final body = jsonDecode(response.body);
|
||||||
|
>>>>>>> 24f532f750daddbb5d414d9056a4e1c4c760a2c4
|
||||||
final message = body['message'];
|
final message = body['message'];
|
||||||
ToastHelper.showWarningToast(context, message);
|
ToastHelper.showWarningToast(context, message);
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@ -4,8 +4,15 @@ import 'file_upload_service.dart';
|
|||||||
|
|
||||||
class MultiFileUploadWidget extends StatefulWidget {
|
class MultiFileUploadWidget extends StatefulWidget {
|
||||||
final bool forceMobile;
|
final bool forceMobile;
|
||||||
|
final bool isRequired;
|
||||||
|
final bool showError; // ✅ ADD THIS
|
||||||
|
|
||||||
const MultiFileUploadWidget({super.key, this.forceMobile = false});
|
const MultiFileUploadWidget({
|
||||||
|
super.key,
|
||||||
|
this.forceMobile = false,
|
||||||
|
this.isRequired = false,
|
||||||
|
this.showError = false, // ✅ ADD THIS
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MultiFileUploadWidget> createState() => _MultiFileUploadWidgetState();
|
State<MultiFileUploadWidget> createState() => _MultiFileUploadWidgetState();
|
||||||
@ -18,27 +25,12 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
|
|||||||
String? errorMessage;
|
String? errorMessage;
|
||||||
|
|
||||||
void _pickFiles() async {
|
void _pickFiles() async {
|
||||||
final error = await fileService.pickFiles(maxFileSizeInMB: 10); // 5 MB limit
|
final error = await fileService.pickFiles(maxFileSizeInMB: 10);
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
errorMessage = error;
|
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 {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -55,6 +47,31 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ Build the button label with RichText to show * in red
|
||||||
|
Widget _buildButtonLabel() {
|
||||||
|
if (!widget.isRequired) {
|
||||||
|
return const Text(
|
||||||
|
"Upload Documents",
|
||||||
|
style: TextStyle(fontSize: 14, color: Colors.black),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return RichText(
|
||||||
|
text: const TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: "Upload Documents ",
|
||||||
|
style: TextStyle(fontSize: 14, color: Colors.black),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: "*", // ✅ red * like other fields
|
||||||
|
style: TextStyle(fontSize: 14, color: Colors.red),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final files = fileService.files;
|
final files = fileService.files;
|
||||||
@ -67,21 +84,14 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
|
|||||||
onPressed: _pickFiles,
|
onPressed: _pickFiles,
|
||||||
icon: const Icon(Icons.file_upload_outlined,
|
icon: const Icon(Icons.file_upload_outlined,
|
||||||
color: Color(0xFFE26728), size: 24),
|
color: Color(0xFFE26728), size: 24),
|
||||||
label: const Text(
|
label: _buildButtonLabel(), // ✅ use rich text label
|
||||||
"Upload Documents",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
side: const BorderSide(color: Color(0xFFE26728)),
|
side: const BorderSide(color: Color(0xFFE26728)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
const Text(
|
const Text(
|
||||||
"Supports only PDF, PNG, JPG, JPEG,HEIC formats (max 10 MB each)",
|
"Supports only PDF, PNG, JPG, JPEG, HEIC formats (max 10 MB each)",
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey),
|
style: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
),
|
),
|
||||||
] else ...[
|
] else ...[
|
||||||
@ -91,14 +101,7 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
|
|||||||
onPressed: _pickFiles,
|
onPressed: _pickFiles,
|
||||||
icon: const Icon(Icons.file_upload_outlined,
|
icon: const Icon(Icons.file_upload_outlined,
|
||||||
color: Color(0xFFE26728), size: 24),
|
color: Color(0xFFE26728), size: 24),
|
||||||
label: const Text(
|
label: _buildButtonLabel(), // ✅ use rich text label
|
||||||
"Upload Documents",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
side: const BorderSide(color: Color(0xFFE26728)),
|
side: const BorderSide(color: Color(0xFFE26728)),
|
||||||
),
|
),
|
||||||
@ -106,7 +109,7 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
|
|||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
const Expanded(
|
const Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Supports only PDF, PNG, JPG, JPEG,HEIC formats (max 10 MB each)",
|
"Supports only PDF, PNG, JPG, JPEG, HEIC formats (max 10 MB each)",
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey),
|
style: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@ -115,10 +118,11 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
if (fileService.files.isEmpty && errorMessage == null) ...[
|
// ✅ Show error only when required AND no files
|
||||||
|
if (widget.isRequired && widget.showError && files.isEmpty && errorMessage == null) ...[
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
const Text(
|
const Text(
|
||||||
"Required",
|
'Please upload the document',
|
||||||
style: TextStyle(color: Colors.red, fontSize: 12),
|
style: TextStyle(color: Colors.red, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -134,7 +138,7 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
...fileService.files.asMap().entries.map((entry) {
|
...fileService.files.asMap().entries.map((entry) {
|
||||||
final index = entry.key;
|
final index = entry.key;
|
||||||
final uploaded = entry.value; // UploadedFile
|
final uploaded = entry.value;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -142,7 +146,8 @@ class _MultiFileUploadWidgetState extends State<MultiFileUploadWidget> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: Text(uploaded.file.name, style: const TextStyle(fontSize: 14)),
|
title: Text(uploaded.file.name,
|
||||||
|
style: const TextStyle(fontSize: 14)),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(Icons.close, color: Colors.red),
|
icon: const Icon(Icons.close, color: Colors.red),
|
||||||
onPressed: () => _removeFile(index),
|
onPressed: () => _removeFile(index),
|
||||||
|
|||||||
@ -66,6 +66,14 @@ class _setPasswordState extends State<setPassword> {
|
|||||||
final confirmPassword = confirmPasswordController.text.trim();
|
final confirmPassword = confirmPasswordController.text.trim();
|
||||||
try {
|
try {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
|
final strongPasswordRegex =
|
||||||
|
RegExp(r'^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&]).{8,}$');
|
||||||
|
if (!strongPasswordRegex.hasMatch(newPassword)) {
|
||||||
|
ToastHelper.showErrorToast(
|
||||||
|
context,
|
||||||
|
'Enter a valid password (8+ chars with letter, number, special char)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (confirmPassword != newPassword) {
|
if (confirmPassword != newPassword) {
|
||||||
ToastHelper.showErrorToast(context, 'Passwords do not match');
|
ToastHelper.showErrorToast(context, 'Passwords do not match');
|
||||||
return;
|
return;
|
||||||
@ -213,15 +221,20 @@ class _setPasswordState extends State<setPassword> {
|
|||||||
}
|
}
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
// Close the app on mobile back button press
|
// 🖥 Desktop / Web → always go back to login
|
||||||
exit(0); // This will exit the app
|
if (kIsWeb || Responsive.isDesktop(context)) {
|
||||||
return false; // Return false to prevent any other actions
|
context.go('/login');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 📱 Mobile → keep existing behavior (exit app)
|
||||||
|
exit(0);
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: _size.height,
|
constraints: BoxConstraints(minHeight: _size.height),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
@ -308,7 +321,7 @@ class _setPasswordState extends State<setPassword> {
|
|||||||
// ),
|
// ),
|
||||||
Container(
|
Container(
|
||||||
margin: marginInsets,
|
margin: marginInsets,
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.center,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
@ -353,8 +366,7 @@ class _setPasswordState extends State<setPassword> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 12,
|
flex: 12,
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment
|
alignment: Alignment.center,
|
||||||
.topLeft, // ✅ Always top-left
|
|
||||||
child: _size.width <= 1100
|
child: _size.width <= 1100
|
||||||
? Image.asset(
|
? Image.asset(
|
||||||
'assets/nhance_app_logo.png',
|
'assets/nhance_app_logo.png',
|
||||||
@ -378,10 +390,9 @@ class _setPasswordState extends State<setPassword> {
|
|||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: Responsive.isDesktop(context)
|
height: Responsive.isDesktop(context)
|
||||||
? _size.height * 0.1
|
? null
|
||||||
: 10,
|
: _size.height * 0.2,
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
|
||||||
Container(
|
Container(
|
||||||
margin: Responsive.isDesktop(context)
|
margin: Responsive.isDesktop(context)
|
||||||
? EdgeInsets.symmetric(
|
? EdgeInsets.symmetric(
|
||||||
@ -464,6 +475,25 @@ class _setPasswordState extends State<setPassword> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
validator: (value) {
|
||||||
|
final password = value ?? '';
|
||||||
|
if (password.isEmpty) {
|
||||||
|
return 'Please enter your new password';
|
||||||
|
}
|
||||||
|
if (password.length < 8) {
|
||||||
|
return 'Password must be at least 8 characters';
|
||||||
|
}
|
||||||
|
if (!RegExp(r'[A-Za-z]').hasMatch(password)) {
|
||||||
|
return 'Password must include at least 1 letter';
|
||||||
|
}
|
||||||
|
if (!RegExp(r'\d').hasMatch(password)) {
|
||||||
|
return 'Password must include at least 1 number';
|
||||||
|
}
|
||||||
|
if (!RegExp(r'[@$!%*#?&]').hasMatch(password)) {
|
||||||
|
return 'Password must include at least 1 special character';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
@ -604,10 +634,10 @@ class _setPasswordState extends State<setPassword> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// _size.height * 0.3
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: Responsive.isDesktop(context)
|
height: Responsive.isDesktop(context)
|
||||||
? _size.height * 0.3
|
? null
|
||||||
: _size.height * 0.2,
|
: _size.height * 0.2,
|
||||||
),
|
),
|
||||||
// SizedBox(
|
// SizedBox(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user