Commit 0515ce45 authored by Sai Srinivas's avatar Sai Srinivas
Browse files

Razorpay setup

parents f3a137b2 f693e7f1
class TransactionListResponse { // class TransactionListResponse {
String? error; // String? error;
String? balanceAmount; // String? balanceAmount;
String? balanceType; // String? balanceType;
String? totalCredit; // String? totalCredit;
String? totalDebit; // String? totalDebit;
Map<String, List<TransactionItem>>? transactions; // Map<String, List<TransactionItem>>? transactions;
String? message; // String? message;
//
TransactionListResponse({ // TransactionListResponse({
this.error, // this.error,
this.balanceAmount, // this.balanceAmount,
this.balanceType, // this.balanceType,
this.totalCredit, // this.totalCredit,
this.totalDebit, // this.totalDebit,
this.transactions, // this.transactions,
this.message, // this.message,
}); // });
//
TransactionListResponse.fromJson(Map<String, dynamic> json) { // TransactionListResponse.fromJson(Map<String, dynamic> json) {
error = json['error']; // error = json['error'];
balanceAmount = json['balance_amount']; // balanceAmount = json['balance_amount'];
balanceType = json['balance_type']; // balanceType = json['balance_type'];
totalCredit = json['total_credit']; // totalCredit = json['total_credit'];
totalDebit = json['total_debit']; // totalDebit = json['total_debit'];
message = json['message']; // message = json['message'];
//
if (json['transactions'] != null) { // if (json['transactions'] != null) {
transactions = {}; // transactions = {};
json['transactions'].forEach((key, value) { // json['transactions'].forEach((key, value) {
transactions![key] = List<TransactionItem>.from( // transactions![key] = List<TransactionItem>.from(
value.map((v) => TransactionItem.fromJson(v)), // value.map((v) => TransactionItem.fromJson(v)),
); // );
}); // });
} // }
} // }
//
Map<String, dynamic> toJson() { // Map<String, dynamic> toJson() {
final data = <String, dynamic>{}; // final data = <String, dynamic>{};
data['error'] = error; // data['error'] = error;
data['balance_amount'] = balanceAmount; // data['balance_amount'] = balanceAmount;
data['balance_type'] = balanceType; // data['balance_type'] = balanceType;
data['total_credit'] = totalCredit; // data['total_credit'] = totalCredit;
data['total_debit'] = totalDebit; // data['total_debit'] = totalDebit;
data['message'] = message; // data['message'] = message;
if (transactions != null) { // if (transactions != null) {
data['transactions'] = transactions!.map((key, value) => // data['transactions'] = transactions!.map((key, value) =>
MapEntry(key, value.map((v) => v.toJson()).toList())); // MapEntry(key, value.map((v) => v.toJson()).toList()));
} // }
return data; // return data;
} // }
} // }
//
class TransactionItem { // class TransactionItem {
String? id; // String? id;
String? billId; // String? billId;
String? atype; // String? atype;
String? type; // String? type;
String? datetime; // String? datetime;
String? cAmount; // String? cAmount;
String? dAmount; // String? dAmount;
String? narration; // String? narration;
//
TransactionItem({ // TransactionItem({
this.id, // this.id,
this.billId, // this.billId,
this.atype, // this.atype,
this.type, // this.type,
this.datetime, // this.datetime,
this.cAmount, // this.cAmount,
this.dAmount, // this.dAmount,
this.narration, // this.narration,
}); // });
//
TransactionItem.fromJson(Map<String, dynamic> json) { // TransactionItem.fromJson(Map<String, dynamic> json) {
id = json['id']; // id = json['id'];
billId = json['bill_id']; // billId = json['bill_id'];
atype = json['atype']; // atype = json['atype'];
type = json['type']; // type = json['type'];
datetime = json['datetime']; // datetime = json['datetime'];
cAmount = json['c_amount']; // cAmount = json['c_amount'];
dAmount = json['d_amount']; // dAmount = json['d_amount'];
narration = json['narration']; // narration = json['narration'];
} // }
//
Map<String, dynamic> toJson() => { // Map<String, dynamic> toJson() => {
'id': id, // 'id': id,
'bill_id': billId, // 'bill_id': billId,
'atype': atype, // 'atype': atype,
'type': type, // 'type': type,
'datetime': datetime, // 'datetime': datetime,
'c_amount': cAmount, // 'c_amount': cAmount,
'd_amount': dAmount, // 'd_amount': dAmount,
'narration': narration, // 'narration': narration,
}; // };
} // }
class PayAmountResponse {
String? error;
String? amount;
String? message;
String? orderId;
String? razorKey;
String? sessionExists;
PayAmountResponse(
{this.error,
this.amount,
this.message,
this.orderId,
this.razorKey,
this.sessionExists});
PayAmountResponse.fromJson(Map<String, dynamic> json) {
error = json['error'];
amount = json['amount'];
message = json['message'];
orderId = json['order_id'];
razorKey = json['razor_key'];
sessionExists = json['session_exists'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['error'] = this.error;
data['amount'] = this.amount;
data['message'] = this.message;
data['order_id'] = this.orderId;
data['razor_key'] = this.razorKey;
data['session_exists'] = this.sessionExists;
return data;
}
}
...@@ -6,6 +6,7 @@ class TransactionListResponse { ...@@ -6,6 +6,7 @@ class TransactionListResponse {
String? totalDebit; String? totalDebit;
Map<String, List<TransactionItem>>? transactions; Map<String, List<TransactionItem>>? transactions;
String? message; String? message;
String? lastPaid;
TransactionListResponse({ TransactionListResponse({
this.error, this.error,
...@@ -24,7 +25,7 @@ class TransactionListResponse { ...@@ -24,7 +25,7 @@ class TransactionListResponse {
totalCredit = json['total_credit']; totalCredit = json['total_credit'];
totalDebit = json['total_debit']; totalDebit = json['total_debit'];
message = json['message']; message = json['message'];
lastPaid = json['last_payment'];
if (json['transactions'] != null) { if (json['transactions'] != null) {
transactions = {}; transactions = {};
json['transactions'].forEach((key, value) { json['transactions'].forEach((key, value) {
...@@ -43,6 +44,7 @@ class TransactionListResponse { ...@@ -43,6 +44,7 @@ class TransactionListResponse {
data['total_credit'] = totalCredit; data['total_credit'] = totalCredit;
data['total_debit'] = totalDebit; data['total_debit'] = totalDebit;
data['message'] = message; data['message'] = message;
data['last_payment'] = lastPaid;
if (transactions != null) { if (transactions != null) {
data['transactions'] = transactions!.map((key, value) => data['transactions'] = transactions!.map((key, value) =>
MapEntry(key, value.map((v) => v.toJson()).toList())); MapEntry(key, value.map((v) => v.toJson()).toList()));
......
...@@ -5,7 +5,7 @@ import 'package:gen_service/Services/api_calling.dart'; ...@@ -5,7 +5,7 @@ import 'package:gen_service/Services/api_calling.dart';
import '../Models/CommonResponse.dart'; import '../Models/CommonResponse.dart';
import '../Models/HelpAndComplaintModels/ComplaintListResponse.dart'; import '../Models/HelpAndComplaintModels/ComplaintListResponse.dart';
import '../Models/HelpAndComplaintModels/GeneratorListResponse.dart'; import '../Models/HelpAndComplaintModels/GeneratorListResponse.dart';
import '../Screens/HelpAndComplaintScreens/DropDownsListResponse.dart'; import '../Models/HelpAndComplaintModels/DropDownsListResponse.dart';
class HelpAndComplaintProvider extends ChangeNotifier { class HelpAndComplaintProvider extends ChangeNotifier {
bool _isLoading = false; bool _isLoading = false;
......
import 'package:flutter/cupertino.dart';
import '../Models/TransactionModels/PayAmountResponse.dart';
import '../Services/api_calling.dart';
class PayAmountProvider with ChangeNotifier {
bool _isLoading = false;
PayAmountResponse? _payResponse;
PaymentStatusResponse? _statusResponse;
String? _errorMessage;
bool get isLoading => _isLoading;
PayAmountResponse? get payResponse => _payResponse;
PaymentStatusResponse? get statusResponse => _statusResponse;
String? get errorMessage => _errorMessage;
/// Pay Amount API
Future<void> payAmount({
required String sessionId,
required String empId,
required String amount,
required String refType,
required String refId,
}) async {
_isLoading = true;
_errorMessage = null;
notifyListeners();
try {
final res = await ApiCalling.payAmountApi(
sessionId,
empId,
amount,
refType,
refId,
);
if (res != null) {
_payResponse = res;
} else {
_errorMessage = "No response from server";
}
} catch (e) {
_errorMessage = "Error: $e";
} finally {
_isLoading = false;
notifyListeners();
}
}
/// Get Payment Status API
Future<void> getPaymentStatus({
required String sessionId,
required String empId,
required String razorpayOrderId,
}) async {
_isLoading = true;
_errorMessage = null;
notifyListeners();
try {
final res = await ApiCalling.getPaymentStatusApi(
sessionId,
empId,
razorpayOrderId,
);
if (res != null) {
_statusResponse = res;
} else {
_errorMessage = "No response from server";
}
} catch (e) {
_errorMessage = "Error: $e";
} finally {
_isLoading = false;
notifyListeners();
}
}
/// Reset all states
void reset() {
_payResponse = null;
_statusResponse = null;
_errorMessage = null;
notifyListeners();
}
}
// Payment Status Response
class PaymentStatusResponse {
int? error;
double? amount;
String? date;
String? message;
int? sessionExists;
PaymentStatusResponse(
{this.error, this.amount, this.date, this.message, this.sessionExists});
PaymentStatusResponse.fromJson(Map<String, dynamic> json) {
error = json['error'];
amount = json['amount'];
date = json['date'];
message = json['message'];
sessionExists = json['session_exists'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['error'] = this.error;
data['amount'] = this.amount;
data['date'] = this.date;
data['message'] = this.message;
data['session_exists'] = this.sessionExists;
return data;
}
}
\ No newline at end of file
...@@ -12,26 +12,40 @@ import '../Services/api_post_request.dart'; ...@@ -12,26 +12,40 @@ import '../Services/api_post_request.dart';
import '../Utility/CustomSnackbar.dart'; import '../Utility/CustomSnackbar.dart';
class TransactionsProvider with ChangeNotifier { class TransactionsProvider with ChangeNotifier {
TransactionListResponse? _transactionList;
bool _isLoading = false; bool _isLoading = false;
String? _errorMessage; String? _errorMessage;
TransactionListResponse? _transactionList; int _currentPage = 1;
bool _hasMore = true;
bool _isLoadingMore = false;
TransactionListResponse? get transactionList => _transactionList;
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
bool get isLoadingMore => _isLoadingMore;
String? get errorMessage => _errorMessage; String? get errorMessage => _errorMessage;
TransactionListResponse? get transactionList => _transactionList; bool get hasMore => _hasMore;
/// Fetch Transactions from API /// Fetch Transactions from API (initial load)
Future<void> fetchTransactions(String accId, String sessionId) async { Future<void> fetchTransactions(String accId, String sessionId) async {
_currentPage = 1;
_hasMore = true;
_isLoading = true; _isLoading = true;
_errorMessage = null; _errorMessage = null;
notifyListeners(); notifyListeners();
try { try {
final response = await ApiCalling.fetchTransactionListApi(accId, sessionId); final response = await ApiCalling.fetchTransactionListApi(
accId,
sessionId,
_currentPage.toString()
);
if (response != null) { if (response != null) {
_transactionList = response; _transactionList = response;
_errorMessage = null; _errorMessage = null;
// Check if we have more data (assuming 15 items per page)
_hasMore = _calculateHasMore(response);
} else { } else {
_errorMessage = "No response from server"; _errorMessage = "No response from server";
} }
...@@ -43,10 +57,86 @@ class TransactionsProvider with ChangeNotifier { ...@@ -43,10 +57,86 @@ class TransactionsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
/// Load more transactions
Future<void> loadMoreTransactions(String accId, String sessionId) async {
if (_isLoadingMore || !_hasMore) return;
_isLoadingMore = true;
notifyListeners();
try {
final response = await ApiCalling.fetchTransactionListApi(
accId,
sessionId,
(_currentPage + 1).toString()
);
debugPrint("\nPage Number ${_currentPage+1}");
if (response != null && response.transactions != null) {
_currentPage++;
// Merge new transactions with existing ones
_mergeTransactions(response);
// Check if we have more data
_hasMore = _calculateHasMore(response);
}
} catch (e) {
debugPrint("Load more error: $e");
}
_isLoadingMore = false;
notifyListeners();
}
/// Merge new transactions with existing data
void _mergeTransactions(TransactionListResponse newResponse) {
if (_transactionList == null) {
_transactionList = newResponse;
return;
}
// Merge transactions by month
if (newResponse.transactions != null) {
if (_transactionList!.transactions == null) {
_transactionList!.transactions = {};
}
newResponse.transactions!.forEach((month, newItems) {
if (_transactionList!.transactions!.containsKey(month)) {
// Month exists, append items
_transactionList!.transactions![month]!.addAll(newItems);
} else {
// New month, add all items
_transactionList!.transactions![month] = newItems;
}
});
}
}
/// Check if there are more pages to load
bool _calculateHasMore(TransactionListResponse response) {
if (response.transactions == null || response.transactions!.isEmpty) {
return false;
}
// Count total items in current response
int totalItems = 0;
response.transactions!.forEach((month, items) {
totalItems += items.length;
});
// If we got less than 15 items, probably no more data
return totalItems >= 15;
}
/// Clear Data /// Clear Data
void clearTransactions() { void clearTransactions() {
_transactionList = null; _transactionList = null;
_errorMessage = null; _errorMessage = null;
_currentPage = 1;
_hasMore = true;
_isLoadingMore = false;
notifyListeners(); notifyListeners();
} }
......
...@@ -85,6 +85,7 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -85,6 +85,7 @@ class _OtpScreenState extends State<OtpScreen> {
if (authProvider.otpResponse?.accId != null) { if (authProvider.otpResponse?.accId != null) {
await prefs.saveString("accId", authProvider.otpResponse!.accId!); await prefs.saveString("accId", authProvider.otpResponse!.accId!);
await prefs.saveString("session_id", authProvider.otpResponse!.sessionId!); await prefs.saveString("session_id", authProvider.otpResponse!.sessionId!);
await prefs.saveString("mob_number", widget.mob);
} }
// ✅ Navigate to Home Screen // ✅ Navigate to Home Screen
...@@ -94,6 +95,7 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -94,6 +95,7 @@ class _OtpScreenState extends State<OtpScreen> {
pageBuilder: (_, __, ___) => HomeScreen( pageBuilder: (_, __, ___) => HomeScreen(
accId: authProvider.otpResponse!.accId!, accId: authProvider.otpResponse!.accId!,
sessionId: authProvider.otpResponse!.sessionId.toString(), sessionId: authProvider.otpResponse!.sessionId.toString(),
mobNumber: widget.mob,
), ),
transitionsBuilder: (_, animation, __, child) { transitionsBuilder: (_, animation, __, child) {
return FadeTransition(opacity: animation, child: child); return FadeTransition(opacity: animation, child: child);
......
...@@ -88,7 +88,7 @@ class _AddComplaintScreenState extends State<AddComplaintScreen> { ...@@ -88,7 +88,7 @@ class _AddComplaintScreenState extends State<AddComplaintScreen> {
StretchMode.blurBackground, StretchMode.blurBackground,
], ],
background: Container( background: Container(
decoration: const BoxDecoration(color: AppColors.primary), decoration: const BoxDecoration(gradient: AppColors.commonAppBarGradient),
child: Padding( child: Padding(
padding: padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 16), const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
...@@ -123,7 +123,7 @@ class _AddComplaintScreenState extends State<AddComplaintScreen> { ...@@ -123,7 +123,7 @@ class _AddComplaintScreenState extends State<AddComplaintScreen> {
/// Main content /// Main content
SliverToBoxAdapter( SliverToBoxAdapter(
child: Container( child: Container(
color: AppColors.primary, color: AppColors.backgroundBottom,
child: Container( child: Container(
padding: padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 20), const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
......
...@@ -114,7 +114,9 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> { ...@@ -114,7 +114,9 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
], ],
background: Container( background: Container(
decoration: decoration:
const BoxDecoration(color: AppColors.primary), const BoxDecoration(
gradient: AppColors.commonAppBarGradient
),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Row( child: Row(
...@@ -149,7 +151,7 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> { ...@@ -149,7 +151,7 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
SliverToBoxAdapter( SliverToBoxAdapter(
child: Container( child: Container(
padding: const EdgeInsets.only(top: 1), padding: const EdgeInsets.only(top: 1),
color: AppColors.primary, color: AppColors.backgroundBottom,
child: Container( child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
decoration: const BoxDecoration( decoration: const BoxDecoration(
...@@ -318,14 +320,14 @@ class ComplaintCard extends StatelessWidget { ...@@ -318,14 +320,14 @@ class ComplaintCard extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade200), // border: Border.all(color: Colors.grey.shade200),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.grey.shade200, // color: Colors.grey.shade200,
blurRadius: 4, // blurRadius: 4,
offset: const Offset(0, 2), // offset: const Offset(0, 2),
) // )
], // ],
), ),
child: Column( child: Column(
children: [ children: [
......
...@@ -108,7 +108,7 @@ class _SelectOrderHelpScreenState extends State<SelectOrderHelpScreen> { ...@@ -108,7 +108,7 @@ class _SelectOrderHelpScreenState extends State<SelectOrderHelpScreen> {
StretchMode.blurBackground, StretchMode.blurBackground,
], ],
background: Container( background: Container(
decoration: const BoxDecoration(color: AppColors.primary), decoration: const BoxDecoration(gradient: AppColors.commonAppBarGradient),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 16, horizontal: 16,
...@@ -145,7 +145,7 @@ class _SelectOrderHelpScreenState extends State<SelectOrderHelpScreen> { ...@@ -145,7 +145,7 @@ class _SelectOrderHelpScreenState extends State<SelectOrderHelpScreen> {
/// Main content /// Main content
SliverToBoxAdapter( SliverToBoxAdapter(
child: Container( child: Container(
color: AppColors.primary, color: AppColors.backgroundBottom,
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 16, horizontal: 16,
......
...@@ -9,8 +9,10 @@ import 'package:gen_service/Screens/ProfileScreen.dart'; ...@@ -9,8 +9,10 @@ import 'package:gen_service/Screens/ProfileScreen.dart';
import 'package:gen_service/Screens/TransactionScreens/TransactionListScreen.dart'; import 'package:gen_service/Screens/TransactionScreens/TransactionListScreen.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../Notifiers/DashboardProvider.dart'; import '../Notifiers/DashboardProvider.dart';
import '../Notifiers/PayAmountProvider.dart';
import '../Utility/AppColors.dart'; import '../Utility/AppColors.dart';
...@@ -20,11 +22,13 @@ import 'generatorDetailsScreen.dart'; ...@@ -20,11 +22,13 @@ import 'generatorDetailsScreen.dart';
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
final String accId; final String accId;
final String sessionId; final String sessionId;
final String mobNumber;
const HomeScreen({ const HomeScreen({
Key? key, Key? key,
required this.accId, required this.accId,
required this.sessionId, required this.sessionId,
required this.mobNumber,
}) : super(key: key); }) : super(key: key);
@override @override
...@@ -33,6 +37,10 @@ class HomeScreen extends StatefulWidget { ...@@ -33,6 +37,10 @@ class HomeScreen extends StatefulWidget {
class _HomeScreenState extends State<HomeScreen> { class _HomeScreenState extends State<HomeScreen> {
late Razorpay _razorpay;
bool? isSuccess;
var paymentMethod = "";
var User_contact = "0";
bool _stretch = true; bool _stretch = true;
DateTime? currentBackPressTime; DateTime? currentBackPressTime;
...@@ -40,12 +48,136 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -40,12 +48,136 @@ class _HomeScreenState extends State<HomeScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_razorpay = Razorpay();
Future.microtask(() { Future.microtask(() {
final dashboardProvider = final dashboardProvider =
Provider.of<DashboardProvider>(context, listen: false); Provider.of<DashboardProvider>(context, listen: false);
dashboardProvider.fetchDashboard(widget.accId, widget.sessionId); dashboardProvider.fetchDashboard(widget.accId, widget.sessionId);
}); });
} }
//_________________________________________________________
void _handlePaymentSuccess(PaymentSuccessResponse response) {
setState(() async {
final provider = Provider.of<PayAmountProvider>(context, listen: false);
await provider.getPaymentStatus(
sessionId: widget.sessionId,
empId: widget.accId,
razorpayOrderId: response.orderId.toString()
);
final data = provider.statusResponse;
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => PaymentSuccessFaillScreen(
// total: "${data?.amount}",
// date: "${data?.date}",
// payMode: "UPI",
// status: "Success",
// )),
// );
_razorpay.clear();
CustomSnackBar.showSuccess(
context: context,
message: data?.message ?? "Payment Success!",
);
// buttonLoading = false;
});
}
void _handlePaymentError(PaymentFailureResponse response) {
setState(() async {
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
});
_razorpay.clear();
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
}
void _handleExternalWallet(ExternalWalletResponse response) {
_razorpay.clear();
}
Future<void> payAmountFunction(String amount) async {
try {
final provider = Provider.of<PayAmountProvider>(context, listen: false);
await provider.payAmount(
sessionId: widget.sessionId,
empId: widget.accId,
amount: amount,
refType: "Gen Service",
refId: "1",
);
final data = provider.payResponse;
if (data != null) {
if (data.error == "0") {
openCheckout(data.orderId, data.razorKey!);
} else {
CustomSnackBar.showError(
context: context,
message: "${data.message}",
);
debugPrint("❌ Could not Complete Payment: ${data.message}");
}
} else {
debugPrint("❌ No response received from PayAmount API");
}
} catch (e) {
debugPrint("❌ 'Error occurred: $e'");
}
}
//razorpay payments__________________________________________________________
void openCheckout(razorPayOrderId, String razorpayKey) async {
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
// _buildCheckWidget();
Map<String, dynamic> options = {
'key': razorpayKey,
'amount': int.parse("${((0) * 100).round()}"),
'name': 'Gen Service',
'order_id': razorPayOrderId,
'description': "Bill",
'currency': 'INR',
'method': 'upi',
'prefill': {'contact': widget.mobNumber, 'email': ''}
};
// print(options);
try {
_razorpay.open(options);
} catch (e, s) {
// FirebaseCrashlytics.instance.log('Error occurred: $e');
// FirebaseCrashlytics.instance.recordError(e, s);
debugPrint(e.toString());
}
}
void verifyPayment(String orderId) {
isSuccess = true;
setState(() {
// toast(context, "Order Placed Successfully");
// print("Verify Payment");
});
_razorpay.clear();
}
// void onError(CFErrorResponse errorResponse, String orderId) {
// isSuccess = false;
// setState(() {
// // print(errorResponse.getMessage());
// // print("Error while making payment");
// });
// }
Future<bool> _onWillPop() async { Future<bool> _onWillPop() async {
...@@ -200,8 +332,8 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -200,8 +332,8 @@ class _HomeScreenState extends State<HomeScreen> {
data.userName.toString(), data.userName.toString(),
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 20, fontSize: 24,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w400,
), ),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
...@@ -211,8 +343,9 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -211,8 +343,9 @@ class _HomeScreenState extends State<HomeScreen> {
Text( Text(
'+91 ${data.mobNum}', '+91 ${data.mobNum}',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w400,
color: Colors.white.withOpacity(0.9), color: Colors.white.withOpacity(0.9),
fontSize: 14, fontSize: 16,
), ),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
...@@ -288,7 +421,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -288,7 +421,7 @@ class _HomeScreenState extends State<HomeScreen> {
Text('Facing Issues?', Text('Facing Issues?',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w400,
color: AppColors.amountText)), color: AppColors.amountText)),
Text( Text(
'Raise a ticket to resolve your issues.', 'Raise a ticket to resolve your issues.',
...@@ -318,7 +451,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -318,7 +451,7 @@ class _HomeScreenState extends State<HomeScreen> {
}, },
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 22),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.amountText, color: AppColors.amountText,
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
...@@ -339,7 +472,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -339,7 +472,7 @@ class _HomeScreenState extends State<HomeScreen> {
'Get in touch With Us', 'Get in touch With Us',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w400,
color: Colors.white), color: Colors.white),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
...@@ -353,7 +486,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -353,7 +486,7 @@ class _HomeScreenState extends State<HomeScreen> {
], ],
), ),
), ),
const Icon(Icons.arrow_circle_right, const Icon(Icons.arrow_circle_right_sharp,
color: Color(0xFFFFFFFF), size: 30), color: Color(0xFFFFFFFF), size: 30),
], ],
), ),
...@@ -471,119 +604,116 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -471,119 +604,116 @@ class _HomeScreenState extends State<HomeScreen> {
description, description,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w400,
color: AppColors.normalText, color: AppColors.normalText,
height: 1.4, height: 1.4,
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Padding( Row(
padding: const EdgeInsets.symmetric(horizontal: 14), children: [
child: Row( // Status Badge with checkmark for AMC Protected
mainAxisAlignment: MainAxisAlignment.spaceBetween, if (amc == "1" || amc == "2")
children: [ Container(
// Status Badge with checkmark for AMC Protected padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
if (amc == "1" || amc == "2") decoration: BoxDecoration(
Container( gradient: amc == "1"
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), ? AppColors.greenStripGradient
decoration: BoxDecoration( : AppColors.fadeGradient,
gradient: amc == "1" borderRadius: BorderRadius.circular(12),
? AppColors.greenStripGradient ),
: AppColors.fadeGradient, child: Row(
borderRadius: BorderRadius.circular(12), mainAxisSize: MainAxisSize.min,
), children: [
child: Row( Row(
mainAxisSize: MainAxisSize.min, children: [
children: [ SvgPicture.asset(
Row( "assets/svg/tick_ic.svg",
children: [ height: 14,
SvgPicture.asset( color: amc == "1"
"assets/svg/tick_ic.svg", ? AppColors.greenICBg
height: 14, : AppColors.subtitleText,
),
const SizedBox(width: 4),
Text(
"AMC ",
style: TextStyle(
fontSize: 11,
fontFamily: "PoppinsBold",
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w700,
color: amc == "1" color: amc == "1"
? AppColors.greenICBg ? AppColors.greenICBg
: AppColors.subtitleText, : AppColors.subtitleText,
), ),
const SizedBox(width: 4), ),
Text( Text(
"AMC ", "Protected",
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
fontFamily: "PoppinsBold", fontFamily: "PoppinsBold",
fontStyle: FontStyle.italic, fontStyle: FontStyle.italic,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: amc == "1" color: amc == "1"
? AppColors.greenICBg ? AppColors.normalText
: AppColors.subtitleText, : AppColors.subtitleText,
),
),
Text(
"Protected",
style: TextStyle(
fontSize: 11,
fontFamily: "PoppinsBold",
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w700,
color: amc == "1"
? AppColors.normalText
: AppColors.subtitleText,
),
), ),
SizedBox(width: 4,), ),
if (amc == "2") SizedBox(width: 4,),
const Icon(Icons.info_outline, color: Colors.red, size: 12,) if (amc == "2")
], const Icon(Icons.info_outline, color: Colors.red, size: 12,)
), ],
], ),
), ],
), ),
),
if (amc == "1" || amc == "2")
// for warranty SizedBox(width: 16,),
if (warranty == "1" || warranty == "2") // for warranty
Container( if (warranty == "1" || warranty == "2")
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), Container(
decoration: BoxDecoration( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
gradient: warranty == "1" decoration: BoxDecoration(
? AppColors.yellowStripGradient gradient: warranty == "1"
: AppColors.fadeGradient, ? AppColors.yellowStripGradient
borderRadius: BorderRadius.circular(12), : AppColors.fadeGradient,
), borderRadius: BorderRadius.circular(12),
child: Row( ),
mainAxisSize: MainAxisSize.min, child: Row(
children: [ mainAxisSize: MainAxisSize.min,
Row( children: [
children: [ Row(
SvgPicture.asset( children: [
"assets/svg/tick2_ic.svg", SvgPicture.asset(
height: 14, "assets/svg/tick2_ic.svg",
height: 14,
color: warranty == "1"
? AppColors.warning
: AppColors.subtitleText,
),
const SizedBox(width: 6),
Text(
" Warranty",
style: TextStyle(
fontSize: 11,
fontFamily: "PoppinsBold",
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w700,
color: warranty == "1" color: warranty == "1"
? AppColors.warning ? AppColors.normalText
: AppColors.subtitleText, : AppColors.subtitleText,
), ),
const SizedBox(width: 6), ),
Text( SizedBox(width: 6,),
"Warranty", if (warranty == "2")
style: TextStyle( const Icon(Icons.info_outline, color: Colors.red, size: 12,)
fontSize: 11, ],
fontFamily: "PoppinsBold", ),
fontStyle: FontStyle.italic, ],
fontWeight: FontWeight.w700,
color: warranty == "1"
? AppColors.normalText
: AppColors.subtitleText,
),
),
SizedBox(width: 6,),
if (warranty == "2")
const Icon(Icons.info_outline, color: Colors.red, size: 12,)
],
),
],
),
), ),
], ),
), ],
) )
], ],
...@@ -633,9 +763,9 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -633,9 +763,9 @@ class _HomeScreenState extends State<HomeScreen> {
Text( Text(
date, date,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 16,
color: AppColors.normalText, color: AppColors.normalText,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w400,
), ),
), ),
Text( Text(
...@@ -643,7 +773,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -643,7 +773,7 @@ class _HomeScreenState extends State<HomeScreen> {
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: AppColors.subtitleText, color: AppColors.subtitleText,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w400,
), ),
), ),
], ],
...@@ -670,7 +800,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -670,7 +800,7 @@ class _HomeScreenState extends State<HomeScreen> {
const Text( const Text(
'Transactions', 'Transactions',
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 15,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.black87, color: Colors.black87,
), ),
...@@ -695,7 +825,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -695,7 +825,7 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(height: 8), const SizedBox(height: 8),
Container( Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.all(22), padding: EdgeInsets.all(22),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: dashboardData.balanceType == 'Pending Balance'? AppColors.balanceCardGradientP : AppColors.balanceCardGradientA, gradient: dashboardData.balanceType == 'Pending Balance'? AppColors.balanceCardGradientP : AppColors.balanceCardGradientA,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
...@@ -703,84 +833,90 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -703,84 +833,90 @@ class _HomeScreenState extends State<HomeScreen> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Column( Expanded(
crossAxisAlignment: CrossAxisAlignment.start, flex: 6,
children: [ child: Column(
Row( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Row(
Text( crossAxisAlignment: CrossAxisAlignment.start,
"₹", children: [
style: TextStyle( Text(
color: Colors.white, "₹",
fontSize: 20, style: TextStyle(
height: 2, color: Colors.white,
fontWeight: FontWeight.w500, fontSize: 20,
height: 2,
fontWeight: FontWeight.w500,
),
), ),
), Text(
Text( dashboardData?.balanceAmount?.toString() ?? "0",
dashboardData?.balanceAmount?.toString() ?? "0", style: TextStyle(
style: TextStyle( color: Colors.white,
color: Colors.white, fontSize: 34,
fontSize: 34, fontWeight: FontWeight.w500,
fontWeight: FontWeight.w500, ),
), ),
), ],
], ),
), const SizedBox(height: 4),
const SizedBox(height: 4), Row(
Row( children: [
children: [ const Icon(Icons.info_outline,
const Icon(Icons.info_outline, color: Colors.white, size: 16),
color: Colors.white, size: 16), const SizedBox(width: 6),
const SizedBox(width: 6), Text(
Text( dashboardData.balanceType ?? '',
dashboardData.balanceType ?? 'Pending Balance', style: const TextStyle(
style: const TextStyle( color: Colors.white,
color: Colors.white, fontWeight: FontWeight.w400,
fontSize: 14, fontSize: 12,
),
), ),
), ],
],
),
],
),
Column(
children: [
Text(
"*Make sure to pay before\n you incur any fines.",
maxLines: 2,
style: TextStyle(
color: const Color(0xAAFFFFFF),
fontSize: 12,
fontWeight: FontWeight.w500,
), ),
), ],
const SizedBox(height: 10), ),
if (dashboardData.balanceType == 'Pending Balance') ),
InkResponse( Expanded(
onTap: () { flex: 6,
// Add pay now logic child: Column(
}, children: [
child: Container( Text(
padding: "*Make sure to pay before\n you incur any fines.",
const EdgeInsets.symmetric(horizontal: 20, vertical: 8), maxLines: 2,
decoration: BoxDecoration( textAlign: TextAlign.end,
color: Colors.white, style: TextStyle(
borderRadius: BorderRadius.circular(20), color: const Color(0xAAFFFFFF),
fontSize: 12,
fontWeight: FontWeight.w400,
), ),
child: const Text( ),
" Pay Now ", const SizedBox(height: 10),
style: TextStyle( if (dashboardData.balanceType == 'Pending Balance')
color: Colors.blue, InkResponse(
fontFamily: "Poppins", onTap: ()=> _openPaymentSheet(context, dashboardData?.balanceAmount!),
fontSize: 14, child: Container(
fontWeight: FontWeight.w500, padding:
const EdgeInsets.symmetric(horizontal: 23, vertical: 7),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: const Text(
" Pay Now ",
style: TextStyle(
color: Colors.blue,
fontFamily: "Poppins",
fontSize: 14,
fontWeight: FontWeight.w500,
),
), ),
), ),
), ),
), ],
], ),
), ),
], ],
), ),
...@@ -873,7 +1009,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -873,7 +1009,7 @@ class _HomeScreenState extends State<HomeScreen> {
"#${c.hashId ?? ''} | ${c.complaintName ?? ''}", "#${c.hashId ?? ''} | ${c.complaintName ?? ''}",
style: const TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.amountText, color: AppColors.amountText,
), ),
), ),
...@@ -882,7 +1018,8 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -882,7 +1018,8 @@ class _HomeScreenState extends State<HomeScreen> {
c.registredDate ?? '', c.registredDate ?? '',
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Colors.grey.shade600, fontWeight: FontWeight.w400,
color: AppColors.subtitleText,
), ),
), ),
], ],
...@@ -891,7 +1028,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -891,7 +1028,7 @@ class _HomeScreenState extends State<HomeScreen> {
// Status badge // Status badge
Container( Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 8), horizontal: 16, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
color: (c.openStatus?.toLowerCase() == 'open') color: (c.openStatus?.toLowerCase() == 'open')
? AppColors.successBG ? AppColors.successBG
...@@ -901,8 +1038,8 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -901,8 +1038,8 @@ class _HomeScreenState extends State<HomeScreen> {
child: Text( child: Text(
c.openStatus ?? '', c.openStatus ?? '',
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w400,
color: (c.openStatus?.toLowerCase() == 'open') color: (c.openStatus?.toLowerCase() == 'open')
? AppColors.success ? AppColors.success
: AppColors.warningText, : AppColors.warningText,
...@@ -923,8 +1060,8 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -923,8 +1060,8 @@ class _HomeScreenState extends State<HomeScreen> {
child: Text( child: Text(
c.productName ?? "Unknown Product", c.productName ?? "Unknown Product",
style: const TextStyle( style: const TextStyle(
fontSize: 14, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w400,
color: AppColors.normalText, color: AppColors.normalText,
), ),
), ),
...@@ -936,7 +1073,7 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -936,7 +1073,7 @@ class _HomeScreenState extends State<HomeScreen> {
"#${c.id ?? ''} | ", "#${c.id ?? ''} | ",
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w400,
color: AppColors.subtitleText, color: AppColors.subtitleText,
), ),
), ),
...@@ -961,4 +1098,248 @@ class _HomeScreenState extends State<HomeScreen> { ...@@ -961,4 +1098,248 @@ class _HomeScreenState extends State<HomeScreen> {
); );
} }
void _openPaymentSheet(BuildContext context, String totalAmountStr) {
TextEditingController amountController = TextEditingController();
bool isPartPayment = false;
final double totalAmount = double.tryParse(totalAmountStr) ?? 0;
showModalBottomSheet(
isScrollControlled: true,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
top: 16,
left: 16,
right: 16,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Handle Bar
Center(
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
),
),
const SizedBox(height: 16),
// Title
const Text(
"Balance Amount Bill",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
const SizedBox(height: 6),
Divider(),
const SizedBox(height: 10),
// Pay Total Option
GestureDetector(
onTap: () {
setState(() => isPartPayment = false);
},
child: Row(
children: [
Radio<bool>(
value: false,
groupValue: isPartPayment,
onChanged: (v) => setState(() => isPartPayment = v!),
activeColor: const Color(0xFF008CDE),
),
// Radio<bool>(
// value: false,
// groupValue: isPartPayment,
// onChanged: (v) => setState(() => isPartPayment = v!),
// ),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Pay Total",
style: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
Text(
"Avoid late payment fees.",
style: TextStyle(
color: Color(0xff5FBB54),
fontSize: 12,
fontFamily: "Poppins",
),
),
],
),
const Spacer(),
Text(
"₹${totalAmount.toStringAsFixed(0)}",
style: const TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
],
),
),
const SizedBox(height: 10),
// Part Payment Option
GestureDetector(
onTap: () {
setState(() => isPartPayment = true);
},
child: Row(
children: [
Radio<bool>(
value: true,
groupValue: isPartPayment,
onChanged: (v) => setState(() => isPartPayment = v!),
activeColor: const Color(0xFF008CDE),
),
const Text(
"Part Payment",
style: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
const SizedBox(width: 24),
Expanded(
child: Container(
height: 50,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
),
child: TextFormField(
controller: amountController,
enabled: isPartPayment,
style: const TextStyle(
fontSize: 14,
fontFamily: "Poppins",
color: Colors.black87,
),
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: "Enter amount",
hintStyle: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
color: Colors.grey,
),
border: InputBorder.none,
),
),
),
),
],
),
),
const SizedBox(height: 6),
Divider(),
const SizedBox(height: 6),
// Continue Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
double enteredAmount = isPartPayment
? double.tryParse(amountController.text) ?? 0
: totalAmount;
if (enteredAmount <= 0) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Please enter a valid amount"),
),
);
return;
}
if (isPartPayment && enteredAmount > totalAmount) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
"Entered amount cannot exceed total amount",
),
),
);
return;
}
Navigator.pop(context);
// Pass selected amount to your payAmountFunction
payAmountFunction(enteredAmount.toStringAsFixed(2));
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF008CDE),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 22),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Continue Payment",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.white,
fontSize: 16,
),
),
SvgPicture.asset(
"assets/svg/continue_ic.svg",
color: Colors.white,
height: 25,
width: 25,
),
],
),
),
),
),
const SizedBox(height: 16),
],
),
);
},
);
},
);
}
} }
\ No newline at end of file
...@@ -356,7 +356,7 @@ class _ProfileScreenState extends State<ProfileScreen> { ...@@ -356,7 +356,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
profileProvider.fetchProfile(widget.accId, widget.sessionId); profileProvider.fetchProfile(widget.accId, widget.sessionId);
}, },
stretchTriggerOffset: 300.0, stretchTriggerOffset: 300.0,
expandedHeight: 245.0, expandedHeight: 260.0,
flexibleSpace: LayoutBuilder( flexibleSpace: LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
final top = constraints.biggest.height; final top = constraints.biggest.height;
...@@ -418,8 +418,8 @@ class _ProfileScreenState extends State<ProfileScreen> { ...@@ -418,8 +418,8 @@ class _ProfileScreenState extends State<ProfileScreen> {
data.name.toString(), data.name.toString(),
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 20, fontSize: 24,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w400,
), ),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
...@@ -429,8 +429,9 @@ class _ProfileScreenState extends State<ProfileScreen> { ...@@ -429,8 +429,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
Text( Text(
'+91 ${data.mobNum}', '+91 ${data.mobNum}',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w400,
color: Colors.white.withOpacity(0.9), color: Colors.white.withOpacity(0.9),
fontSize: 14, fontSize: 16,
), ),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
...@@ -449,7 +450,7 @@ class _ProfileScreenState extends State<ProfileScreen> { ...@@ -449,7 +450,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
" Logout ", " Logout ",
style: TextStyle( style: TextStyle(
color: AppColors.normalText, color: AppColors.normalText,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w600,
fontSize: 14, fontSize: 14,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
...@@ -582,7 +583,7 @@ class _ProfileScreenState extends State<ProfileScreen> { ...@@ -582,7 +583,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
padding: EdgeInsets.all(16), padding: EdgeInsets.all(16),
child: Row( child: Row(
children: [ children: [
if(title != "State" && title != "Sub Locality")
Container( Container(
padding: EdgeInsets.all(title =="Address" ? 8 :12), padding: EdgeInsets.all(title =="Address" ? 8 :12),
decoration: BoxDecoration( decoration: BoxDecoration(
...@@ -595,20 +596,7 @@ class _ProfileScreenState extends State<ProfileScreen> { ...@@ -595,20 +596,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
), ),
if(title != "Email ID" && title != "Address")
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.all(14),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(18)
),
child: SizedBox(
width: 24,
height: 24,
),
),
),
SizedBox(width: 14,), SizedBox(width: 14,),
Expanded( Expanded(
flex: 7, flex: 7,
......
...@@ -117,6 +117,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt ...@@ -117,6 +117,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
Future<void> _navigateToDashboard() async { Future<void> _navigateToDashboard() async {
final String? savedAccId = await prefs.getString("accId"); final String? savedAccId = await prefs.getString("accId");
final String? savedSessionId = await prefs.getString("session_id"); final String? savedSessionId = await prefs.getString("session_id");
final String? mobNumber = await prefs.getString("mob_number");
if (savedAccId != null && savedAccId.isNotEmpty) { if (savedAccId != null && savedAccId.isNotEmpty) {
Navigator.pushReplacement( Navigator.pushReplacement(
...@@ -125,6 +126,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt ...@@ -125,6 +126,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
pageBuilder: (_, __, ___) => HomeScreen( pageBuilder: (_, __, ___) => HomeScreen(
accId: savedAccId, accId: savedAccId,
sessionId: savedSessionId.toString(), sessionId: savedSessionId.toString(),
mobNumber: mobNumber.toString(),
), ),
transitionsBuilder: (_, animation, __, child) { transitionsBuilder: (_, animation, __, child) {
return FadeTransition( return FadeTransition(
...@@ -513,7 +515,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt ...@@ -513,7 +515,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
"Avantect Web Grid", "Avantech Web Grid",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:gen_service/Notifiers/TransactionsProvider.dart'; import 'package:gen_service/Notifiers/TransactionsProvider.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../../Notifiers/PayAmountProvider.dart';
import '../../Utility/AppColors.dart'; import '../../Utility/AppColors.dart';
import '../../Utility/CustomSnackbar.dart'; import '../../Utility/CustomSnackbar.dart';
import '../../Utility/SharedpreferencesService.dart';
class BillDetailScreen extends StatefulWidget { class BillDetailScreen extends StatefulWidget {
final String sessionId; final String sessionId;
...@@ -21,15 +24,159 @@ class BillDetailScreen extends StatefulWidget { ...@@ -21,15 +24,159 @@ class BillDetailScreen extends StatefulWidget {
} }
class _BillDetailScreenState extends State<BillDetailScreen> { class _BillDetailScreenState extends State<BillDetailScreen> {
late Razorpay _razorpay;
bool? isSuccess;
var paymentMethod = "";
var User_contact = "0";
final prefs = SharedPreferencesService.instance;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_razorpay =Razorpay();
Future.microtask(() { Future.microtask(() {
final provider = Provider.of<TransactionsProvider>(context, listen: false); final provider = Provider.of<TransactionsProvider>(context, listen: false);
provider.fetchBillDetails(widget.accId, widget.sessionId, widget.billId); provider.fetchBillDetails(widget.accId, widget.sessionId, widget.billId);
}); });
} }
//_________________________________________________________
void _handlePaymentSuccess(PaymentSuccessResponse response) {
setState(() async {
final provider = Provider.of<PayAmountProvider>(context, listen: false);
await provider.getPaymentStatus(
sessionId: widget.sessionId,
empId: widget.accId,
razorpayOrderId: response.orderId.toString()
);
final data = provider.statusResponse;
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => PaymentSuccessFaillScreen(
// total: "${data?.amount}",
// date: "${data?.date}",
// payMode: "UPI",
// status: "Success",
// )),
// );
_razorpay.clear();
CustomSnackBar.showSuccess(
context: context,
message: data?.message ?? "Payment Success!",
);
// buttonLoading = false;
});
}
void _handlePaymentError(PaymentFailureResponse response) {
setState(() async {
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => PaymentSuccessFaillScreen(
// total: "${data?.amount}",
// date: "${data?.date}",
// payMode: "UPI",
// status: "Fail",
// )),
// );
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
});
_razorpay.clear();
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
}
void _handleExternalWallet(ExternalWalletResponse response) {
_razorpay.clear();
}
Future<void> payAmountFunction(String amount, String id) async {
try {
final provider = Provider.of<PayAmountProvider>(context, listen: false);
await provider.payAmount(
sessionId: widget.sessionId,
empId: widget.accId,
amount: amount,
refType: "Payment",
refId: id,
);
final data = provider.payResponse;
if (data != null) {
if (data.error == "0") {
openCheckout(data.orderId, data.razorKey!);
} else {
CustomSnackBar.showError(
context: context,
message: "${data.message}",
);
debugPrint("❌ Could not Complete Payment: ${data.message}");
}
} else {
debugPrint("❌ No response received from PayAmount API");
}
} catch (e) {
debugPrint("❌ 'Error occurred: $e'");
}
}
//razorpay payments__________________________________________________________
void openCheckout(razorPayOrderId, String razorpayKey) async {
final String? mobNumber = await prefs.getString("mob_number");
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
// _buildCheckWidget();
Map<String, dynamic> options = {
'key': razorpayKey,
'amount': int.parse("${((0) * 100).round()}"),
'name': 'Gen Service',
'order_id': razorPayOrderId,
'description': "Bill",
'currency': 'INR',
'method': 'upi',
'prefill': {'contact': mobNumber, 'email': ''}
};
// print(options);
try {
_razorpay.open(options);
} catch (e, s) {
// FirebaseCrashlytics.instance.log('Error occurred: $e');
// FirebaseCrashlytics.instance.recordError(e, s);
debugPrint(e.toString());
}
}
void verifyPayment(String orderId) {
isSuccess = true;
setState(() {
// toast(context, "Order Placed Successfully");
// print("Verify Payment");
});
_razorpay.clear();
}
// void onError(CFErrorResponse errorResponse, String orderId) {
// isSuccess = false;
// setState(() {
// // print(errorResponse.getMessage());
// // print("Error while making payment");
// });
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<TransactionsProvider>( return Consumer<TransactionsProvider>(
...@@ -92,7 +239,7 @@ class _BillDetailScreenState extends State<BillDetailScreen> { ...@@ -92,7 +239,7 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
// Amount // Amount
Text( Text(
"₹${details.totalAmount ?? "0"}", "₹${details.totalAmount}",
style: const TextStyle( style: const TextStyle(
fontSize: 32, fontSize: 32,
fontFamily: "Poppins", fontFamily: "Poppins",
...@@ -221,7 +368,17 @@ class _BillDetailScreenState extends State<BillDetailScreen> { ...@@ -221,7 +368,17 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
Expanded( Expanded(
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
// Razorpay or Payment if(details.totalAmount == "0.00") {
CustomSnackBar.showWarning(
context: context,
message: "Invalid amount or less then 1",
);
}else{
Navigator.pop(context);
// handle payment navigation
payAmountFunction(details.totalAmount.toString(), details.id.toString());
}
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppColors.amountText, backgroundColor: AppColors.amountText,
......
...@@ -3,8 +3,13 @@ import 'package:flutter_svg/flutter_svg.dart'; ...@@ -3,8 +3,13 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:gen_service/Screens/TransactionScreens/BillDetailScreen.dart'; import 'package:gen_service/Screens/TransactionScreens/BillDetailScreen.dart';
import 'package:gen_service/Screens/TransactionScreens/PaymentDetails.dart'; import 'package:gen_service/Screens/TransactionScreens/PaymentDetails.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../../Models/TransactionModels/TransactionListResponse.dart';
import '../../Notifiers/PayAmountProvider.dart';
import '../../Notifiers/TransactionsProvider.dart'; import '../../Notifiers/TransactionsProvider.dart';
import '../../Utility/AppColors.dart'; import '../../Utility/AppColors.dart';
import '../../Utility/CustomSnackbar.dart';
import '../../Utility/SharedpreferencesService.dart';
class TransactionListScreen extends StatefulWidget { class TransactionListScreen extends StatefulWidget {
final String accId; final String accId;
...@@ -22,14 +27,175 @@ class TransactionListScreen extends StatefulWidget { ...@@ -22,14 +27,175 @@ class TransactionListScreen extends StatefulWidget {
class _TransactionScreenState extends State<TransactionListScreen> { class _TransactionScreenState extends State<TransactionListScreen> {
bool _stretch = true; bool _stretch = true;
late Razorpay _razorpay;
bool? isSuccess;
var paymentMethod = "";
var User_contact = "0";
final ScrollController _scrollController = ScrollController();
final prefs = SharedPreferencesService.instance;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_razorpay = Razorpay();
// Initial data load
Future.microtask(() { Future.microtask(() {
Provider.of<TransactionsProvider>(context, listen: false) Provider.of<TransactionsProvider>(context, listen: false)
.fetchTransactions(widget.accId, widget.sessionId); .fetchTransactions(widget.accId, widget.sessionId);
}); });
// Setup scroll listener for pagination
_scrollController.addListener(_scrollListener);
}
//_________________________________________________________
void _handlePaymentSuccess(PaymentSuccessResponse response) {
setState(() async {
final provider = Provider.of<PayAmountProvider>(context, listen: false);
await provider.getPaymentStatus(
sessionId: widget.sessionId,
empId: widget.accId,
razorpayOrderId: response.orderId.toString()
);
final data = provider.statusResponse;
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => PaymentSuccessFaillScreen(
// total: "${data?.amount}",
// date: "${data?.date}",
// payMode: "UPI",
// status: "Success",
// )),
// );
_razorpay.clear();
CustomSnackBar.showSuccess(
context: context,
message: data?.message ?? "Payment Success!",
);
// buttonLoading = false;
});
}
void _handlePaymentError(PaymentFailureResponse response) {
setState(() async {
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
});
_razorpay.clear();
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
}
void _handleExternalWallet(ExternalWalletResponse response) {
_razorpay.clear();
}
Future<void> payAmountFunction(String amount) async {
try {
final provider = Provider.of<PayAmountProvider>(context, listen: false);
await provider.payAmount(
sessionId: widget.sessionId,
empId: widget.accId,
amount: amount,
refType: "Payment",
refId: "1",
);
final data = provider.payResponse;
if (data != null) {
if (data.error == "0") {
openCheckout(data.orderId, data.razorKey!);
} else {
CustomSnackBar.showError(
context: context,
message: "${data.message}",
);
debugPrint("❌ Could not Complete Payment: ${data.message}");
}
} else {
debugPrint("❌ No response received from PayAmount API");
}
} catch (e) {
debugPrint("❌ 'Error occurred: $e'");
}
}
//razorpay payments__________________________________________________________
void openCheckout(razorPayOrderId, String razorpayKey) async {
final String? mobNumber = await prefs.getString("mob_number");
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
// _buildCheckWidget();
Map<String, dynamic> options = {
'key': razorpayKey,
'amount': int.parse("${((0) * 100).round()}"),
'name': 'Gen Service',
'order_id': razorPayOrderId,
'description': "Bill",
'currency': 'INR',
'method': 'upi',
'prefill': {'contact': mobNumber, 'email': ''}
};
// print(options);
try {
_razorpay.open(options);
} catch (e, s) {
// FirebaseCrashlytics.instance.log('Error occurred: $e');
// FirebaseCrashlytics.instance.recordError(e, s);
debugPrint(e.toString());
}
}
void verifyPayment(String orderId) {
isSuccess = true;
setState(() {
// toast(context, "Order Placed Successfully");
// print("Verify Payment");
});
_razorpay.clear();
}
// void onError(CFErrorResponse errorResponse, String orderId) {
// isSuccess = false;
// setState(() {
// // print(errorResponse.getMessage());
// // print("Error while making payment");
// });
// }
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _scrollListener() {
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent - 200) {
_loadMore();
}
}
void _loadMore() {
final provider = Provider.of<TransactionsProvider>(context, listen: false);
if (!provider.isLoadingMore && provider.hasMore) {
provider.loadMoreTransactions(widget.accId, widget.sessionId);
}
} }
@override @override
...@@ -38,11 +204,11 @@ class _TransactionScreenState extends State<TransactionListScreen> { ...@@ -38,11 +204,11 @@ class _TransactionScreenState extends State<TransactionListScreen> {
final balance = provider.transactionList?.balanceAmount ?? "0"; final balance = provider.transactionList?.balanceAmount ?? "0";
final balanceType = provider.transactionList?.balanceType ?? "Pending"; final balanceType = provider.transactionList?.balanceType ?? "Pending";
final lastPaid = provider.transactionList?.lastPaid;
final totalCredit = provider.transactionList?.totalCredit ?? "0"; final totalCredit = provider.transactionList?.totalCredit ?? "0";
final totalDebit = provider.transactionList?.totalDebit ?? "0"; final totalDebit = provider.transactionList?.totalDebit ?? "0";
final transactions = provider.transactionList?.transactions ?? {}; final transactions = provider.transactionList?.transactions ?? {};
bool isPending = balanceType.toLowerCase() =="pending balance"; bool isPending = balanceType.toLowerCase() == "pending balance";
return RefreshIndicator.adaptive( return RefreshIndicator.adaptive(
color: AppColors.amountText, color: AppColors.amountText,
...@@ -51,80 +217,144 @@ class _TransactionScreenState extends State<TransactionListScreen> { ...@@ -51,80 +217,144 @@ class _TransactionScreenState extends State<TransactionListScreen> {
Provider.of<TransactionsProvider>(context, listen: false) Provider.of<TransactionsProvider>(context, listen: false)
.fetchTransactions(widget.accId, widget.sessionId); .fetchTransactions(widget.accId, widget.sessionId);
}, },
child: Scaffold( child: Scaffold(
backgroundColor: AppColors.backgroundRegular, backgroundColor: AppColors.backgroundRegular,
body: CustomScrollView( body: CustomScrollView(
controller: _scrollController, // Add controller here
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
slivers: [ slivers: [
/// Top SliverAppBar (balance card) /// Top SliverAppBar (balance card) - No changes
SliverAppBar( SliverAppBar(
stretch: _stretch, stretch: _stretch,
pinned: true, pinned: true,
expandedHeight: 245, expandedHeight: isPending ? 252 : 210,
backgroundColor: AppColors.errorBg, backgroundColor: isPending ? AppColors.errorBg : Color(0xFF4076FF),
elevation: 0, // Remove shadow elevation: 0,
leading: Container(),
leading: Container(), // Remove back button toolbarHeight: 0,
toolbarHeight: 0, // Remove toolbar space collapsedHeight: 0,
collapsedHeight: 0, // Completely collapse to 0 height
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
stretchModes: const [StretchMode.zoomBackground], stretchModes: const [StretchMode.zoomBackground],
background: Container( background: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: isPending ? AppColors.balanceBarGradientP : AppColors.balanceBarGradientA, gradient: isPending
? AppColors.balanceBarGradientP
: AppColors.balanceBarGradientA,
), ),
child: SafeArea( child: SafeArea(
child: Padding( child: Column(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), children: [
child: Column( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
const SizedBox(height: 20), SizedBox(width: 8,),
const Text( InkResponse(
"Transactions", onTap: () => Navigator.pop(context, true),
style: TextStyle( child: SvgPicture.asset(
color: Colors.white, color: Colors.white,
fontSize: 22, "assets/svg/continue_left_ic.svg",
fontWeight: FontWeight.bold, height: 30,
), ),
),
const SizedBox(height: 20),
Text(
"₹$balance",
style: const TextStyle(
color: Colors.white,
fontSize: 36,
fontWeight: FontWeight.w600,
), ),
), const SizedBox(width: 10),
Text( const Text(
"$balanceType", "Transactions",
style: const TextStyle(color: Colors.white70, fontSize: 16), style: TextStyle(
), fontSize: 16,
const SizedBox(height: 10), fontFamily: "Poppins",
if (isPending) fontWeight: FontWeight.w400,
ElevatedButton( color: Colors.white,
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.deepOrange,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
), ),
), ),
child: const Text("Pay Now"), ],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 20),
Text(
"₹$balance",
style: const TextStyle(
color: Colors.white,
fontSize: 34,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 2),
Text(
"$balanceType",
style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w400),
),
if(isPending == false)
const SizedBox(height: 4),
if(isPending == false)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.check_circle,
color: Colors.green,
size: 20,
),
SizedBox(width: 2,),
Text(
"Last Paid on $lastPaid.",
maxLines: 1,
style: TextStyle(
color: const Color(0xFeFFFFFF),
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
],
),
const SizedBox(height: 10),
if (isPending)
ElevatedButton(
onPressed: () =>_openPaymentSheet(context, balance),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.deepOrange,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
child: Text(
"Pay Now",
style: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
color: AppColors.buttonColor,
),
),
),
SizedBox(height: 8,),
if (isPending)
Text(
"*Make sure to pay before you incur any fines.",
maxLines: 1,
style: TextStyle(
color: const Color(0xAAFFFFFF),
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
],
), ),
], ),
), ],
), ),
), ),
), ),
), ),
), ),
/// Summary Row (Paid / Pending) /// Summary Row and Transaction List
SliverToBoxAdapter( SliverToBoxAdapter(
child: Container( child: Container(
color: isPending ? AppColors.errorBg : Color(0xFF4076FF), color: isPending ? AppColors.errorBg : Color(0xFF4076FF),
...@@ -139,7 +369,7 @@ class _TransactionScreenState extends State<TransactionListScreen> { ...@@ -139,7 +369,7 @@ class _TransactionScreenState extends State<TransactionListScreen> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 4,), const SizedBox(height: 4),
// Summary Card // Summary Card
Container( Container(
margin: const EdgeInsets.all(16), margin: const EdgeInsets.all(16),
...@@ -159,89 +389,139 @@ class _TransactionScreenState extends State<TransactionListScreen> { ...@@ -159,89 +389,139 @@ class _TransactionScreenState extends State<TransactionListScreen> {
), ),
), ),
// Transaction List // Transaction List
ListView.builder( _buildTransactionList(provider, transactions),
shrinkWrap: true, // important for embedding inside SliverToBoxAdapter
physics: const NeverScrollableScrollPhysics(), // disable inner scrolling
itemCount: transactions.length,
itemBuilder: (context, index) {
final month = transactions.keys.elementAt(index);
final items = transactions[month]!;
return Container(
color: AppColors.backgroundRegular,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
month,
style: const TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
const SizedBox(height: 8),
...items.map((item) {
final type = item.atype ?? "Debit";
final title = item.narration ?? "No details";
final date = item.datetime ?? "";
final id = item.id ?? "";
final amount = type.toLowerCase() == "credit"
? "₹${item.cAmount ?? "0"}"
: "₹${item.dAmount ?? "0"}";
return InkResponse(
onTap: () {
// for credit
if (item.atype == "Credit") {
showDialog(
context: context,
builder: (context) => PaymentdetailDialog(
sessionId: widget.sessionId,
accId: widget.accId,
billId: item.billId.toString(),
),
);
} else {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BillDetailScreen(
sessionId: widget.sessionId,
accId: widget.accId,
billId: item.billId.toString())
)
);
}
},
child: _buildTransactionItem(
type: type,
title: title,
id: id,
date: date,
amount: amount,
),
);
}).toList(),
],
),
);
},
),
], ],
), ),
), ),
), ),
) ),
/// Loading indicator for pagination
if (provider.isLoadingMore)
const SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: CircularProgressIndicator(color: AppColors.buttonColor),
),
),
),
/// No more data indicator
if (!provider.hasMore && transactions.isNotEmpty)
const SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: Text(
"No more transactions",
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
),
),
),
], ],
), ),
), ),
); );
} }
Widget _buildTransactionList(TransactionsProvider provider, Map<String, List<TransactionItem>> transactions) {
if (provider.isLoading && transactions.isEmpty) {
return const Padding(
padding: EdgeInsets.all(16.0),
child: Center(child: CircularProgressIndicator(color: AppColors.buttonColor)),
);
}
if (transactions.isEmpty && !provider.isLoading) {
return const Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: Text(
"No transactions found",
style: TextStyle(color: Colors.grey, fontSize: 16),
),
),
);
}
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: transactions.length,
itemBuilder: (context, index) {
final month = transactions.keys.elementAt(index);
final items = transactions[month]!;
return Container(
color: AppColors.backgroundRegular,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
month,
style: const TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
fontSize: 14,
),
),
const SizedBox(height: 8),
...items.map((item) {
final type = item.atype ?? "Debit";
final title = item.narration ?? "No details";
final date = item.datetime ?? "";
final id = item.id ?? "";
final amount = type.toLowerCase() == "credit"
? "₹${item.cAmount ?? "0"}"
: "₹${item.dAmount ?? "0"}";
return InkResponse(
onTap: () {
if (item.atype == "Credit") {
showDialog(
context: context,
builder: (context) => PaymentdetailDialog(
sessionId: widget.sessionId,
accId: widget.accId,
billId: item.billId.toString(),
),
);
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BillDetailScreen(
sessionId: widget.sessionId,
accId: widget.accId,
billId: item.billId.toString(),
),
),
);
}
},
child: _buildTransactionItem(
type: type,
title: title,
id: id,
date: date,
amount: amount,
),
);
}).toList(),
],
),
);
},
);
}
/// Summary Card Item /// Summary Card Item
Widget _buildSummaryItem(String value, String label, Color color) { Widget _buildSummaryItem(String value, String label, Color color) {
return Row( return Row(
...@@ -293,7 +573,7 @@ class _TransactionScreenState extends State<TransactionListScreen> { ...@@ -293,7 +573,7 @@ class _TransactionScreenState extends State<TransactionListScreen> {
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 14), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(20),
), ),
child: Row( child: Row(
children: [ children: [
...@@ -344,7 +624,7 @@ class _TransactionScreenState extends State<TransactionListScreen> { ...@@ -344,7 +624,7 @@ class _TransactionScreenState extends State<TransactionListScreen> {
style: const TextStyle( style: const TextStyle(
fontFamily: "Poppins", fontFamily: "Poppins",
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.normal, fontWeight: FontWeight.w400,
color: Colors.black, color: Colors.black,
), ),
), ),
...@@ -366,4 +646,248 @@ class _TransactionScreenState extends State<TransactionListScreen> { ...@@ -366,4 +646,248 @@ class _TransactionScreenState extends State<TransactionListScreen> {
), ),
); );
} }
// payment sheet
void _openPaymentSheet(BuildContext context, String totalAmountStr) {
TextEditingController amountController = TextEditingController();
bool isPartPayment = false;
final double totalAmount = double.tryParse(totalAmountStr) ?? 0;
showModalBottomSheet(
isScrollControlled: true,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
top: 16,
left: 16,
right: 16,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Handle Bar
Center(
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
),
),
const SizedBox(height: 16),
// Title
const Text(
"Balance Amount Bill",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
const SizedBox(height: 6),
Divider(),
const SizedBox(height: 10),
// Pay Total Option
GestureDetector(
onTap: () {
setState(() => isPartPayment = false);
},
child: Row(
children: [
Radio<bool>(
value: false,
groupValue: isPartPayment,
onChanged: (v) => setState(() => isPartPayment = v!),
activeColor: const Color(0xFF008CDE),
),
// Radio<bool>(
// value: false,
// groupValue: isPartPayment,
// onChanged: (v) => setState(() => isPartPayment = v!),
// ),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Pay Total",
style: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
Text(
"Avoid late payment fees.",
style: TextStyle(
color: Color(0xff5FBB54),
fontSize: 12,
fontFamily: "Poppins",
),
),
],
),
const Spacer(),
Text(
"₹${totalAmount.toStringAsFixed(0)}",
style: const TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
],
),
),
const SizedBox(height: 10),
// Part Payment Option
GestureDetector(
onTap: () {
setState(() => isPartPayment = true);
},
child: Row(
children: [
Radio<bool>(
value: true,
groupValue: isPartPayment,
onChanged: (v) => setState(() => isPartPayment = v!),
activeColor: const Color(0xFF008CDE),
),
const Text(
"Part Payment",
style: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
const SizedBox(width: 24),
Expanded(
child: Container(
height: 50,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
),
child: TextFormField(
controller: amountController,
enabled: isPartPayment,
style: const TextStyle(
fontSize: 14,
fontFamily: "Poppins",
color: Colors.black87,
),
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: "Enter amount",
hintStyle: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
color: Colors.grey,
),
border: InputBorder.none,
),
),
),
),
],
),
),
const SizedBox(height: 6),
Divider(),
const SizedBox(height: 6),
// Continue Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
double enteredAmount = isPartPayment
? double.tryParse(amountController.text) ?? 0
: totalAmount;
if (enteredAmount <= 0) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Please enter a valid amount"),
),
);
return;
}
if (isPartPayment && enteredAmount > totalAmount) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
"Entered amount cannot exceed total amount",
),
),
);
return;
}
Navigator.pop(context);
// Pass selected amount to your payAmountFunction
payAmountFunction(enteredAmount.toStringAsFixed(2));
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF008CDE),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 22),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Continue Payment",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.white,
fontSize: 16,
),
),
SvgPicture.asset(
"assets/svg/continue_ic.svg",
color: Colors.white,
height: 25,
width: 25,
),
],
),
),
),
),
const SizedBox(height: 16),
],
),
);
},
);
},
);
}
} }
\ No newline at end of file
...@@ -59,7 +59,7 @@ class _GeneratordetailsscreenState extends State<Generatordetailsscreen> { ...@@ -59,7 +59,7 @@ class _GeneratordetailsscreenState extends State<Generatordetailsscreen> {
final error = detailsProvider.errorMessage; final error = detailsProvider.errorMessage;
final data = detailsProvider.detailsResponse; final data = detailsProvider.detailsResponse;
final genDetails = data!.genDetails??GenDetails(); final genDetails = data!.genDetails??GenDetails();
final locDetails = data!.locationDetails??LocationDetails(); final locDetails = data.locationDetails??LocationDetails();
final quotationsList = data.quotations??[]; final quotationsList = data.quotations??[];
final scheduleList = data.schedule ?? []; final scheduleList = data.schedule ?? [];
final amcQuotationsList = data.amcQuotations??[]; final amcQuotationsList = data.amcQuotations??[];
......
...@@ -24,6 +24,8 @@ const amcQuoteListUrl = "${baseUrl}all_amc_quotations"; ...@@ -24,6 +24,8 @@ const amcQuoteListUrl = "${baseUrl}all_amc_quotations";
const complaintListUrl = "${baseUrl}all_complaint_list"; const complaintListUrl = "${baseUrl}all_complaint_list";
const downloadBillUrl = "${baseUrl}download_bill"; const downloadBillUrl = "${baseUrl}download_bill";
const downloadRecieptUrl = "${baseUrl}download_reciept"; const downloadRecieptUrl = "${baseUrl}download_reciept";
const payAmountUrl = "${baseUrl}pay_amount";
const getPaymentStatusUrl = "${baseUrl}get_payment_status";
/// Help and complaints /// Help and complaints
const addComplaintUrl = "${baseUrl}add_complaint"; const addComplaintUrl = "${baseUrl}add_complaint";
......
...@@ -15,8 +15,10 @@ import '../Models/AuthResponse.dart'; ...@@ -15,8 +15,10 @@ import '../Models/AuthResponse.dart';
import '../Models/CommonResponse.dart'; import '../Models/CommonResponse.dart';
import '../Models/DashboardResponse.dart'; import '../Models/DashboardResponse.dart';
import '../Models/HelpAndComplaintModels/GeneratorListResponse.dart'; import '../Models/HelpAndComplaintModels/GeneratorListResponse.dart';
import '../Models/TransactionModels/PayAmountResponse.dart';
import '../Models/TransactionModels/TransactionListResponse.dart'; import '../Models/TransactionModels/TransactionListResponse.dart';
import '../Screens/HelpAndComplaintScreens/DropDownsListResponse.dart'; import '../Models/HelpAndComplaintModels/DropDownsListResponse.dart';
import '../Notifiers/PayAmountProvider.dart';
import 'api_URLs.dart'; import 'api_URLs.dart';
import 'api_post_request.dart'; import 'api_post_request.dart';
import 'package:http/http.dart' as http show MultipartFile; import 'package:http/http.dart' as http show MultipartFile;
...@@ -150,12 +152,14 @@ class ApiCalling { ...@@ -150,12 +152,14 @@ class ApiCalling {
static Future<TransactionListResponse?> fetchTransactionListApi( static Future<TransactionListResponse?> fetchTransactionListApi(
String accId, String accId,
String sessionId, String sessionId,
String pageNumber,
) async { ) async {
debugPrint("###############################Transaction Api calling "); debugPrint("###############################Transaction Api calling ");
try { try {
Map<String, String> data = { Map<String, String> data = {
"acc_id": accId, "acc_id": accId,
"session_id": sessionId, "session_id": sessionId,
"page_number": pageNumber,
}; };
final res = await post(data, transactionsUrl, {}); final res = await post(data, transactionsUrl, {});
...@@ -286,6 +290,66 @@ class ApiCalling { ...@@ -286,6 +290,66 @@ class ApiCalling {
} }
} }
/// pay_amount
static Future<PayAmountResponse?> payAmountApi(
String sessionId,
String empId,
String ammount,
String refType,
String refId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"acc_id": empId,
"amount": ammount,
"ref_type": refType,
"ref_id": refId,
};
final res = await post(data, payAmountUrl, {});
debugPrint("PayAmount Response ${res?.body}");
if (res != null) {
return PayAmountResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error (payAmountApi): $e");
return null;
}
}
/// Fetch or get_payment_status
static Future<PaymentStatusResponse?> getPaymentStatusApi(
String sessionId,
String empId,
String razorpayOrderId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"razorpay_order_id": razorpayOrderId,
};
final res = await post(data, getPaymentStatusUrl, {});
if (res != null) {
return PaymentStatusResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error (getPaymentStatusApi): $e");
return null;
}
}
//___________________________________Help and Complaints //___________________________________Help and Complaints
......
...@@ -45,7 +45,7 @@ class AppColors { ...@@ -45,7 +45,7 @@ class AppColors {
static const Color backgroundLight = Color(0xFFFFFFFF); static const Color backgroundLight = Color(0xFFFFFFFF);
static const Color backgroundDark = Color(0xFF111827); static const Color backgroundDark = Color(0xFF111827);
static const Color backgroundRegular = Color(0xFFF2F2F2); static const Color backgroundRegular = Color(0xFFF2F2F2);
static const Color backgroundBottom = Color(0xFF4076FF);
//Button //Button
static const Color buttonColor = Color(0xFF008CDE); static const Color buttonColor = Color(0xFF008CDE);
...@@ -72,7 +72,7 @@ class AppColors { ...@@ -72,7 +72,7 @@ class AppColors {
end: Alignment.bottomRight, end: Alignment.bottomRight,
colors: [ colors: [
AppColors.subtitleText, AppColors.subtitleText,
Color(0xFFFFFFFF), Color(0x00FFFFFF),
], ],
); );
...@@ -147,4 +147,13 @@ class AppColors { ...@@ -147,4 +147,13 @@ class AppColors {
Color(0xFF4076FF), Color(0xFF4076FF),
], ],
); );
static const LinearGradient commonAppBarGradient = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFF04Bfef),
Color(0xFF4076FF),
],
);
} }
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment