Yojna & Cheque done
This commit is contained in:
175
lib/features/account_opening/screens/account_opening_screen.dart
Normal file
175
lib/features/account_opening/screens/account_opening_screen.dart
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import 'package:flutter/material.dart'; // Keep if User model is generic
|
||||||
|
import 'package:kmobile/features/account_opening/screens/fd_screen.dart';
|
||||||
|
import 'package:kmobile/features/account_opening/screens/loan_screen.dart';
|
||||||
|
import 'package:kmobile/features/account_opening/screens/rd_screen.dart';
|
||||||
|
import 'package:kmobile/features/account_opening/screens/td_screen.dart';
|
||||||
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
|
import '../../../l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class AccountOpeningScreen extends StatefulWidget {
|
||||||
|
const AccountOpeningScreen({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AccountOpeningScreen> createState() => _AccountOpeningScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccountOpeningScreenState extends State<AccountOpeningScreen> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text(
|
||||||
|
"Account Opening",
|
||||||
|
),
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: AccountOpeningCardTile(
|
||||||
|
icon: Symbols.savings,
|
||||||
|
label: "Fixed Deposit (FD)",
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const FdScreen(
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: AccountOpeningCardTile(
|
||||||
|
icon: Symbols.currency_rupee,
|
||||||
|
label: "Term Deposit",
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const TermDepositScreen()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: AccountOpeningCardTile(
|
||||||
|
icon: Symbols.account_balance,
|
||||||
|
label: AppLocalizations.of(context).recurringDeposit,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const RecurringDepositScreen() ),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: AccountOpeningCardTile(
|
||||||
|
icon: Symbols.credit_card,
|
||||||
|
label: "Request Loan",
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const LoanScreen()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IgnorePointer(
|
||||||
|
child: Center(
|
||||||
|
child: Opacity(
|
||||||
|
opacity: 0.07,
|
||||||
|
child: ClipOval(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/logo.png',
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountOpeningCardTile extends StatelessWidget {
|
||||||
|
final IconData icon;
|
||||||
|
final String label;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final bool disable;
|
||||||
|
|
||||||
|
const AccountOpeningCardTile({
|
||||||
|
super.key,
|
||||||
|
required this.icon,
|
||||||
|
required this.label,
|
||||||
|
required this.onTap,
|
||||||
|
this.disable = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return Card(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
|
),
|
||||||
|
elevation: 4,
|
||||||
|
child: InkWell(
|
||||||
|
onTap:
|
||||||
|
disable ? null : onTap,
|
||||||
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0),
|
||||||
|
child: Center(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
icon,
|
||||||
|
size: 48,
|
||||||
|
color: disable
|
||||||
|
? theme.disabledColor
|
||||||
|
: theme.colorScheme.primary,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: theme.textTheme.titleLarge?.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: disable
|
||||||
|
? theme.disabledColor
|
||||||
|
: theme.colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
244
lib/features/account_opening/screens/fd_screen.dart
Normal file
244
lib/features/account_opening/screens/fd_screen.dart
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/features/account_opening/screens/interest_rates_screen.dart';
|
||||||
|
|
||||||
|
class FdScreen extends StatefulWidget {
|
||||||
|
const FdScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FdScreen> createState() => _FdScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FdScreenState extends State<FdScreen> {
|
||||||
|
final TextEditingController _debitAccountController = TextEditingController();
|
||||||
|
final TextEditingController _amountController = TextEditingController();
|
||||||
|
final TextEditingController _yearsController = TextEditingController();
|
||||||
|
final TextEditingController _monthsController = TextEditingController();
|
||||||
|
final TextEditingController _daysController = TextEditingController();
|
||||||
|
|
||||||
|
String _rateOfInterest = "N/A";
|
||||||
|
String _maturityDate = "N/A";
|
||||||
|
String _maturityAmount = "N/A";
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_debitAccountController.dispose();
|
||||||
|
_amountController.dispose();
|
||||||
|
_yearsController.dispose();
|
||||||
|
_monthsController.dispose();
|
||||||
|
_daysController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Fixed Deposit (FD)'),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Explanation Tile
|
||||||
|
Card(
|
||||||
|
margin: const EdgeInsets.only(bottom: 20),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Earn more on your savings with a simple, secure Fixed Deposit.',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Debit Account Number
|
||||||
|
TextFormField(
|
||||||
|
controller: _debitAccountController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Debit Account Number',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
// Enter Amount
|
||||||
|
TextFormField(
|
||||||
|
controller: _amountController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Enter Amount',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
prefixText: '₹ '
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
// Duration and Interest Rates Link
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Duration',
|
||||||
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const InterestRatesScreen()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'Interest Rates',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
|
// Duration TextBoxes
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _yearsController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Years',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _monthsController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Months',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _daysController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Days',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
// Rate of Interest and Maturity Date Display
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Rate of Interest',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
_rateOfInterest,
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Maturity Date',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
_maturityDate,
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
// Maturity Amount Display
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Maturity Amount',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
_maturityAmount,
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
|
||||||
|
// Proceed Button
|
||||||
|
Center(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Implement proceed logic
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 15),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Proceed',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class InterestRatesScreen extends StatelessWidget {
|
||||||
|
const InterestRatesScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Interest Rates'),
|
||||||
|
),
|
||||||
|
body: const Center(
|
||||||
|
child: Text('This page will display a table of interest rates.'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
lib/features/account_opening/screens/loan_screen.dart
Normal file
19
lib/features/account_opening/screens/loan_screen.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class LoanScreen extends StatelessWidget {
|
||||||
|
const LoanScreen({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text("Request Loan"),
|
||||||
|
),
|
||||||
|
body: const Center(
|
||||||
|
child: Text("Loan Account"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
lib/features/account_opening/screens/rd_screen.dart
Normal file
19
lib/features/account_opening/screens/rd_screen.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class RecurringDepositScreen extends StatelessWidget {
|
||||||
|
const RecurringDepositScreen({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text("Recurring Deposit"),
|
||||||
|
),
|
||||||
|
body: const Center(
|
||||||
|
child: Text("Recurring Deposit"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
lib/features/account_opening/screens/td_screen.dart
Normal file
19
lib/features/account_opening/screens/td_screen.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TermDepositScreen extends StatelessWidget {
|
||||||
|
const TermDepositScreen({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text("Term Deposit (TD)"),
|
||||||
|
),
|
||||||
|
body: const Center(
|
||||||
|
child: Text("Term Deposit (TD)"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -90,12 +90,12 @@ class CardTile extends StatelessWidget {
|
|||||||
const Text(
|
const Text(
|
||||||
"Kangra Central Co-operative Bank",
|
"Kangra Central Co-operative Bank",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Color.fromARGB(255, 238, 237, 237),
|
||||||
fontSize: 15.5,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.visible,
|
||||||
maxLines: 1,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class _CardManagementScreen extends State<CardManagementScreen> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
automaticallyImplyLeading: false,
|
|
||||||
title: Text(
|
title: Text(
|
||||||
AppLocalizations.of(context).cardManagement,
|
AppLocalizations.of(context).cardManagement,
|
||||||
),
|
),
|
||||||
@@ -61,7 +60,7 @@ class _CardManagementScreen extends State<CardManagementScreen> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
disabled: true,
|
disabled: false,
|
||||||
),
|
),
|
||||||
Divider(height: 1, color: Theme.of(context).dividerColor),
|
Divider(height: 1, color: Theme.of(context).dividerColor),
|
||||||
CardManagementTile(
|
CardManagementTile(
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
AppLocalizations.of(context).cardDetails,
|
AppLocalizations.of(context).changeCardPin,
|
||||||
),
|
),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
),
|
),
|
||||||
@@ -66,12 +66,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
isDense: true,
|
isDense: true,
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
enabledBorder: const OutlineInputBorder(
|
enabledBorder: const OutlineInputBorder(),
|
||||||
borderSide: BorderSide(color: Colors.black),
|
focusedBorder: const OutlineInputBorder(),
|
||||||
),
|
|
||||||
focusedBorder: const OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(color: Colors.black, width: 2),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
@@ -92,13 +88,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
filled: true,
|
filled: true,
|
||||||
fillColor:
|
fillColor:
|
||||||
Theme.of(context).scaffoldBackgroundColor,
|
Theme.of(context).scaffoldBackgroundColor,
|
||||||
enabledBorder: const OutlineInputBorder(
|
enabledBorder: const OutlineInputBorder(),
|
||||||
borderSide: BorderSide(color: Colors.black),
|
focusedBorder: const OutlineInputBorder(),
|
||||||
),
|
|
||||||
focusedBorder: const OutlineInputBorder(
|
|
||||||
borderSide:
|
|
||||||
BorderSide(color: Colors.black, width: 2),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
@@ -123,13 +114,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
filled: true,
|
filled: true,
|
||||||
fillColor:
|
fillColor:
|
||||||
Theme.of(context).scaffoldBackgroundColor,
|
Theme.of(context).scaffoldBackgroundColor,
|
||||||
enabledBorder: const OutlineInputBorder(
|
enabledBorder: const OutlineInputBorder(),
|
||||||
borderSide: BorderSide(color: Colors.black),
|
focusedBorder: const OutlineInputBorder(),
|
||||||
),
|
|
||||||
focusedBorder: const OutlineInputBorder(
|
|
||||||
borderSide:
|
|
||||||
BorderSide(color: Colors.black, width: 2),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
validator: (value) => value != null &&
|
validator: (value) => value != null &&
|
||||||
value.isNotEmpty
|
value.isNotEmpty
|
||||||
@@ -149,12 +135,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
|||||||
isDense: true,
|
isDense: true,
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
enabledBorder: const OutlineInputBorder(
|
enabledBorder: const OutlineInputBorder(),
|
||||||
borderSide: BorderSide(color: Colors.black),
|
focusedBorder: const OutlineInputBorder(),
|
||||||
),
|
|
||||||
focusedBorder: const OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(color: Colors.black, width: 2),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
keyboardType: TextInputType.phone,
|
keyboardType: TextInputType.phone,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:kmobile/data/models/user.dart';
|
import 'package:kmobile/data/models/user.dart';
|
||||||
import 'package:kmobile/features/cheque/screens/cheque_enquiry_screen.dart';
|
import 'package:kmobile/features/cheque/screens/cheque_enquiry_screen.dart';
|
||||||
|
import 'package:kmobile/features/cheque/screens/positive_pay_screen.dart';
|
||||||
|
import 'package:kmobile/features/cheque/screens/revoke_stop_screen.dart';
|
||||||
import 'package:kmobile/features/cheque/screens/stop_cheque_screen.dart';
|
import 'package:kmobile/features/cheque/screens/stop_cheque_screen.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import '../../../l10n/app_localizations.dart';
|
import '../../../l10n/app_localizations.dart';
|
||||||
@@ -42,8 +44,6 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
|||||||
child: ChequeManagementCardTile(
|
child: ChequeManagementCardTile(
|
||||||
icon: Symbols.payments,
|
icon: Symbols.payments,
|
||||||
label: AppLocalizations.of(context).chequeEnquiryTitle,
|
label: AppLocalizations.of(context).chequeEnquiryTitle,
|
||||||
subtitle:
|
|
||||||
AppLocalizations.of(context).chequeEnquirySubtitle,
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -61,7 +61,6 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
|||||||
child: ChequeManagementCardTile(
|
child: ChequeManagementCardTile(
|
||||||
icon: Symbols.block_sharp,
|
icon: Symbols.block_sharp,
|
||||||
label: AppLocalizations.of(context).stopCheque,
|
label: AppLocalizations.of(context).stopCheque,
|
||||||
subtitle: AppLocalizations.of(context).stopChequeSubtitle,
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -75,6 +74,40 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ChequeManagementCardTile(
|
||||||
|
icon: Symbols.stop_circle,
|
||||||
|
label: AppLocalizations.of(context).revokeStop,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => RevokeStopChequeScreen(
|
||||||
|
users: users,
|
||||||
|
selectedIndex: selectedAccountIndex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ChequeManagementCardTile(
|
||||||
|
icon: Symbols.check_circle, // Using check_circle for Positive Pay
|
||||||
|
label: AppLocalizations.of(context).positivePayTitle,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => PositivePayScreen(
|
||||||
|
users: users,
|
||||||
|
selectedIndex: selectedAccountIndex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -101,7 +134,6 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
|||||||
class ChequeManagementCardTile extends StatelessWidget {
|
class ChequeManagementCardTile extends StatelessWidget {
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String label;
|
final String label;
|
||||||
final String? subtitle;
|
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final bool disable;
|
final bool disable;
|
||||||
|
|
||||||
@@ -109,7 +141,6 @@ class ChequeManagementCardTile extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.label,
|
required this.label,
|
||||||
this.subtitle,
|
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.disable = false,
|
this.disable = false,
|
||||||
});
|
});
|
||||||
@@ -152,19 +183,6 @@ class ChequeManagementCardTile extends StatelessWidget {
|
|||||||
: theme.colorScheme.onSurface,
|
: theme.colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (subtitle != null)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: Text(
|
|
||||||
subtitle!,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: theme.textTheme.bodyMedium?.copyWith(
|
|
||||||
color: disable
|
|
||||||
? theme.disabledColor
|
|
||||||
: theme.colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
334
lib/features/cheque/screens/positive_pay_screen.dart
Normal file
334
lib/features/cheque/screens/positive_pay_screen.dart
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/api/services/cheque_service.dart';
|
||||||
|
import 'package:kmobile/data/models/user.dart';
|
||||||
|
import 'package:kmobile/di/injection.dart';
|
||||||
|
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class PositivePayScreen extends StatefulWidget {
|
||||||
|
final List<User> users;
|
||||||
|
final int selectedIndex;
|
||||||
|
const PositivePayScreen({
|
||||||
|
super.key,
|
||||||
|
required this.users,
|
||||||
|
required this.selectedIndex,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PositivePayScreen> createState() => _PositivePayScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PositivePayScreenState extends State<PositivePayScreen> {
|
||||||
|
User? _selectedAccount;
|
||||||
|
List<User> _filteredUsers = [];
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
final _chequeNumberController = TextEditingController();
|
||||||
|
final _chequeDateController = TextEditingController();
|
||||||
|
final _amountController = TextEditingController();
|
||||||
|
final _payeeController = TextEditingController();
|
||||||
|
final _chequeService = getIt<ChequeService>();
|
||||||
|
String? _ciFromCheque;
|
||||||
|
String? _ciToCheque;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_filteredUsers = widget.users
|
||||||
|
.where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
|
||||||
|
.toList();
|
||||||
|
// Pre-fill the account number if possible
|
||||||
|
if (widget.users.isNotEmpty && widget.selectedIndex < widget.users.length) {
|
||||||
|
if (_filteredUsers.isNotEmpty) {
|
||||||
|
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
||||||
|
_selectedAccount = widget.users[widget.selectedIndex];
|
||||||
|
} else {
|
||||||
|
_selectedAccount = _filteredUsers.first;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_selectedAccount = widget.users[widget.selectedIndex];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_filteredUsers.isNotEmpty) {
|
||||||
|
_selectedAccount = _filteredUsers.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_loadChequeDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadChequeDetails() async {
|
||||||
|
if (_selectedAccount == null) return;
|
||||||
|
|
||||||
|
String instrType;
|
||||||
|
switch (_selectedAccount!.accountType) {
|
||||||
|
case 'SA':
|
||||||
|
case 'SB':
|
||||||
|
instrType = '10';
|
||||||
|
break;
|
||||||
|
case 'CA':
|
||||||
|
instrType = '11';
|
||||||
|
break;
|
||||||
|
case 'CC':
|
||||||
|
instrType = '13';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
instrType = '10';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final data = await _chequeService.ChequeEnquiry(
|
||||||
|
accountNumber: _selectedAccount!.accountNo!,
|
||||||
|
instrType: instrType,
|
||||||
|
);
|
||||||
|
final ciCheque = data.where((cheque) => cheque.type == 'CI').toList();
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
if (ciCheque.isNotEmpty) {
|
||||||
|
_ciFromCheque = ciCheque.first.fromCheque;
|
||||||
|
_ciToCheque = ciCheque.first.toCheque;
|
||||||
|
} else {
|
||||||
|
_ciFromCheque = null;
|
||||||
|
_ciToCheque = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_ciFromCheque = null;
|
||||||
|
_ciToCheque = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_chequeNumberController.dispose();
|
||||||
|
_chequeDateController.dispose();
|
||||||
|
_amountController.dispose();
|
||||||
|
_payeeController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _showResponseDialog(String title, String message) async {
|
||||||
|
return showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false, // user must tap button!
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(title),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: ListBody(
|
||||||
|
children: <Widget>[
|
||||||
|
Text(message),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text(AppLocalizations.of(context).closeButton),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(
|
||||||
|
AppLocalizations.of(context).positivePay, // Will be replaced by localization
|
||||||
|
),
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
DropdownButtonFormField<User>(
|
||||||
|
value: _selectedAccount,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).accountNumber,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
items: _filteredUsers.map((user) {
|
||||||
|
return DropdownMenuItem<User>(
|
||||||
|
value: user,
|
||||||
|
child: Text(user.accountNo.toString()),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (User? newUser) {
|
||||||
|
setState(() {
|
||||||
|
_selectedAccount = newUser;
|
||||||
|
_loadChequeDetails();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) {
|
||||||
|
return AppLocalizations.of(context).accountNumberRequired;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
TextFormField(
|
||||||
|
controller: _chequeNumberController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).chequeNumberLabel,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
errorMaxLines: 2,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return AppLocalizations.of(context).pleaseEnterChequeNumber;
|
||||||
|
}
|
||||||
|
final chequeNumber = int.tryParse(value);
|
||||||
|
final fromCheque = int.tryParse(_ciFromCheque ?? '');
|
||||||
|
final toCheque = int.tryParse(_ciToCheque ?? '');
|
||||||
|
if (chequeNumber == null) {
|
||||||
|
return AppLocalizations.of(context).invalidChequeNumberFormatError;
|
||||||
|
}
|
||||||
|
if (fromCheque != null && toCheque != null) {
|
||||||
|
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
|
||||||
|
return AppLocalizations.of(context).chequeNumberRangeError(
|
||||||
|
_ciFromCheque!, _ciToCheque!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
TextFormField(
|
||||||
|
controller: _chequeDateController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).chequeIssuedDate,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
suffixIcon: const Icon(Icons.calendar_today),
|
||||||
|
),
|
||||||
|
readOnly: true,
|
||||||
|
onTap: () async {
|
||||||
|
DateTime? pickedDate = await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: DateTime.now(),
|
||||||
|
firstDate: DateTime(2000),
|
||||||
|
lastDate: DateTime.now(),
|
||||||
|
);
|
||||||
|
if (pickedDate != null) {
|
||||||
|
// Format the date as you wish
|
||||||
|
String formattedDate = "${pickedDate.year}-${pickedDate.month.toString().padLeft(2, '0')}-${pickedDate.day.toString().padLeft(2, '0')}";
|
||||||
|
_chequeDateController.text = formattedDate;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return AppLocalizations.of(context).pleaseSelectChequeIssuedDate;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
TextFormField(
|
||||||
|
controller: _payeeController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).payeeName,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
TextFormField(
|
||||||
|
controller: _amountController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).amountLabel,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
prefixText: '₹ ',
|
||||||
|
),
|
||||||
|
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return AppLocalizations.of(context).pleaseEnterAmount;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32.0),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
// Process data
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => TransactionPinScreen(
|
||||||
|
onPinCompleted: (ctx, pin) async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
try {
|
||||||
|
final response = await _chequeService.registerPPS(
|
||||||
|
cheque_no: _chequeNumberController.text,
|
||||||
|
account_number:
|
||||||
|
_selectedAccount!.accountNo!,
|
||||||
|
issue_date:
|
||||||
|
_chequeDateController.text,
|
||||||
|
amount: _amountController.text,
|
||||||
|
payee_name: _payeeController.text,
|
||||||
|
tpin: pin,
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
String responseString = response.toString();
|
||||||
|
if(responseString == 'PPS Registered Successfully'){
|
||||||
|
_showResponseDialog('REGISTRATION SUCCESFUL',
|
||||||
|
'Your Positive Pay Request has been registered succesfully');
|
||||||
|
}
|
||||||
|
if(responseString.contains('Cheque already registered')){
|
||||||
|
_showResponseDialog('ERROR',
|
||||||
|
'Your Request for the selected cheque number has already been registered');
|
||||||
|
}
|
||||||
|
if(responseString.contains('INCORRECT_TPIN')){
|
||||||
|
_showResponseDialog('Invalid TPIN',
|
||||||
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
try {
|
||||||
|
final errorBodyString =
|
||||||
|
e.toString().split('Exception: ')[1];
|
||||||
|
final errorBody = jsonDecode(errorBodyString);
|
||||||
|
if (errorBody.containsKey('error') &&
|
||||||
|
errorBody['error'] == 'INCORRECT_TPIN') {
|
||||||
|
_showResponseDialog('Invalid TPIN',
|
||||||
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
} else {
|
||||||
|
_showResponseDialog(
|
||||||
|
'Error', 'Internal Server Error');
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
_showResponseDialog(
|
||||||
|
'Error', 'Internal Server Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(AppLocalizations.of(context).proceedButton),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
338
lib/features/cheque/screens/revoke _stop_multiple_screen.dart
Normal file
338
lib/features/cheque/screens/revoke _stop_multiple_screen.dart
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/api/services/cheque_service.dart';
|
||||||
|
import 'package:kmobile/data/models/user.dart';
|
||||||
|
import 'package:kmobile/di/injection.dart';
|
||||||
|
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class RevokeStopMultipleChequesScreen extends StatefulWidget {
|
||||||
|
final User selectedAccount;
|
||||||
|
final String date;
|
||||||
|
final String instrType;
|
||||||
|
final String fromCheque;
|
||||||
|
final String toCheque;
|
||||||
|
|
||||||
|
const RevokeStopMultipleChequesScreen(
|
||||||
|
{super.key,
|
||||||
|
required this.selectedAccount,
|
||||||
|
required this.date,
|
||||||
|
required this.instrType,
|
||||||
|
required this.fromCheque,
|
||||||
|
required this.toCheque});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RevokeStopMultipleChequesScreen> createState() =>
|
||||||
|
_RevokeStopMultipleChequesScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RevokeStopMultipleChequesScreenState extends State<RevokeStopMultipleChequesScreen> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
final _stopFromChequeNoController = TextEditingController();
|
||||||
|
final _stopToChequeNoController = TextEditingController();
|
||||||
|
final _stopIssueDateController = TextEditingController();
|
||||||
|
final _stopExpiryDateController = TextEditingController();
|
||||||
|
final _stopAmountController = TextEditingController();
|
||||||
|
final _chequeService = getIt<ChequeService>();
|
||||||
|
|
||||||
|
String? _selectedComment;
|
||||||
|
final _otherCommentController = TextEditingController();
|
||||||
|
bool _showOtherCommentField = false;
|
||||||
|
final List<String> _commentOptions = [
|
||||||
|
'Cheque Found',
|
||||||
|
'Cheque Fixed',
|
||||||
|
'Other'
|
||||||
|
];
|
||||||
|
|
||||||
|
Future<void> _selectDate(TextEditingController controller) async {
|
||||||
|
final DateTime? picked = await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: DateTime.now(),
|
||||||
|
firstDate: DateTime.now(),
|
||||||
|
lastDate: DateTime(2101),
|
||||||
|
);
|
||||||
|
if (picked != null) {
|
||||||
|
setState(() {
|
||||||
|
controller.text =
|
||||||
|
'${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _showResponseDialog(String title, String message) async {
|
||||||
|
return showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false, // user must tap button!
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(title),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: ListBody(
|
||||||
|
children: <Widget>[
|
||||||
|
Text(message),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: const Text('Close'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(AppLocalizations.of(context).revokeMultipleStops),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
elevation: 0,
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: ListTile(
|
||||||
|
leading: Image.asset(
|
||||||
|
'assets/images/logo.png',
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
title: Text(widget.selectedAccount.accountNo!),
|
||||||
|
subtitle:
|
||||||
|
Text(AppLocalizations.of(context).accountNumberTitle),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopFromChequeNoController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).fromChequeNumberHint,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
errorMaxLines: 2,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return AppLocalizations.of(context)
|
||||||
|
.pleaseEnterChequeNumberError;
|
||||||
|
}
|
||||||
|
final chequeNumber = int.tryParse(value);
|
||||||
|
final fromCheque = int.tryParse(widget.fromCheque);
|
||||||
|
final toCheque = int.tryParse(widget.toCheque);
|
||||||
|
if (chequeNumber == null ||
|
||||||
|
fromCheque == null ||
|
||||||
|
toCheque == null) {
|
||||||
|
return AppLocalizations.of(context)
|
||||||
|
.invalidChequeNumberFormatError;
|
||||||
|
}
|
||||||
|
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
|
||||||
|
return AppLocalizations.of(context).chequeNumberRangeError(
|
||||||
|
widget.fromCheque, widget.toCheque);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopToChequeNoController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).toChequeNumberHint,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
errorMaxLines: 2,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return AppLocalizations.of(context)
|
||||||
|
.pleaseEnterChequeNumberError;
|
||||||
|
}
|
||||||
|
final chequeNumber = int.tryParse(value);
|
||||||
|
final fromCheque = int.tryParse(widget.fromCheque);
|
||||||
|
final toCheque = int.tryParse(widget.toCheque);
|
||||||
|
if (chequeNumber == null ||
|
||||||
|
fromCheque == null ||
|
||||||
|
toCheque == null) {
|
||||||
|
return AppLocalizations.of(context)
|
||||||
|
.invalidChequeNumberFormatError;
|
||||||
|
}
|
||||||
|
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
|
||||||
|
return AppLocalizations.of(context).chequeNumberRangeError(
|
||||||
|
widget.fromCheque, widget.toCheque);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
initialValue: widget.instrType,
|
||||||
|
readOnly: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).instrumentTypeLabel,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopIssueDateController,
|
||||||
|
readOnly: true,
|
||||||
|
onTap: () => _selectDate(_stopIssueDateController),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).revokeIssueDate,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: const Icon(Icons.calendar_today),
|
||||||
|
onPressed: () => _selectDate(_stopIssueDateController),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.datetime,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopExpiryDateController,
|
||||||
|
readOnly: true,
|
||||||
|
onTap: () => _selectDate(_stopExpiryDateController),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).revokeExpiryDate,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: const Icon(Icons.calendar_today),
|
||||||
|
onPressed: () => _selectDate(_stopExpiryDateController),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.datetime,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopAmountController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).revokeAmount,
|
||||||
|
prefixText: '₹ ',
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
DropdownButtonFormField<String>(
|
||||||
|
value: _selectedComment,
|
||||||
|
items: _commentOptions.map((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (newValue) {
|
||||||
|
setState(() {
|
||||||
|
_selectedComment = newValue;
|
||||||
|
_showOtherCommentField = newValue == 'Other';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).revokeComment,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_showOtherCommentField)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 16.0),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _otherCommentController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: "Other Reasons :",
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => TransactionPinScreen(
|
||||||
|
onPinCompleted: (ctx, pin) async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
try {
|
||||||
|
final response = await _chequeService.revokeStop(
|
||||||
|
accountno: widget.selectedAccount.accountNo!,
|
||||||
|
removeFromChequeNo:
|
||||||
|
_stopFromChequeNoController.text,
|
||||||
|
instrType: widget.instrType,
|
||||||
|
removeToChequeNo:
|
||||||
|
_stopToChequeNoController.text,
|
||||||
|
removeIssueDate: _stopIssueDateController.text,
|
||||||
|
removeExpiryDate: _stopExpiryDateController.text,
|
||||||
|
removeAmount: _stopAmountController.text,
|
||||||
|
removeComment: _selectedComment == 'Other'
|
||||||
|
? _otherCommentController.text
|
||||||
|
: _selectedComment ?? '',
|
||||||
|
tpin: pin,
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
final decodedResponse = jsonDecode(response);
|
||||||
|
String responseString = response.toString(); // used as the case only for incorrect TPIN
|
||||||
|
final status = decodedResponse['status'];
|
||||||
|
final message = decodedResponse['message'];
|
||||||
|
final code = decodedResponse['code'];
|
||||||
|
if (status == 'SUCCESS') {
|
||||||
|
_showResponseDialog('Success', message);
|
||||||
|
} if (status == 'ERROR') {
|
||||||
|
String errMessage = "error";
|
||||||
|
if(code == '0172') {
|
||||||
|
errMessage = 'The selected Cheque is not stopped';
|
||||||
|
} else if(code == '0748') {
|
||||||
|
errMessage = 'The selected Cheque is already presented';
|
||||||
|
}
|
||||||
|
_showResponseDialog('Error', errMessage);
|
||||||
|
}
|
||||||
|
if(responseString.contains('INCORRECT_TPIN')){
|
||||||
|
_showResponseDialog('Invalid TPIN',
|
||||||
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
}
|
||||||
|
} on Exception catch (e) {
|
||||||
|
try {
|
||||||
|
final errorBodyString =
|
||||||
|
e.toString().split('Exception: ')[1];
|
||||||
|
final errorBody = jsonDecode(errorBodyString);
|
||||||
|
if (errorBody.containsKey('error') &&
|
||||||
|
errorBody['error'] == 'INCORRECT_TPIN') {
|
||||||
|
_showResponseDialog('Invalid TPIN',
|
||||||
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
} else {
|
||||||
|
_showResponseDialog(
|
||||||
|
'Error', 'Internal Server Error');
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
_showResponseDialog(
|
||||||
|
'Error', 'Internal Server Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(AppLocalizations.of(context).revokeStopButton),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,351 +1,361 @@
|
|||||||
// import 'package:kmobile/data/models/user.dart';
|
import 'package:kmobile/data/models/user.dart';
|
||||||
// import 'package:kmobile/di/injection.dart';
|
import 'package:kmobile/di/injection.dart';
|
||||||
// import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
// import 'package:kmobile/api/services/cheque_service.dart';
|
import 'package:kmobile/api/services/cheque_service.dart';
|
||||||
// // import 'package:kmobile/features/cheque/screens/revoke_stop_multiple_screen.dart';
|
import 'package:kmobile/features/cheque/screens/revoke%20_stop_multiple_screen.dart';
|
||||||
// // import 'package:kmobile/features/cheque/screens/revoke_stop_single_screen.dart';
|
import 'package:kmobile/features/cheque/screens/revoke_stop_single_screen.dart';
|
||||||
// import 'package:kmobile/l10n/app_localizations.dart';
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
// class RevokeStopChequeScreen extends StatefulWidget {
|
class RevokeStopChequeScreen extends StatefulWidget {
|
||||||
// final List<User> users;
|
final List<User> users;
|
||||||
// final int selectedIndex;
|
final int selectedIndex;
|
||||||
|
|
||||||
// const RevokeStopChequeScreen(
|
const RevokeStopChequeScreen(
|
||||||
// {
|
{
|
||||||
// super.key,
|
super.key,
|
||||||
// required this.users,
|
required this.users,
|
||||||
// required this.selectedIndex,
|
required this.selectedIndex,
|
||||||
// });
|
});
|
||||||
|
|
||||||
// @override
|
@override
|
||||||
// State<RevokeStopChequeScreen> createState() => _RevokeStopChequeScreenState();
|
State<RevokeStopChequeScreen> createState() => _RevokeStopChequeScreenState();
|
||||||
// }
|
}
|
||||||
|
|
||||||
// class _RevokeStopChequeScreenState extends State<RevokeStopChequeScreen> {
|
class _RevokeStopChequeScreenState extends State<RevokeStopChequeScreen> {
|
||||||
// User? _selectedAccount;
|
User? _selectedAccount;
|
||||||
// var service = getIt<ChequeService>();
|
var service = getIt<ChequeService>();
|
||||||
// bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
// List<Cheque> _stCheques = [];
|
List<Cheque> _stCheques = [];
|
||||||
// List<User> _filteredUsers = [];
|
List<User> _filteredUsers = [];
|
||||||
|
String? _ciFromCheque;
|
||||||
|
String? _ciToCheque;
|
||||||
|
|
||||||
// @override
|
@override
|
||||||
// void initState() {
|
void initState() {
|
||||||
// super.initState();
|
super.initState();
|
||||||
// _filteredUsers = widget.users
|
_filteredUsers = widget.users
|
||||||
// .where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
|
.where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
|
||||||
// .toList();
|
.toList();
|
||||||
|
|
||||||
// if (widget.users.isNotEmpty && widget.selectedIndex < widget.users.length) {
|
if (widget.users.isNotEmpty && widget.selectedIndex < widget.users.length) {
|
||||||
// if (_filteredUsers.isNotEmpty) {
|
if (_filteredUsers.isNotEmpty) {
|
||||||
// if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
||||||
// _selectedAccount = widget.users[widget.selectedIndex];
|
_selectedAccount = widget.users[widget.selectedIndex];
|
||||||
// } else {
|
} else {
|
||||||
// _selectedAccount = _filteredUsers.first;
|
_selectedAccount = _filteredUsers.first;
|
||||||
// }
|
}
|
||||||
// } else {
|
} else {
|
||||||
// _selectedAccount = widget.users[widget.selectedIndex];
|
_selectedAccount = widget.users[widget.selectedIndex];
|
||||||
// }
|
}
|
||||||
// } else {
|
} else {
|
||||||
// if (_filteredUsers.isNotEmpty) {
|
if (_filteredUsers.isNotEmpty) {
|
||||||
// _selectedAccount = _filteredUsers.first;
|
_selectedAccount = _filteredUsers.first;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// _loadCheques();
|
_loadCheques();
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Future<void> _loadCheques() async {
|
Future<void> _loadCheques() async {
|
||||||
// if (_selectedAccount == null) {
|
if (_selectedAccount == null) {
|
||||||
// setState(() {
|
setState(() {
|
||||||
// _isLoading = false;
|
_isLoading = false;
|
||||||
// _stCheques = [];
|
_stCheques = [];
|
||||||
// });
|
});
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// setState(() {
|
setState(() {
|
||||||
// _isLoading = true;
|
_isLoading = true;
|
||||||
// });
|
});
|
||||||
|
|
||||||
// String instrType;
|
String instrType;
|
||||||
// switch (_selectedAccount!.accountType) {
|
switch (_selectedAccount!.accountType) {
|
||||||
// case 'SA':
|
case 'SA':
|
||||||
// case 'SB':
|
case 'SB':
|
||||||
// instrType = '10';
|
instrType = '10';
|
||||||
// break;
|
break;
|
||||||
// case 'CA':
|
case 'CA':
|
||||||
// instrType = '11';
|
instrType = '11';
|
||||||
// break;
|
break;
|
||||||
// case 'CC':
|
case 'CC':
|
||||||
// instrType = '13';
|
instrType = '13';
|
||||||
// break;
|
break;
|
||||||
// default:
|
default:
|
||||||
// instrType = '10';
|
instrType = '10';
|
||||||
// }
|
}
|
||||||
|
|
||||||
// try {
|
try {
|
||||||
// final data = await service.ChequeEnquiry(
|
final data = await service.ChequeEnquiry(
|
||||||
// accountNumber: _selectedAccount!.accountNo!, instrType: instrType);
|
accountNumber: _selectedAccount!.accountNo!, instrType: instrType);
|
||||||
// final stCheques = data.where((cheque) => cheque.type == 'ST').toList();
|
final stCheques = data.where((cheque) => cheque.type == 'ST').toList();
|
||||||
// setState(() {
|
final ciCheque = data.where((cheque) => cheque.type == 'CI').toList();
|
||||||
// _stCheques = stCheques;
|
setState(() {
|
||||||
// _isLoading = false;
|
_stCheques = stCheques;
|
||||||
// });
|
if (ciCheque.isNotEmpty) {
|
||||||
// } catch (e) {
|
_ciFromCheque = ciCheque.first.fromCheque;
|
||||||
// setState(() {
|
_ciToCheque = ciCheque.first.toCheque;
|
||||||
// _isLoading = false;
|
} else {
|
||||||
// _stCheques = [];
|
_ciFromCheque = null;
|
||||||
// });
|
_ciToCheque = null;
|
||||||
// ScaffoldMessenger.of(context).showSnackBar(
|
}
|
||||||
// SnackBar(
|
_isLoading = false;
|
||||||
// content: Text('Failed to fetch cheque status: ${e.toString()}'),
|
});
|
||||||
// ),
|
} catch (e) {
|
||||||
// );
|
setState(() {
|
||||||
// }
|
_isLoading = false;
|
||||||
// }
|
_stCheques = [];
|
||||||
|
});
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Failed to fetch cheque status: ${e.toString()}'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// String _getAccountTypeDisplayName(String accountType) {
|
String _getAccountTypeDisplayName(String accountType) {
|
||||||
// switch (accountType.toLowerCase()) {
|
switch (accountType.toLowerCase()) {
|
||||||
// case 'sa':
|
case 'sa':
|
||||||
// return AppLocalizations.of(context).savingsAccount;
|
return AppLocalizations.of(context).savingsAccount;
|
||||||
// case 'sb':
|
case 'sb':
|
||||||
// return AppLocalizations.of(context).savingsAccount;
|
return AppLocalizations.of(context).savingsAccount;
|
||||||
// case 'ca':
|
case 'ca':
|
||||||
// return "Current Account";
|
return "Current Account";
|
||||||
// case 'cc':
|
case 'cc':
|
||||||
// return "Cash Credit Account";
|
return "Cash Credit Account";
|
||||||
// default:
|
default:
|
||||||
// return accountType;
|
return accountType;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// @override
|
@override
|
||||||
// Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// return Scaffold(
|
return Scaffold(
|
||||||
// appBar: AppBar(
|
appBar: AppBar(
|
||||||
// title: Text(AppLocalizations.of(context).revokeStop),
|
title: Text(AppLocalizations.of(context).revokeStop),
|
||||||
// centerTitle: false,
|
centerTitle: false,
|
||||||
// ),
|
),
|
||||||
// body: Stack(
|
body: Stack(
|
||||||
// children: [
|
children: [
|
||||||
// Padding(
|
Padding(
|
||||||
// padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
// child: Column(children: [
|
child: Column(children: [
|
||||||
// Card(
|
Card(
|
||||||
// elevation: 4,
|
elevation: 4,
|
||||||
// margin: const EdgeInsets.symmetric(vertical: 8.0),
|
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
// child: Padding(
|
child: Padding(
|
||||||
// padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
// child: Row(
|
child: Row(
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
// children: [
|
children: [
|
||||||
// Text(
|
Text(
|
||||||
// AppLocalizations.of(context).accountNumber,
|
AppLocalizations.of(context).accountNumber,
|
||||||
// style: const TextStyle(
|
style: const TextStyle(
|
||||||
// fontWeight: FontWeight.bold, fontSize: 18),
|
fontWeight: FontWeight.bold, fontSize: 18),
|
||||||
// ),
|
),
|
||||||
// const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
// if (_selectedAccount != null)
|
if (_selectedAccount != null)
|
||||||
// Expanded(
|
Expanded(
|
||||||
// child: DropdownButton<User>(
|
child: DropdownButton<User>(
|
||||||
// value: _selectedAccount,
|
value: _selectedAccount,
|
||||||
// onChanged: (User? newUser) {
|
onChanged: (User? newUser) {
|
||||||
// if (newUser != null) {
|
if (newUser != null) {
|
||||||
// setState(() {
|
setState(() {
|
||||||
// _selectedAccount = newUser;
|
_selectedAccount = newUser;
|
||||||
// _loadCheques();
|
_loadCheques();
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
// },
|
},
|
||||||
// items: _filteredUsers.map((user) {
|
items: _filteredUsers.map((user) {
|
||||||
// return DropdownMenuItem<User>(
|
return DropdownMenuItem<User>(
|
||||||
// value: user,
|
value: user,
|
||||||
// child: Text(user.accountNo.toString()),
|
child: Text(user.accountNo.toString()),
|
||||||
// );
|
);
|
||||||
// }).toList(),
|
}).toList(),
|
||||||
// ),
|
),
|
||||||
// )
|
)
|
||||||
// else
|
else
|
||||||
// Text(AppLocalizations.of(context).noAccountsFound),
|
Text(AppLocalizations.of(context).noAccountsFound),
|
||||||
// ],
|
],
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
// Row(
|
Row(
|
||||||
// children: [
|
children: [
|
||||||
// Expanded(
|
Expanded(
|
||||||
// child: Card(
|
child: Card(
|
||||||
// color: Theme.of(context).colorScheme.primaryContainer,
|
color: Theme.of(context).colorScheme.primaryContainer,
|
||||||
// elevation: 4,
|
elevation: 4,
|
||||||
// child: InkWell(
|
child: InkWell(
|
||||||
// onTap: () {
|
onTap: () {
|
||||||
// if (_selectedAccount != null &&
|
if (_selectedAccount != null &&
|
||||||
// _stCheques.isNotEmpty) {
|
_stCheques.isNotEmpty) {
|
||||||
// Navigator.push(
|
Navigator.push(
|
||||||
// context,
|
context,
|
||||||
// MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
// builder: (context) =>
|
builder: (context) =>
|
||||||
// RevokeStopSingleChequeScreen(
|
RevokeStopSingleChequeScreen(
|
||||||
// selectedAccount: _selectedAccount!,
|
selectedAccount: _selectedAccount!,
|
||||||
// date: _stCheques.first.Date!,
|
date: _stCheques.first.Date!,
|
||||||
// instrType: _stCheques.first.InstrType!,
|
instrType: _stCheques.first.InstrType!,
|
||||||
// fromCheque: _stCheques.first.fromCheque!,
|
fromCheque: _ciFromCheque ?? _stCheques.first.fromCheque!,
|
||||||
// toCheque: _stCheques.first.toCheque!,
|
toCheque: _ciToCheque ?? _stCheques.first.toCheque!,
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// );
|
);
|
||||||
// } else {
|
} else {
|
||||||
// ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
// const SnackBar(
|
const SnackBar(
|
||||||
// content: Text("No stopped cheques present"),
|
content: Text("No stopped cheques present"),
|
||||||
// ),
|
),
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
// },
|
},
|
||||||
// child: Padding(
|
child: Padding(
|
||||||
// padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
// child: Center(
|
child: Center(
|
||||||
// child: Text(
|
child: Text(
|
||||||
// AppLocalizations.of(context).revokeSingleStopTitle,
|
AppLocalizations.of(context).revokeSingleStopTitle,
|
||||||
// textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
// style: TextStyle(
|
style: TextStyle(
|
||||||
// fontSize: 16,
|
fontSize: 16,
|
||||||
// fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
// color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
// .colorScheme
|
.colorScheme
|
||||||
// .onPrimaryContainer,
|
.onPrimaryContainer,
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
// Expanded(
|
Expanded(
|
||||||
// child: Card(
|
child: Card(
|
||||||
// color: Theme.of(context).colorScheme.primaryContainer,
|
color: Theme.of(context).colorScheme.primaryContainer,
|
||||||
// elevation: 4,
|
elevation: 4,
|
||||||
// child: InkWell(
|
child: InkWell(
|
||||||
// onTap: () {
|
onTap: () {
|
||||||
// if (_selectedAccount != null &&
|
if (_selectedAccount != null &&
|
||||||
// _stCheques.isNotEmpty) {
|
_stCheques.isNotEmpty) {
|
||||||
// Navigator.push(
|
Navigator.push(
|
||||||
// context,
|
context,
|
||||||
// MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
// builder: (context) =>
|
builder: (context) =>
|
||||||
// RevokeStopMultipleChequesScreen(
|
RevokeStopMultipleChequesScreen(
|
||||||
// selectedAccount: _selectedAccount!,
|
selectedAccount: _selectedAccount!,
|
||||||
// date: _stCheques.first.Date!,
|
date: _stCheques.first.Date!,
|
||||||
// instrType: _stCheques.first.InstrType!,
|
instrType: _stCheques.first.InstrType!,
|
||||||
// fromCheque: _stCheques.first.fromCheque!,
|
fromCheque: _ciFromCheque ?? _stCheques.first.fromCheque!,
|
||||||
// toCheque: _stCheques.first.toCheque!,
|
toCheque: _ciToCheque ?? _stCheques.first.toCheque!,
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// );
|
);
|
||||||
// } else {
|
} else {
|
||||||
// ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
// SnackBar(
|
SnackBar(
|
||||||
// content: Text(AppLocalizations.of(context)
|
content: Text(AppLocalizations.of(context)
|
||||||
// .pleaseSelectAccountFirst),
|
.pleaseSelectAccountFirst),
|
||||||
// ),
|
),
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
// },
|
},
|
||||||
// child: Padding(
|
child: Padding(
|
||||||
// padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
// child: Center(
|
child: Center(
|
||||||
// child: Text(
|
child: Text(
|
||||||
// AppLocalizations.of(context).revokeMultipleStops,
|
AppLocalizations.of(context).revokeMultipleStops,
|
||||||
// textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
// style: TextStyle(
|
style: TextStyle(
|
||||||
// fontSize: 16,
|
fontSize: 16,
|
||||||
// fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
// color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
// .colorScheme
|
.colorScheme
|
||||||
// .onSecondaryContainer,
|
.onSecondaryContainer,
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ],
|
],
|
||||||
// ),
|
),
|
||||||
// const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
// Expanded(
|
Expanded(
|
||||||
// child: _isLoading
|
child: _isLoading
|
||||||
// ? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
// : _stCheques.isEmpty
|
: _stCheques.isEmpty
|
||||||
// ? Center(
|
? Center(
|
||||||
// child: Text(AppLocalizations.of(context)
|
child: Text(AppLocalizations.of(context)
|
||||||
// .noChequeIssuedStatus))
|
.noChequeIssuedStatus))
|
||||||
// : ListView.builder(
|
: ListView.builder(
|
||||||
// itemCount: _stCheques.length,
|
itemCount: _stCheques.length,
|
||||||
// itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
// return _buildSTTile(context, _stCheques[index]);
|
return _buildSTTile(context, _stCheques[index]);
|
||||||
// },
|
},
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ]),
|
]),
|
||||||
// ),
|
),
|
||||||
// IgnorePointer(
|
IgnorePointer(
|
||||||
// child: Center(
|
child: Center(
|
||||||
// child: Opacity(
|
child: Opacity(
|
||||||
// opacity: 0.07, // Reduced opacity
|
opacity: 0.07, // Reduced opacity
|
||||||
// child: ClipOval(
|
child: ClipOval(
|
||||||
// child: Image.asset(
|
child: Image.asset(
|
||||||
// 'assets/images/logo.png',
|
'assets/images/logo.png',
|
||||||
// width: 200, // Adjust size as needed
|
width: 200, // Adjust size as needed
|
||||||
// height: 200, // Adjust size as needed
|
height: 200, // Adjust size as needed
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// ],
|
],
|
||||||
// ),
|
),
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Widget _buildSTTile(BuildContext context, Cheque cheque) {
|
Widget _buildSTTile(BuildContext context, Cheque cheque) {
|
||||||
// return Card(
|
return Card(
|
||||||
// margin: const EdgeInsets.symmetric(
|
margin: const EdgeInsets.symmetric(
|
||||||
// vertical: 8.0,
|
vertical: 8.0,
|
||||||
// ),
|
),
|
||||||
// child: Padding(
|
child: Padding(
|
||||||
// padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
// child: Column(
|
child: Column(
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
// children: [
|
children: [
|
||||||
// Text(AppLocalizations.of(context).stopChequeLabel,
|
Text(AppLocalizations.of(context).stopChequeLabel,
|
||||||
// style: Theme.of(context).textTheme.titleLarge),
|
style: Theme.of(context).textTheme.titleLarge),
|
||||||
// const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
// _buildInfoRow('From Cheque:', cheque.fromCheque),
|
_buildInfoRow('From Cheque:', cheque.fromCheque),
|
||||||
// _buildInfoRow('To Cheque:', cheque.toCheque),
|
_buildInfoRow('To Cheque:', cheque.toCheque),
|
||||||
// _buildInfoRow('Account Type:',
|
_buildInfoRow('Account Type:',
|
||||||
// _getAccountTypeDisplayName(_selectedAccount!.accountType!)),
|
_getAccountTypeDisplayName(_selectedAccount!.accountType!)),
|
||||||
// _buildInfoRow('Branch Code:', cheque.branchCode),
|
_buildInfoRow('Branch Code:', cheque.branchCode),
|
||||||
// _buildInfoRow('Stop Issue Date:', cheque.stopIssueDate),
|
_buildInfoRow('Stop Issue Date:', cheque.stopIssueDate),
|
||||||
// _buildInfoRow('Stop Expiry Date:', cheque.StopExpiryDate),
|
_buildInfoRow('Stop Expiry Date:', cheque.StopExpiryDate),
|
||||||
// _buildInfoRow('Cheques Count:', cheque.Chequescount),
|
_buildInfoRow('Cheques Count:', cheque.Chequescount),
|
||||||
// ],
|
],
|
||||||
// ),
|
),
|
||||||
// ),
|
),
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Widget _buildInfoRow(String label, String? value) {
|
Widget _buildInfoRow(String label, String? value) {
|
||||||
// return Padding(
|
return Padding(
|
||||||
// padding: const EdgeInsets.symmetric(vertical: 4.0),
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||||
// child: Row(
|
child: Row(
|
||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
// children: [
|
children: [
|
||||||
// Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||||
// Text(value ?? ''),
|
Text(value ?? ''),
|
||||||
// ],
|
],
|
||||||
// ),
|
),
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|||||||
304
lib/features/cheque/screens/revoke_stop_single_screen.dart
Normal file
304
lib/features/cheque/screens/revoke_stop_single_screen.dart
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:kmobile/data/models/user.dart';
|
||||||
|
import 'package:kmobile/di/injection.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/api/services/cheque_service.dart';
|
||||||
|
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class RevokeStopSingleChequeScreen extends StatefulWidget {
|
||||||
|
final User selectedAccount;
|
||||||
|
final String date;
|
||||||
|
final String instrType;
|
||||||
|
final String fromCheque;
|
||||||
|
final String toCheque;
|
||||||
|
|
||||||
|
const RevokeStopSingleChequeScreen(
|
||||||
|
{super.key,
|
||||||
|
required this.selectedAccount,
|
||||||
|
required this.date,
|
||||||
|
required this.instrType,
|
||||||
|
required this.fromCheque,
|
||||||
|
required this.toCheque});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RevokeStopSingleChequeScreen> createState() => _RevokeStopSingleChequeScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RevokeStopSingleChequeScreenState extends State<RevokeStopSingleChequeScreen> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
final _stopFromChequeNoController = TextEditingController();
|
||||||
|
final _stopIssueDateController = TextEditingController();
|
||||||
|
final _stopExpiryDateController = TextEditingController();
|
||||||
|
final _stopAmountController = TextEditingController();
|
||||||
|
final _chequeService = getIt<ChequeService>();
|
||||||
|
|
||||||
|
String? _selectedComment;
|
||||||
|
final _otherCommentController = TextEditingController();
|
||||||
|
bool _showOtherCommentField = false;
|
||||||
|
final List<String> _commentOptions = [
|
||||||
|
'Cheque Found',
|
||||||
|
'Cheque Fixed',
|
||||||
|
'Other'
|
||||||
|
];
|
||||||
|
|
||||||
|
Future<void> _selectDate(TextEditingController controller) async {
|
||||||
|
final DateTime? picked = await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: DateTime.now(),
|
||||||
|
firstDate: DateTime.now(),
|
||||||
|
lastDate: DateTime(2101),
|
||||||
|
);
|
||||||
|
if (picked != null) {
|
||||||
|
setState(() {
|
||||||
|
controller.text =
|
||||||
|
'${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _showResponseDialog(String title, String message) async {
|
||||||
|
return showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false, // user must tap button!
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(title),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: ListBody(
|
||||||
|
children: <Widget>[
|
||||||
|
Text(message),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text(AppLocalizations.of(context).closeButton),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(AppLocalizations.of(context).revokeSingleStopTitle)),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
elevation: 0,
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: ListTile(
|
||||||
|
leading: Image.asset(
|
||||||
|
'assets/images/logo.png',
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
title: Text(widget.selectedAccount.accountNo!),
|
||||||
|
subtitle:
|
||||||
|
Text(AppLocalizations.of(context).accountNumberLabel),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopFromChequeNoController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).chequeNumberLabel,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
errorMaxLines: 2,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return AppLocalizations.of(context)
|
||||||
|
.pleaseEnterChequeNumberError;
|
||||||
|
}
|
||||||
|
final chequeNumber = int.tryParse(value);
|
||||||
|
final fromCheque = int.tryParse(widget.fromCheque);
|
||||||
|
final toCheque = int.tryParse(widget.toCheque);
|
||||||
|
if (chequeNumber == null ||
|
||||||
|
fromCheque == null ||
|
||||||
|
toCheque == null) {
|
||||||
|
return AppLocalizations.of(context)
|
||||||
|
.invalidChequeNumberFormatError;
|
||||||
|
}
|
||||||
|
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
|
||||||
|
return AppLocalizations.of(context).chequeNumberRangeError(
|
||||||
|
widget.fromCheque, widget.toCheque);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
initialValue: widget.instrType,
|
||||||
|
readOnly: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).instrumentTypeLabel,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopIssueDateController,
|
||||||
|
readOnly: true,
|
||||||
|
onTap: () => _selectDate(_stopIssueDateController),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).revokeIssueDate,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: const Icon(Icons.calendar_today),
|
||||||
|
onPressed: () => _selectDate(_stopIssueDateController),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.datetime,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopExpiryDateController,
|
||||||
|
readOnly: true,
|
||||||
|
onTap: () => _selectDate(_stopExpiryDateController),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).revokeExpiryDate,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: const Icon(Icons.calendar_today),
|
||||||
|
onPressed: () => _selectDate(_stopExpiryDateController),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.datetime,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFormField(
|
||||||
|
controller: _stopAmountController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).revokeAmount,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
DropdownButtonFormField<String>(
|
||||||
|
value: _selectedComment,
|
||||||
|
items: _commentOptions.map((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (newValue) {
|
||||||
|
setState(() {
|
||||||
|
_selectedComment = newValue;
|
||||||
|
_showOtherCommentField = newValue == 'Other';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context).revokeComment,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_showOtherCommentField)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 16.0),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _otherCommentController,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: "Other Reasons :",
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => TransactionPinScreen(
|
||||||
|
onPinCompleted: (ctx, pin) async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
try {
|
||||||
|
final response = await _chequeService.revokeStop(
|
||||||
|
accountno: widget.selectedAccount.accountNo!,
|
||||||
|
removeFromChequeNo:
|
||||||
|
_stopFromChequeNoController.text,
|
||||||
|
instrType: widget.instrType,
|
||||||
|
removeToChequeNo:
|
||||||
|
_stopFromChequeNoController.text,
|
||||||
|
removeIssueDate: _stopIssueDateController.text,
|
||||||
|
removeExpiryDate: _stopExpiryDateController.text,
|
||||||
|
removeAmount: _stopAmountController.text,
|
||||||
|
removeComment: _selectedComment == 'Other'
|
||||||
|
? _otherCommentController.text
|
||||||
|
: _selectedComment ?? '',
|
||||||
|
tpin: pin,
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
final decodedResponse = jsonDecode(response);
|
||||||
|
String responseString = response.toString(); // used as the case only for incorrect TPIN
|
||||||
|
final status = decodedResponse['status'];
|
||||||
|
final message = decodedResponse['message'];
|
||||||
|
final code = decodedResponse['code'];
|
||||||
|
if (status == 'SUCCESS') {
|
||||||
|
_showResponseDialog('Success', message);
|
||||||
|
} if (status == 'ERROR') {
|
||||||
|
String errMessage = "error";
|
||||||
|
if(code == '0172') {
|
||||||
|
errMessage = 'The selected Cheque is not stopped';
|
||||||
|
} else if(code == '0748') {
|
||||||
|
errMessage = 'The selected Cheque is already presented';
|
||||||
|
}
|
||||||
|
_showResponseDialog('Error', errMessage);
|
||||||
|
}
|
||||||
|
if(responseString.contains('INCORRECT_TPIN')){
|
||||||
|
_showResponseDialog('Invalid TPIN',
|
||||||
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
try {
|
||||||
|
final errorBodyString =
|
||||||
|
e.toString().split('Exception: ')[1];
|
||||||
|
final errorBody = jsonDecode(errorBodyString);
|
||||||
|
if (errorBody.containsKey('error') &&
|
||||||
|
errorBody['error'] == 'INCORRECT_TPIN') {
|
||||||
|
_showResponseDialog('Invalid TPIN',
|
||||||
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
} else {
|
||||||
|
_showResponseDialog(
|
||||||
|
'Error', 'Internal Server Error');
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
_showResponseDialog(
|
||||||
|
'Error', 'Internal Server Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(AppLocalizations.of(context).revokeStopButton),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -309,6 +309,7 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
);
|
);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final decodedResponse = jsonDecode(response);
|
final decodedResponse = jsonDecode(response);
|
||||||
|
String responseString = response.toString(); // used as the case only for incorrect TPIN
|
||||||
final status = decodedResponse['status'];
|
final status = decodedResponse['status'];
|
||||||
final message = decodedResponse['message'];
|
final message = decodedResponse['message'];
|
||||||
final code = decodedResponse['code'];
|
final code = decodedResponse['code'];
|
||||||
@@ -323,6 +324,10 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
|||||||
}
|
}
|
||||||
_showResponseDialog('Error', errMessage);
|
_showResponseDialog('Error', errMessage);
|
||||||
}
|
}
|
||||||
|
if(responseString.contains('INCORRECT_TPIN')){
|
||||||
|
_showResponseDialog('Invalid TPIN',
|
||||||
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
}
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
try {
|
try {
|
||||||
final errorBodyString =
|
final errorBodyString =
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
|||||||
);
|
);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final decodedResponse = jsonDecode(response);
|
final decodedResponse = jsonDecode(response);
|
||||||
|
String responseString = response.toString(); // used as the case only for incorrect TPIN
|
||||||
final status = decodedResponse['status'];
|
final status = decodedResponse['status'];
|
||||||
final message = decodedResponse['message'];
|
final message = decodedResponse['message'];
|
||||||
final code = decodedResponse['code'];
|
final code = decodedResponse['code'];
|
||||||
@@ -293,6 +293,10 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
|||||||
}
|
}
|
||||||
_showResponseDialog('Error', errMessage);
|
_showResponseDialog('Error', errMessage);
|
||||||
}
|
}
|
||||||
|
if(responseString.contains('INCORRECT_TPIN')){
|
||||||
|
_showResponseDialog('Invalid TPIN',
|
||||||
|
'The TPIN you entered is incorrect. Please try again.');
|
||||||
|
}
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
try {
|
try {
|
||||||
final errorBodyString =
|
final errorBodyString =
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import 'package:kmobile/features/auth/controllers/auth_state.dart';
|
|||||||
import 'package:kmobile/features/cheque/screens/cheque_management_screen.dart';
|
import 'package:kmobile/features/cheque/screens/cheque_management_screen.dart';
|
||||||
import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart';
|
import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart';
|
||||||
import 'package:kmobile/features/beneficiaries/screens/manage_beneficiaries_screen.dart';
|
import 'package:kmobile/features/beneficiaries/screens/manage_beneficiaries_screen.dart';
|
||||||
import 'package:kmobile/features/enquiry/screens/enquiry_screen.dart';
|
|
||||||
import 'package:kmobile/features/fund_transfer/screens/fund_transfer_screen.dart';
|
import 'package:kmobile/features/fund_transfer/screens/fund_transfer_screen.dart';
|
||||||
import 'package:kmobile/features/profile/profile_screen.dart';
|
import 'package:kmobile/features/profile/profile_screen.dart';
|
||||||
import 'package:kmobile/features/quick_pay/screens/quick_pay_screen.dart';
|
import 'package:kmobile/features/quick_pay/screens/quick_pay_screen.dart';
|
||||||
import 'package:kmobile/features/service/screens/branch_locator_screen.dart';
|
import 'package:kmobile/features/service/screens/branch_locator_screen.dart';
|
||||||
|
import 'package:kmobile/features/yojna/screens/gov_scheme_screen.dart';
|
||||||
import 'package:kmobile/security/secure_storage.dart';
|
import 'package:kmobile/security/secure_storage.dart';
|
||||||
import 'package:local_auth/local_auth.dart';
|
import 'package:local_auth/local_auth.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
@@ -636,13 +636,14 @@ class _DashboardScreenState extends State<DashboardScreen>
|
|||||||
ManageBeneficiariesScreen(
|
ManageBeneficiariesScreen(
|
||||||
customerName: currAccount.name!)));
|
customerName: currAccount.name!)));
|
||||||
}, disable: false),
|
}, disable: false),
|
||||||
_buildQuickLink(Symbols.support_agent,
|
_buildQuickLink(Symbols.family_group,
|
||||||
AppLocalizations.of(context).contactUs, () {
|
AppLocalizations.of(context).governmentSchemes, () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
const EnquiryScreen()));
|
GovSchemeScreen(users: users,
|
||||||
|
selectedIndex: selectedAccountIndex)));
|
||||||
}),
|
}),
|
||||||
_buildQuickLink(
|
_buildQuickLink(
|
||||||
Symbols.checkbook,
|
Symbols.checkbook,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import 'package:kmobile/features/account_opening/screens/account_opening_screen.dart';
|
||||||
|
import 'package:kmobile/features/card/screens/card_management_screen.dart';
|
||||||
import 'package:kmobile/features/service/screens/atm_locator_screen.dart';
|
import 'package:kmobile/features/service/screens/atm_locator_screen.dart';
|
||||||
|
import 'package:kmobile/features/service/screens/enquiry_screen.dart';
|
||||||
import '../../../l10n/app_localizations.dart';
|
import '../../../l10n/app_localizations.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
@@ -43,7 +46,6 @@ class _ServiceScreen extends State<ServiceScreen> {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ServiceManagementTile(
|
child: ServiceManagementTile(
|
||||||
icon: Symbols.question_mark,
|
icon: Symbols.question_mark,
|
||||||
@@ -57,7 +59,6 @@ class _ServiceScreen extends State<ServiceScreen> {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ServiceManagementTile(
|
child: ServiceManagementTile(
|
||||||
icon: Symbols.location_pin,
|
icon: Symbols.location_pin,
|
||||||
@@ -71,6 +72,45 @@ class _ServiceScreen extends State<ServiceScreen> {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// Expanded(
|
||||||
|
// child: ServiceManagementTile(
|
||||||
|
// icon: Symbols.box,
|
||||||
|
// label: "Account Opening",
|
||||||
|
// onTap: () {
|
||||||
|
// Navigator.push(
|
||||||
|
// context,
|
||||||
|
// MaterialPageRoute(
|
||||||
|
// builder: (context) => const AccountOpeningScreen()));
|
||||||
|
// },
|
||||||
|
// disabled: false,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Expanded(
|
||||||
|
// child: ServiceManagementTile(
|
||||||
|
// icon: Symbols.credit_card,
|
||||||
|
// label: AppLocalizations.of(context).cardManagement,
|
||||||
|
// onTap: () {
|
||||||
|
// Navigator.push(
|
||||||
|
// context,
|
||||||
|
// MaterialPageRoute(
|
||||||
|
// builder: (context) => const CardManagementScreen()));
|
||||||
|
// },
|
||||||
|
// disabled: false,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
Expanded(
|
||||||
|
child: ServiceManagementTile(
|
||||||
|
icon: Symbols.support_agent,
|
||||||
|
label: AppLocalizations.of(context).contactUs,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const EnquiryScreen()));
|
||||||
|
},
|
||||||
|
disabled: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
// No Spacer() needed here as Expanded children will fill space
|
// No Spacer() needed here as Expanded children will fill space
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -122,8 +162,8 @@ class ServiceManagementTile extends StatelessWidget {
|
|||||||
onTap:
|
onTap:
|
||||||
disabled ? null : onTap, // Disable InkWell if the tile is disabled
|
disabled ? null : onTap, // Disable InkWell if the tile is disabled
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
child: Padding(
|
child: Center(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0),
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@@ -148,6 +188,7 @@ class ServiceManagementTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
113
lib/features/yojna/screens/apy_screen.dart
Normal file
113
lib/features/yojna/screens/apy_screen.dart
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/data/models/user.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class APYScreen extends StatefulWidget {
|
||||||
|
final List<User> users;
|
||||||
|
final int selectedIndex;
|
||||||
|
const APYScreen({
|
||||||
|
super.key,
|
||||||
|
required this.users,
|
||||||
|
required this.selectedIndex,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<APYScreen> createState() => _APYScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _APYScreenState extends State<APYScreen> {
|
||||||
|
User? _selectedAccount;
|
||||||
|
List<User> _filteredUsers = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_filteredUsers = widget.users
|
||||||
|
.where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// Pre-fill the account number if possible
|
||||||
|
if (widget.users.isNotEmpty && widget.selectedIndex < widget.users.length) {
|
||||||
|
if (_filteredUsers.isNotEmpty) {
|
||||||
|
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
||||||
|
_selectedAccount = widget.users[widget.selectedIndex];
|
||||||
|
} else {
|
||||||
|
_selectedAccount = _filteredUsers.first;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_selectedAccount = widget.users[widget.selectedIndex];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_filteredUsers.isNotEmpty) {
|
||||||
|
_selectedAccount = _filteredUsers.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(l10n.apyRegistration),
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
elevation: 2,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Text(
|
||||||
|
l10n.apyDescription,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Card(
|
||||||
|
elevation: 2,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
DropdownButtonFormField<User>(
|
||||||
|
value: _selectedAccount,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: l10n.accountNumber,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 20, horizontal: 12),
|
||||||
|
),
|
||||||
|
items: _filteredUsers.map((user) {
|
||||||
|
return DropdownMenuItem<User>(
|
||||||
|
value: user,
|
||||||
|
child: Text(user.accountNo.toString()),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (User? newUser) {
|
||||||
|
setState(() {
|
||||||
|
_selectedAccount = newUser;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) {
|
||||||
|
return l10n.accountNumberRequired;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
165
lib/features/yojna/screens/gov_scheme_screen.dart
Normal file
165
lib/features/yojna/screens/gov_scheme_screen.dart
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/data/models/user.dart';
|
||||||
|
import 'package:kmobile/features/yojna/screens/apy_screen.dart';
|
||||||
|
import 'package:kmobile/features/yojna/screens/pm_main_screen.dart';
|
||||||
|
import '../../../l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class GovSchemeScreen extends StatefulWidget {
|
||||||
|
final List<User> users;
|
||||||
|
final int selectedIndex;
|
||||||
|
const GovSchemeScreen({
|
||||||
|
super.key,
|
||||||
|
required this.users,
|
||||||
|
required this.selectedIndex,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GovSchemeScreen> createState() => _GovSchemeScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GovSchemeScreenState extends State<GovSchemeScreen> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(l10n.governmentSchemes),
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: GovSchemeTile(
|
||||||
|
logoText: "PMJJBY/PMSBY",
|
||||||
|
label: l10n.pradhanMantriYojana,
|
||||||
|
subtitle: l10n.enrollPMJJBYPMSBY,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => PMMainScreen(
|
||||||
|
users: widget.users,
|
||||||
|
selectedIndex: widget.selectedIndex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: GovSchemeTile(
|
||||||
|
logoText: "APY",
|
||||||
|
label: l10n.registerForAtalPensionYojana,
|
||||||
|
subtitle: l10n.secureYourFutureAPY,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => APYScreen(
|
||||||
|
users: widget.users,
|
||||||
|
selectedIndex: widget.selectedIndex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);// Action for APY will be added later
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IgnorePointer(
|
||||||
|
child: Center(
|
||||||
|
child: Opacity(
|
||||||
|
opacity: 0.07,
|
||||||
|
child: ClipOval(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/logo.png',
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GovSchemeTile extends StatelessWidget {
|
||||||
|
final String logoText;
|
||||||
|
final String label;
|
||||||
|
final String? subtitle;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final bool disable;
|
||||||
|
|
||||||
|
const GovSchemeTile({
|
||||||
|
super.key,
|
||||||
|
required this.logoText,
|
||||||
|
required this.label,
|
||||||
|
this.subtitle,
|
||||||
|
required this.onTap,
|
||||||
|
this.disable = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return Card(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
|
),
|
||||||
|
elevation: 4,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: disable ? null : onTap,
|
||||||
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 36.0, horizontal: 16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
logoText,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: logoText.length > 5 ? 28 : 40,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: theme.colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: theme.textTheme.headlineSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: disable
|
||||||
|
? theme.disabledColor
|
||||||
|
: theme.colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (subtitle != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Text(
|
||||||
|
subtitle!,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
|
color: disable
|
||||||
|
? theme.disabledColor
|
||||||
|
: theme.colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
339
lib/features/yojna/screens/pm_main_screen.dart
Normal file
339
lib/features/yojna/screens/pm_main_screen.dart
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/api/services/yojna_service.dart';
|
||||||
|
import 'package:kmobile/data/models/user.dart';
|
||||||
|
import 'package:kmobile/di/injection.dart';
|
||||||
|
import 'package:kmobile/features/yojna/screens/pmjjby_screen.dart';
|
||||||
|
import 'package:kmobile/features/yojna/screens/pmsby_screen.dart';
|
||||||
|
import 'package:kmobile/features/yojna/screens/pmjjby_enquiry_screen.dart';
|
||||||
|
import 'package:kmobile/features/yojna/screens/pmsby_enquiry_screen.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class PMMainScreen extends StatefulWidget {
|
||||||
|
final List<User> users;
|
||||||
|
final int selectedIndex;
|
||||||
|
const PMMainScreen({
|
||||||
|
super.key,
|
||||||
|
required this.users,
|
||||||
|
required this.selectedIndex,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PMMainScreen> createState() => _PMMainScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PMMainScreenState extends State<PMMainScreen> {
|
||||||
|
User? _selectedAccount;
|
||||||
|
List<User> _filteredUsers = [];
|
||||||
|
String? _selectedScheme;
|
||||||
|
|
||||||
|
List<String> _getSchemes(AppLocalizations l10n) => [
|
||||||
|
l10n.pmjjbyFull,
|
||||||
|
l10n.pmsbyFull,
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_filteredUsers = widget.users
|
||||||
|
.where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
|
||||||
|
.toList();
|
||||||
|
// Pre-fill the account number if possible
|
||||||
|
if (widget.users.isNotEmpty && widget.selectedIndex < widget.users.length) {
|
||||||
|
if (_filteredUsers.isNotEmpty) {
|
||||||
|
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
|
||||||
|
_selectedAccount = widget.users[widget.selectedIndex];
|
||||||
|
} else {
|
||||||
|
_selectedAccount = _filteredUsers.first;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_selectedAccount = widget.users[widget.selectedIndex];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_filteredUsers.isNotEmpty) {
|
||||||
|
_selectedAccount = _filteredUsers.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleCreate() async {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
if (_selectedAccount == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(l10n.pleaseSelectAccountNumber)),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_selectedScheme == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(l10n.pleaseSelectSchemeFirst)),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String schemeCode = (_selectedScheme == l10n.pmjjbyFull) ? '02' : '01';
|
||||||
|
|
||||||
|
// Show loading
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Row(
|
||||||
|
children: [
|
||||||
|
const CircularProgressIndicator(),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Text(l10n.fetchingDetails),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
duration: const Duration(seconds: 2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await getIt<YojnaService>().fetchpmydetails(
|
||||||
|
scheme: schemeCode,
|
||||||
|
action: 'C',
|
||||||
|
accountno: _selectedAccount!.accountNo!,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
Map<String, dynamic>? data;
|
||||||
|
if (response is Map<String, dynamic>) {
|
||||||
|
data = response;
|
||||||
|
} else if (response is List && response.isNotEmpty && response[0] is Map<String, dynamic>) {
|
||||||
|
data = response[0] as Map<String, dynamic>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data != null && data.isNotEmpty) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
if (_selectedScheme == l10n.pmjjbyFull) {
|
||||||
|
return PMJJBYScreen(initialData: data!);
|
||||||
|
} else {
|
||||||
|
return PMSBYScreen(initialData: data!);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(l10n.failedToFetchDetails)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(l10n.genericError(e.toString()))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleEnquiry() {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
if (_selectedAccount == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(l10n.pleaseSelectAccountNumber)),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_selectedScheme == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(l10n.pleaseSelectSchemeFirst)),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
if (_selectedScheme == l10n.pmjjbyFull) {
|
||||||
|
return PMJJBYEnquiryScreen(cifNumber: _selectedAccount!.cifNumber);
|
||||||
|
} else {
|
||||||
|
return PMSBYEnquiryScreen(cifNumber: _selectedAccount!.cifNumber);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
final schemes = _getSchemes(l10n);
|
||||||
|
|
||||||
|
// Ensure _selectedScheme is valid if it was set in a different language
|
||||||
|
if (_selectedScheme != null && !schemes.contains(_selectedScheme)) {
|
||||||
|
// Try to find the corresponding scheme in the new language
|
||||||
|
// This is a bit tricky, but since we only have two:
|
||||||
|
// If it doesn't match, it might be from the other language.
|
||||||
|
// For simplicity, we can just reset it or try to guess.
|
||||||
|
// Better to use non-localized values for the state, but let's just reset for now if it doesn't match
|
||||||
|
_selectedScheme = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(l10n.pradhanMantriYojana),
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
elevation: 2,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Text(
|
||||||
|
l10n.pmjjbyPmsbyDescription,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Card(
|
||||||
|
elevation: 2,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
DropdownButtonFormField<User>(
|
||||||
|
value: _selectedAccount,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: l10n.accountNumber,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 20, horizontal: 12),
|
||||||
|
),
|
||||||
|
items: _filteredUsers.map((user) {
|
||||||
|
return DropdownMenuItem<User>(
|
||||||
|
value: user,
|
||||||
|
child: Text(user.accountNo.toString()),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (User? newUser) {
|
||||||
|
setState(() {
|
||||||
|
_selectedAccount = newUser;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null) {
|
||||||
|
return l10n.accountNumberRequired;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
DropdownButtonFormField<String>(
|
||||||
|
value: _selectedScheme,
|
||||||
|
isExpanded: true,
|
||||||
|
isDense: false,
|
||||||
|
itemHeight: null,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: l10n.selectScheme,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 12, horizontal: 12),
|
||||||
|
),
|
||||||
|
selectedItemBuilder: (BuildContext context) {
|
||||||
|
return schemes.map((String scheme) {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
scheme,
|
||||||
|
style: const TextStyle(fontSize: 14),
|
||||||
|
softWrap: true,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.visible,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
},
|
||||||
|
items: schemes.map((String scheme) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: scheme,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12.0),
|
||||||
|
child: Text(
|
||||||
|
scheme,
|
||||||
|
style: const TextStyle(fontSize: 15),
|
||||||
|
|
||||||
|
softWrap: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
_selectedScheme = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: _handleCreate,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).colorScheme.primaryContainer,
|
||||||
|
foregroundColor:
|
||||||
|
Theme.of(context).colorScheme.onPrimaryContainer,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
elevation: 4,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
l10n.create,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: _handleEnquiry,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).colorScheme.primaryContainer,
|
||||||
|
foregroundColor:
|
||||||
|
Theme.of(context).colorScheme.onPrimaryContainer,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
elevation: 4,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
l10n.enquiry,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
218
lib/features/yojna/screens/pmjjby_enquiry_screen.dart
Normal file
218
lib/features/yojna/screens/pmjjby_enquiry_screen.dart
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/api/services/yojna_service.dart';
|
||||||
|
import 'package:kmobile/di/injection.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class PMJJBYEnquiryScreen extends StatefulWidget {
|
||||||
|
final String? cifNumber;
|
||||||
|
|
||||||
|
const PMJJBYEnquiryScreen({
|
||||||
|
super.key,
|
||||||
|
required this.cifNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PMJJBYEnquiryScreen> createState() => _PMJJBYEnquiryScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PMJJBYEnquiryScreenState extends State<PMJJBYEnquiryScreen> {
|
||||||
|
String? _selectedFinancialYear;
|
||||||
|
bool _isLoading = false;
|
||||||
|
Map<String, dynamic>? _enquiryData;
|
||||||
|
String? _errorMessage;
|
||||||
|
|
||||||
|
final List<String> _financialYears = [
|
||||||
|
'2021-2022',
|
||||||
|
'2022-2023',
|
||||||
|
'2023-2024',
|
||||||
|
'2024-2025',
|
||||||
|
'2025-2026',
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_selectedFinancialYear = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchEnquiryData() async {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
if (_selectedFinancialYear == null || widget.cifNumber == null) return;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isLoading = true;
|
||||||
|
_enquiryData = null;
|
||||||
|
_errorMessage = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
final formattedYear = _selectedFinancialYear!.replaceAll('-', '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await getIt<YojnaService>().enquiry(
|
||||||
|
scheme: '02',
|
||||||
|
action: 'E',
|
||||||
|
financialyear: formattedYear,
|
||||||
|
customerno: widget.cifNumber,
|
||||||
|
);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
if (response is Map<String, dynamic>) {
|
||||||
|
if (response['status'] == 'FAILED') {
|
||||||
|
_errorMessage = response['message'] ?? l10n.noRecordFound;
|
||||||
|
} else {
|
||||||
|
_enquiryData = response;
|
||||||
|
}
|
||||||
|
} else if (response is List && response.isNotEmpty) {
|
||||||
|
_enquiryData = response[0] as Map<String, dynamic>;
|
||||||
|
} else {
|
||||||
|
_errorMessage = l10n.noDataFoundYear;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
setState(() {
|
||||||
|
_errorMessage = l10n.genericError(e.toString());
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setState(() {
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(l10n.pmjjbyDetails),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
elevation: 4,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
leading: const Icon(Icons.person, color: Colors.blue),
|
||||||
|
title: Text(l10n.cifNumber),
|
||||||
|
subtitle: Text(
|
||||||
|
widget.cifNumber ?? l10n.notApplicable,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
DropdownButtonFormField<String>(
|
||||||
|
value: _selectedFinancialYear,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: l10n.selectFinancialYear,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
prefixIcon: const Icon(Icons.calendar_today),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
),
|
||||||
|
items: _financialYears.map((String year) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: year,
|
||||||
|
child: Text(year),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
_selectedFinancialYear = newValue;
|
||||||
|
});
|
||||||
|
_fetchEnquiryData();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
if (_isLoading)
|
||||||
|
const Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(20.0),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (_errorMessage != null)
|
||||||
|
Card(
|
||||||
|
color: Colors.red.shade50,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Text(
|
||||||
|
_errorMessage!,
|
||||||
|
style: TextStyle(color: Colors.red.shade700, fontWeight: FontWeight.bold),
|
||||||
|
//textAlign: Center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (_enquiryData != null)
|
||||||
|
Card(
|
||||||
|
elevation: 4,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
l10n.schemeDetails,
|
||||||
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
_buildDetailRow(l10n.customerName, _enquiryData!['customername']),
|
||||||
|
_buildDetailRow(l10n.policyNumber, _enquiryData!['policynumber']),
|
||||||
|
_buildDetailRow(l10n.accountNumber, _enquiryData!['accountno']),
|
||||||
|
_buildDetailRow(l10n.premiumAmount, _enquiryData!['preimiumamount']),
|
||||||
|
_buildDetailRow(l10n.nomineeName, _enquiryData!['nomineename']),
|
||||||
|
_buildDetailRow(l10n.date, _enquiryData!['transactiondate']),
|
||||||
|
_buildDetailRow(l10n.journalNo, _enquiryData!['journalno']),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDetailRow(String label, dynamic value) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.w500, color: Colors.grey),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
value?.toString() ?? AppLocalizations.of(context).notApplicable,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
333
lib/features/yojna/screens/pmjjby_screen.dart
Normal file
333
lib/features/yojna/screens/pmjjby_screen.dart
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/api/services/yojna_service.dart';
|
||||||
|
import 'package:kmobile/di/injection.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class PMJJBYScreen extends StatefulWidget {
|
||||||
|
final Map<String, dynamic>? initialData;
|
||||||
|
const PMJJBYScreen({super.key, this.initialData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PMJJBYScreen> createState() => _PMJJBYScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PMJJBYScreenState extends State<PMJJBYScreen> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
// Controllers for all requested fields
|
||||||
|
late final _aadhaarController = TextEditingController(text: widget.initialData?['aadharno']?.toString());
|
||||||
|
late final _accountNoController = TextEditingController(text: widget.initialData?['accountno']?.toString());
|
||||||
|
late final _balanceController = TextEditingController(text: widget.initialData?['availablebalance']?.toString());
|
||||||
|
late final _countryController = TextEditingController(text: widget.initialData?['country']?.toString() ?? 'IN');
|
||||||
|
late final _dobController = TextEditingController(text: widget.initialData?['customerdob']?.toString());
|
||||||
|
late final _nameController = TextEditingController(text: widget.initialData?['customername']?.toString());
|
||||||
|
late final _customerNoController = TextEditingController(text: widget.initialData?['customerno']?.toString());
|
||||||
|
late final _acctOpeningDateController = TextEditingController(text: widget.initialData?['dateofacctopening']?.toString());
|
||||||
|
late final _emailController = TextEditingController(text: widget.initialData?['emailid']?.toString());
|
||||||
|
late final _financialYearController = TextEditingController(text: widget.initialData?['financialyear']?.toString());
|
||||||
|
late final _genderController = TextEditingController(text: widget.initialData?['gender']?.toString());
|
||||||
|
late final _ifscController = TextEditingController(text: widget.initialData?['ifsccode']?.toString());
|
||||||
|
late final _marriedController = TextEditingController(text: widget.initialData?['married']?.toString());
|
||||||
|
late final _mobileController = TextEditingController(text: widget.initialData?['mobileno']?.toString());
|
||||||
|
late final _panController = TextEditingController(text: widget.initialData?['pan']?.toString());
|
||||||
|
late final _pincodeController = TextEditingController(text: widget.initialData?['pincode']?.toString());
|
||||||
|
late final _policyNumberController = TextEditingController(text: widget.initialData?['policynumber']?.toString());
|
||||||
|
late final _premiumAmountController = TextEditingController(text: widget.initialData?['premiumamount']?.toString());
|
||||||
|
late final _stateController = TextEditingController(text: widget.initialData?['state']?.toString());
|
||||||
|
|
||||||
|
// Mapping options
|
||||||
|
final Map<String, String> _healthStatusOptions = {
|
||||||
|
'1': 'Excellent',
|
||||||
|
'2': 'Good',
|
||||||
|
'3': 'Bad',
|
||||||
|
};
|
||||||
|
|
||||||
|
final Map<String, String> _relationshipOptions = {
|
||||||
|
'01': 'Self',
|
||||||
|
'02': 'Wife',
|
||||||
|
'03': 'Father',
|
||||||
|
'04': 'Mother',
|
||||||
|
'05': 'Son',
|
||||||
|
'06': 'Daughter',
|
||||||
|
'07': 'Brother',
|
||||||
|
'08': 'Sister',
|
||||||
|
'09': 'Father-in-law',
|
||||||
|
'10': 'Mother-in-law',
|
||||||
|
'11': 'Grandson',
|
||||||
|
'12': 'Granddaughter',
|
||||||
|
'13': 'Grandfather',
|
||||||
|
'14': 'Grandmother',
|
||||||
|
'15': 'Brother-in-law',
|
||||||
|
'16': 'Sister-in-law',
|
||||||
|
'17': 'Husband',
|
||||||
|
'18': 'Guardian',
|
||||||
|
'99': 'Others',
|
||||||
|
};
|
||||||
|
|
||||||
|
final Map<String, String> _minorOptions = {
|
||||||
|
'Y': 'Yes',
|
||||||
|
'N': 'No',
|
||||||
|
};
|
||||||
|
|
||||||
|
final Map<String, String> _ruralOptions = {
|
||||||
|
'R': 'Rural',
|
||||||
|
'U': 'Urban',
|
||||||
|
'S': 'Semi-Urban',
|
||||||
|
'M': 'Metro',
|
||||||
|
};
|
||||||
|
|
||||||
|
final _healthStatusController = TextEditingController();
|
||||||
|
final _collectionChannelController = TextEditingController();
|
||||||
|
final _nomineeNameController = TextEditingController();
|
||||||
|
final _nomineeAddressController = TextEditingController();
|
||||||
|
final _nomineeRelationshipController = TextEditingController();
|
||||||
|
final _nomineeMinorController = TextEditingController();
|
||||||
|
final _ruralCategoryController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
// Initialize dropdown controllers if data exists in initialData
|
||||||
|
if (widget.initialData != null) {
|
||||||
|
if (widget.initialData!.containsKey('ruralcategory')) {
|
||||||
|
_ruralCategoryController.text = widget.initialData!['ruralcategory'].toString();
|
||||||
|
}
|
||||||
|
if (widget.initialData!.containsKey('healthstatus')) {
|
||||||
|
_healthStatusController.text = widget.initialData!['healthstatus'].toString();
|
||||||
|
}
|
||||||
|
if (widget.initialData!.containsKey('nomineerelationship')) {
|
||||||
|
_nomineeRelationshipController.text = widget.initialData!['nomineerelationship'].toString();
|
||||||
|
}
|
||||||
|
if (widget.initialData!.containsKey('nomineeminor')) {
|
||||||
|
_nomineeMinorController.text = widget.initialData!['nomineeminor'].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_aadhaarController.dispose();
|
||||||
|
_accountNoController.dispose();
|
||||||
|
_balanceController.dispose();
|
||||||
|
_countryController.dispose();
|
||||||
|
_dobController.dispose();
|
||||||
|
_nameController.dispose();
|
||||||
|
_customerNoController.dispose();
|
||||||
|
_acctOpeningDateController.dispose();
|
||||||
|
_emailController.dispose();
|
||||||
|
_financialYearController.dispose();
|
||||||
|
_genderController.dispose();
|
||||||
|
_ifscController.dispose();
|
||||||
|
_marriedController.dispose();
|
||||||
|
_mobileController.dispose();
|
||||||
|
_panController.dispose();
|
||||||
|
_pincodeController.dispose();
|
||||||
|
_policyNumberController.dispose();
|
||||||
|
_premiumAmountController.dispose();
|
||||||
|
_stateController.dispose();
|
||||||
|
_healthStatusController.dispose();
|
||||||
|
_collectionChannelController.dispose();
|
||||||
|
_nomineeNameController.dispose();
|
||||||
|
_nomineeAddressController.dispose();
|
||||||
|
_nomineeRelationshipController.dispose();
|
||||||
|
_nomineeMinorController.dispose();
|
||||||
|
_ruralCategoryController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isFetched(String key) {
|
||||||
|
return widget.initialData != null &&
|
||||||
|
widget.initialData!.containsKey(key) &&
|
||||||
|
widget.initialData![key]?.toString().isNotEmpty == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleRegister() async {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
// Show loading spinner
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (context) => const Center(child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await getIt<YojnaService>().secondvalidationPMJJBY(
|
||||||
|
aadharno: _aadhaarController.text,
|
||||||
|
accountno: _accountNoController.text,
|
||||||
|
availablebalance: _balanceController.text,
|
||||||
|
country: _countryController.text,
|
||||||
|
customerdob: _dobController.text,
|
||||||
|
customername: _nameController.text,
|
||||||
|
customerno: _customerNoController.text,
|
||||||
|
dateofacctopening: _acctOpeningDateController.text,
|
||||||
|
emailid: _emailController.text,
|
||||||
|
financialyear: _financialYearController.text,
|
||||||
|
gender: _genderController.text,
|
||||||
|
ifsccode: _ifscController.text,
|
||||||
|
married: _marriedController.text,
|
||||||
|
mobileno: _mobileController.text,
|
||||||
|
pan: _panController.text,
|
||||||
|
pincode: _pincodeController.text,
|
||||||
|
policynumber: _policyNumberController.text,
|
||||||
|
premiumamount: _premiumAmountController.text,
|
||||||
|
state: _stateController.text,
|
||||||
|
healthstatus: _healthStatusController.text,
|
||||||
|
collectionchannel: _collectionChannelController.text,
|
||||||
|
nomineename: _nomineeNameController.text,
|
||||||
|
nomineeaddress: _nomineeAddressController.text,
|
||||||
|
nomineerelationship: _nomineeRelationshipController.text,
|
||||||
|
nomineeminor: _nomineeMinorController.text,
|
||||||
|
ruralcategory: _ruralCategoryController.text,
|
||||||
|
);
|
||||||
|
String x = response.toString();
|
||||||
|
if(x.contains('RECORD ALREADY EXISTS')){
|
||||||
|
x= l10n.recordAlreadyExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
// Close loading spinner
|
||||||
|
Navigator.pop(context);
|
||||||
|
// Show response dialog
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text(l10n.response),
|
||||||
|
content: SingleChildScrollView(child: Text(x)),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
|
},
|
||||||
|
child: Text(l10n.close),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.pop(context); // Close loading spinner
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(l10n.genericError(e.toString()))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(l10n.pmjjbyRegistration),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
_buildTextField(_nameController, l10n.customerName, readOnly: _isFetched('customername')),
|
||||||
|
_buildTextField(_customerNoController, l10n.customerNo, readOnly: _isFetched('customerno')),
|
||||||
|
_buildTextField(_accountNoController, l10n.accountNumber, keyboardType: TextInputType.number, readOnly: _isFetched('accountno')),
|
||||||
|
_buildTextField(_balanceController, l10n.availableBalance, keyboardType: TextInputType.number, readOnly: _isFetched('availablebalance')),
|
||||||
|
_buildTextField(_aadhaarController, l10n.aadhaarNo, keyboardType: TextInputType.number, readOnly: _isFetched('aadharno')),
|
||||||
|
_buildTextField(_dobController, l10n.customerDobFormat, readOnly: _isFetched('customerdob')),
|
||||||
|
_buildTextField(_genderController, l10n.gender, readOnly: _isFetched('gender')),
|
||||||
|
_buildTextField(_marriedController, l10n.marriedYesNo, readOnly: _isFetched('married')),
|
||||||
|
_buildTextField(_mobileController, l10n.mobileNumber, keyboardType: TextInputType.phone, readOnly: _isFetched('mobileno')),
|
||||||
|
_buildTextField(_emailController, 'Email ID', keyboardType: TextInputType.emailAddress, readOnly: _isFetched('emailid')),
|
||||||
|
_buildTextField(_panController, l10n.pan, readOnly: _isFetched('pan')),
|
||||||
|
_buildTextField(_ifscController, l10n.ifscCode, readOnly: _isFetched('ifsccode')),
|
||||||
|
_buildTextField(_acctOpeningDateController, l10n.dateOfAcctOpening, readOnly: _isFetched('dateofacctopening')),
|
||||||
|
_buildTextField(_pincodeController, l10n.pincode, keyboardType: TextInputType.number, readOnly: _isFetched('pincode')),
|
||||||
|
_buildTextField(_stateController, l10n.state, readOnly: _isFetched('state')),
|
||||||
|
_buildTextField(_countryController, l10n.country, readOnly: _isFetched('country')),
|
||||||
|
_buildDropdownField(_ruralCategoryController, l10n.ruralCategory, _ruralOptions, readOnly: _isFetched('ruralcategory')),
|
||||||
|
const Divider(height: 32),
|
||||||
|
Text(l10n.policyDetails, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildTextField(_policyNumberController, l10n.policyNumber, readOnly: _isFetched('policynumber')),
|
||||||
|
_buildTextField(_premiumAmountController, l10n.premiumAmount, keyboardType: TextInputType.number, readOnly: _isFetched('premiumamount')),
|
||||||
|
_buildTextField(_financialYearController, l10n.financialYear, readOnly: _isFetched('financialyear')),
|
||||||
|
_buildDropdownField(_healthStatusController, l10n.healthStatus, _healthStatusOptions),
|
||||||
|
_buildTextField(_collectionChannelController, l10n.collectionChannel),
|
||||||
|
const Divider(height: 32),
|
||||||
|
Text(l10n.nomineeDetails, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildTextField(_nomineeNameController, l10n.nomineeName),
|
||||||
|
_buildTextField(_nomineeAddressController, l10n.nomineeAddress),
|
||||||
|
_buildDropdownField(_nomineeRelationshipController, l10n.nomineeRelationship, _relationshipOptions, readOnly: _isFetched('nomineerelationship')),
|
||||||
|
_buildDropdownField(_nomineeMinorController, l10n.nomineeMinor, _minorOptions, readOnly: _isFetched('nomineeminor')),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: _handleRegister,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
l10n.register,
|
||||||
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDropdownField(
|
||||||
|
TextEditingController controller, String label, Map<String, String> options,
|
||||||
|
{bool readOnly = false}) {
|
||||||
|
// Determine current value
|
||||||
|
String? currentValue = options.containsKey(controller.text) ? controller.text : null;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 16.0),
|
||||||
|
child: DropdownButtonFormField<String>(
|
||||||
|
value: currentValue,
|
||||||
|
onChanged: readOnly ? null : (newValue) {
|
||||||
|
setState(() {
|
||||||
|
controller.text = newValue ?? '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: label,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
||||||
|
),
|
||||||
|
items: options.entries.map((entry) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: entry.key,
|
||||||
|
child: Text("${entry.key} - ${entry.value}"),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTextField(TextEditingController controller, String label, {TextInputType keyboardType = TextInputType.text, bool readOnly = false}) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 16.0),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: controller,
|
||||||
|
readOnly: readOnly,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: label,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
||||||
|
),
|
||||||
|
keyboardType: keyboardType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
218
lib/features/yojna/screens/pmsby_enquiry_screen.dart
Normal file
218
lib/features/yojna/screens/pmsby_enquiry_screen.dart
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/api/services/yojna_service.dart';
|
||||||
|
import 'package:kmobile/di/injection.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class PMSBYEnquiryScreen extends StatefulWidget {
|
||||||
|
final String? cifNumber;
|
||||||
|
|
||||||
|
const PMSBYEnquiryScreen({
|
||||||
|
super.key,
|
||||||
|
required this.cifNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PMSBYEnquiryScreen> createState() => _PMSBYEnquiryScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PMSBYEnquiryScreenState extends State<PMSBYEnquiryScreen> {
|
||||||
|
String? _selectedFinancialYear;
|
||||||
|
bool _isLoading = false;
|
||||||
|
Map<String, dynamic>? _enquiryData;
|
||||||
|
String? _errorMessage;
|
||||||
|
|
||||||
|
final List<String> _financialYears = [
|
||||||
|
'2021-2022',
|
||||||
|
'2022-2023',
|
||||||
|
'2023-2024',
|
||||||
|
'2024-2025',
|
||||||
|
'2025-2026',
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_selectedFinancialYear = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchEnquiryData() async {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
if (_selectedFinancialYear == null || widget.cifNumber == null) return;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isLoading = true;
|
||||||
|
_enquiryData = null;
|
||||||
|
_errorMessage = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
final formattedYear = _selectedFinancialYear!.replaceAll('-', '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await getIt<YojnaService>().enquiry(
|
||||||
|
scheme: '01',
|
||||||
|
action: 'E',
|
||||||
|
financialyear: formattedYear,
|
||||||
|
customerno: widget.cifNumber,
|
||||||
|
);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
if (response is Map<String, dynamic>) {
|
||||||
|
if (response['status'] == 'FAILED') {
|
||||||
|
_errorMessage = response['message'] ?? l10n.noRecordFound;
|
||||||
|
} else {
|
||||||
|
_enquiryData = response;
|
||||||
|
}
|
||||||
|
} else if (response is List && response.isNotEmpty) {
|
||||||
|
_enquiryData = response[0] as Map<String, dynamic>;
|
||||||
|
} else {
|
||||||
|
_errorMessage = l10n.noDataFoundYear;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
setState(() {
|
||||||
|
_errorMessage = l10n.genericError(e.toString());
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setState(() {
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(l10n.pmsbyDetails),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
elevation: 4,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
leading: const Icon(Icons.person, color: Colors.blue),
|
||||||
|
title: Text(l10n.cifNumber),
|
||||||
|
subtitle: Text(
|
||||||
|
widget.cifNumber ?? l10n.notApplicable,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
DropdownButtonFormField<String>(
|
||||||
|
value: _selectedFinancialYear,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: l10n.selectFinancialYear,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
prefixIcon: const Icon(Icons.calendar_today),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
),
|
||||||
|
items: _financialYears.map((String year) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: year,
|
||||||
|
child: Text(year),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
_selectedFinancialYear = newValue;
|
||||||
|
});
|
||||||
|
_fetchEnquiryData();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
if (_isLoading)
|
||||||
|
const Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(20.0),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (_errorMessage != null)
|
||||||
|
Card(
|
||||||
|
color: Colors.red.shade50,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Text(
|
||||||
|
_errorMessage!,
|
||||||
|
style: TextStyle(color: Colors.red.shade700, fontWeight: FontWeight.bold),
|
||||||
|
//textAlign: Center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else if (_enquiryData != null)
|
||||||
|
Card(
|
||||||
|
elevation: 4,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
l10n.schemeDetails,
|
||||||
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
_buildDetailRow(l10n.customerName, _enquiryData!['customername']),
|
||||||
|
_buildDetailRow(l10n.policyNumber, _enquiryData!['policynumber'] ?? _enquiryData!['policyno']),
|
||||||
|
_buildDetailRow(l10n.accountNumber, _enquiryData!['accountno']),
|
||||||
|
_buildDetailRow(l10n.premiumAmount, _enquiryData!['preimiumamount'] ?? _enquiryData!['premiumamount']),
|
||||||
|
_buildDetailRow(l10n.nomineeName, _enquiryData!['nomineename']),
|
||||||
|
_buildDetailRow(l10n.date, _enquiryData!['transactiondate']),
|
||||||
|
_buildDetailRow(l10n.journalNo, _enquiryData!['journalno']),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDetailRow(String label, dynamic value) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.w500, color: Colors.grey),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
value?.toString() ?? AppLocalizations.of(context).notApplicable,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
350
lib/features/yojna/screens/pmsby_screen.dart
Normal file
350
lib/features/yojna/screens/pmsby_screen.dart
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kmobile/api/services/yojna_service.dart';
|
||||||
|
import 'package:kmobile/di/injection.dart';
|
||||||
|
import 'package:kmobile/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class PMSBYScreen extends StatefulWidget {
|
||||||
|
final Map<String, dynamic>? initialData;
|
||||||
|
const PMSBYScreen({super.key, this.initialData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PMSBYScreen> createState() => _PMSBYScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PMSBYScreenState extends State<PMSBYScreen> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
// Controllers for all requested fields
|
||||||
|
late final _aadhaarController = TextEditingController(text: widget.initialData?['aadharno']?.toString());
|
||||||
|
late final _accountNoController = TextEditingController(text: widget.initialData?['accountno']?.toString());
|
||||||
|
late final _balanceController = TextEditingController(text: widget.initialData?['availablebalance']?.toString());
|
||||||
|
late final _countryController = TextEditingController(text: widget.initialData?['country']?.toString() ?? 'IN');
|
||||||
|
late final _dobController = TextEditingController(text: widget.initialData?['customerdob']?.toString());
|
||||||
|
late final _nameController = TextEditingController(text: widget.initialData?['customername']?.toString());
|
||||||
|
late final _customerNoController = TextEditingController(text: widget.initialData?['customerno']?.toString());
|
||||||
|
late final _acctOpeningDateController = TextEditingController(text: widget.initialData?['dateofacctopening']?.toString());
|
||||||
|
late final _emailController = TextEditingController(text: widget.initialData?['emailid']?.toString());
|
||||||
|
late final _financialYearController = TextEditingController(text: widget.initialData?['financialyear']?.toString());
|
||||||
|
late final _genderController = TextEditingController(text: widget.initialData?['gender']?.toString());
|
||||||
|
late final _ifscController = TextEditingController(text: widget.initialData?['ifsccode']?.toString());
|
||||||
|
late final _marriedController = TextEditingController(text: widget.initialData?['married']?.toString());
|
||||||
|
late final _mobileController = TextEditingController(text: widget.initialData?['mobileno']?.toString());
|
||||||
|
late final _panController = TextEditingController(text: widget.initialData?['pan']?.toString());
|
||||||
|
late final _pincodeController = TextEditingController(text: widget.initialData?['pincode']?.toString());
|
||||||
|
late final _policyNumberController = TextEditingController(text: widget.initialData?['policyno']?.toString());
|
||||||
|
late final _premiumAmountController = TextEditingController(text: widget.initialData?['premiumamount']?.toString());
|
||||||
|
late final _stateController = TextEditingController(text: widget.initialData?['state']?.toString());
|
||||||
|
late final _address1Controller = TextEditingController(text: widget.initialData?['address1']?.toString());
|
||||||
|
late final _address2Controller = TextEditingController(text: widget.initialData?['address2']?.toString());
|
||||||
|
late final _cityController = TextEditingController(text: widget.initialData?['city']?.toString());
|
||||||
|
late final _relationWithNomineeController = TextEditingController(text: widget.initialData?['relationwithnominee']?.toString());
|
||||||
|
late final _policyStatusController = TextEditingController(text: widget.initialData?['policystatus']?.toString());
|
||||||
|
|
||||||
|
// Mapping options
|
||||||
|
final Map<String, String> _healthStatusOptions = {
|
||||||
|
'1': 'Excellent',
|
||||||
|
'2': 'Good',
|
||||||
|
'3': 'Bad',
|
||||||
|
};
|
||||||
|
|
||||||
|
final Map<String, String> _relationshipOptions = {
|
||||||
|
'01': 'Self',
|
||||||
|
'02': 'Wife',
|
||||||
|
'03': 'Father',
|
||||||
|
'04': 'Mother',
|
||||||
|
'05': 'Son',
|
||||||
|
'06': 'Daughter',
|
||||||
|
'07': 'Brother',
|
||||||
|
'08': 'Sister',
|
||||||
|
'09': 'Father-in-law',
|
||||||
|
'10': 'Mother-in-law',
|
||||||
|
'11': 'Grandson',
|
||||||
|
'12': 'Granddaughter',
|
||||||
|
'13': 'Grandfather',
|
||||||
|
'14': 'Grandmother',
|
||||||
|
'15': 'Brother-in-law',
|
||||||
|
'16': 'Sister-in-law',
|
||||||
|
'17': 'Husband',
|
||||||
|
'18': 'Guardian',
|
||||||
|
'99': 'Others',
|
||||||
|
};
|
||||||
|
|
||||||
|
final Map<String, String> _minorOptions = {
|
||||||
|
'Y': 'Yes',
|
||||||
|
'N': 'No',
|
||||||
|
};
|
||||||
|
|
||||||
|
final Map<String, String> _ruralOptions = {
|
||||||
|
'R': 'Rural',
|
||||||
|
'U': 'Urban',
|
||||||
|
'S': 'Semi-Urban',
|
||||||
|
'M': 'Metro',
|
||||||
|
};
|
||||||
|
|
||||||
|
final _healthStatusController = TextEditingController();
|
||||||
|
final _collectionChannelController = TextEditingController();
|
||||||
|
final _nomineeNameController = TextEditingController();
|
||||||
|
final _nomineeAddressController = TextEditingController();
|
||||||
|
final _nomineeRelationshipController = TextEditingController();
|
||||||
|
final _nomineeMinorController = TextEditingController();
|
||||||
|
final _ruralCategoryController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
// Initialize dropdown controllers if data exists in initialData
|
||||||
|
if (widget.initialData != null) {
|
||||||
|
if (widget.initialData!.containsKey('ruralcategory')) {
|
||||||
|
_ruralCategoryController.text = widget.initialData!['ruralcategory'].toString();
|
||||||
|
}
|
||||||
|
if (widget.initialData!.containsKey('healthstatus')) {
|
||||||
|
_healthStatusController.text = widget.initialData!['healthstatus'].toString();
|
||||||
|
}
|
||||||
|
if (widget.initialData!.containsKey('relationwithnominee')) {
|
||||||
|
_nomineeRelationshipController.text = widget.initialData!['relationwithnominee'].toString();
|
||||||
|
}
|
||||||
|
if (widget.initialData!.containsKey('nomineeminor')) {
|
||||||
|
_nomineeMinorController.text = widget.initialData!['nomineeminor'].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_aadhaarController.dispose();
|
||||||
|
_accountNoController.dispose();
|
||||||
|
_balanceController.dispose();
|
||||||
|
_countryController.dispose();
|
||||||
|
_dobController.dispose();
|
||||||
|
_nameController.dispose();
|
||||||
|
_customerNoController.dispose();
|
||||||
|
_acctOpeningDateController.dispose();
|
||||||
|
_emailController.dispose();
|
||||||
|
_financialYearController.dispose();
|
||||||
|
_genderController.dispose();
|
||||||
|
_ifscController.dispose();
|
||||||
|
_marriedController.dispose();
|
||||||
|
_mobileController.dispose();
|
||||||
|
_panController.dispose();
|
||||||
|
_pincodeController.dispose();
|
||||||
|
_policyNumberController.dispose();
|
||||||
|
_premiumAmountController.dispose();
|
||||||
|
_stateController.dispose();
|
||||||
|
_address1Controller.dispose();
|
||||||
|
_address2Controller.dispose();
|
||||||
|
_cityController.dispose();
|
||||||
|
_relationWithNomineeController.dispose();
|
||||||
|
_policyStatusController.dispose();
|
||||||
|
_healthStatusController.dispose();
|
||||||
|
_collectionChannelController.dispose();
|
||||||
|
_nomineeNameController.dispose();
|
||||||
|
_nomineeAddressController.dispose();
|
||||||
|
_nomineeRelationshipController.dispose();
|
||||||
|
_nomineeMinorController.dispose();
|
||||||
|
_ruralCategoryController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isFetched(String key) {
|
||||||
|
return widget.initialData != null &&
|
||||||
|
widget.initialData!.containsKey(key) &&
|
||||||
|
widget.initialData![key]?.toString().isNotEmpty == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleRegister() async {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
// Show loading spinner
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (context) => const Center(child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await getIt<YojnaService>().secondvalidationPMSBY(
|
||||||
|
aadharno: _aadhaarController.text,
|
||||||
|
accountno: _accountNoController.text,
|
||||||
|
address1: _address1Controller.text,
|
||||||
|
address2: _address2Controller.text,
|
||||||
|
availablebalance: _balanceController.text,
|
||||||
|
city: _cityController.text,
|
||||||
|
country: _countryController.text,
|
||||||
|
customerdob: _dobController.text,
|
||||||
|
customername: _nameController.text,
|
||||||
|
customerno: _customerNoController.text,
|
||||||
|
emailid: _emailController.text,
|
||||||
|
financialyear: _financialYearController.text,
|
||||||
|
gender: _genderController.text,
|
||||||
|
married: _marriedController.text,
|
||||||
|
mobileno: _mobileController.text,
|
||||||
|
pan: _panController.text,
|
||||||
|
pincode: _pincodeController.text,
|
||||||
|
policyno: _policyNumberController.text,
|
||||||
|
premiumamount: _premiumAmountController.text,
|
||||||
|
state: _stateController.text,
|
||||||
|
healthstatus: _healthStatusController.text,
|
||||||
|
nomineename: _nomineeNameController.text,
|
||||||
|
nomineeadress: _nomineeAddressController.text,
|
||||||
|
relationwithnominee: _relationWithNomineeController.text,
|
||||||
|
nomineeminor: _nomineeMinorController.text,
|
||||||
|
collectionchannel: _collectionChannelController.text,
|
||||||
|
ruralcategory: _ruralCategoryController.text,
|
||||||
|
policystatus: _policyStatusController.text,
|
||||||
|
);
|
||||||
|
String x = response.toString();
|
||||||
|
if(x.contains('RECORD ALREADY EXISTS')){
|
||||||
|
x= l10n.recordAlreadyExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
// Close loading spinner
|
||||||
|
Navigator.pop(context);
|
||||||
|
// Show response dialog
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text(l10n.response),
|
||||||
|
content: SingleChildScrollView(child: Text(x)),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
|
},
|
||||||
|
child: Text(l10n.close),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.pop(context); // Close loading spinner
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(l10n.genericError(e.toString()))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(l10n.pmsbyRegistration),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
_buildTextField(_nameController, l10n.customerName, readOnly: _isFetched('customername')),
|
||||||
|
_buildTextField(_customerNoController, l10n.customerNo, readOnly: _isFetched('customerno')),
|
||||||
|
_buildTextField(_accountNoController, l10n.accountNumber, keyboardType: TextInputType.number, readOnly: _isFetched('accountno')),
|
||||||
|
_buildTextField(_balanceController, l10n.availableBalance, keyboardType: TextInputType.number, readOnly: _isFetched('availablebalance')),
|
||||||
|
_buildTextField(_aadhaarController, l10n.aadhaarNo, keyboardType: TextInputType.number, readOnly: _isFetched('aadharno')),
|
||||||
|
_buildTextField(_dobController, l10n.customerDobFormat, readOnly: _isFetched('customerdob')),
|
||||||
|
_buildTextField(_genderController, l10n.gender, readOnly: _isFetched('gender')),
|
||||||
|
_buildTextField(_marriedController, l10n.marriedYesNo, readOnly: _isFetched('married')),
|
||||||
|
_buildTextField(_mobileController, l10n.mobileNumber, keyboardType: TextInputType.phone, readOnly: _isFetched('mobileno')),
|
||||||
|
_buildTextField(_emailController, 'Email ID', keyboardType: TextInputType.emailAddress, readOnly: _isFetched('emailid')),
|
||||||
|
_buildTextField(_address1Controller, l10n.address1, readOnly: _isFetched('address1')),
|
||||||
|
_buildTextField(_address2Controller, l10n.address2, readOnly: _isFetched('address2')),
|
||||||
|
_buildTextField(_cityController, l10n.city, readOnly: _isFetched('city')),
|
||||||
|
_buildTextField(_panController, l10n.pan, readOnly: _isFetched('pan')),
|
||||||
|
_buildTextField(_ifscController, l10n.ifscCode, readOnly: _isFetched('ifsccode')),
|
||||||
|
_buildTextField(_acctOpeningDateController, l10n.dateOfAcctOpening, readOnly: _isFetched('dateofacctopening')),
|
||||||
|
_buildTextField(_pincodeController, l10n.pincode, keyboardType: TextInputType.number, readOnly: _isFetched('pincode')),
|
||||||
|
_buildTextField(_stateController, l10n.state, readOnly: _isFetched('state')),
|
||||||
|
_buildTextField(_countryController, l10n.country, readOnly: _isFetched('country')),
|
||||||
|
_buildDropdownField(_ruralCategoryController, l10n.ruralCategory, _ruralOptions, readOnly: _isFetched('ruralcategory')),
|
||||||
|
const Divider(height: 32),
|
||||||
|
Text(l10n.policyDetails, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildTextField(_policyNumberController, l10n.policyNumber, readOnly: _isFetched('policyno')),
|
||||||
|
_buildTextField(_premiumAmountController, l10n.premiumAmount, keyboardType: TextInputType.number, readOnly: _isFetched('premiumamount')),
|
||||||
|
_buildTextField(_financialYearController, l10n.financialYear, readOnly: _isFetched('financialyear')),
|
||||||
|
_buildTextField(_policyStatusController, l10n.policyStatus, readOnly: _isFetched('policystatus')),
|
||||||
|
_buildDropdownField(_healthStatusController, l10n.healthStatus, _healthStatusOptions),
|
||||||
|
_buildTextField(_collectionChannelController, l10n.collectionChannel),
|
||||||
|
const Divider(height: 32),
|
||||||
|
Text(l10n.nomineeDetails, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildTextField(_nomineeNameController, l10n.nomineeName),
|
||||||
|
_buildTextField(_nomineeAddressController, l10n.nomineeAddress),
|
||||||
|
_buildDropdownField(_relationWithNomineeController, l10n.relationWithNominee, _relationshipOptions, readOnly: _isFetched('relationwithnominee')),
|
||||||
|
_buildTextField(_nomineeRelationshipController, l10n.nomineeRelationship),
|
||||||
|
_buildDropdownField(_nomineeMinorController, l10n.nomineeMinor, _minorOptions, readOnly: _isFetched('nomineeminor')),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: _handleRegister,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
l10n.register,
|
||||||
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDropdownField(
|
||||||
|
TextEditingController controller, String label, Map<String, String> options,
|
||||||
|
{bool readOnly = false}) {
|
||||||
|
// Determine current value
|
||||||
|
String? currentValue = options.containsKey(controller.text) ? controller.text : null;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 16.0),
|
||||||
|
child: DropdownButtonFormField<String>(
|
||||||
|
value: currentValue,
|
||||||
|
onChanged: readOnly ? null : (newValue) {
|
||||||
|
setState(() {
|
||||||
|
controller.text = newValue ?? '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: label,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
||||||
|
),
|
||||||
|
items: options.entries.map((entry) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: entry.key,
|
||||||
|
child: Text("${entry.key} - ${entry.value}"),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTextField(TextEditingController controller, String label, {TextInputType keyboardType = TextInputType.text, bool readOnly = false}) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 16.0),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: controller,
|
||||||
|
readOnly: readOnly,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: label,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
|
||||||
|
),
|
||||||
|
keyboardType: keyboardType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user