Change TPIn #4

This commit is contained in:
2025-11-08 20:07:04 +05:30
parent c26cc507a1
commit b5b6c6ed49
3 changed files with 171 additions and 189 deletions

View File

@@ -194,6 +194,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
}, },
), ),
ListTile( ListTile(
leading: const Icon(Icons.password),
title: Text('Change TPIN'), title: Text('Change TPIN'),
onTap: () async { onTap: () async {
// 1. Get the AuthService instance // 1. Get the AuthService instance

View File

@@ -1,17 +1,16 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
import 'package:kmobile/features/dashboard/screens/dashboard_screen.dart';
import 'package:kmobile/widgets/pin_input_field.dart'; import 'package:kmobile/widgets/pin_input_field.dart';
import '../../../api/services/change_password_service.dart'; import '../../../api/services/change_password_service.dart';
class ChangeTpinOtpScreen extends StatefulWidget { class ChangeTpinOtpScreen extends StatefulWidget {
final String oldTpin;
final String newTpin; final String newTpin;
final String mobileNumber; // Receive mobile number final String mobileNumber;
const ChangeTpinOtpScreen({ const ChangeTpinOtpScreen({
super.key, super.key,
required this.oldTpin,
required this.newTpin, required this.newTpin,
required this.mobileNumber, required this.mobileNumber,
}); });
@@ -22,7 +21,8 @@
class _ChangeTpinOtpScreenState extends State<ChangeTpinOtpScreen> { class _ChangeTpinOtpScreenState extends State<ChangeTpinOtpScreen> {
final _otpController = TextEditingController(); final _otpController = TextEditingController();
final ChangePasswordService _changePasswordService = getIt<ChangePasswordService>(); final ChangePasswordService _changePasswordService =
getIt<ChangePasswordService>();
bool _isLoading = false; bool _isLoading = false;
void _handleVerifyOtp() async { void _handleVerifyOtp() async {
@@ -37,44 +37,43 @@
_isLoading = true; _isLoading = true;
}); });
String message = 'An unknown error occurred.';
bool success = false;
try { try {
// 1. Validate the OTP // 1. Validate the OTP first.
final responseString = await _changePasswordService.validateOtp( await _changePasswordService.validateOtp(
otp: _otpController.text, otp: _otpController.text,
mobileNumber: widget.mobileNumber, mobileNumber: '8981274001',
); );
final response = jsonDecode(responseString);
// 2. Check status and set message // 2. If OTP is valid, then call validateChangeTpin.
if (response['statusCode'] == 200 || response['statusCode'] == 2000) { await _changePasswordService.validateChangeTpin(
message = 'TPIN changed successfully!'; oldTpin: widget.oldTpin,
success = true; newTpin: widget.newTpin,
} else { );
message = response['message'] ?? 'Invalid OTP. Please try again.';
// 3. Show success message.
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('TPIN changed successfully!'),
backgroundColor: Colors.green,
),
);
// 4. Navigate back to the profile screen or home.
Navigator.of(context).popUntil((route) => route.isFirst);
} }
} catch (e) { } catch (e) {
message = 'Failed to verify OTP: $e';
} finally {
// 3. Show feedback
if (mounted) { if (mounted) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text(message), content: Text('An error occurred: $e'),
backgroundColor: success ? Colors.green : Colors.red, backgroundColor: Colors.red,
), ),
); );
// 4. Navigate to dashboard after 5 seconds
Timer(const Duration(seconds: 5), () {
if (mounted) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => const DashboardScreen()),
(Route<dynamic> route) => false,
);
} }
} finally {
if (mounted) {
setState(() {
_isLoading = false;
}); });
} }
} }

View File

@@ -1,24 +1,24 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
import 'package:kmobile/features/profile/tpin/change_tpin_otp_screen.dart'; import 'package:kmobile/features/profile/tpin/change_tpin_otp_screen.dart';
import 'package:kmobile/widgets/pin_input_field.dart'; import 'package:kmobile/widgets/pin_input_field.dart';
import '../../../api/services/change_password_service.dart'; import '../../../api/services/change_password_service.dart';
import 'dart:convert';
class ChangeTpinScreen extends StatefulWidget { class ChangeTpinScreen extends StatefulWidget {
final String mobileNumber; final String mobileNumber;
const ChangeTpinScreen({super.key, required this.mobileNumber}); const ChangeTpinScreen({super.key, required this.mobileNumber});
@override @override
State<ChangeTpinScreen> createState() => _ChangeTpinScreenState(); State<ChangeTpinScreen> createState() => _ChangeTpinScreenState();
} }
class _ChangeTpinScreenState extends State<ChangeTpinScreen> { class _ChangeTpinScreenState extends State<ChangeTpinScreen> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _oldTpinController = TextEditingController(); final _oldTpinController = TextEditingController();
final _newTpinController = TextEditingController(); final _newTpinController = TextEditingController();
final _confirmTpinController = TextEditingController(); final _confirmTpinController = TextEditingController();
final ChangePasswordService _changePasswordService = getIt<ChangePasswordService>(); final ChangePasswordService _changePasswordService =
getIt<ChangePasswordService>();
bool _isLoading = false; bool _isLoading = false;
@override @override
@@ -35,43 +35,25 @@
_isLoading = true; _isLoading = true;
}); });
try { try {
// 1. Validate the current TPIN and new TPIN // 1. Get OTP for TPIN change.
final responseString = await _changePasswordService.validateChangeTpin(
oldTpin: _oldTpinController.text,
newTpin: _newTpinController.text,
);
// The service throws an exception for non-200 HTTP status,
// so we assume HTTP 200 here and check the body.
final response = jsonDecode(responseString);
// 2. Check the status code from the response body
if (response.statusCode == 200) {
// 3. Get OTP for TPIN change
await _changePasswordService.getOtpTpin(mobileNumber: '8981274001'); await _changePasswordService.getOtpTpin(mobileNumber: '8981274001');
// 4. Navigate to OTP screen // 2. Navigate to the OTP screen on success.
if (mounted) { if (mounted) {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => ChangeTpinOtpScreen( builder: (context) => ChangeTpinOtpScreen(
oldTpin: _oldTpinController.text,
newTpin: _newTpinController.text, newTpin: _newTpinController.text,
mobileNumber: '8981274001', // Pass mobile number mobileNumber: '8981274001',
), ),
), ),
); );
} }
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(response['message'] ?? 'Invalid TPIN details')
));
}
}
} catch (e) { } catch (e) {
if (mounted) { if (mounted) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('An error occurred: $e')), SnackBar(content: Text('Failed to send OTP: $e')),
); );
} }
} finally { } finally {
@@ -161,4 +143,4 @@
), ),
); );
} }
} }