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(
|
||||
"Kangra Central Co-operative Bank",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 15.5,
|
||||
color: Color.fromARGB(255, 238, 237, 237),
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.visible,
|
||||
maxLines: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -19,7 +19,6 @@ class _CardManagementScreen extends State<CardManagementScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: Text(
|
||||
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),
|
||||
CardManagementTile(
|
||||
|
||||
@@ -45,7 +45,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).cardDetails,
|
||||
AppLocalizations.of(context).changeCardPin,
|
||||
),
|
||||
centerTitle: false,
|
||||
),
|
||||
@@ -66,12 +66,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
enabledBorder: const OutlineInputBorder(),
|
||||
focusedBorder: const OutlineInputBorder(),
|
||||
),
|
||||
keyboardType: TextInputType.number,
|
||||
textInputAction: TextInputAction.next,
|
||||
@@ -92,13 +88,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
filled: true,
|
||||
fillColor:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
enabledBorder: const OutlineInputBorder(),
|
||||
focusedBorder: const OutlineInputBorder(),
|
||||
),
|
||||
keyboardType: TextInputType.number,
|
||||
textInputAction: TextInputAction.next,
|
||||
@@ -123,13 +114,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
filled: true,
|
||||
fillColor:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
enabledBorder: const OutlineInputBorder(),
|
||||
focusedBorder: const OutlineInputBorder(),
|
||||
),
|
||||
validator: (value) => value != null &&
|
||||
value.isNotEmpty
|
||||
@@ -149,12 +135,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
enabledBorder: const OutlineInputBorder(),
|
||||
focusedBorder: const OutlineInputBorder(),
|
||||
),
|
||||
textInputAction: TextInputAction.done,
|
||||
keyboardType: TextInputType.phone,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:kmobile/data/models/user.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:material_symbols_icons/material_symbols_icons.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
@@ -42,8 +44,6 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
child: ChequeManagementCardTile(
|
||||
icon: Symbols.payments,
|
||||
label: AppLocalizations.of(context).chequeEnquiryTitle,
|
||||
subtitle:
|
||||
AppLocalizations.of(context).chequeEnquirySubtitle,
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
@@ -61,7 +61,6 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
child: ChequeManagementCardTile(
|
||||
icon: Symbols.block_sharp,
|
||||
label: AppLocalizations.of(context).stopCheque,
|
||||
subtitle: AppLocalizations.of(context).stopChequeSubtitle,
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
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 {
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final String? subtitle;
|
||||
final VoidCallback onTap;
|
||||
final bool disable;
|
||||
|
||||
@@ -109,7 +141,6 @@ class ChequeManagementCardTile extends StatelessWidget {
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.label,
|
||||
this.subtitle,
|
||||
required this.onTap,
|
||||
this.disable = false,
|
||||
});
|
||||
@@ -152,19 +183,6 @@ class ChequeManagementCardTile extends StatelessWidget {
|
||||
: 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -173,4 +191,4 @@ class ChequeManagementCardTile extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
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/di/injection.dart';
|
||||
// import 'package:flutter/material.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_stop_single_screen.dart';
|
||||
// import 'package:kmobile/l10n/app_localizations.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/cheque/screens/revoke%20_stop_multiple_screen.dart';
|
||||
import 'package:kmobile/features/cheque/screens/revoke_stop_single_screen.dart';
|
||||
import 'package:kmobile/l10n/app_localizations.dart';
|
||||
|
||||
// class RevokeStopChequeScreen extends StatefulWidget {
|
||||
// final List<User> users;
|
||||
// final int selectedIndex;
|
||||
class RevokeStopChequeScreen extends StatefulWidget {
|
||||
final List<User> users;
|
||||
final int selectedIndex;
|
||||
|
||||
// const RevokeStopChequeScreen(
|
||||
// {
|
||||
// super.key,
|
||||
// required this.users,
|
||||
// required this.selectedIndex,
|
||||
// });
|
||||
const RevokeStopChequeScreen(
|
||||
{
|
||||
super.key,
|
||||
required this.users,
|
||||
required this.selectedIndex,
|
||||
});
|
||||
|
||||
// @override
|
||||
// State<RevokeStopChequeScreen> createState() => _RevokeStopChequeScreenState();
|
||||
// }
|
||||
@override
|
||||
State<RevokeStopChequeScreen> createState() => _RevokeStopChequeScreenState();
|
||||
}
|
||||
|
||||
// class _RevokeStopChequeScreenState extends State<RevokeStopChequeScreen> {
|
||||
// User? _selectedAccount;
|
||||
// var service = getIt<ChequeService>();
|
||||
// bool _isLoading = true;
|
||||
// List<Cheque> _stCheques = [];
|
||||
// List<User> _filteredUsers = [];
|
||||
class _RevokeStopChequeScreenState extends State<RevokeStopChequeScreen> {
|
||||
User? _selectedAccount;
|
||||
var service = getIt<ChequeService>();
|
||||
bool _isLoading = true;
|
||||
List<Cheque> _stCheques = [];
|
||||
List<User> _filteredUsers = [];
|
||||
String? _ciFromCheque;
|
||||
String? _ciToCheque;
|
||||
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
// _filteredUsers = widget.users
|
||||
// .where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
|
||||
// .toList();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_filteredUsers = widget.users
|
||||
.where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
|
||||
.toList();
|
||||
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// _loadCheques();
|
||||
// }
|
||||
_loadCheques();
|
||||
}
|
||||
|
||||
// Future<void> _loadCheques() async {
|
||||
// if (_selectedAccount == null) {
|
||||
// setState(() {
|
||||
// _isLoading = false;
|
||||
// _stCheques = [];
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// setState(() {
|
||||
// _isLoading = true;
|
||||
// });
|
||||
Future<void> _loadCheques() async {
|
||||
if (_selectedAccount == null) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
_stCheques = [];
|
||||
});
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
|
||||
// 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';
|
||||
// }
|
||||
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 service.ChequeEnquiry(
|
||||
// accountNumber: _selectedAccount!.accountNo!, instrType: instrType);
|
||||
// final stCheques = data.where((cheque) => cheque.type == 'ST').toList();
|
||||
// setState(() {
|
||||
// _stCheques = stCheques;
|
||||
// _isLoading = false;
|
||||
// });
|
||||
// } catch (e) {
|
||||
// setState(() {
|
||||
// _isLoading = false;
|
||||
// _stCheques = [];
|
||||
// });
|
||||
// ScaffoldMessenger.of(context).showSnackBar(
|
||||
// SnackBar(
|
||||
// content: Text('Failed to fetch cheque status: ${e.toString()}'),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
try {
|
||||
final data = await service.ChequeEnquiry(
|
||||
accountNumber: _selectedAccount!.accountNo!, instrType: instrType);
|
||||
final stCheques = data.where((cheque) => cheque.type == 'ST').toList();
|
||||
final ciCheque = data.where((cheque) => cheque.type == 'CI').toList();
|
||||
setState(() {
|
||||
_stCheques = stCheques;
|
||||
if (ciCheque.isNotEmpty) {
|
||||
_ciFromCheque = ciCheque.first.fromCheque;
|
||||
_ciToCheque = ciCheque.first.toCheque;
|
||||
} else {
|
||||
_ciFromCheque = null;
|
||||
_ciToCheque = null;
|
||||
}
|
||||
_isLoading = false;
|
||||
});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
_stCheques = [];
|
||||
});
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Failed to fetch cheque status: ${e.toString()}'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// String _getAccountTypeDisplayName(String accountType) {
|
||||
// switch (accountType.toLowerCase()) {
|
||||
// case 'sa':
|
||||
// return AppLocalizations.of(context).savingsAccount;
|
||||
// case 'sb':
|
||||
// return AppLocalizations.of(context).savingsAccount;
|
||||
// case 'ca':
|
||||
// return "Current Account";
|
||||
// case 'cc':
|
||||
// return "Cash Credit Account";
|
||||
// default:
|
||||
// return accountType;
|
||||
// }
|
||||
// }
|
||||
String _getAccountTypeDisplayName(String accountType) {
|
||||
switch (accountType.toLowerCase()) {
|
||||
case 'sa':
|
||||
return AppLocalizations.of(context).savingsAccount;
|
||||
case 'sb':
|
||||
return AppLocalizations.of(context).savingsAccount;
|
||||
case 'ca':
|
||||
return "Current Account";
|
||||
case 'cc':
|
||||
return "Cash Credit Account";
|
||||
default:
|
||||
return accountType;
|
||||
}
|
||||
}
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return Scaffold(
|
||||
// appBar: AppBar(
|
||||
// title: Text(AppLocalizations.of(context).revokeStop),
|
||||
// centerTitle: false,
|
||||
// ),
|
||||
// body: Stack(
|
||||
// children: [
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.all(16.0),
|
||||
// child: Column(children: [
|
||||
// Card(
|
||||
// elevation: 4,
|
||||
// margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(16.0),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// AppLocalizations.of(context).accountNumber,
|
||||
// style: const TextStyle(
|
||||
// fontWeight: FontWeight.bold, fontSize: 18),
|
||||
// ),
|
||||
// const SizedBox(width: 16),
|
||||
// if (_selectedAccount != null)
|
||||
// Expanded(
|
||||
// child: DropdownButton<User>(
|
||||
// value: _selectedAccount,
|
||||
// onChanged: (User? newUser) {
|
||||
// if (newUser != null) {
|
||||
// setState(() {
|
||||
// _selectedAccount = newUser;
|
||||
// _loadCheques();
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// items: _filteredUsers.map((user) {
|
||||
// return DropdownMenuItem<User>(
|
||||
// value: user,
|
||||
// child: Text(user.accountNo.toString()),
|
||||
// );
|
||||
// }).toList(),
|
||||
// ),
|
||||
// )
|
||||
// else
|
||||
// Text(AppLocalizations.of(context).noAccountsFound),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 20),
|
||||
// Row(
|
||||
// children: [
|
||||
// Expanded(
|
||||
// child: Card(
|
||||
// color: Theme.of(context).colorScheme.primaryContainer,
|
||||
// elevation: 4,
|
||||
// child: InkWell(
|
||||
// onTap: () {
|
||||
// if (_selectedAccount != null &&
|
||||
// _stCheques.isNotEmpty) {
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) =>
|
||||
// RevokeStopSingleChequeScreen(
|
||||
// selectedAccount: _selectedAccount!,
|
||||
// date: _stCheques.first.Date!,
|
||||
// instrType: _stCheques.first.InstrType!,
|
||||
// fromCheque: _stCheques.first.fromCheque!,
|
||||
// toCheque: _stCheques.first.toCheque!,
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// } else {
|
||||
// ScaffoldMessenger.of(context).showSnackBar(
|
||||
// const SnackBar(
|
||||
// content: Text("No stopped cheques present"),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// },
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(16.0),
|
||||
// child: Center(
|
||||
// child: Text(
|
||||
// AppLocalizations.of(context).revokeSingleStopTitle,
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Theme.of(context)
|
||||
// .colorScheme
|
||||
// .onPrimaryContainer,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 10),
|
||||
// Expanded(
|
||||
// child: Card(
|
||||
// color: Theme.of(context).colorScheme.primaryContainer,
|
||||
// elevation: 4,
|
||||
// child: InkWell(
|
||||
// onTap: () {
|
||||
// if (_selectedAccount != null &&
|
||||
// _stCheques.isNotEmpty) {
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) =>
|
||||
// RevokeStopMultipleChequesScreen(
|
||||
// selectedAccount: _selectedAccount!,
|
||||
// date: _stCheques.first.Date!,
|
||||
// instrType: _stCheques.first.InstrType!,
|
||||
// fromCheque: _stCheques.first.fromCheque!,
|
||||
// toCheque: _stCheques.first.toCheque!,
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// } else {
|
||||
// ScaffoldMessenger.of(context).showSnackBar(
|
||||
// SnackBar(
|
||||
// content: Text(AppLocalizations.of(context)
|
||||
// .pleaseSelectAccountFirst),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// },
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(16.0),
|
||||
// child: Center(
|
||||
// child: Text(
|
||||
// AppLocalizations.of(context).revokeMultipleStops,
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Theme.of(context)
|
||||
// .colorScheme
|
||||
// .onSecondaryContainer,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(height: 20),
|
||||
// Expanded(
|
||||
// child: _isLoading
|
||||
// ? const Center(child: CircularProgressIndicator())
|
||||
// : _stCheques.isEmpty
|
||||
// ? Center(
|
||||
// child: Text(AppLocalizations.of(context)
|
||||
// .noChequeIssuedStatus))
|
||||
// : ListView.builder(
|
||||
// itemCount: _stCheques.length,
|
||||
// itemBuilder: (context, index) {
|
||||
// return _buildSTTile(context, _stCheques[index]);
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ]),
|
||||
// ),
|
||||
// IgnorePointer(
|
||||
// child: Center(
|
||||
// child: Opacity(
|
||||
// opacity: 0.07, // Reduced opacity
|
||||
// child: ClipOval(
|
||||
// child: Image.asset(
|
||||
// 'assets/images/logo.png',
|
||||
// width: 200, // Adjust size as needed
|
||||
// height: 200, // Adjust size as needed
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(AppLocalizations.of(context).revokeStop),
|
||||
centerTitle: false,
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(children: [
|
||||
Card(
|
||||
elevation: 4,
|
||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).accountNumber,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 18),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
if (_selectedAccount != null)
|
||||
Expanded(
|
||||
child: DropdownButton<User>(
|
||||
value: _selectedAccount,
|
||||
onChanged: (User? newUser) {
|
||||
if (newUser != null) {
|
||||
setState(() {
|
||||
_selectedAccount = newUser;
|
||||
_loadCheques();
|
||||
});
|
||||
}
|
||||
},
|
||||
items: _filteredUsers.map((user) {
|
||||
return DropdownMenuItem<User>(
|
||||
value: user,
|
||||
child: Text(user.accountNo.toString()),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
)
|
||||
else
|
||||
Text(AppLocalizations.of(context).noAccountsFound),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Card(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
elevation: 4,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (_selectedAccount != null &&
|
||||
_stCheques.isNotEmpty) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
RevokeStopSingleChequeScreen(
|
||||
selectedAccount: _selectedAccount!,
|
||||
date: _stCheques.first.Date!,
|
||||
instrType: _stCheques.first.InstrType!,
|
||||
fromCheque: _ciFromCheque ?? _stCheques.first.fromCheque!,
|
||||
toCheque: _ciToCheque ?? _stCheques.first.toCheque!,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text("No stopped cheques present"),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Center(
|
||||
child: Text(
|
||||
AppLocalizations.of(context).revokeSingleStopTitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Card(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
elevation: 4,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (_selectedAccount != null &&
|
||||
_stCheques.isNotEmpty) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
RevokeStopMultipleChequesScreen(
|
||||
selectedAccount: _selectedAccount!,
|
||||
date: _stCheques.first.Date!,
|
||||
instrType: _stCheques.first.InstrType!,
|
||||
fromCheque: _ciFromCheque ?? _stCheques.first.fromCheque!,
|
||||
toCheque: _ciToCheque ?? _stCheques.first.toCheque!,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(AppLocalizations.of(context)
|
||||
.pleaseSelectAccountFirst),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Center(
|
||||
child: Text(
|
||||
AppLocalizations.of(context).revokeMultipleStops,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: _isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: _stCheques.isEmpty
|
||||
? Center(
|
||||
child: Text(AppLocalizations.of(context)
|
||||
.noChequeIssuedStatus))
|
||||
: ListView.builder(
|
||||
itemCount: _stCheques.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildSTTile(context, _stCheques[index]);
|
||||
},
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
IgnorePointer(
|
||||
child: Center(
|
||||
child: Opacity(
|
||||
opacity: 0.07, // Reduced opacity
|
||||
child: ClipOval(
|
||||
child: Image.asset(
|
||||
'assets/images/logo.png',
|
||||
width: 200, // Adjust size as needed
|
||||
height: 200, // Adjust size as needed
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Widget _buildSTTile(BuildContext context, Cheque cheque) {
|
||||
// return Card(
|
||||
// margin: const EdgeInsets.symmetric(
|
||||
// vertical: 8.0,
|
||||
// ),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(16.0),
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Text(AppLocalizations.of(context).stopChequeLabel,
|
||||
// style: Theme.of(context).textTheme.titleLarge),
|
||||
// const SizedBox(height: 8),
|
||||
// _buildInfoRow('From Cheque:', cheque.fromCheque),
|
||||
// _buildInfoRow('To Cheque:', cheque.toCheque),
|
||||
// _buildInfoRow('Account Type:',
|
||||
// _getAccountTypeDisplayName(_selectedAccount!.accountType!)),
|
||||
// _buildInfoRow('Branch Code:', cheque.branchCode),
|
||||
// _buildInfoRow('Stop Issue Date:', cheque.stopIssueDate),
|
||||
// _buildInfoRow('Stop Expiry Date:', cheque.StopExpiryDate),
|
||||
// _buildInfoRow('Cheques Count:', cheque.Chequescount),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
Widget _buildSTTile(BuildContext context, Cheque cheque) {
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(AppLocalizations.of(context).stopChequeLabel,
|
||||
style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 8),
|
||||
_buildInfoRow('From Cheque:', cheque.fromCheque),
|
||||
_buildInfoRow('To Cheque:', cheque.toCheque),
|
||||
_buildInfoRow('Account Type:',
|
||||
_getAccountTypeDisplayName(_selectedAccount!.accountType!)),
|
||||
_buildInfoRow('Branch Code:', cheque.branchCode),
|
||||
_buildInfoRow('Stop Issue Date:', cheque.stopIssueDate),
|
||||
_buildInfoRow('Stop Expiry Date:', cheque.StopExpiryDate),
|
||||
_buildInfoRow('Cheques Count:', cheque.Chequescount),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Widget _buildInfoRow(String label, String? value) {
|
||||
// return Padding(
|
||||
// padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
// Text(value ?? ''),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
Widget _buildInfoRow(String label, String? value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
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;
|
||||
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'];
|
||||
@@ -323,6 +324,10 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
|
||||
}
|
||||
_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 =
|
||||
|
||||
@@ -278,7 +278,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
||||
);
|
||||
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'];
|
||||
@@ -293,12 +293,16 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
|
||||
}
|
||||
_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') &&
|
||||
final errorBody = jsonDecode(errorBodyString);
|
||||
if (errorBody.containsKey('error') &&
|
||||
errorBody['error'] == 'INCORRECT_TPIN') {
|
||||
_showResponseDialog('Invalid TPIN',
|
||||
'The TPIN you entered is incorrect. Please try again.');
|
||||
|
||||
@@ -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/customer_info/screens/customer_info_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/profile/profile_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/yojna/screens/gov_scheme_screen.dart';
|
||||
import 'package:kmobile/security/secure_storage.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
@@ -636,13 +636,14 @@ class _DashboardScreenState extends State<DashboardScreen>
|
||||
ManageBeneficiariesScreen(
|
||||
customerName: currAccount.name!)));
|
||||
}, disable: false),
|
||||
_buildQuickLink(Symbols.support_agent,
|
||||
AppLocalizations.of(context).contactUs, () {
|
||||
_buildQuickLink(Symbols.family_group,
|
||||
AppLocalizations.of(context).governmentSchemes, () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const EnquiryScreen()));
|
||||
GovSchemeScreen(users: users,
|
||||
selectedIndex: selectedAccountIndex)));
|
||||
}),
|
||||
_buildQuickLink(
|
||||
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/enquiry_screen.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
@@ -43,7 +46,6 @@ class _ServiceScreen extends State<ServiceScreen> {
|
||||
disabled: false,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ServiceManagementTile(
|
||||
icon: Symbols.question_mark,
|
||||
@@ -57,7 +59,6 @@ class _ServiceScreen extends State<ServiceScreen> {
|
||||
disabled: false,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: ServiceManagementTile(
|
||||
icon: Symbols.location_pin,
|
||||
@@ -71,7 +72,46 @@ class _ServiceScreen extends State<ServiceScreen> {
|
||||
disabled: false,
|
||||
),
|
||||
),
|
||||
// No Spacer() needed here as Expanded children will fill space
|
||||
// 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
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -122,32 +162,33 @@ class ServiceManagementTile extends StatelessWidget {
|
||||
onTap:
|
||||
disabled ? null : onTap, // Disable InkWell if the tile is disabled
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 48, // Make icon larger
|
||||
color:
|
||||
disabled ? theme.disabledColor : theme.colorScheme.primary,
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 48, // Make icon larger
|
||||
color:
|
||||
disabled ? theme.disabledColor : theme.colorScheme.primary,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
label,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: disabled
|
||||
? theme.disabledColor
|
||||
: theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
label,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: disabled
|
||||
? theme.disabledColor
|
||||
: theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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