Code updated

This commit is contained in:
risnaman
2026-09-19 16:21:37 +05:30
parent 012969ae21
commit 212df37f8a
4 changed files with 352 additions and 357 deletions
+3 -1
View File
@@ -1,8 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="authsec_flutter_hybrid"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true"
+16 -8
View File
@@ -213,23 +213,32 @@ class _CreateAccountScreenState extends State<CreateAccountScreen> {
onTap: () async {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
{
try {
print('form data is $formData');
final response =
await userService.createAccount(formData);
account_id = response['account_id'].toString();
var parsedId;
if (response is Map) {
parsedId = response['account_id'] ??
response['id'] ??
response['sysAccountId'] ??
response['accountId'] ??
response['item']?['account_id'] ??
response['item']?['id'];
} else {
parsedId = response;
}
account_id = parsedId?.toString();
print(
'after create account account id is $account_id');
// ignore: use_build_context_synchronously
Navigator.pop(
_context, account_id); // Pop with account_id
// Navigator.pop(context);
if (!mounted) return;
Navigator.pop(context, account_id);
} catch (e) {
// ignore: use_build_context_synchronously
if (!mounted) return;
showDialog(
context: context,
builder: (BuildContext context) {
@@ -249,7 +258,6 @@ class _CreateAccountScreenState extends State<CreateAccountScreen> {
);
}
}
}
},
),
),
+51 -17
View File
@@ -4,7 +4,42 @@ import '../../resources/api_constants.dart';
class SignUpApiService {
final String baseUrl = ApiConstants.baseUrl;
final Dio dio = Dio();
late final Dio dio;
SignUpApiService() {
dio = Dio(BaseOptions(
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10),
headers: {
'Content-Type': 'application/json',
},
));
}
String _formatError(dynamic e, String defaultMessage) {
if (e is DioException) {
if (e.response != null && e.response?.data != null) {
final data = e.response!.data;
if (data is Map) {
if (data['message'] != null) return data['message'].toString();
if (data['operationMessage'] != null) return data['operationMessage'].toString();
if (data['error'] != null) return data['error'].toString();
} else if (data is String && data.isNotEmpty) {
return data;
}
}
if (e.type == DioExceptionType.connectionTimeout ||
e.type == DioExceptionType.sendTimeout ||
e.type == DioExceptionType.receiveTimeout) {
return 'Connection timed out. Please check your network and backend.';
}
if (e.type == DioExceptionType.connectionError) {
return 'Cannot connect to server at $baseUrl. Please verify the backend is running.';
}
return e.message ?? defaultMessage;
}
return defaultMessage.isNotEmpty ? '$defaultMessage: $e' : e.toString();
}
// get all account
Future<List<Map<String, dynamic>>> getallAccount(String token) async {
@@ -17,18 +52,15 @@ class SignUpApiService {
print('response data is ... $responseData');
if (responseData is List) {
// If the response is a list, cast it to the expected type
final entities = responseData.cast<Map<String, dynamic>>();
return entities;
} else if (responseData is Map<String, dynamic>) {
// If the response is a single object, wrap it in a list
return [responseData];
} else {
// Handle other unexpected response types here
throw Exception('Unexpected response type');
}
} catch (e) {
throw Exception('Failed to Account: $e');
throw Exception(_formatError(e, 'Failed to fetch Account'));
}
}
@@ -36,14 +68,18 @@ class SignUpApiService {
Future<Map<String, dynamic>> createAccount(
Map<String, dynamic> entity) async {
try {
// dio.options.headers['Authorization'] = 'Bearer $token';
final response = await dio
.post('$baseUrl/token/users/sysaccount/savesysaccount', data: entity);
print('created account is $response');
if (response.data is Map<String, dynamic>) {
return response.data;
} else if (response.data is Map) {
return Map<String, dynamic>.from(response.data);
}
return {'account_id': response.data.toString()};
} catch (e) {
throw Exception('Failed To Create Account: $e');
throw Exception(_formatError(e, 'Failed to Create Account'));
}
}
@@ -51,41 +87,39 @@ class SignUpApiService {
Future<void> sendEmail(Map<String, dynamic> entity) async {
try {
print("in post api...$entity");
// dio.options.headers['Authorization'] = 'Bearer $token';
await dio.post('$baseUrl/token/user/send_email', data: entity);
print(entity);
} catch (e) {
throw Exception('Failed to Send Email: $e');
throw Exception(_formatError(e, 'Failed to Send Email'));
}
}
// RESEND EMAIL FOR OTP
Future<void> resendEmail(String email) async {
try {
// dio.options.headers['Authorization'] = 'Bearer $token';
await dio.post('$baseUrl/token/user/resend_otp?email=$email');
} catch (e) {
throw Exception('Failed to ReSend Email: $e');
throw Exception(_formatError(e, 'Failed to Resend OTP'));
}
}
// OTP VEFICATION
// OTP VERIFICATION
Future<void> otpverification(String email, String otp) async {
try {
// dio.options.headers['Authorization'] = 'Bearer $token';
await dio
.post('$baseUrl/token/user/otp_verification?email=$email&otp=$otp');
} catch (e) {
throw Exception('Failed to Verify Otp: $e');
throw Exception(_formatError(e, 'Failed to Verify OTP'));
}
}
Future<void> createuser(Map<String, dynamic> entity) async {
try {
print("in post api...$entity");
await dio.post('$baseUrl/token/addOneAppUser', data: entity);
print(entity);
} catch (e) {
throw Exception('Failed to create User: $e');
throw Exception(_formatError(e, 'Failed to Create User'));
}
}
@@ -96,7 +130,7 @@ class SignUpApiService {
await dio.put('$baseUrl/api/updateAppUserDto/$entityId', data: entity);
print(entity);
} catch (e) {
throw Exception('Failed to update Backend: $e');
throw Exception(_formatError(e, 'Failed to update User'));
}
}
@@ -105,7 +139,7 @@ class SignUpApiService {
dio.options.headers['Authorization'] = 'Bearer $token';
await dio.delete('$baseUrl/api/delete_usr/$entityId');
} catch (e) {
throw Exception('Failed to delete User: $e');
throw Exception(_formatError(e, 'Failed to delete User'));
}
}
}
+152 -201
View File
@@ -37,22 +37,18 @@ class _SignUpUserScreenState extends State<SignUpUserScreenNew> {
final Map<String, dynamic> formData = {};
final _formKey = GlobalKey<FormState>();
var selectedAccount;
TextEditingController emailcontroller = TextEditingController();
var email;
var otp;
var confirmPassword;
bool _passwordVisible = false;
bool _isPasswordValid = true;
void _validatePassword(String password) {
setState(() {
_isPasswordValid = password.isNotEmpty;
});
}
final TextEditingController emailcontroller = TextEditingController();
String? otp;
bool _isLoading = false;
RegistrationStep currentStep = RegistrationStep.SendOTP;
@override
void dispose() {
emailcontroller.dispose();
super.dispose();
}
void moveToNextStep() {
setState(() {
if (currentStep == RegistrationStep.SendOTP) {
@@ -66,25 +62,96 @@ class _SignUpUserScreenState extends State<SignUpUserScreenNew> {
}
void showSuccessMessage(String message) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: const Duration(seconds: 2),
duration: const Duration(seconds: 3),
backgroundColor: Colors.green,
),
);
}
void showErrorMessage(String error) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(error),
duration: const Duration(seconds: 2),
duration: const Duration(seconds: 4),
backgroundColor: Colors.red,
),
);
}
Future<void> _handleSendOtp() async {
FocusManager.instance.primaryFocus?.unfocus();
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
final email = emailcontroller.text.trim();
formData['usrGrpId'] = 41;
formData['email'] = email;
setState(() => _isLoading = true);
try {
print('send email data is $formData');
await userService.sendEmail(formData);
if (!mounted) return;
showSuccessMessage('OTP sent to $email');
moveToNextStep();
} catch (e) {
if (!mounted) return;
showErrorMessage('Failed to send OTP: $e');
} finally {
if (mounted) setState(() => _isLoading = false);
}
}
}
Future<void> _handleVerifyOtp() async {
FocusManager.instance.primaryFocus?.unfocus();
final enteredOtp = otp?.trim();
if (enteredOtp == null || enteredOtp.length < 6) {
showErrorMessage('Please enter the complete 6-digit OTP');
return;
}
final email = emailcontroller.text.trim();
setState(() => _isLoading = true);
try {
print('Verifying email: $email with OTP: $enteredOtp');
await userService.otpverification(email, enteredOtp);
if (!mounted) return;
showSuccessMessage('Email verified successfully');
moveToNextStep();
} catch (e) {
if (!mounted) return;
showErrorMessage('Failed to verify OTP: $e');
} finally {
if (mounted) setState(() => _isLoading = false);
}
}
Future<void> _handleResendOtp() async {
final email = emailcontroller.text.trim();
if (email.isEmpty) {
showErrorMessage('Email address is missing');
return;
}
setState(() => _isLoading = true);
try {
await userService.resendEmail(email);
if (!mounted) return;
showSuccessMessage('OTP resent to $email');
} catch (e) {
if (!mounted) return;
showErrorMessage('Failed to resend OTP: $e');
} finally {
if (mounted) setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -98,23 +165,27 @@ class _SignUpUserScreenState extends State<SignUpUserScreenNew> {
svgPath: ImageConstant.imgArrowleft,
margin: getMargin(left: 16, top: 13, bottom: 17),
onTap: () {
if (currentStep == RegistrationStep.VerifyOTP) {
setState(() => currentStep = RegistrationStep.SendOTP);
} else if (currentStep == RegistrationStep.EnterUserInfo) {
setState(() => currentStep = RegistrationStep.VerifyOTP);
} else {
Navigator.pop(context);
}
}),
centerTitle: true,
title: AppbarTitle(text: "Create User")),
body: Builder(
builder: (BuildContext context) {
return SingleChildScrollView(
child: Padding(
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: SizedBox(
height: MediaQuery.of(context).size.height *
0.5, // Use 50% of the screen height
child: ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
child: _buildStepContent(),
),
),
);
}
Widget _buildStepContent() {
if (currentStep == RegistrationStep.SendOTP) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -125,12 +196,15 @@ class _SignUpUserScreenState extends State<SignUpUserScreenNew> {
textAlign: TextAlign.left,
style: AppStyle.txtGilroyMedium16Bluegray900),
CustomTextFormField(
focusNode: FocusNode(),
controller: emailcontroller,
validator: (value) {
if (value == null || value.isEmpty) {
if (value == null || value.trim().isEmpty) {
return 'Please enter Email';
}
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value.trim())) {
return 'Please enter a valid email address';
}
return null;
},
hintText: "Enter Your Email",
@@ -139,92 +213,26 @@ class _SignUpUserScreenState extends State<SignUpUserScreenNew> {
CustomButton(
height: getVerticalSize(50),
width: getHorizontalSize(396),
text: "Send OTP",
text: _isLoading ? "Sending OTP..." : "Send OTP",
margin: getMargin(top: 25),
onTap: () async {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
formData['usrGrpId'] = 41;
formData['email'] = emailcontroller.text;
try {
print('send email data is $formData');
await userService.sendEmail(formData);
await Future.delayed(
const Duration(seconds: 2));
moveToNextStep();
} catch (e) {
showErrorMessage(
'Failed to send OTP: $e');
}
}
},
onTap: _isLoading ? null : _handleSendOtp,
),
Align(
alignment: Alignment.center,
child: Padding(
padding: getPadding(top: 28, bottom: 5),
child: RichText(
text: TextSpan(children: [
TextSpan(
text: "",
style: TextStyle(
color: ColorConstant.fromHex(
"#ff12282a"),
fontSize: getFontSize(16),
fontFamily: 'Gilroy',
fontWeight: FontWeight.w400)),
TextSpan(
text: " ",
style: TextStyle(
color: ColorConstant.fromHex(
"#ff12282a"),
fontSize: getFontSize(16),
fontFamily: 'Gilroy',
fontWeight: FontWeight.w700)),
TextSpan(
text: "",
style: TextStyle(
color: ColorConstant.fromHex(
"#ff0061ff"),
fontSize: getFontSize(16),
fontFamily: 'Gilroy',
fontWeight: FontWeight.w700,
decoration:
TextDecoration.underline))
]),
textAlign: TextAlign.left)))
]);
}
else if(currentStep == RegistrationStep.VerifyOTP) {
],
);
} else if (currentStep == RegistrationStep.VerifyOTP) {
return Container(
width: double.maxFinite,
padding: getPadding(
left: 16,
top: 76,
right: 16,
),
padding: getPadding(left: 16, top: 30, right: 16),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
CustomImageView(
svgPath: ImageConstant.imgMobile,
height: getVerticalSize(
82,
),
width: getHorizontalSize(
51,
),
height: getVerticalSize(82),
width: getHorizontalSize(51),
),
Padding(
padding: getPadding(
top: 29,
),
padding: getPadding(top: 24),
child: Text(
"Email Verification",
overflow: TextOverflow.ellipsis,
@@ -233,21 +241,16 @@ class _SignUpUserScreenState extends State<SignUpUserScreenNew> {
),
),
Container(
width: getHorizontalSize(
302,
),
margin: getMargin(
left: 46,
top: 19,
right: 46,
),
width: getHorizontalSize(302),
margin: getMargin(left: 16, top: 16, right: 16),
child: Text(
"A mail with a 6-digit verification code was just sent to ${emailcontroller.text}",
"A mail with a 6-digit verification code was just sent to ${emailcontroller.text.trim()}",
maxLines: null,
textAlign: TextAlign.center,
style: AppStyle.txtGilroyMedium16,
),
),
const SizedBox(height: 24),
Pinput(
length: 6,
showCursor: true,
@@ -265,134 +268,82 @@ class _SignUpUserScreenState extends State<SignUpUserScreenNew> {
fontWeight: FontWeight.w600,
),
),
onChanged: (value) {
otp = value;
},
onCompleted: (value) {
setState(() {
otp = value;
});
},
),
CustomButton(
height: getVerticalSize(
50,
height: getVerticalSize(50),
text: _isLoading ? "Verifying..." : "Next",
margin: getMargin(top: 30),
onTap: _isLoading ? null : _handleVerifyOtp,
),
text: "Next",
margin: getMargin(
top: 40,
),
onTap: () async {
try {
print('email is $email and otp is $otp');
await userService.otpverification(emailcontroller.text, otp);
moveToNextStep();
showSuccessMessage(
'Email verified successfully');
} catch (e) {
showErrorMessage('Failed to verify OTP: $e');
}
},
),
GestureDetector(
onTap: () async {
try {
await userService.resendEmail(email);
await Future.delayed(
const Duration(seconds: 5));
showSuccessMessage('OTP RESEND');
} catch (e) {
showErrorMessage(
'Failed to resend OTP: $e');
}
},
child: Padding(
padding: getPadding(top: 3),
child: Text("Forgot Password?",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style:
AppStyle.txtGilroyMedium14BlueA700)),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: getPadding(
top: 18,
bottom: 5,
),
child: Row(
children: [
Padding(
padding: getPadding(
top: 2,
),
child: Text(
padding: getPadding(top: 24, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Didnt get the code?",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: AppStyle.txtGilroyMedium16,
),
),
Padding(
padding: getPadding(
left: 12,
bottom: 1,
),
const SizedBox(width: 8),
InkWell(
onTap: _isLoading ? null : _handleResendOtp,
child: Text(
"Resend",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: AppStyle.txtGilroySemiBold16BlueA700,
),
),
],
),
),
),
],
),
);
}
else if (currentStep ==
RegistrationStep.EnterUserInfo) {
} else if (currentStep == RegistrationStep.EnterUserInfo) {
return Column(
children: [
const SizedBox(height: 40),
CustomImageView(
svgPath: ImageConstant.imgMobile,
height: getVerticalSize(82),
width: getHorizontalSize(51),
),
const SizedBox(height: 20),
Text(
"Email Verified!",
style: AppStyle.txtGilroySemiBold24,
),
const SizedBox(height: 10),
Text(
"Please proceed to enter your registration details.",
textAlign: TextAlign.center,
style: AppStyle.txtGilroyMedium16,
),
CustomButton(
height: getVerticalSize(
50,
),
height: getVerticalSize(50),
text: "Go to Registration Details",
margin: getMargin(
top: 40,
),
onTap: () async {
margin: getMargin(top: 40),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
RegistrationDetailsScreen(email: emailcontroller.text),
RegistrationDetailsScreen(email: emailcontroller.text.trim()),
),
);
},
),
],
);
}
else{
} else {
return Container();
}
},
),
),
),
),
);
},
),
);
}
}