Commits (2)
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_468_717" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<path d="M24 0H0V24H24V0Z" fill="white"/>
</mask>
<g mask="url(#mask0_468_717)">
<path d="M12 18.75C11.59 18.75 11.25 18.41 11.25 18V15C11.25 14.59 11.59 14.25 12 14.25C12.41 14.25 12.75 14.59 12.75 15V18C12.75 18.41 12.41 18.75 12 18.75Z" fill="white"/>
<path d="M17.6 22.5608H6.39996C4.57996 22.5608 2.91996 21.1608 2.61996 19.3708L1.28996 11.4008C1.06996 10.1608 1.67996 8.5708 2.66996 7.7808L9.59996 2.2308C10.94 1.1508 13.05 1.1608 14.4 2.2408L21.33 7.7808C22.31 8.5708 22.91 10.1608 22.71 11.4008L21.38 19.3608C21.08 21.1308 19.38 22.5608 17.6 22.5608ZM11.99 2.9308C11.46 2.9308 10.93 3.0908 10.54 3.4008L3.60996 8.9608C3.04996 9.4108 2.64996 10.4508 2.76996 11.1608L4.09996 19.1208C4.27996 20.1708 5.32996 21.0608 6.39996 21.0608H17.6C18.67 21.0608 19.72 20.1708 19.9 19.1108L21.23 11.1508C21.34 10.4508 20.94 9.3908 20.39 8.9508L13.46 3.4108C13.06 3.0908 12.52 2.9308 11.99 2.9308Z" fill="white"/>
</g>
</svg>
...@@ -3,6 +3,7 @@ class BillListResponse { ...@@ -3,6 +3,7 @@ class BillListResponse {
List<Bills>? bills; List<Bills>? bills;
LatestBill? latestBill; LatestBill? latestBill;
String? message; String? message;
String? payAmount;
int? sessionExists; int? sessionExists;
BillListResponse( BillListResponse(
...@@ -24,6 +25,7 @@ class BillListResponse { ...@@ -24,6 +25,7 @@ class BillListResponse {
? new LatestBill.fromJson(json['latest_bill']) ? new LatestBill.fromJson(json['latest_bill'])
: null; : null;
message = json['message']; message = json['message'];
payAmount = json['pay_amount'];
sessionExists = json['session_exists']; sessionExists = json['session_exists'];
} }
...@@ -37,6 +39,7 @@ class BillListResponse { ...@@ -37,6 +39,7 @@ class BillListResponse {
data['latest_bill'] = this.latestBill!.toJson(); data['latest_bill'] = this.latestBill!.toJson();
} }
data['message'] = this.message; data['message'] = this.message;
data['pay_amount'] = this.payAmount;
data['session_exists'] = this.sessionExists; data['session_exists'] = this.sessionExists;
return data; return data;
} }
......
class PayAmountResponse {
String? error;
String? amount;
String? message;
String? orderId;
String? razorKey;
PayAmountResponse(
{this.error, this.amount, this.message, this.orderId, this.razorKey});
PayAmountResponse.fromJson(Map<String, dynamic> json) {
error = json['error'];
amount = json['amount'];
message = json['message'];
orderId = json['order_id'];
razorKey = json['razor_key'];
}
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;
return data;
}
}
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:gen_rentals/Services/api_calling.dart';
import '../Models/CommonResponse.dart';
import '../Models/TransactionModels/PayAmountResponse.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;
}
}
...@@ -4,9 +4,13 @@ import 'package:gen_rentals/Models/BillsModels/BillDetailsResponse.dart'; ...@@ -4,9 +4,13 @@ import 'package:gen_rentals/Models/BillsModels/BillDetailsResponse.dart';
import 'package:gen_rentals/Utility/AppColors.dart'; import 'package:gen_rentals/Utility/AppColors.dart';
import 'package:gen_rentals/Utility/Reusablewidgets.dart'; import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../../Notifier/BillProvider.dart'; import '../../Notifier/BillProvider.dart';
import '../../Notifier/PayAmountProvider.dart';
import '../../Utility/CustomSnackbar.dart';
import '../DashboardScreen.dart'; import '../DashboardScreen.dart';
import '../TransactionScreens/PaymentSuccessfailScreen.dart';
import 'BillDetailScreen.dart'; import 'BillDetailScreen.dart';
...@@ -27,15 +31,123 @@ class BillDetailListScreen extends StatefulWidget { ...@@ -27,15 +31,123 @@ class BillDetailListScreen extends StatefulWidget {
} }
class _BillDetailListScreenState extends State<BillDetailListScreen> { class _BillDetailListScreenState extends State<BillDetailListScreen> {
late Razorpay _razorpay;
bool? isSuccess;
var paymentMethod = "";
var User_contact = "0";
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_razorpay =Razorpay();
Future.microtask(() { Future.microtask(() {
final provider = Provider.of<BillProvider>(context, listen: false); final provider = Provider.of<BillProvider>(context, listen: false);
provider.fetchBillList(widget.sessionId, widget.orderId, widget.accId); provider.fetchBillList(widget.sessionId, widget.orderId, widget.accId);
}); });
} }
void _handlePaymentSuccess(PaymentSuccessResponse response) {
setState(() {
CustomSnackBar.showSuccess(
context: context,
message: "Payment Success!",
);
// buttonLoading = false;
});
}
void _handlePaymentError(PaymentFailureResponse response) {
setState(() {
CustomSnackBar.showError(
context: context,
message: "Payment failed!",
);
// buttonLoading = false;
});
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
}
void _handleExternalWallet(ExternalWalletResponse response) {}
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: "Could not Complete Payment: ${data.message}",
);
debugPrint("❌ Could not Complete Payment: ${data.message}");
}
} else {
debugPrint("❌ No response received from PayAmount API");
}
} catch (e) {
CustomSnackBar.showError(
context: context,
message: '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 Rentals',
'order_id': razorPayOrderId,
'description': "Bill",
'currency': 'INR',
'method': 'upi',
'prefill': {'contact': User_contact, '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");
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<BillProvider>( return Consumer<BillProvider>(
...@@ -136,13 +248,27 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> { ...@@ -136,13 +248,27 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( InkResponse(
"₹${latest.totalPrice ?? '0'}", onTap: () {
style: TextStyle( Navigator.push(
fontFamily: "Poppins", context,
color: AppColors.cardAmountText, MaterialPageRoute(builder: (context) => PaymentSuccessFaillScreen(
fontSize: 34,
fontWeight: FontWeight.w500, total: "10218",
date: "8th Oct, 2025",
payMode: "UPI",
status: "Fail",
)),
);
},
child: Text(
"₹${latest.totalPrice ?? '0'}",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.cardAmountText,
fontSize: 34,
fontWeight: FontWeight.w500,
),
), ),
), ),
Container( Container(
...@@ -175,26 +301,26 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> { ...@@ -175,26 +301,26 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
], ],
), ),
// Pending // Pending
// if(latest.billPaid == "No") if(latest.billPaid == "No")
// InkResponse( InkResponse(
// onTap: () => showPaymentBottomSheet(context, payBill: "1299", payTotal: "4218"), onTap: () => _openPaymentSheet(context, provider.billListResponse!.payAmount.toString(), latest.totalPrice ?? '0', latest.orderId.toString()),
// child: Container( child: Container(
// padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
// horizontal: 12, vertical: 8), horizontal: 12, vertical: 8),
// decoration: BoxDecoration( decoration: BoxDecoration(
// color: const Color(0xE0008CDE), color: const Color(0xE0008CDE),
// borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(14),
// ), ),
// child: const Text( child: const Text(
// "Pay Now", "Pay Now",
// style: TextStyle( style: TextStyle(
// color: Colors.white, color: Colors.white,
// fontSize: 14, fontSize: 14,
// fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
// ), ),
// ), ),
// ), ),
// ), ),
], ],
), ),
), ),
...@@ -290,7 +416,7 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> { ...@@ -290,7 +416,7 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
padding: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.only(bottom: 8),
child: InkResponse( child: InkResponse(
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => BillDetailScreen( MaterialPageRoute(builder: (context) => BillDetailScreen(
sessionId: widget.sessionId, sessionId: widget.sessionId,
...@@ -405,6 +531,234 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> { ...@@ -405,6 +531,234 @@ class _BillDetailListScreenState extends State<BillDetailListScreen> {
); );
} }
/// Pay balance sheet
void _openPaymentSheet(BuildContext context, String totalAmountStr, String billAmount, String id) {
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(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Radio<bool>(
value: true,
groupValue: isPartPayment,
onChanged: (v) => setState(() => isPartPayment = v!),
activeColor: const Color(0xFF008CDE),
),
Text(
"Pay Bill",
style: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
],
),
const SizedBox(width: 24),
Text(
"₹${billAmount}",
style: const TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
],
),
),
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), id);
},
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),
],
),
);
},
);
},
);
}
void showPaymentBottomSheet( void showPaymentBottomSheet(
BuildContext context, { BuildContext context, {
String? payTotal = "4218", String? payTotal = "4218",
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../../Notifier/BillProvider.dart'; import '../../Notifier/BillProvider.dart';
import '../../Notifier/PayAmountProvider.dart';
import '../../Utility/AppColors.dart'; import '../../Utility/AppColors.dart';
import '../../Utility/CustomSnackbar.dart';
import '../../Utility/Reusablewidgets.dart'; import '../../Utility/Reusablewidgets.dart';
class BillDetailScreen extends StatefulWidget { class BillDetailScreen extends StatefulWidget {
...@@ -22,6 +25,12 @@ class BillDetailScreen extends StatefulWidget { ...@@ -22,6 +25,12 @@ 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";
// Responsive text size function // Responsive text size function
double getResponsiveTextSize(BuildContext context, double baseSize) { double getResponsiveTextSize(BuildContext context, double baseSize) {
final double width = MediaQuery.of(context).size.width; final double width = MediaQuery.of(context).size.width;
...@@ -55,12 +64,110 @@ class _BillDetailScreenState extends State<BillDetailScreen> { ...@@ -55,12 +64,110 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_razorpay = Razorpay();
Future.microtask(() { Future.microtask(() {
final provider = Provider.of<BillProvider>(context, listen: false); final provider = Provider.of<BillProvider>(context, listen: false);
provider.fetchBillDetails(widget.sessionId, widget.accId, widget.billId); provider.fetchBillDetails(widget.sessionId, widget.accId, widget.billId);
}); });
} }
void _handlePaymentSuccess(PaymentSuccessResponse response) {
setState(() {
CustomSnackBar.showSuccess(
context: context,
message: "Payment Success!",
);
// buttonLoading = false;
});
}
void _handlePaymentError(PaymentFailureResponse response) {
setState(() {
CustomSnackBar.showError(
context: context,
message: "Payment failed!",
);
// buttonLoading = false;
});
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
}
void _handleExternalWallet(ExternalWalletResponse response) {}
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: "Could not Complete Payment: ${data.message}",
);
debugPrint("❌ Could not Complete Payment: ${data.message}");
}
} else {
debugPrint("❌ No response received from PayAmount API");
}
} catch (e) {
CustomSnackBar.showError(
context: context,
message: '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 Rentals',
'order_id': razorPayOrderId,
'description': "Bill",
'currency': 'INR',
'method': 'upi',
'prefill': {'contact': User_contact, '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");
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width; final screenWidth = MediaQuery.of(context).size.width;
...@@ -230,7 +337,7 @@ class _BillDetailScreenState extends State<BillDetailScreen> { ...@@ -230,7 +337,7 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
], ],
), ),
), ),
bottomNavigationBar: _buildBottomButtons(provider, isPaid, screenWidth, screenHeight), bottomNavigationBar: _buildBottomButtons(provider, isPaid, screenWidth, screenHeight, details.totalPrice ?? "0", details.id ?? ""),
), ),
); );
}, },
...@@ -238,7 +345,7 @@ class _BillDetailScreenState extends State<BillDetailScreen> { ...@@ -238,7 +345,7 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
} }
/// Conditional Bottom Buttons based on payment status /// Conditional Bottom Buttons based on payment status
Widget _buildBottomButtons(BillProvider provider, bool isPaid, double screenWidth, double screenHeight) { Widget _buildBottomButtons(BillProvider provider, bool isPaid, double screenWidth, double screenHeight, String totalPrice, String id ) {
return Container( return Container(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: getResponsivePadding(context), horizontal: getResponsivePadding(context),
...@@ -257,33 +364,35 @@ class _BillDetailScreenState extends State<BillDetailScreen> { ...@@ -257,33 +364,35 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
child: Row( child: Row(
children: [ children: [
// Pay Now Button (only if not paid) // Pay Now Button (only if not paid)
// if (!isPaid) ...[ if (!isPaid) ...[
// Expanded( Expanded(
// child: ElevatedButton( child: ElevatedButton(
// onPressed: () { onPressed: () {
// _showPayNowDialog(screenWidth, screenHeight); Navigator.pop(context);
// }, // handle payment navigation
// style: ElevatedButton.styleFrom( payAmountFunction(totalPrice, id);
// backgroundColor: AppColors.buttonColor, },
// foregroundColor: Colors.white, style: ElevatedButton.styleFrom(
// shape: RoundedRectangleBorder( backgroundColor: AppColors.buttonColor,
// borderRadius: BorderRadius.circular(screenWidth * 0.03), foregroundColor: Colors.white,
// ), shape: RoundedRectangleBorder(
// padding: EdgeInsets.symmetric(vertical: screenHeight * 0.018), borderRadius: BorderRadius.circular(screenWidth * 0.03),
// elevation: 0, ),
// ), padding: EdgeInsets.symmetric(vertical: screenHeight * 0.018),
// child: Text( elevation: 0,
// "Pay Now", ),
// style: TextStyle( child: Text(
// fontSize: getResponsiveTextSize(context, 14), "Pay Now",
// fontFamily: "Poppins", style: TextStyle(
// fontWeight: FontWeight.w600, fontSize: getResponsiveTextSize(context, 14),
// ), fontFamily: "Poppins",
// ), fontWeight: FontWeight.w600,
// ), ),
// ), ),
// SizedBox(width: screenWidth * 0.03), ),
// ], ),
SizedBox(width: screenWidth * 0.03),
],
// Download Receipt Button // Download Receipt Button
Expanded( Expanded(
......
...@@ -14,7 +14,10 @@ import 'package:gen_rentals/Utility/Reusablewidgets.dart'; ...@@ -14,7 +14,10 @@ import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../Models/DashboardResponse.dart'; import '../Models/DashboardResponse.dart';
import '../Notifier/DashboardProvider.dart'; import '../Notifier/DashboardProvider.dart';
import '../Notifier/PayAmountProvider.dart';
import 'TransactionScreens/PaymentSuccessfailScreen.dart';
import 'authScreen/LoginScreen.dart'; import 'authScreen/LoginScreen.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
class DashboardScreen extends StatefulWidget { class DashboardScreen extends StatefulWidget {
final String accId; final String accId;
...@@ -28,9 +31,16 @@ class DashboardScreen extends StatefulWidget { ...@@ -28,9 +31,16 @@ class DashboardScreen extends StatefulWidget {
class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingObserver { class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingObserver {
DateTime? currentBackPressTime; DateTime? currentBackPressTime;
late Razorpay _razorpay;
bool? isSuccess;
var paymentMethod = "";
var User_contact = "0";
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_razorpay = Razorpay();
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
...@@ -38,6 +48,138 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb ...@@ -38,6 +48,138 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}); });
} }
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",
)),
);
CustomSnackBar.showSuccess(
context: context,
message: data?.message ?? "Payment Success!",
);
// buttonLoading = false;
});
}
void _handlePaymentError(PaymentFailureResponse response) {
setState(() async {
final provider = Provider.of<PayAmountProvider>(context, listen: false);
await provider.getPaymentStatus(
sessionId: widget.sessionId,
empId: widget.accId,
razorpayOrderId: ""
);
final data = provider.statusResponse;
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.",
);
});
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
}
void _handleExternalWallet(ExternalWalletResponse response) {}
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 {
_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 Rentals',
'order_id': razorPayOrderId,
'description': "Payment",
'currency': 'INR',
'method': 'upi',
'prefill': {'contact': User_contact, '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");
});
}
// void onError(CFErrorResponse errorResponse, String orderId) {
// isSuccess = false;
// setState(() {
// // print(errorResponse.getMessage());
// // print("Error while making payment");
// });
// }
@override @override
void dispose() { void dispose() {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
...@@ -362,7 +504,6 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb ...@@ -362,7 +504,6 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
Text( Text(
dashboardData?.balanceAmount?.toString() ?? "0", dashboardData?.balanceAmount?.toString() ?? "0",
style: TextStyle( style: TextStyle(
color: Colors.black, color: Colors.black,
fontSize: getResponsiveTextSize(context, 34), fontSize: getResponsiveTextSize(context, 34),
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
...@@ -370,6 +511,18 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb ...@@ -370,6 +511,18 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
), ),
], ],
), ),
InkResponse(
onTap: () => _openPaymentSheet(context, dashboardData!.balanceAmount.toString()),
child: Text(
"Pay Now",
style: TextStyle(
color: Colors.blue,
fontFamily: "Poppins",
fontSize: getResponsiveTextSize(context, 14),
fontWeight: FontWeight.w500,
),
),
),
], ],
), ),
SizedBox(height: screenHeight * 0.015), SizedBox(height: screenHeight * 0.015),
...@@ -794,7 +947,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb ...@@ -794,7 +947,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
], ],
), ),
// Gradient expiry badge // Gradient expiry badge
if (product.expiringText != null && product.expiringText!.isNotEmpty) if (product.expiringText != null && product.expiringText!.isNotEmpty)
Container( Container(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
...@@ -1112,6 +1265,251 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb ...@@ -1112,6 +1265,251 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
); );
} }
} }
/// Pay balance 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),
],
),
);
},
);
},
);
}
void showPaymentBottomSheet( void showPaymentBottomSheet(
BuildContext context, { BuildContext context, {
...@@ -1204,7 +1602,7 @@ class _PaymentBottomSheetContentState extends State<PaymentBottomSheetContent> { ...@@ -1204,7 +1602,7 @@ class _PaymentBottomSheetContentState extends State<PaymentBottomSheetContent> {
} }
void _handleContinuePayment() { void _handleContinuePayment() {
// Validation // Validation
if (selectedOption == -1) { if (selectedOption == -1) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar( const SnackBar(
......
...@@ -27,7 +27,7 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -27,7 +27,7 @@ class _HelpScreenState extends State<HelpScreen> {
void initState() { void initState() {
super.initState(); super.initState();
/// Fetch ticket list on screen load /// Fetch ticket list on screen load
Future.microtask(() async { Future.microtask(() async {
final provider = Provider.of<HelpAndEnquiryProvider>(context, listen: false); final provider = Provider.of<HelpAndEnquiryProvider>(context, listen: false);
await provider.fetchTicketList( await provider.fetchTicketList(
...@@ -37,7 +37,7 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -37,7 +37,7 @@ class _HelpScreenState extends State<HelpScreen> {
}); });
} }
// (unchanged) // (unchanged)
final List<Map<String, dynamic>> createNewTickets = [ final List<Map<String, dynamic>> createNewTickets = [
{ {
'title': 'Payment Issues', 'title': 'Payment Issues',
...@@ -102,7 +102,7 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -102,7 +102,7 @@ class _HelpScreenState extends State<HelpScreen> {
), ),
), ),
// Provider Consumer used here // Provider Consumer used here
body: Consumer<HelpAndEnquiryProvider>( body: Consumer<HelpAndEnquiryProvider>(
builder: (context, provider, _) { builder: (context, provider, _) {
if (provider.isLoading) { if (provider.isLoading) {
...@@ -257,7 +257,7 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -257,7 +257,7 @@ class _HelpScreenState extends State<HelpScreen> {
); );
} }
/// Processing tickets from provider /// Processing tickets from provider
Widget _buildProcessingTicketsSection(List<dynamic> tickets) { Widget _buildProcessingTicketsSection(List<dynamic> tickets) {
if (tickets.isEmpty) { if (tickets.isEmpty) {
return const Center(child: Text("No processing tickets")); return const Center(child: Text("No processing tickets"));
...@@ -294,7 +294,7 @@ class _HelpScreenState extends State<HelpScreen> { ...@@ -294,7 +294,7 @@ class _HelpScreenState extends State<HelpScreen> {
); );
} }
/// Closed tickets from provider /// Closed tickets from provider
Widget _buildClosedTicketsSection(List<dynamic> tickets) { Widget _buildClosedTicketsSection(List<dynamic> tickets) {
if (tickets.isEmpty) { if (tickets.isEmpty) {
return const Center(child: Text("No closed tickets")); return const Center(child: Text("No closed tickets"));
......
...@@ -90,7 +90,7 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> { ...@@ -90,7 +90,7 @@ class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
), ),
SizedBox(width: screenWidth * 0.025), SizedBox(width: screenWidth * 0.025),
Text( Text(
"Bill Details", "Order Details",
style: TextStyle( style: TextStyle(
fontFamily: "Poppins", fontFamily: "Poppins",
fontSize: isSmallScreen ? 14 : 16, fontSize: isSmallScreen ? 14 : 16,
......
...@@ -26,7 +26,7 @@ class _BillPendingToastState extends State<BillPendingToast> { ...@@ -26,7 +26,7 @@ class _BillPendingToastState extends State<BillPendingToast> {
void initState() { void initState() {
super.initState(); super.initState();
/// 🔹 Fetch data after one frame (safe after build) /// Fetch data after one frame (safe after build)
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
final provider = Provider.of<TransactionsProvider>(context, listen: false); final provider = Provider.of<TransactionsProvider>(context, listen: false);
provider.fetchPaymentReceiptDetails( provider.fetchPaymentReceiptDetails(
...@@ -246,27 +246,27 @@ class _BillPendingToastState extends State<BillPendingToast> { ...@@ -246,27 +246,27 @@ class _BillPendingToastState extends State<BillPendingToast> {
), ),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
// Expanded( Expanded(
// child: ElevatedButton( child: ElevatedButton(
// onPressed: widget.onPayNow, onPressed: widget.onPayNow,
// style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
// backgroundColor: AppColors.amountText, backgroundColor: AppColors.amountText,
// shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(50),
// ), ),
// padding: const EdgeInsets.symmetric(vertical: 14), padding: const EdgeInsets.symmetric(vertical: 14),
// ), ),
// child: const Text( child: const Text(
// "Pay Now", "Pay Now",
// style: TextStyle( style: TextStyle(
// fontSize: 15, fontSize: 15,
// fontFamily: "Poppins", fontFamily: "Poppins",
// fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
// color: Colors.white, color: Colors.white,
// ), ),
// ), ),
// ), ),
// ), ),
], ],
), ),
], ],
......
...@@ -25,7 +25,7 @@ class _BillStatusToastState extends State<BillStatusToast> { ...@@ -25,7 +25,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
void initState() { void initState() {
super.initState(); super.initState();
// Automatically fetch data when dialog opens // Automatically fetch data when dialog opens
Future.microtask(() { Future.microtask(() {
final provider = final provider =
Provider.of<TransactionsProvider>(context, listen: false); Provider.of<TransactionsProvider>(context, listen: false);
...@@ -105,7 +105,7 @@ class _BillStatusToastState extends State<BillStatusToast> { ...@@ -105,7 +105,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Title & Amount // Title & Amount
const Text( const Text(
"Payment Receipt", "Payment Receipt",
style: TextStyle( style: TextStyle(
...@@ -130,7 +130,7 @@ class _BillStatusToastState extends State<BillStatusToast> { ...@@ -130,7 +130,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
const Divider(thickness: 1, color: Color(0xFFE6E6E6)), const Divider(thickness: 1, color: Color(0xFFE6E6E6)),
const SizedBox(height: 12), const SizedBox(height: 12),
// Payment Details // Payment Details
const Align( const Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
...@@ -153,7 +153,7 @@ class _BillStatusToastState extends State<BillStatusToast> { ...@@ -153,7 +153,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
const Divider(thickness: 1, color: Color(0xFFE6E6E6)), const Divider(thickness: 1, color: Color(0xFFE6E6E6)),
const SizedBox(height: 12), const SizedBox(height: 12),
// Products // Products
const Align( const Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
...@@ -177,7 +177,7 @@ class _BillStatusToastState extends State<BillStatusToast> { ...@@ -177,7 +177,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
const Divider(thickness: 1, color: Color(0xFFE6E6E6)), const Divider(thickness: 1, color: Color(0xFFE6E6E6)),
const SizedBox(height: 8), const SizedBox(height: 8),
// Total // Total
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
...@@ -204,7 +204,7 @@ class _BillStatusToastState extends State<BillStatusToast> { ...@@ -204,7 +204,7 @@ class _BillStatusToastState extends State<BillStatusToast> {
const SizedBox(height: 22), const SizedBox(height: 22),
// Download Button // Download Button
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: ElevatedButton.icon( child: ElevatedButton.icon(
......
...@@ -3,14 +3,32 @@ import 'package:gen_rentals/Utility/Reusablewidgets.dart'; ...@@ -3,14 +3,32 @@ import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import '../../Utility/AppColors.dart'; import '../../Utility/AppColors.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
class PaymentSuccessfulScreen extends StatefulWidget { import '../../Utility/SharedpreferencesService.dart';
const PaymentSuccessfulScreen({super.key}); import '../DashboardScreen.dart';
class PaymentSuccessFaillScreen extends StatefulWidget {
final String total;
final String date;
final String payMode;
final String status;
const PaymentSuccessFaillScreen({
super.key,
required this.total,
required this.date,
required this.payMode,
required this.status,
});
@override @override
State<PaymentSuccessfulScreen> createState() => _PaymentSuccessfulScreenState(); State<PaymentSuccessFaillScreen> createState() => _PaymentSuccessFaillScreenState();
} }
class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> { class _PaymentSuccessFaillScreenState extends State<PaymentSuccessFaillScreen> {
final prefs = SharedPreferencesService.instance;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
...@@ -38,6 +56,7 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> { ...@@ -38,6 +56,7 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
const SizedBox(height: 40), const SizedBox(height: 40),
// Success Icon // Success Icon
if (widget.status == "Success")
Container( Container(
width: double.infinity, width: double.infinity,
height: 140, height: 140,
...@@ -48,23 +67,45 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> { ...@@ -48,23 +67,45 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
width: 80, width: 80,
), ),
), ),
if (widget.status == "Fail")
Container(
width: double.infinity,
height: 140,
color: Colors.white,
child: Image.asset(
'assets/images/failed_pay_gif.gif',
height: 80,
width: 80,
),
),
const SizedBox(height: 24), const SizedBox(height: 24),
// Success Title // Success Title
if (widget.status == "Success")
const Text( const Text(
"Payment Successful", "Payment Successful",
style: TextStyle( style: TextStyle(
fontFamily: "Poppins",
fontSize: 24, fontSize: 24,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: AppColors.normalText, color: AppColors.normalText,
), ),
), ),
if (widget.status == "Fail")
const Text(
"Payment Failed",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w500,
color: AppColors.normalText,
),
),
const SizedBox(height: 8), const SizedBox(height: 8),
// Success Message // Success Message
if (widget.status == "Success")
Text( Text(
"Now enjoy a seamless,\nuninterrupted rental service.", "Now enjoy a seamless,\nuninterrupted rental service.",
textAlign: TextAlign.center, textAlign: TextAlign.center,
...@@ -76,49 +117,85 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> { ...@@ -76,49 +117,85 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
height: 1.5, height: 1.5,
), ),
), ),
if (widget.status == "Fail")
Text(
"There may be an issue with your,\n Payment, please try again.",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Poppins",
fontSize: 16,
fontWeight: FontWeight.w400,
color: AppColors.subtitleText,
height: 1.5,
),
),
const SizedBox(height: 22),
Text(
"₹${widget.total}",
style: TextStyle(
fontSize: 34,
fontWeight: FontWeight.w500,
color: AppColors.normalText,
),
),
const SizedBox(height: 9),
Divider(),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(height: 25), const SizedBox(height: 25),
const SectionHeading(title: "Payment Details"), SectionHeading(
title: "Payment Details",
textStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColors.normalText,
),
),
// Payment Details Section // Payment Details Section
_buildSection( _buildSection(
children: [ children: [
_buildDetailRow(title: "Date", value: "8th Oct, 2025"), _buildDetailRow(title: "Date", value: "8th Oct, 2025"),
_buildDetailRow(title: "Payment Mode", value: "Credit Card **56"), _buildDetailRow(title: "Payment Mode", value: widget.payMode),
_buildDetailRow(
title: "Payment Status",
value: "Paid",
valueStyle: const TextStyle(
color: Color(0xFF4CAF50),
fontWeight: FontWeight.w600,
),
),
], ],
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
const SizedBox(height: 2),
const SectionHeading(title: "Bill Details"), Divider(),
// Bill Details Section Padding(
_buildSection( padding: const EdgeInsets.all(8.0),
children: [ child: Row(
_buildDetailRow(title: "Total Amount", value: "₹421"), mainAxisAlignment: MainAxisAlignment.spaceBetween,
_buildDetailRow(title: "Bill Cycle", value: "7th Sep, 2025 – 7th Oct, 2025"), children: [
_buildDetailRow(title: "Bill Generated Date", value: "8th Oct, 2025"), const SectionHeading(
_buildDetailRow(title: "Payable Amount", value: "₹421"), title: "Total",
_buildDetailRow(title: "Paid Date/Due Date", value: "7th Oct, 2025"), textStyle: TextStyle(
], fontSize: 16,
), fontWeight: FontWeight.w500,
color: AppColors.normalText,
),
),
Text(
"₹${widget.total}",
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.normalText,
),
)
],
),
)
], ],
), ),
const SizedBox(height: 25), const SizedBox(height: 110),
if (widget.status == "Fail")
// Back to Home Button
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: ElevatedButton( child: ElevatedButton(
...@@ -134,20 +211,16 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> { ...@@ -134,20 +211,16 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
), ),
padding: const EdgeInsets.symmetric(vertical: 16), padding: const EdgeInsets.symmetric(vertical: 16),
), ),
child: const Padding( child: Padding(
padding: EdgeInsets.symmetric(horizontal: 22), padding: const EdgeInsets.symmetric(horizontal: 22),
child: Row( child: Text(
mainAxisAlignment: MainAxisAlignment.center, "Pay Now",
children: [ style: TextStyle(
Text( fontFamily: "Poppins",
"Back to Home", color: Color(0xFFFFFFFF),
style: TextStyle( fontSize: 16,
color: Color(0xFFFFFFFF), fontWeight: FontWeight.w500,
fontSize: 16, ),
fontWeight: FontWeight.w500,
),
),
],
), ),
), ),
), ),
...@@ -159,6 +232,59 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> { ...@@ -159,6 +232,59 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
), ),
), ),
), ),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () async {
final String? savedAccId = await prefs.getString("accId");
final String? savedSessionId = await prefs.getString("session_id");
// Add navigation logic here
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DashboardScreen(sessionId: savedSessionId!, accId: savedAccId.toString(),)
)
//route
);
},
style: ElevatedButton.styleFrom(
backgroundColor: widget.status == "Fail" ? AppColors.backgroundRegular : AppColors.buttonColor,
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.center,
children: [
SvgPicture.asset(
"assets/svg/homes_ic.svg",
color: widget.status == "Fail" ? Colors.blue : Color(0xFFFFFFFF),
height: 22,
width: 22,
),
SizedBox(width: 12),
Text(
"Back to Home",
style: TextStyle(
fontFamily: "Poppins",
color: widget.status == "Fail" ? Colors.blue : Color(0xFFFFFFFF),
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
),
),
); );
} }
...@@ -167,9 +293,9 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> { ...@@ -167,9 +293,9 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
}) { }) {
return Container( return Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFFF8F9FA), color: const Color(0x11F8F9FA),
borderRadius: BorderRadius.circular(18), borderRadius: BorderRadius.circular(18),
), ),
child: Column( child: Column(
...@@ -218,7 +344,7 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> { ...@@ -218,7 +344,7 @@ class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
style: valueStyle ?? const TextStyle( style: valueStyle ?? const TextStyle(
fontFamily: "Poppins", fontFamily: "Poppins",
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w500,
color: AppColors.normalText, color: AppColors.normalText,
), ),
), ),
......
...@@ -2,14 +2,17 @@ import 'package:flutter/material.dart'; ...@@ -2,14 +2,17 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:gen_rentals/Screens/TransactionScreens/BillStatusToast.dart'; import 'package:gen_rentals/Screens/TransactionScreens/BillStatusToast.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../../Notifier/BillProvider.dart'; import '../../Notifier/BillProvider.dart';
import '../../Notifier/PayAmountProvider.dart';
import '../../Notifier/TransactionsProvider.dart'; import '../../Notifier/TransactionsProvider.dart';
import '../../Utility/AppColors.dart'; import '../../Utility/AppColors.dart';
import '../../Utility/CustomSnackbar.dart'; import '../../Utility/CustomSnackbar.dart';
import '../BillScreens/BillDetailScreen.dart'; import '../BillScreens/BillDetailScreen.dart';
import '../DashboardScreen.dart'; import '../DashboardScreen.dart';
import 'BillPendingToast.dart'; import 'BillPendingToast.dart';
import 'PaymentSuccessfailScreen.dart';
class TransactionsScreen extends StatefulWidget { class TransactionsScreen extends StatefulWidget {
...@@ -26,8 +29,15 @@ class TransactionsScreen extends StatefulWidget { ...@@ -26,8 +29,15 @@ class TransactionsScreen extends StatefulWidget {
} }
class _TransactionsScreenState extends State<TransactionsScreen> { class _TransactionsScreenState extends State<TransactionsScreen> {
bool isSuccess = false;
late Razorpay _razorpay;
var paymentMethod = "";
var User_contact = "0";
@override @override
void initState() { void initState() {
_razorpay = Razorpay();
super.initState(); super.initState();
Future.microtask(() { Future.microtask(() {
Provider.of<TransactionsProvider>(context, listen: false) Provider.of<TransactionsProvider>(context, listen: false)
...@@ -35,6 +45,125 @@ class _TransactionsScreenState extends State<TransactionsScreen> { ...@@ -35,6 +45,125 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
}); });
} }
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",
)),
);
CustomSnackBar.showSuccess(
context: context,
message: data?.message ?? "Payment Success!",
);
// buttonLoading = false;
});
}
void _handlePaymentError(PaymentFailureResponse response) {
setState(() async {
final provider = Provider.of<PayAmountProvider>(context, listen: false);
await provider.getPaymentStatus(
sessionId: widget.sessionId,
empId: widget.accId,
razorpayOrderId: ""
);
final data = provider.statusResponse;
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.",
);
});
CustomSnackBar.showError(
context: context,
message: "Payment failed, please try again.",
);
}
void _handleExternalWallet(ExternalWalletResponse response) {}
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 {
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
_razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
//
Map<String, dynamic> options = {
'key': razorpayKey,
'amount': int.parse("${((0) * 100).round()}"),
'name': 'Gen Rentals',
'order_id': razorPayOrderId,
'description': "Payment",
'currency': 'INR',
'method': 'upi',
'prefill': {'contact': User_contact, 'email': ''}
};
// print(options);
try {
_razorpay.open(options);
} catch (e, s) {
debugPrint(e.toString());
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final provider = Provider.of<TransactionsProvider>(context); final provider = Provider.of<TransactionsProvider>(context);
...@@ -110,6 +239,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> { ...@@ -110,6 +239,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
SizedBox(height: 8), SizedBox(height: 8),
...items.map((txn) => InkResponse( ...items.map((txn) => InkResponse(
onTap: () async { onTap: () async {
final amount = txn.amount ?? 0;
final provider = Provider.of<TransactionsProvider>(context, listen: false); final provider = Provider.of<TransactionsProvider>(context, listen: false);
await provider.fetchPaymentReceiptDetails( await provider.fetchPaymentReceiptDetails(
widget.sessionId, widget.sessionId,
...@@ -119,6 +249,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> { ...@@ -119,6 +249,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
if (txn.type == "Credit") { if (txn.type == "Credit") {
showDialog( showDialog(
context: context, context: context,
builder: (context) => BillStatusToast( builder: (context) => BillStatusToast(
sessionId: widget.sessionId, sessionId: widget.sessionId,
...@@ -136,6 +267,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> { ...@@ -136,6 +267,7 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
onPayNow: () { onPayNow: () {
Navigator.pop(context); Navigator.pop(context);
// handle payment navigation // handle payment navigation
payAmountFunction(amount.toString());
}, },
), ),
); );
...@@ -346,18 +478,18 @@ class _TransactionsScreenState extends State<TransactionsScreen> { ...@@ -346,18 +478,18 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
), ),
// InkResponse( InkResponse(
// onTap: () => showPaymentBottomSheet(context), onTap: () => _openPaymentSheet(context , balance.toString()),
// child: Text( child: Text(
// "Pay Now", "Pay Now",
// style: TextStyle( style: TextStyle(
// fontFamily: "Poppins", fontFamily: "Poppins",
// color: Color(0xFF008CDE), color: Color(0xFF008CDE),
// fontSize: 14, fontSize: 14,
// fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
// ), ),
// ), ),
// ), ),
], ],
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
...@@ -451,25 +583,248 @@ class _TransactionsScreenState extends State<TransactionsScreen> { ...@@ -451,25 +583,248 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
); );
} }
void showPaymentBottomSheet( void _openPaymentSheet(BuildContext context, String totalAmountStr) {
BuildContext context, { TextEditingController amountController = TextEditingController();
String? payTotal = "4218", bool isPartPayment = false;
String? payBill = "2018", final double totalAmount = double.tryParse(totalAmountStr) ?? 0;
}) {
showModalBottomSheet( showModalBottomSheet(
isScrollControlled: true,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
context: context, context: context,
isScrollControlled: true, // This is important builder: (context) {
backgroundColor: Colors.transparent, return StatefulBuilder(
isDismissible: true, builder: (context, setState) {
enableDrag: true, return Padding(
builder: (BuildContext context) { padding: EdgeInsets.only(
return PaymentBottomSheetContent( bottom: MediaQuery.of(context).viewInsets.bottom,
payTotal: payTotal, top: 16,
payBill: payBill, left: 16,
billFlag: false, right: 16,
partFlag: true, ),
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),
],
),
);
},
); );
}, },
); );
} }
} }
// forgot_password_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class ForgotPasswordScreen extends StatelessWidget {
const ForgotPasswordScreen({super.key});
@override
Widget build(BuildContext context) {
final emailController = TextEditingController();
return Scaffold(
backgroundColor: const Color(0xFFF5F8FC),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.network(
"https://genrentals.in/assets/img/logo-black.svg",
height: 70,
),
const SizedBox(height: 20),
const Text(
"Forgot Password",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 6,
offset: Offset(0, 2),
)
],
),
child: Column(
children: [
TextFormField(
controller: emailController,
decoration: InputDecoration(
labelText: "Email Address",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(6),
),
),
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
height: 45,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2563EB),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content:
Text("Password reset link sent to email")),
);
},
child: const Text(
"Confirm",
style: TextStyle(color: Colors.white),
),
),
)
],
),
),
],
),
),
),
);
}
}
...@@ -14,6 +14,8 @@ const billListUrl = "${baseUrl}bill_list"; ...@@ -14,6 +14,8 @@ const billListUrl = "${baseUrl}bill_list";
const downloadBillUrl = "${baseUrl}download_bill"; const downloadBillUrl = "${baseUrl}download_bill";
const paymentReceiptDetailsUrl = "${baseUrl}payment_receipt_details"; const paymentReceiptDetailsUrl = "${baseUrl}payment_receipt_details";
const downloadReceiptUrl = "${baseUrl}download_receipt"; const downloadReceiptUrl = "${baseUrl}download_receipt";
const payAmountUrl = "${baseUrl}pay_amount";
const getPaymentStatusUrl = "${baseUrl}get_payment_status";
/// info /// info
const checkInOutSubmitUrl = "${baseUrl}check_in_out_submit"; const checkInOutSubmitUrl = "${baseUrl}check_in_out_submit";
......
...@@ -14,10 +14,12 @@ import 'package:gen_rentals/Models/HelpAndEnquiryModels/ticketListResponse.dart' ...@@ -14,10 +14,12 @@ import 'package:gen_rentals/Models/HelpAndEnquiryModels/ticketListResponse.dart'
import '../Models/BillsModels/BillDetailsResponse.dart'; import '../Models/BillsModels/BillDetailsResponse.dart';
import '../Models/DashboardResponse.dart'; import '../Models/DashboardResponse.dart';
import '../Models/RentalPaymentDetailsResponse.dart'; import '../Models/RentalPaymentDetailsResponse.dart';
import '../Models/TransactionModels/PayAmountResponse.dart';
import '../Models/TransactionModels/TransactionsResponse.dart'; import '../Models/TransactionModels/TransactionsResponse.dart';
import '../Models/orderDetailsBillResponse.dart'; import '../Models/orderDetailsBillResponse.dart';
import '../Models/rentalAccountResponse.dart'; import '../Models/rentalAccountResponse.dart';
import '../Models/rentalContactResponse.dart'; import '../Models/rentalContactResponse.dart';
import '../Notifier/PayAmountProvider.dart';
import '../Notifier/RentalContactProvider .dart'; import '../Notifier/RentalContactProvider .dart';
import 'api_URLs.dart'; import 'api_URLs.dart';
import 'api_post_request.dart'; import 'api_post_request.dart';
...@@ -101,27 +103,61 @@ class ApiCalling { ...@@ -101,27 +103,61 @@ class ApiCalling {
} }
/// Fetch Rental Account Info /// pay_amount
static Future<RentalAccountResponse?> fetchRentalAccountInfoApi( static Future<PayAmountResponse?> payAmountApi(
String sessionId, String sessionId,
String empId, 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 { ) async {
try { try {
Map<String, String> data = { Map<String, String> data = {
"session_id": sessionId, "session_id": sessionId,
"emp_id": empId, "emp_id": empId,
"razorpay_order_id": razorpayOrderId,
}; };
final res = await post(data, getRentalAccInfoUrl, {}); final res = await post(data, getPaymentStatusUrl, {});
if (res != null) { if (res != null) {
return RentalAccountResponse.fromJson(jsonDecode(res.body)); return PaymentStatusResponse.fromJson(jsonDecode(res.body));
} else { } else {
debugPrint("Null Response"); debugPrint("Null Response");
return null; return null;
} }
} catch (e) { } catch (e) {
debugPrint("❌ API Error (fetchRentalAccountInfo): $e"); debugPrint("❌ API Error (razorpay_order_id): $e");
return null; return null;
} }
} }
...@@ -296,32 +332,7 @@ class ApiCalling { ...@@ -296,32 +332,7 @@ class ApiCalling {
} }
/// Fetch Order Details Product
static Future<OrderDetailsProductResponse?> fetchOrderDetailProductApi(
String sessionId,
String empId,
String orderId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"order_id": orderId,
};
final res = await post(data, orderDetailsProductUrl, {});
if (res != null) {
return OrderDetailsProductResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error (fetchOrderDetailProduct): $e");
return null;
}
}
/// Fetch Order Details Main /// Fetch Order Details Main
static Future<OrderDetailsMainResponse?> fetchOrderDetailMainApi( static Future<OrderDetailsMainResponse?> fetchOrderDetailMainApi(
......
...@@ -5,6 +5,7 @@ import 'package:gen_rentals/Notifier/HelpAndEnquiryProvider.dart'; ...@@ -5,6 +5,7 @@ import 'package:gen_rentals/Notifier/HelpAndEnquiryProvider.dart';
import 'package:gen_rentals/Notifier/TransactionsProvider.dart'; import 'package:gen_rentals/Notifier/TransactionsProvider.dart';
import 'package:gen_rentals/Screens/SplashScreen.dart'; import 'package:gen_rentals/Screens/SplashScreen.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'Notifier/PayAmountProvider.dart';
import 'Notifier/RentalContactProvider .dart'; import 'Notifier/RentalContactProvider .dart';
import 'Notifier/SubscribeOrderDetailsProvider.dart'; import 'Notifier/SubscribeOrderDetailsProvider.dart';
import 'Notifier/theme_provider.dart'; import 'Notifier/theme_provider.dart';
...@@ -36,6 +37,7 @@ class MyApp extends StatelessWidget { ...@@ -36,6 +37,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => TransactionsProvider()), ChangeNotifierProvider(create: (_) => TransactionsProvider()),
ChangeNotifierProvider(create: (_) => HelpAndEnquiryProvider()), ChangeNotifierProvider(create: (_) => HelpAndEnquiryProvider()),
ChangeNotifierProvider(create: (_) => BillProvider()), ChangeNotifierProvider(create: (_) => BillProvider()),
ChangeNotifierProvider(create: (_) => PayAmountProvider()),
], ],
child: Consumer<ThemeProvider>( child: Consumer<ThemeProvider>(
builder: (context, themeProvider, child) { builder: (context, themeProvider, child) {
......
...@@ -153,6 +153,14 @@ packages: ...@@ -153,6 +153,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.3" version: "7.0.3"
eventify:
dependency: transitive
description:
name: eventify
sha256: b829429f08586cc2001c628e7499e3e3c2493a1d895fd73b00ecb23351aa5a66
url: "https://pub.dev"
source: hosted
version: "1.0.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
...@@ -296,6 +304,14 @@ packages: ...@@ -296,6 +304,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
fluttertoast:
dependency: transitive
description:
name: fluttertoast
sha256: "90778fe0497fe3a09166e8cf2e0867310ff434b794526589e77ec03cf08ba8e8"
url: "https://pub.dev"
source: hosted
version: "8.2.14"
google_fonts: google_fonts:
dependency: "direct main" dependency: "direct main"
description: description:
...@@ -672,6 +688,14 @@ packages: ...@@ -672,6 +688,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
razorpay_flutter:
dependency: "direct main"
description:
name: razorpay_flutter
sha256: "7d86b2a2ba2c3a71366bbfb65664236ba4b12fd6aeaed4c13dfc5c998786b2d6"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
rxdart: rxdart:
dependency: transitive dependency: transitive
description: description:
......
...@@ -52,6 +52,8 @@ dependencies: ...@@ -52,6 +52,8 @@ dependencies:
path_provider: ^2.1.4 path_provider: ^2.1.4
open_filex: ^4.4.0 open_filex: ^4.4.0
photo_view: ^0.14.0 photo_view: ^0.14.0
razorpay_flutter: ^1.4.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
......