diff --git a/lib/api/services/cheque_service.dart b/lib/api/services/cheque_service.dart new file mode 100644 index 0000000..70db445 --- /dev/null +++ b/lib/api/services/cheque_service.dart @@ -0,0 +1,138 @@ +import 'dart:convert'; + +import 'package:dio/dio.dart'; + +class Cheque { + final String? type; + final String? InstrType; + final String? Date; + final String? branchCode; + final String? fromCheque; + final String? toCheque; + final String? Chequescount; + final String? ChequeNumber; + final String? transactionCode; + final int? amount; + final String? status; + final String? stopIssueDate; + final String? StopExpiryDate; + + Cheque({ + this.type, + this.InstrType, + this.Date, + this.branchCode, + this.fromCheque, + this.toCheque, + this.Chequescount, + this.ChequeNumber, + this.transactionCode, + this.amount, + this.status, + this.stopIssueDate, + this.StopExpiryDate, + }); + + factory Cheque.fromJson(Map json) { + return Cheque( + type: json['type'] ?? '', + InstrType: json['InstrType'] ?? '', + Date: json['Date'] ?? '', + branchCode: json['branchCode'] ?? '', + fromCheque: json['fromCheque'] ?? '', + toCheque: json['toCheque'] ?? '', + Chequescount: json['Chequescount'] ?? '', + ChequeNumber: json['ChequeNumber'] ?? '', + transactionCode: json['transactionCode'] ?? '', + amount: json['amount'], + status: json['status'] ?? '', + stopIssueDate: json['stopIssueDate'] ?? '', + StopExpiryDate: json['StopExpiryDate'] ?? '', + ); + } + + static List listFromJson(List jsonList) { + final chequeList = + jsonList.map((cheque) => Cheque.fromJson(cheque)).toList(); + return chequeList; + } +} + +class ChequeService { + final Dio _dio; + ChequeService(this._dio); + + Future> ChequeEnquiry({ + required String accountNumber, + required String instrType, + }) async { + try { + final response = await _dio.get( + "/api/cheque/enquiry", + queryParameters: { + 'accountNumber': accountNumber, + 'instrumentType': instrType, + }, + options: Options( + headers: { + "Content-Type": "application/json", + }, + ), + ); + + if (response.statusCode == 200) { + if (response.data is Map && + response.data.containsKey('records')) { + final records = response.data['records']; + if (records is List) { + return Cheque.listFromJson(records); + } + } + throw Exception( + "Unexpected API response format: 'records' list not found or malformed"); + } else { + throw Exception("Failed to fetch"); + } + } catch (e) { + print('Error in ChequeEnquiry: $e'); + throw e; + } + } + + Future stopCheque({ + required String accountno, + required String stopFromChequeNo, + required String instrType, + String? stopToChequeNo, + String? stopIssueDate, + String? stopExpiryDate, + String? stopAmount, + String? stopComment, + String? chequeIssueDate, + required String tpin, + }) async { + final response = await _dio.post( + '/api/cheque/stop', + options: Options( + validateStatus: (int? status) => true, + receiveDataWhenStatusError: true, + ), + data: { + 'accountNumber': accountno, + 'stopFromChequeNo': stopFromChequeNo, + 'instrumentType': instrType, + 'stopToChequeNo': stopToChequeNo, + 'stopIssueDate': stopIssueDate, + 'stopExpiryDate': stopExpiryDate, + 'stopAmount': stopAmount, + 'stopComment': stopComment, + 'chqIssueDate': chequeIssueDate, + 'tpin': tpin, + }, + ); + if (response.statusCode != 200) { + throw Exception(jsonEncode(response.data)); + } + return response.toString(); + } +} diff --git a/lib/di/injection.dart b/lib/di/injection.dart index 0e7aabc..43826f1 100644 --- a/lib/di/injection.dart +++ b/lib/di/injection.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:kmobile/api/services/branch_service.dart'; +import 'package:kmobile/api/services/cheque_service.dart'; import 'package:kmobile/api/services/limit_service.dart'; import 'package:kmobile/api/services/rtgs_service.dart'; import 'package:kmobile/api/services/neft_service.dart'; @@ -56,6 +57,7 @@ Future setupDependencies() async { getIt.registerSingleton(RtgsService(getIt())); getIt.registerSingleton(ImpsService(getIt())); getIt.registerSingleton(BranchService(getIt())); + getIt.registerSingleton(ChequeService(getIt())); getIt.registerLazySingleton( () => ChangePasswordService(getIt()), ); @@ -74,7 +76,7 @@ Dio _createDioClient() { final dio = Dio( BaseOptions( baseUrl: - 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', //test + 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com', //test //'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod //'https://kccbmbnk.net', //prod small connectTimeout: const Duration(seconds: 60), diff --git a/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart b/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart index 0b82538..50ffe95 100644 --- a/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart +++ b/lib/features/beneficiaries/screens/manage_beneficiaries_screen.dart @@ -147,7 +147,8 @@ class _ManageBeneficiariesScreen extends State { child: TextField( controller: _searchController, decoration: InputDecoration( - hintText: "Search by name or account number", + hintText: + AppLocalizations.of(context).searchByNameOrAccountHint, prefixIcon: const Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), diff --git a/lib/features/cheque/screens/cheque_enquiry_screen.dart b/lib/features/cheque/screens/cheque_enquiry_screen.dart new file mode 100644 index 0000000..7f17a2a --- /dev/null +++ b/lib/features/cheque/screens/cheque_enquiry_screen.dart @@ -0,0 +1,361 @@ +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/l10n/app_localizations.dart'; + +class ChequeEnquiryScreen extends StatefulWidget { + final List users; + final int selectedIndex; + const ChequeEnquiryScreen({ + super.key, + required this.users, + required this.selectedIndex, + }); + + @override + State createState() => _ChequeEnquiryScreenState(); +} + +class _ChequeEnquiryScreenState extends State { + User? _selectedAccount; + final TextEditingController _searchController = TextEditingController(); + var service = getIt(); + bool _isLoading = true; + List _allCheques = []; + Map> _groupedCheques = {}; + List _filteredUsers = []; + + @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; + } + } + + _loadCheques(); + _searchController.addListener(() { + _filterCheques(_searchController.text); + }); + } + + Future _loadCheques() async { + if (_selectedAccount == null) { + setState(() { + _isLoading = false; + _groupedCheques = {}; + }); + 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'; + } + + try { + final data = await service.ChequeEnquiry( + accountNumber: _selectedAccount!.accountNo!, instrType: instrType); + _allCheques = data; + _groupedCheques.clear(); + for (var cheque in _allCheques) { + if (cheque.type != null) { + if (!_groupedCheques.containsKey(cheque.type)) { + _groupedCheques[cheque.type!] = []; + } + _groupedCheques[cheque.type!]!.add(cheque); + } + } + setState(() { + _isLoading = false; + }); + } catch (e) { + setState(() { + _isLoading = false; + _groupedCheques = {}; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to fetch cheque status: ${e.toString()}'), + ), + ); + } + } + + void _filterCheques(String query) { + _groupedCheques.clear(); + List filteredCheques; + if (query.isEmpty) { + filteredCheques = _allCheques; + } else { + filteredCheques = _allCheques.where((cheque) { + final lowerQuery = query.toLowerCase(); + return (cheque.ChequeNumber?.toLowerCase().contains(lowerQuery) ?? + false) || + (cheque.status?.toLowerCase().contains(lowerQuery) ?? false) || + (cheque.fromCheque?.toLowerCase().contains(lowerQuery) ?? false) || + (cheque.toCheque?.toLowerCase().contains(lowerQuery) ?? false); + }).toList(); + } + + for (var cheque in filteredCheques) { + if (cheque.type != null) { + if (!_groupedCheques.containsKey(cheque.type)) { + _groupedCheques[cheque.type!] = []; + } + _groupedCheques[cheque.type!]!.add(cheque); + } + } + + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(AppLocalizations.of(context).chequeEnquiryTitle), + 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( + value: _selectedAccount, + onChanged: (User? newUser) { + if (newUser != null) { + setState(() { + _selectedAccount = newUser; + _loadCheques(); + }); + } + }, + items: _filteredUsers.map((user) { + return DropdownMenuItem( + value: user, + child: Text(user.accountNo.toString()), + ); + }).toList(), + ), + ) + else + const Text('No accounts found'), + ], + ), + ), + ), + const SizedBox(height: 20), + Card( + elevation: 4, + margin: const EdgeInsets.symmetric(vertical: 8.0), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: TextField( + controller: _searchController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context) + .searchByChequeDetailsHint, + prefixIcon: const Icon(Icons.search), + border: InputBorder + .none, // Remove border to make it look like it's inside the card + ), + ), + ), + ), + const SizedBox(height: 20), + Expanded( + child: _isLoading + ? const Center(child: CircularProgressIndicator()) + : _groupedCheques.isEmpty + ? Center( + child: Text(AppLocalizations.of(context) + .noChequeStatusFound)) + : ListView( + children: _groupedCheques.entries.map((entry) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ...entry.value.map((cheque) => + ChequeStatusTile(cheque: cheque)), + ], + ); + }).toList(), + ), + ), + ], + ), + ), + 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 + ), + ), + ), + ), + ), + ], + ), + ); + } +} + +class ChequeStatusTile extends StatelessWidget { + final Cheque cheque; + + const ChequeStatusTile({ + super.key, + required this.cheque, + }); + + @override + Widget build(BuildContext context) { + switch (cheque.type) { + case 'CI': + return _buildCiTile(context); + case 'PR': + return _buildPrTile(context); + case 'ST': + return _buildStTile(context); + default: + return const SizedBox.shrink(); + } + } + + Widget _buildCiTile(BuildContext context) { + 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).chequebookIssuedLabel, + style: Theme.of(context).textTheme.titleLarge), + const SizedBox(height: 8), + _buildInfoRow('Branch Code:', cheque.branchCode), + _buildInfoRow('From Cheque:', cheque.fromCheque), + _buildInfoRow('To Cheque:', cheque.toCheque), + _buildInfoRow('Date:', cheque.Date), + _buildInfoRow('Cheques Count:', cheque.Chequescount), + ], + ), + ), + ); + } + + Widget _buildPrTile(BuildContext context) { + 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).presentedChequeLabel, + style: Theme.of(context).textTheme.titleLarge), + const SizedBox(height: 8), + _buildInfoRow('Branch Code:', cheque.branchCode), + _buildInfoRow('Cheque Number:', cheque.ChequeNumber), + _buildInfoRow('Date:', cheque.Date), + _buildInfoRow('Transaction Code:', cheque.transactionCode), + _buildInfoRow('Amount:', '₹ ${cheque.amount.toString()}'), + _buildInfoRow('Status:', cheque.status), + ], + ), + ), + ); + } + + Widget _buildStTile(BuildContext context) { + 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('Branch Code:', cheque.branchCode), + _buildInfoRow('From Cheque:', cheque.fromCheque), + _buildInfoRow('To Cheque:', cheque.toCheque), + _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 ?? ''), + ], + ), + ); + } +} diff --git a/lib/features/cheque/screens/cheque_management_screen.dart b/lib/features/cheque/screens/cheque_management_screen.dart index fa0a4c5..1cb5267 100644 --- a/lib/features/cheque/screens/cheque_management_screen.dart +++ b/lib/features/cheque/screens/cheque_management_screen.dart @@ -1,16 +1,27 @@ import 'package:flutter/material.dart'; -import 'package:kmobile/features/enquiry/screens/enquiry_screen.dart'; +import 'package:kmobile/data/models/user.dart'; +import 'package:kmobile/features/cheque/screens/cheque_enquiry_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'; class ChequeManagementScreen extends StatefulWidget { - const ChequeManagementScreen({super.key}); + final List users; + final int selectedIndex; + const ChequeManagementScreen({ + super.key, + required this.users, + required this.selectedIndex, + }); @override State createState() => _ChequeManagementScreen(); } class _ChequeManagementScreen extends State { + List get users => widget.users; + int get selectedAccountIndex => widget.selectedIndex; + @override Widget build(BuildContext context) { return Scaffold( @@ -22,52 +33,50 @@ class _ChequeManagementScreen extends State { ), body: Stack( children: [ - ListView( - children: [ - const SizedBox(height: 15), - ChequeManagementTile( - icon: Symbols.add, - label: AppLocalizations.of(context).requestChequeBook, - onTap: () {}, - ), - Divider(height: 1, color: Theme.of(context).dividerColor), - ChequeManagementTile( - icon: Symbols.data_alert, - label: AppLocalizations.of(context).enquiry, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const EnquiryScreen()), - ); - }, - ), - Divider(height: 1, color: Theme.of(context).dividerColor), - ChequeManagementTile( - icon: Symbols.approval_delegation, - label: AppLocalizations.of(context).chequeDeposit, - onTap: () {}, - ), - Divider(height: 1, color: Theme.of(context).dividerColor), - ChequeManagementTile( - icon: Symbols.front_hand, - label: AppLocalizations.of(context).stopCheque, - onTap: () {}, - ), - Divider(height: 1, color: Theme.of(context).dividerColor), - ChequeManagementTile( - icon: Symbols.cancel_presentation, - label: AppLocalizations.of(context).revokeStop, - onTap: () {}, - ), - Divider(height: 1, color: Theme.of(context).dividerColor), - ChequeManagementTile( - icon: Symbols.payments, - label: AppLocalizations.of(context).positivePay, - onTap: () {}, - ), - Divider(height: 1, color: Theme.of(context).dividerColor), - ], + Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ChequeManagementCardTile( + icon: Symbols.payments, + label: AppLocalizations.of(context).chequeEnquiryTitle, + subtitle: + AppLocalizations.of(context).chequeEnquirySubtitle, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChequeEnquiryScreen( + users: users, + selectedIndex: selectedAccountIndex, + ), + ), + ); + }, + ), + ), + Expanded( + child: ChequeManagementCardTile( + icon: Symbols.block_sharp, + label: AppLocalizations.of(context).stopCheque, + subtitle: AppLocalizations.of(context).stopChequeSubtitle, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StopChequeScreen( + users: users, + selectedIndex: selectedAccountIndex, + ), + ), + ); + }, + ), + ), + ], + ), ), IgnorePointer( child: Center( @@ -89,25 +98,79 @@ class _ChequeManagementScreen extends State { } } -class ChequeManagementTile extends StatelessWidget { +class ChequeManagementCardTile extends StatelessWidget { final IconData icon; final String label; + final String? subtitle; final VoidCallback onTap; + final bool disable; - const ChequeManagementTile({ + const ChequeManagementCardTile({ super.key, required this.icon, required this.label, + this.subtitle, required this.onTap, + this.disable = false, }); @override Widget build(BuildContext context) { - return ListTile( - leading: Icon(icon), - title: Text(label), - trailing: const Icon(Symbols.arrow_right, size: 20), - onTap: onTap, + 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, // Add some elevation for better visual separation + child: InkWell( + onTap: + disable ? 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: Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 48, // Make icon larger + 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, + ), + ), + 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, + ), + ), + ), + ], + ), + ), + ), + ), + ), ); } } diff --git a/lib/features/cheque/screens/stop_cheque_screen.dart b/lib/features/cheque/screens/stop_cheque_screen.dart new file mode 100644 index 0000000..46556ea --- /dev/null +++ b/lib/features/cheque/screens/stop_cheque_screen.dart @@ -0,0 +1,349 @@ +import 'package:flutter/material.dart'; +import 'package:kmobile/features/cheque/screens/stop_multiple_cheques_screen.dart'; +import 'package:kmobile/features/cheque/screens/stop_single_cheque_screen.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/l10n/app_localizations.dart'; + +class StopChequeScreen extends StatefulWidget { + final List users; + final int selectedIndex; + const StopChequeScreen({ + super.key, + required this.users, + required this.selectedIndex, + }); + + @override + State createState() => _StopChequeScreenState(); +} + +class _StopChequeScreenState extends State { + User? _selectedAccount; + var service = getIt(); + bool _isLoading = true; + Cheque? _ciCheque; + List _filteredUsers = []; + + @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; + } + } + + _loadCheques(); + } + + Future _loadCheques() async { + if (_selectedAccount == null) { + setState(() { + _isLoading = false; + _ciCheque = null; + }); + 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'; + } + + try { + final data = await service.ChequeEnquiry( + accountNumber: _selectedAccount!.accountNo!, instrType: instrType); + final ciCheques = data.where((cheque) => cheque.type == 'CI').toList(); + setState(() { + _ciCheque = ciCheques.isNotEmpty ? ciCheques.first : null; + _isLoading = false; + }); + } catch (e) { + setState(() { + _isLoading = false; + _ciCheque = null; + }); + 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; + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(AppLocalizations.of(context).stopChequeTitle), + 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( + value: _selectedAccount, + onChanged: (User? newUser) { + if (newUser != null) { + setState(() { + _selectedAccount = newUser; + _loadCheques(); + }); + } + }, + items: _filteredUsers.map((user) { + return DropdownMenuItem( + 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 && _ciCheque != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StopSingleChequeScreen( + selectedAccount: _selectedAccount!, + date: _ciCheque!.Date!, + instrType: _ciCheque!.InstrType!, + fromCheque: _ciCheque!.fromCheque!, + toCheque: _ciCheque!.toCheque!, + ), + ), + ); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context) + .noChequebookToStop), + ), + ); + } + }, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Center( + child: Text( + AppLocalizations.of(context) + .stopSingleChequeTitle, + 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) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + StopMultipleChequesScreen( + selectedAccount: _selectedAccount!, + date: _ciCheque!.Date!, + instrType: _ciCheque!.InstrType!, + fromCheque: _ciCheque!.fromCheque!, + toCheque: _ciCheque!.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) + .stopMultipleChequesButton, + 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()) + : _ciCheque == null + ? Center( + child: Text(AppLocalizations.of(context) + .noChequeIssuedStatus)) + : _buildCiTile(context, _ciCheque!), + ), + ], + ), + ), + 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 _buildCiTile(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).chequebookDetailsTitle, + style: Theme.of(context).textTheme.titleLarge), + const SizedBox(height: 8), + _buildInfoRow('Account Number:', _selectedAccount!.accountNo!), + _buildInfoRow('Customer Name:', _selectedAccount!.name!), + _buildInfoRow('CIF Number:', _selectedAccount!.cifNumber!), + _buildInfoRow('Account Type:', + _getAccountTypeDisplayName(_selectedAccount!.accountType!)), + _buildInfoRow('Branch Code:', cheque.branchCode), + _buildInfoRow('Starting Cheque Number:', cheque.fromCheque), + _buildInfoRow('Ending Cheque Number:', cheque.toCheque), + _buildInfoRow('Issue Date:', cheque.Date), + _buildInfoRow('Number of Cheques:', cheque.Chequescount), + _buildInfoRow('Instrument Type:', cheque.InstrType), + ], + ), + ), + ); + } + + 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 ?? ''), + ], + ), + ); + } +} diff --git a/lib/features/cheque/screens/stop_multiple_cheques_screen.dart b/lib/features/cheque/screens/stop_multiple_cheques_screen.dart new file mode 100644 index 0000000..607e543 --- /dev/null +++ b/lib/features/cheque/screens/stop_multiple_cheques_screen.dart @@ -0,0 +1,287 @@ +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 StopMultipleChequesScreen extends StatefulWidget { + final User selectedAccount; + final String date; + final String instrType; + final String fromCheque; + final String toCheque; + + const StopMultipleChequesScreen( + {super.key, + required this.selectedAccount, + required this.date, + required this.instrType, + required this.fromCheque, + required this.toCheque}); + + @override + State createState() => + _StopMultipleChequesScreenState(); +} + +class _StopMultipleChequesScreenState extends State { + final _formKey = GlobalKey(); + final _stopFromChequeNoController = TextEditingController(); + final _stopToChequeNoController = TextEditingController(); + final _stopIssueDateController = TextEditingController(); + final _stopExpiryDateController = TextEditingController(); + final _stopAmountController = TextEditingController(); + final _stopCommentController = TextEditingController(); + final _chequeService = getIt(); + + String _formatDate(String dateString) { + if (dateString.length != 8) { + return dateString; // Return as is if not in expected ddmmyyyy format + } + try { + final day = dateString.substring(0, 2); + final month = dateString.substring(2, 4); + final year = dateString.substring(4, 8); + return '$day/$month/$year'; + } catch (e) { + return dateString; // Return original string on error + } + } + + Future _showResponseDialog(String title, String message) async { + return showDialog( + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: Text(title), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text(message), + ], + ), + ), + actions: [ + TextButton( + child: const Text('Close'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(AppLocalizations.of(context).stopMultipleChequesTitle), + ), + 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(), + ), + 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(), + ), + 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, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).stopIssueDateHint, + border: const OutlineInputBorder(), + ), + keyboardType: TextInputType.datetime, + ), + const SizedBox(height: 16), + TextFormField( + controller: _stopExpiryDateController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).stopExpiryDateHint, + border: const OutlineInputBorder(), + ), + keyboardType: TextInputType.datetime, + ), + const SizedBox(height: 16), + TextFormField( + controller: _stopAmountController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).stopAmountHint, + border: const OutlineInputBorder(), + ), + keyboardType: TextInputType.number, + ), + const SizedBox(height: 16), + TextFormField( + controller: _stopCommentController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).stopCommentHint, + border: const OutlineInputBorder(), + ), + ), + const SizedBox(height: 16), + TextFormField( + initialValue: _formatDate(widget.date), + readOnly: true, + decoration: InputDecoration( + labelText: + AppLocalizations.of(context).chequebookIssueDateHint, + border: const OutlineInputBorder(), + ), + ), + 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.stopCheque( + accountno: widget.selectedAccount.accountNo!, + stopFromChequeNo: + _stopFromChequeNoController.text, + instrType: widget.instrType, + stopToChequeNo: _stopToChequeNoController.text, + stopIssueDate: _stopIssueDateController.text, + stopExpiryDate: _stopExpiryDateController.text, + stopAmount: _stopAmountController.text, + stopComment: _stopCommentController.text, + chequeIssueDate: widget.date, + tpin: pin, + ); + if (!mounted) return; + final decodedResponse = jsonDecode(response); + final status = decodedResponse['status']; + final message = decodedResponse['message']; + if (status == 'SUCCESS') { + _showResponseDialog('Success', message); + } else { + _showResponseDialog('Error', message); + } + } on Exception catch (e) { + print('inside catch block'); + print(e.toString()); + + 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).stopChequeButton), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/cheque/screens/stop_single_cheque_screen.dart b/lib/features/cheque/screens/stop_single_cheque_screen.dart new file mode 100644 index 0000000..c9355f5 --- /dev/null +++ b/lib/features/cheque/screens/stop_single_cheque_screen.dart @@ -0,0 +1,256 @@ +import 'dart:convert'; +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 StopSingleChequeScreen extends StatefulWidget { + final User selectedAccount; + final String date; + final String instrType; + final String fromCheque; + final String toCheque; + + const StopSingleChequeScreen( + {super.key, + required this.selectedAccount, + required this.date, + required this.instrType, + required this.fromCheque, + required this.toCheque}); + + @override + State createState() => _StopSingleChequeScreenState(); +} + +class _StopSingleChequeScreenState extends State { + final _formKey = GlobalKey(); + final _stopFromChequeNoController = TextEditingController(); + final _stopIssueDateController = TextEditingController(); + final _stopExpiryDateController = TextEditingController(); + final _stopAmountController = TextEditingController(); + final _stopCommentController = TextEditingController(); + final _chequeService = getIt(); + + String _formatDate(String dateString) { + if (dateString.length != 8) { + return dateString; // Return as is if not in expected ddmmyyyy format + } + try { + final day = dateString.substring(0, 2); + final month = dateString.substring(2, 4); + final year = dateString.substring(4, 8); + return '$day/$month/$year'; + } catch (e) { + return dateString; // Return original string on error + } + } + + Future _showResponseDialog(String title, String message) async { + return showDialog( + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: Text(title), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text(message), + ], + ), + ), + actions: [ + 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).stopSingleChequeTitle), + ), + 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: OutlineInputBorder(), + ), + 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, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).stopIssueDateLabel, + border: const OutlineInputBorder(), + ), + keyboardType: TextInputType.datetime, + ), + const SizedBox(height: 16), + TextFormField( + controller: _stopExpiryDateController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).stopExpiryDateLabel, + border: const OutlineInputBorder(), + ), + keyboardType: TextInputType.datetime, + ), + const SizedBox(height: 16), + TextFormField( + controller: _stopAmountController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).stopAmountHint, + border: const OutlineInputBorder(), + ), + keyboardType: TextInputType.number, + ), + const SizedBox(height: 16), + TextFormField( + controller: _stopCommentController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).stopCommentHint, + border: const OutlineInputBorder(), + ), + ), + const SizedBox(height: 16), + TextFormField( + initialValue: _formatDate(widget.date), + readOnly: true, + decoration: InputDecoration( + labelText: + AppLocalizations.of(context).chequebookIssueDateHint, + border: const OutlineInputBorder(), + ), + ), + 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.stopCheque( + accountno: widget.selectedAccount.accountNo!, + stopFromChequeNo: + _stopFromChequeNoController.text, + instrType: widget.instrType, + stopToChequeNo: + _stopFromChequeNoController.text, + stopIssueDate: _stopIssueDateController.text, + stopExpiryDate: _stopExpiryDateController.text, + stopAmount: _stopAmountController.text, + stopComment: _stopCommentController.text, + chequeIssueDate: widget.date, + tpin: pin, + ); + if (!mounted) return; + final decodedResponse = jsonDecode(response); + final status = decodedResponse['status']; + final message = decodedResponse['message']; + if (status == 'SUCCESS') { + _showResponseDialog('Success', message); + } else { + _showResponseDialog('Error', message); + } + } on Exception catch (e) { + print('inside catch block'); + print(e.toString()); + + 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).stopChequeButton), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/dashboard/screens/dashboard_screen.dart b/lib/features/dashboard/screens/dashboard_screen.dart index 6e5be62..225f854 100644 --- a/lib/features/dashboard/screens/dashboard_screen.dart +++ b/lib/features/dashboard/screens/dashboard_screen.dart @@ -8,6 +8,7 @@ import 'package:kmobile/features/accounts/screens/account_statement_screen.dart' import 'package:kmobile/features/accounts/screens/all_accounts_screen.dart'; import 'package:kmobile/features/auth/controllers/auth_cubit.dart'; 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'; @@ -443,7 +444,8 @@ class _DashboardScreenState extends State final accountType = currAccount.accountType?.toLowerCase(); final isPaymentDisabled = accountType != 'sa' && accountType != 'sb' && - accountType != 'ca'; + accountType != 'ca' && + accountType != 'cc'; // first‐time load if (!_txInitialized) { _txInitialized = true; @@ -643,20 +645,19 @@ class _DashboardScreenState extends State const EnquiryScreen())); }), _buildQuickLink( - Symbols.person, - AppLocalizations.of(context).profile, + Symbols.checkbook, + AppLocalizations.of(context).chequeManagement, () { Navigator.push( context, MaterialPageRoute( - builder: (context) => ProfileScreen( - mobileNumber: mobileNumberToPass, - customerNo: customerNo, - customerName: customerName), + builder: (context) => ChequeManagementScreen( + users: users, + selectedIndex: selectedAccountIndex), ), ); }, - disable: false, + disable: isPaymentDisabled, ), ], ), diff --git a/lib/features/enquiry/screens/enquiry_screen.dart b/lib/features/enquiry/screens/enquiry_screen.dart index 432a379..d6528dc 100644 --- a/lib/features/enquiry/screens/enquiry_screen.dart +++ b/lib/features/enquiry/screens/enquiry_screen.dart @@ -129,7 +129,7 @@ class _EnquiryScreen extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - "Complaint Form", + AppLocalizations.of(context).complaintFormTitle, style: TextStyle( fontSize: 15, color: Theme.of(context).colorScheme.primary, diff --git a/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart index abb5b0e..1f27f94 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart @@ -496,7 +496,7 @@ class _FundTransferAmountScreenState extends State { Text(AppLocalizations.of(context).fetchingDailyLimit), if (!_isLoadingLimit && _limit != null) Text( - 'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', + '${AppLocalizations.of(context).remainingDailyLimit} ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', style: Theme.of(context).textTheme.bodySmall, ), const Spacer(), diff --git a/lib/features/fund_transfer/screens/fund_transfer_beneficiary_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_beneficiary_screen.dart index 9ed0bc2..9de3adc 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_beneficiary_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_beneficiary_screen.dart @@ -198,7 +198,8 @@ class _FundTransferBeneficiaryScreenState child: TextField( controller: _searchController, decoration: InputDecoration( - hintText: "Search by name or account number", + hintText: + AppLocalizations.of(context).searchByNameOrAccountHint, prefixIcon: const Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), diff --git a/lib/features/fund_transfer/screens/fund_transfer_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_screen.dart index 9c14d4a..c16ffab 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_screen.dart @@ -42,7 +42,7 @@ class FundTransferScreen extends StatelessWidget { Expanded( child: FundTransferManagementTile( icon: Symbols.person, - label: "Self Pay", + label: AppLocalizations.of(context).selfPay, subtitle: AppLocalizations.of(context).ftselfpaysubtitle, onTap: () { diff --git a/lib/features/fund_transfer/screens/fund_transfer_self_accounts_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_self_accounts_screen.dart index 272ac20..fe9cd61 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_self_accounts_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_self_accounts_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/features/fund_transfer/screens/fund_transfer_self_amount_screen.dart'; +import 'package:kmobile/l10n/app_localizations.dart'; import 'package:kmobile/widgets/bank_logos.dart'; class FundTransferSelfAccountsScreen extends StatelessWidget { @@ -43,7 +44,7 @@ class FundTransferSelfAccountsScreen extends StatelessWidget { return Scaffold( appBar: AppBar( - title: const Text("Select Account"), + title: Text(AppLocalizations.of(context).selectAccount), ), body: Stack( children: [ diff --git a/lib/features/fund_transfer/screens/fund_transfer_self_amount_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_self_amount_screen.dart index 4df45c3..19f7335 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_self_amount_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_self_amount_screen.dart @@ -7,6 +7,7 @@ import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/di/injection.dart'; import 'package:kmobile/features/fund_transfer/screens/payment_animation.dart'; import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart'; +import 'package:kmobile/l10n/app_localizations.dart'; import 'package:kmobile/widgets/bank_logos.dart'; class FundTransferSelfAmountScreen extends StatefulWidget { @@ -134,7 +135,7 @@ class _FundTransferSelfAmountScreenState Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text("Fund Transfer"), + title: Text(AppLocalizations.of(context).fundTransferTitle), ), body: SafeArea( child: Stack( @@ -148,7 +149,7 @@ class _FundTransferSelfAmountScreenState children: [ // Debit Account (User) Text( - "Debit From", + AppLocalizations.of(context).debitFromLabel, style: Theme.of(context).textTheme.titleSmall, ), Card( @@ -168,7 +169,7 @@ class _FundTransferSelfAmountScreenState // Credit Account (Self) Text( - "Credited To", + AppLocalizations.of(context).creditedTo, style: Theme.of(context).textTheme.titleSmall, ), Card( @@ -186,9 +187,10 @@ class _FundTransferSelfAmountScreenState // Remarks TextFormField( controller: _remarksController, - decoration: const InputDecoration( - labelText: "Remarks (Optional)", - border: OutlineInputBorder(), + decoration: InputDecoration( + labelText: + AppLocalizations.of(context).remarksOptionalHint, + border: const OutlineInputBorder(), ), ), const SizedBox(height: 24), @@ -197,18 +199,18 @@ class _FundTransferSelfAmountScreenState TextFormField( controller: _amountController, keyboardType: TextInputType.number, - decoration: const InputDecoration( - labelText: "Amount", - border: OutlineInputBorder(), - prefixIcon: Icon(Icons.currency_rupee), + decoration: InputDecoration( + labelText: AppLocalizations.of(context).amountLabel, + border: const OutlineInputBorder(), + prefixIcon: const Icon(Icons.currency_rupee), ), validator: (value) { if (value == null || value.isEmpty) { - return "Amount is required"; + return AppLocalizations.of(context).amountRequired; } if (double.tryParse(value) == null || double.parse(value) <= 0) { - return "Please enter a valid amount"; + return AppLocalizations.of(context).validAmountError; } return null; }, @@ -216,10 +218,12 @@ class _FundTransferSelfAmountScreenState const SizedBox(height: 8), // Daily Limit Display - if (_isLoadingLimit) const Text('Fetching daily limit...'), + if (_isLoadingLimit) + Text(AppLocalizations.of(context) + .fetchingDailyLimitLoader), if (!_isLoadingLimit && _limit != null) Text( - 'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', + '${AppLocalizations.of(context).remainingDailyLimit} ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', style: Theme.of(context).textTheme.bodySmall, ), const Spacer(), @@ -232,7 +236,7 @@ class _FundTransferSelfAmountScreenState style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), ), - child: const Text("Proceed"), + child: Text(AppLocalizations.of(context).proceedButton), ), ), const SizedBox(height: 10), diff --git a/lib/features/profile/daily_transaction_limit.dart b/lib/features/profile/daily_transaction_limit.dart index 6a5a766..c905114 100644 --- a/lib/features/profile/daily_transaction_limit.dart +++ b/lib/features/profile/daily_transaction_limit.dart @@ -83,8 +83,8 @@ class _DailyLimitScreenState extends State { if (value > 200000) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: const Text( - "Limit To be Set must be less than 200000"), + content: + Text(localizations.limitToBeSetMustBeLessThan200000), behavior: SnackBarBehavior.floating, backgroundColor: theme.colorScheme.error, ), @@ -184,7 +184,7 @@ class _DailyLimitScreenState extends State { if (_currentLimit != null) ...[ const SizedBox(height: 24), Text( - "Remaining Limit Today", // This should be localized + localizations.remainingLimitToday, // This should be localized style: theme.textTheme.titleMedium, ), const SizedBox(height: 4), diff --git a/lib/features/service/screens/atm_locator_screen.dart b/lib/features/service/screens/atm_locator_screen.dart index 0a39ebe..7f30f0a 100644 --- a/lib/features/service/screens/atm_locator_screen.dart +++ b/lib/features/service/screens/atm_locator_screen.dart @@ -76,7 +76,8 @@ class _ATMLocatorScreenState extends State { onChanged: _filterAtms, // Updated: Call _filterAtms on text change decoration: InputDecoration( - hintText: "Name/Address", // Hint text for the search bar + hintText: AppLocalizations.of(context) + .nameAddress, // Hint text for the search bar prefixIcon: const Icon(Icons.search), // Search icon border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), @@ -90,9 +91,9 @@ class _ATMLocatorScreenState extends State { child: _isLoading ? _buildShimmerList() // Display shimmer while loading : _filteredAtms.isEmpty - ? const Center( - child: Text( - "No matching ATMs found")) // Message if no ATMs found + ? Center( + child: Text(AppLocalizations.of(context) + .noMatchingAtmsFound)) // Message if no ATMs found : ListView.builder( itemCount: _filteredAtms .length, // Number of items in the filtered list diff --git a/lib/features/service/screens/branch_locator_screen.dart b/lib/features/service/screens/branch_locator_screen.dart index 5decdc4..ad4ec4e 100644 --- a/lib/features/service/screens/branch_locator_screen.dart +++ b/lib/features/service/screens/branch_locator_screen.dart @@ -69,7 +69,7 @@ class _BranchLocatorScreenState extends State { controller: _searchController, onChanged: _filterBranches, // Updated decoration: InputDecoration( - hintText: "Branch Name", + hintText: AppLocalizations.of(context).searchbranch, prefixIcon: const Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), @@ -83,9 +83,9 @@ class _BranchLocatorScreenState extends State { child: _isLoading ? _buildShimmerList() // Changed to shimmer : _filteredBranches.isEmpty - ? const Center( - child: Text( - "No matching branches found")) // Updated tex + ? Center( + child: Text(AppLocalizations.of(context) + .noMatchingBranchesFound)) // Updated tex : ListView.builder( itemCount: _filteredBranches.length, itemBuilder: (context, index) { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index bc471c8..a51c010 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -416,5 +416,144 @@ "kycdetails": "KYC Details", "viewall": "View All", "branchlocator": "Branch Locator", -"atmlocator": "ATM Locator" +"atmlocator": "ATM Locator", + "limitSetError": "Limit to be set must be less than {maxAmount}", + "genericError": "Error: {errorMessage}", + "limitUpdatedSuccess": "Limit Updated", + "remainingLimitToday": "Remaining Limit Today", + "branchNameHint": "Branch Name", + "noMatchingBranches": "No matching branches found", + "selfPay": "Self Pay", + "savingsAccountType": "Savings", + "amountExceedsDailyLimit": "Amount exceeds remaining daily limit of ", + "incorrectTpinError": "Please Enter the correct TPIN", + "insufficientFundsError": "Your account does not have sufficient balance", + "somethingWentWrongError": "Something Went Wrong", + "currencyINR": "INR", + "remainingDailyLimit": "Remaining Daily Limit:", + "searchByNameOrAccount": "Search by name or account number", + "beneficiaryCooldownMessage": "Beneficiary will be enabled after the cooldown period.", + "notApplicable": "N/A", + "savingsAccountLabel": "Savings Account", + "loanAccountLabel": "Loan Account", + "termDepositLabel": "Term Deposit", + "recurringDepositLabel": "Recurring Deposit", + "currentAccountLabel": "Current Account", + "unknownAccountLabel": "Unknown Account", + "selectAccountTitle": "Select Account", + "noOtherAccounts": "No other accounts found", + "kccbBankName": "Kangra Central Co-operative Bank", + "fundTransferTitle": "Fund Transfer", + "debitFromLabel": "Debit From", + "creditToLabel": "Credited To", + "remarksOptionalHint": "Remarks (Optional)", + "amountLabel": "Amount", + "amountRequiredError": "Amount is required", + "validAmountError": "Please enter a valid amount", + "fetchingDailyLimitLoader": "Fetching daily limit...", + "proceedButton": "Proceed", + "enterKey": "Enter", + "backKey": "back", + "doneKey": "done", + "transactionDate": "On {date}", + "paymentResultPng": "/payment_result.png", + "rubikFont": "Rubik", + "transactionDateLabel": "Date: {date}", + "utrLabel": "UTR: {utr}", + "searchByNameOrAccountHint": "Search by name or account number", + "savingsAccountDropdown": "Savings", + "beneficiaryExistsError": "Beneficiary already exists", + "somethingWentWrongShort": "Something went Wrong", + "currentAccountDropdown": "Current", + "failedToDeleteBeneficiaryError": "Failed to delete beneficiary: {error}", + "notAvailable": "N/A", + "bankNameLabel": "Bank Name", + "accountNumberLabel": "Account Number", + "accountTypeLabel": "Account Type", + "ifscCodeLabel": "IFSC Code", + "branchNameLabel": "Branch Name", + "enquiryEmailSubject": "Enquiry", + "couldNotOpenEmailApp": "Could not open email app for {email}", + "couldNotOpenDialer": "Could not open dialer for {phone}", + "couldNotLaunchUrl": "Could not launch {url}", + "complaintFormUrl": "https://kccbhp.bank.in/complaint-form/", + "complaintFormTitle": "Complaint Form", + "chairmanEmail": "chairman@kccb.in", + "chairmanPhone": "01892-222677", + "mdEmail": "md@kccb.in", + "mdPhone": "01892-224969", + "gmwEmail": "gmw@kccb.in", + "gmwPhone": "01892-223280", + "gmnEmail": "gmn@kccb.in", + "gmnPhone": "01892-224607", + "atmNameAddressHint": "Name/Address", + "noMatchingAtms": "No matching ATMs found", + "faq1Question": "How do I log in to the mobile banking app?", + "faq1Answer": "You can log in using your customer number and password. Biometric login (fingerprint) and MPIN is also available for supported evices.", + "faq2Question": "Is my banking information secure on this app?", + "faq2Answer": "Yes. We use industry-standard encryption and multi-factor authentication to ensure your data is safe.", + "faq3Question": "How can I check my account balance?", + "faq3Answer": "Once logged in, your account balance will be displayed on the home screen. You can also view detailed balances under the “Accounts” section.", + "faq4Question": "Can I transfer money to other bank accounts?", + "faq4Answer": "Yes. You can use NEFT, RTGS or IMPS to transfer funds to any bank account in India.", + "faq5Question": "How do I view my transaction history?", + "faq5Answer": "Click on the “Account Statement” icon under the Home Screen to view recent and past transactions.", + "chequeEnquiryTitle": "Cheque Enquiry", + "chequeEnquirySubtitle": "You can view the status of your issued cheque book, presented cheques and details of stopped cheques including relevant dates, cheque numbers and other essential information", + "stopChequeSubtitle": "Initiate stop for one or more cheques from your issued checkbook. This essential service helps prevent unauthorized transactions and protects against fraud.", + "chequeEnquiryFailedError": "Failed to fetch cheque status: {error}", + "accountNumberTitle": "Account Number", + "noAccountsFound": "No accounts found", + "searchByChequeDetailsHint": "Search by Cheque Details", + "noChequeStatusFound": "No cheque status found.", + "chequebookIssuedLabel": "Chequebook Issued (CI)", + "branchCodeLabel": "Branch Code:", + "fromChequeLabel": "From Cheque:", + "toChequeLabel": "To Cheque:", + "dateLabel": "Date:", + "chequesCountLabel": "Cheques Count:", + "presentedChequeLabel": "Presented Cheque (PR)", + "chequeNumberLabel": "Cheque Number:", + "transactionCodeLabel": "Transaction Code:", + "amountLabelWithColon": "Amount:", + "statusLabel": "Status:", + "stopChequeLabel": "Stop Cheque (ST)", + "stopIssueDateLabel": "Stop Issue Date:", + "stopExpiryDateLabel": "Stop Expiry Date:", + "emptyString": "", + "cashCreditAccountLabel": "Cash Credit Account", + "stopChequeTitle": "Stop Cheque", + "noChequebookToStop": "No cheque book found to stop cheques from.", + "stopSingleChequeButton": "Stop Single Cheque", + "pleaseSelectAccountFirst": "Please select an account first.", + "stopMultipleChequesButton": "Stop Multiple Cheques", + "noChequeIssuedStatus": "No Cheque Issued status found.", + "chequebookDetailsTitle": "Chequebook Details", + "customerNameLabel": "Customer Name:", + "cifNumberLabel": "CIF Number:", + "startingChequeNumberLabel": "Starting Cheque Number:", + "endingChequeNumberLabel": "Ending Cheque Number:", + "issueDateLabel": "Issue Date:", + "numberOfChequesLabel": "Number of Cheques:", + "instrumentTypeLabel": "Instrument Type:", + "closeButton": "Close", + "stopSingleChequeTitle": "Stop Single Cheque", + "chequeNumberHint": "Cheque Number *", + "pleaseEnterChequeNumberError": "Please enter a cheque number", + "invalidChequeNumberFormatError": "Invalid cheque number format", + "chequeNumberRangeError": "Cheque number must be between {from} and {to}", + "instrumentTypeHint": "Instrument Type *", + "stopIssueDateHint": "Stop Issue Date", + "stopExpiryDateHint": "Stop Expiry Date", + "stopAmountHint": "Stop Amount", + "stopCommentHint": "Stop Comment", + "chequebookIssueDateHint": "Chequebook Issue Date", + "successStatus": "Success", + "errorStatus": "Error", + "incorrectTpinErrorMessage": "The TPIN you entered is incorrect. Please try again.", + "internalServerError": "Internal Server Error", + "stopChequeButton": "Stop Cheque", + "stopMultipleChequesTitle": "Stop Multiple Cheques", + "fromChequeNumberHint": "From Cheque Number *", + "toChequeNumberHint": "To Cheque Number *" } diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 4525199..4b7d1a0 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -417,5 +417,144 @@ "kycdetails": "केवाईसी विवरण", "viewall": "सभी देखें", "branchlocator": "शाखा लोकेटर", -"atmlocator": "एटीएम लोकेटर" +"atmlocator": "एटीएम लोकेटर", + "limitSetError": "निर्धारित की जाने वाली सीमा {maxAmount} से कम होनी चाहिए।", + "genericError": "त्रुटि: {errorMessage}", + "limitUpdatedSuccess": "सीमा अपडेट हो गई", + "remainingLimitToday": "आज की शेष सीमा", + "branchNameHint": "शाखा का नाम", + "noMatchingBranches": "कोई मेल खाने वाली शाखा नहीं मिली", + "selfPay": "स्वयं भुगतान", + "savingsAccountType": "बचत खाता", + "amountExceedsDailyLimit": "राशि की शेष दैनिक सीमा से अधिक है", + "incorrectTpinError": "कृपया सही टीपिन दर्ज करें", + "insufficientFundsError": "आपके खाते में पर्याप्त शेष राशि नहीं है", + "somethingWentWrongError": "कुछ गलत हो गया", + "currencyINR": "INR", + "remainingDailyLimit": "शेष दैनिक सीमा:", + "searchByNameOrAccount": "नाम या खाता संख्या से खोजें", + "beneficiaryCooldownMessage": "कूलडाउन अवधि के बाद लाभार्थी सक्षम हो जाएगा।", + "notApplicable": "लागू नहीं", + "savingsAccountLabel": "बचत खाता", + "loanAccountLabel": "ऋण खाता", + "termDepositLabel": "सावधि जमा", + "recurringDepositLabel": "आवर्ती जमा", + "currentAccountLabel": "चालू खाता", + "unknownAccountLabel": "अज्ञात खाता", + "selectAccountTitle": "खाता चुनें", + "noOtherAccounts": "कोई अन्य खाता नहीं मिला", + "kccbBankName": "कांगड़ा केंद्रीय सहकारी बैंक", + "fundTransferTitle": "धन हस्तांतरण", + "debitFromLabel": "से डेबिट करें", + "creditToLabel": "को क्रेडिट करें", + "remarksOptionalHint": "टिप्पणी (वैकल्पिक)", + "amountLabel": "राशि", + "amountRequiredError": "राशि आवश्यक है", + "validAmountError": "कृपया एक वैध राशि दर्ज करें", + "fetchingDailyLimitLoader": "दैनिक सीमा लाई जा रही है...", + "proceedButton": "आगे बढ़ें", + "enterKey": "दर्ज करें", + "backKey": "वापस", + "doneKey": "पूर्ण", + "transactionDate": "{date} को", + "paymentResultPng": "/payment_result.png", + "rubikFont": "Rubik", + "transactionDateLabel": "दिनांक: {date}", + "utrLabel": "UTR: {utr}", + "searchByNameOrAccountHint": "नाम या खाता संख्या से खोजें", + "savingsAccountDropdown": "बचत", + "beneficiaryExistsError": "लाभार्थी पहले से मौजूद है", + "somethingWentWrongShort": "कुछ गलत हो गया", + "currentAccountDropdown": "चालू", + "failedToDeleteBeneficiaryError": "लाभार्थी को हटाने में विफल: {error}", + "notAvailable": "उपलब्ध नहीं है", + "bankNameLabel": "बैंक का नाम", + "accountNumberLabel": "खाता संख्या", + "accountTypeLabel": "खाते का प्रकार", + "ifscCodeLabel": "IFSC कोड", + "branchNameLabel": "शाखा का नाम", + "enquiryEmailSubject": "पूछताछ", + "couldNotOpenEmailApp": "{email} के लिए ईमेल ऐप नहीं खोला जा सका", + "couldNotOpenDialer": "{phone} के लिए डायलर नहीं खोला जा सका", + "couldNotLaunchUrl": "{url} लॉन्च नहीं किया जा सका", + "complaintFormUrl": "https://kccbhp.bank.in/complaint-form/", + "complaintFormTitle": "शिकायत प्रपत्र", + "chairmanEmail": "chairman@kccb.in", + "chairmanPhone": "01892-222677", + "mdEmail": "md@kccb.in", + "mdPhone": "01892-224969", + "gmwEmail": "gmw@kccb.in", + "gmwPhone": "01892-223280", + "gmnEmail": "gmn@kccb.in", + "gmnPhone": "01892-224607", + "atmNameAddressHint": "नाम/पता", + "noMatchingAtms": "कोई मेल खाने वाला एटीएम नहीं मिला", + "faq1Question": "मैं मोबाइल बैंकिंग ऐप में कैसे लॉग इन करूं?", + "faq1Answer": "आप अपने ग्राहक नंबर और पासवर्ड का उपयोग करके लॉग इन कर सकते हैं। समर्थित उपकरणों के लिए बायोमेट्रिक लॉगिन (फिंगरप्रिंट) और एमपिन भी उ।", + "faq2Question": "क्या इस ऐप पर मेरी बैंकिंग जानकारी सुरक्षित है?", + "faq2Answer": "हां। हम आपके डेटा को सुरक्षित रखने के लिए उद्योग-मानक एन्क्रिप्शन और बहु-कारक प्रमाणीकरण का उपयोग करते हैं।", + "faq3Question": "मैं अपने खाते की शेष राशि कैसे देख सकता हूं?", + "faq3Answer": "लॉग इन करने के बाद, आपके खाते की शेष राशि होम स्क्रीन पर प्रदर्शित होगी। आप “खाते” अनुभाग के तहत विस्तृत शेष राशि भी देख सकते हैं।", + "faq4Question": "क्या मैं अन्य बैंक खातों में पैसे ट्रांसफर कर सकता हूं?", + "faq4Answer": "हां। आप भारत में किसी भी बैंक खाते में धनराशि स्थानांतरित करने के लिए एनईएफटी, आरटीजीएस या आईएमपीएस का उपयोग कर सकते हैं।", + "faq5Question": "मैं अपना लेनदेन इतिहास कैसे देखूं?", + "faq5Answer": "हाल के और पिछले लेनदेन देखने के लिए होम स्क्रीन के नीचे “खाता विवरण” आइकन पर क्लिक करें।", + "chequeEnquiryTitle": "चेक पूछताछ", + "chequeEnquirySubtitle": "आप अपनी जारी की गई चेक बुक, प्रस्तुत किए गए चेकों और रोके गए चेकों के विवरण देख सकते हैं, जिसमें प्रासंगिक तिथियां, चेक नं्य आवश्यक जानकारी शामिल है", + "stopChequeSubtitle": "अपनी जारी की गई चेकबुक से एक या अधिक चेकों के लिए स्टॉप आरंभ करें। यह आवश्यक सेवा अनधिकृत लेनदेन को रोकने और धोखाधड़ी से बचानद करती है।", + "chequeEnquiryFailedError": "चेक स्थिति लाने में विफल: {error}", + "accountNumberTitle": "खाता संख्या", + "noAccountsFound": "कोई खाता नहीं मिला", + "searchByChequeDetailsHint": "चेक विवरण द्वारा खोजें", + "noChequeStatusFound": "कोई चेक स्थिति नहीं मिली।", + "chequebookIssuedLabel": "चेकबुक जारी (CI)", + "branchCodeLabel": "शाखा कोड:", + "fromChequeLabel": "चेक से:", + "toChequeLabel": "चेक तक:", + "dateLabel": "दिनांक:", + "chequesCountLabel": "चेकों की संख्या:", + "presentedChequeLabel": "प्रस्तुत चेक (PR)", + "chequeNumberLabel": "चेक नंबर:", + "transactionCodeLabel": "लेनदेन कोड:", + "amountLabelWithColon": "राशि:", + "statusLabel": "स्थिति:", + "stopChequeLabel": "चेक रोकें (ST)", + "stopIssueDateLabel": "रोक जारी करने की तारीख:", + "stopExpiryDateLabel": "रोक समाप्ति तिथि:", + "emptyString": "", + "cashCreditAccountLabel": "नकद क्रेडिट खाता", + "stopChequeTitle": "चेक रोकें", + "noChequebookToStop": "से चेक रोकने के लिए कोई चेक बुक नहीं मिली।", + "stopSingleChequeButton": "एकल चेक रोकें", + "pleaseSelectAccountFirst": "कृपया पहले एक खाता चुनें।", + "stopMultipleChequesButton": "एकाधिक चेक रोकें", + "noChequeIssuedStatus": "कोई चेक जारी स्थिति नहीं मिली।", + "chequebookDetailsTitle": "चेकबुक विवरण", + "customerNameLabel": "ग्राहक का नाम:", + "cifNumberLabel": "CIF नंबर:", + "startingChequeNumberLabel": "प्रारंभिक चेक नंबर:", + "endingChequeNumberLabel": "अंतिम चेक नंबर:", + "issueDateLabel": "जारी करने की तारीख:", + "numberOfChequesLabel": "चेकों की संख्या:", + "instrumentTypeLabel": "उपकरण का प्रकार:", + "closeButton": "बंद करें", + "stopSingleChequeTitle": "एकल चेक रोकें", + "chequeNumberHint": "चेक नंबर *", + "pleaseEnterChequeNumberError": "कृपया एक चेक नंबर दर्ज करें", + "invalidChequeNumberFormatError": "अमान्य चेक नंबर प्रारूप", + "chequeNumberRangeError": "चेक नंबर {from} और {to} के बीच होना चाहिए", + "instrumentTypeHint": "उपकरण का प्रकार *", + "stopIssueDateHint": "रोक जारी करने की तारीख", + "stopExpiryDateHint": "रोक समाप्ति तिथि", + "stopAmountHint": "राशि रोकें", + "stopCommentHint": "टिप्पणी रोकें", + "chequebookIssueDateHint": "चेकबुक जारी करने की तारीख", + "successStatus": "सफलता", + "errorStatus": "त्रुटि", + "incorrectTpinErrorMessage": "आपके द्वारा दर्ज किया गया टीपिन गलत है। कृपया पुन: प्रयास करें।", + "internalServerError": "आंतरिक सर्वर त्रुटि", + "stopChequeButton": "चेक रोकें", + "stopMultipleChequesTitle": "एकाधिक चेक रोकें", + "fromChequeNumberHint": "चेक नंबर से *", + "toChequeNumberHint": "चेक नंबर तक *" } diff --git a/pubspec.lock b/pubspec.lock index b9d69fe..3eb1b9b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" checked_yaml: dependency: transitive description: @@ -93,18 +93,18 @@ packages: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" collection: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.1" + version: "1.18.0" confetti: dependency: "direct main" description: @@ -189,10 +189,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.1" ffi: dependency: transitive description: @@ -425,10 +425,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.20.2" + version: "0.19.0" jailbreak_root_detection: dependency: "direct main" description: @@ -457,26 +457,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "11.0.2" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.10" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.1" lints: dependency: transitive description: @@ -537,10 +537,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: @@ -561,10 +561,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.15.0" mime: dependency: transitive description: @@ -609,10 +609,10 @@ packages: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -881,7 +881,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_span: dependency: transitive description: @@ -902,18 +902,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.1" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -934,10 +934,10 @@ packages: dependency: transitive description: name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.7.2" timezone: dependency: transitive description: @@ -1054,10 +1054,10 @@ packages: dependency: transitive description: name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.1.4" vm_service: dependency: transitive description: @@ -1115,5 +1115,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.8.0-0 <4.0.0" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.24.0"