IFSC Code Validation and Add Beneficiary Validation API integration

This commit is contained in:
2025-08-07 18:12:31 +05:30
parent c4d4261afc
commit 99e23bf21d
17 changed files with 416 additions and 271 deletions

View File

@@ -1,6 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:kmobile/api/services/beneficiary_service.dart';
import 'package:kmobile/data/models/ifsc.dart';
import 'package:kmobile/data/models/beneficiary.dart';
import 'beneficiary_result_page.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import '../../../di/injection.dart';
import '../../../l10n/app_localizations.dart';
class AddBeneficiaryScreen extends StatefulWidget {
@@ -21,7 +26,9 @@ class _AddBeneficiaryScreen extends State<AddBeneficiaryScreen> {
final TextEditingController branchNameController = TextEditingController();
final TextEditingController ifscController = TextEditingController();
final TextEditingController phoneController = TextEditingController();
bool _isLoading2 = false;
late String accountType;
@override
@@ -34,7 +41,7 @@ class _AddBeneficiaryScreen extends State<AddBeneficiaryScreen> {
});
}
void _submitForm() {
/*void _submitForm() {
if (_formKey.currentState!.validate()) {
// Handle successful submission
ScaffoldMessenger.of(context).showSnackBar(
@@ -56,11 +63,11 @@ class _AddBeneficiaryScreen extends State<AddBeneficiaryScreen> {
onPressed: () {
// Navigate to Payment Screen or do something
},
style: TextButton.styleFrom(foregroundColor: Colors.blue[200]),
style: TextButton.styleFrom(foregroundColor: Theme.of(context).primaryColorLight),
child: Text(AppLocalizations.of(context).payNow),
),
IconButton(
icon: const Icon(Icons.close, color: Colors.white),
icon: Icon(Icons.close, color: Theme.of(context).scaffoldBackgroundColor),
onPressed: () {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
},
@@ -70,58 +77,82 @@ class _AddBeneficiaryScreen extends State<AddBeneficiaryScreen> {
),
);
}
}*/
ifsc? _ifscData;
bool _isLoading = false;
void _validateIFSC() async {
var beneficiaryService = getIt<BeneficiaryService>();
final ifsc = ifscController.text.trim().toUpperCase();
if (ifsc.isEmpty) return;
setState(() {
_isLoading = true;
_ifscData = null;
});
final result = await beneficiaryService.validateIFSC(ifsc);
setState(() {
_isLoading = false;
_ifscData = result;
});
if (result == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Invalid IFSC code')),
);
bankNameController.clear();
branchNameController.clear();
} else {
print("Valid IFSC: ${result.bankName}, ${result.branchName}");
bankNameController.text = result.bankName;
branchNameController.text = result.branchName;
}
}
void _validateIFSC() async {
final ifsc = ifscController.text.trim().toUpperCase();
// 🔹 Format check
final isValidFormat = RegExp(r'^[A-Z]{4}0[A-Z0-9]{6}$').hasMatch(ifsc);
if (!isValidFormat) {
bankNameController.clear();
branchNameController.clear();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(AppLocalizations.of(context).invalidIfscFormat)),
);
return;
}
await Future.delayed(
const Duration(seconds: 2),
); //Mock delay for 2 sec to imitate api call
// 🔹 Mock IFSC lookup (you can replace this with API)
const mockIfscData = {
'KCCB0001234': {
'bank': 'Kangra Central Co-operative Bank',
'branch': 'Dharamshala',
},
'SBIN0004567': {
'bank': 'State Bank of India',
'branch': 'Connaught Place',
},
};
String _selectedAccountType = 'Savings'; // default value
if (mockIfscData.containsKey(ifsc)) {
final data = mockIfscData[ifsc]!;
bankNameController.text = data['bank']!;
branchNameController.text = data['branch']!;
} else {
bankNameController.clear();
branchNameController.clear();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(AppLocalizations.of(context).noIfscDetails)),
void validateAndAddBeneficiary() async {
setState(() {
_isLoading = true;
});
final beneficiary = Beneficiary(
accountNo: accountNumberController.text.trim(),
accountType: _selectedAccountType,
name: nameController.text.trim(),
ifscCode: ifscController.text.trim(),
);
var service = getIt<BeneficiaryService>();
try {
await service.sendForValidation(beneficiary);
bool isFound = await service.checkIfFound(beneficiary.accountNo);
if (context.mounted) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BeneficiaryResultPage(isSuccess: isFound),
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Something went wrong during validation.")),
);
} finally {
if (mounted) {
setState(() {
_isLoading2 = false;
});
}
}
}
/*
🔸 Optional: Use real IFSC API like:
final response = await http.get(Uri.parse('https://ifsc.razorpay.com/$ifsc'));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
bankNameController.text = data['BANK'];
branchNameController.text = data['BRANCH'];
}
*/
}
@override
Widget build(BuildContext context) {
@@ -263,110 +294,7 @@ class _AddBeneficiaryScreen extends State<AddBeneficiaryScreen> {
? AppLocalizations.of(context).nameRequired
: null,
),
/*const SizedBox(height: 24),
TextFormField(
controller: bankNameController,
decoration: const InputDecoration(
labelText: 'Beneficiary Bank Name',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.next,
validator: (value) =>
value == null || value.isEmpty ? "Bank name is required" : null,
),
const SizedBox(height: 24),
TextFormField(
controller: branchNameController,
decoration: const InputDecoration(
labelText: 'Branch Name',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.next,
validator: (value) =>
value == null || value.isEmpty ? "Branch name is required" : null,
),
const SizedBox(height: 24),
Row(
children: [
Expanded(
flex: 2,
child: TextFormField(
controller: ifscController,
decoration: const InputDecoration(
labelText: 'IFSC Code',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
textInputAction: TextInputAction.next,
validator: (value) => value == null || value.length < 5
? "Enter a valid IFSC"
: null,
),
),
const SizedBox(width: 16),
Expanded(
flex: 2,
child: DropdownButtonFormField<String>(
value: accountType,
decoration: const InputDecoration(
labelText: 'Account Type',
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
items: ['Savings', 'Current']
.map((type) => DropdownMenuItem(
value: type,
child: Text(type),
))
.toList(),
onChanged: (value) {
setState(() {
accountType = value!;
});
},
),
),
],
),*/
const SizedBox(height: 24),
// 🔹 IFSC Code Field
TextFormField(
@@ -538,7 +466,8 @@ class _AddBeneficiaryScreen extends State<AddBeneficiaryScreen> {
child: SizedBox(
width: 250,
child: ElevatedButton(
onPressed: _submitForm,
onPressed: _isLoading2 ? null :
validateAndAddBeneficiary,
style: ElevatedButton.styleFrom(
shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16),