"lib/Utility/toast.dart" did not exist on "a2b314a9767c554b97dc4dd00590341c66fe1e99"
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final TextEditingController _mobileController = TextEditingController();
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Colors.blue,
body: Stack(
children: [
/// 🔹 Background image
Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background_png.png"),
fit: BoxFit.cover,
),
),
),
/// 🔹 Main content (scrollable & keyboard-safe)
SafeArea(
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom, // moves up with keyboard
),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox(height: 80),
/// 🔹 Logo
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(width: 20,),
SvgPicture.asset(
"assets/svg/genesis_logo_2io.svg",
height: 48,
color: Colors.white,
),
]
),
const SizedBox(height: 12),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 26, vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Login to",
style: TextStyle(
fontSize: 48,
fontFamily: "PoppinsLight",
fontWeight: FontWeight.w100,
color: Colors.white,
),
),
Text(
"continue",
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
],
),
),
],
),
const SizedBox(height: 20),
/// 🔹 Bottom Sheet style area
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24),
),
),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"Enter Registered Mobile No.",
style: TextStyle(
fontSize: 14,
color: Colors.black54,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 10),
/// 🔹 Mobile Field
TextFormField(
controller: _mobileController,
keyboardType: TextInputType.phone,
maxLength: 10,
decoration: InputDecoration(
hintText: "Enter Mobile No.",
counterText: "",
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderSide: BorderSide(color: Colors.grey.shade300),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderSide: const BorderSide(color: Colors.blue, width: 1.2),
),
filled: true,
fillColor: Colors.grey.shade100,
),
validator: (value) {
if (value == null || value.isEmpty) {
return "Please enter mobile number";
} else if (value.length != 10) {
return "Enter valid 10-digit number";
}
return null;
},
),
const SizedBox(height: 20),
/// 🔹 Continue Button (Always visible)
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF0086F1),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
),
onPressed: () {
if (_formKey.currentState!.validate()) {
FocusScope.of(context).unfocus();
// TODO: Add API call here
}
},
child: const Text(
"Continue",
style: TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
),
),
],
),
),
),
],
),
),
),
);
},
),
),
],
),
);
}
}
......@@ -7,8 +7,12 @@ import 'package:gen_service/Notifiers/HelpAndComplaintProvider.dart';
import 'package:gen_service/Screens/HelpAndComplaintScreens/jobcardListScreen.dart';
import 'package:gen_service/Screens/HelpAndComplaintScreens/serviceListScreen.dart';
import 'package:provider/provider.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../../Notifiers/PayAmountProvider.dart';
import '../../Utility/AppColors.dart';
import '../../Utility/CustomSnackbar.dart';
import '../../Utility/SharedpreferencesService.dart';
class ComplaintDetailsScreen extends StatefulWidget {
final accId;
......@@ -27,13 +31,20 @@ class ComplaintDetailsScreen extends StatefulWidget {
}
class _ComplaintDetailsScreenState extends State<ComplaintDetailsScreen> {
late Razorpay _razorpay;
bool? isSuccess;
var paymentMethod = "";
var User_contact = "0";
bool bottomSheetButtonClicked = false;
final prefs = SharedPreferencesService.instance;
@override
void initState() {
// TODO: implement initState
super.initState();
_razorpay = Razorpay();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final provider = Provider.of<HelpAndComplaintProvider>(
context,
......@@ -52,6 +63,132 @@ class _ComplaintDetailsScreenState extends State<ComplaintDetailsScreen> {
//_________________________________________________________
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 {
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
Widget build(BuildContext context) {
return Consumer<HelpAndComplaintProvider>(
......@@ -98,14 +235,121 @@ class _ComplaintDetailsScreenState extends State<ComplaintDetailsScreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final provider = Provider.of<HelpAndComplaintProvider>(
context,
listen: false,
);
await provider.fetchComplaintDetailsAPI(
widget.accId,
widget.sessionId,
widget.complaintId,
);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
TextButton(
onPressed: () {
// Go back or navigate to home
Navigator.maybePop(context);
},
child: const Text(
"Go Back",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
),
),
),
],
),
),
),
);
}
if (data == null) {
return SafeArea(
maintainBottomViewPadding: true,
......@@ -411,6 +655,7 @@ class _ComplaintDetailsScreenState extends State<ComplaintDetailsScreen> {
color: AppColors.subtitleText,
),
InkResponse(
onTap: ()=> _openPaymentSheet(context, jobCardsData!.totalPrice.toString()),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 16,
......@@ -872,4 +1117,248 @@ class _ComplaintDetailsScreenState extends State<ComplaintDetailsScreen> {
});
});
}
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),
],
),
);
},
);
},
);
}
}
......@@ -60,14 +60,119 @@ class _ComplaintListScreenState extends State<ComplaintListScreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final provider = Provider.of<HelpAndComplaintProvider>(
context,
listen: false,
);
provider.fetchComplaintsList(
accId: widget.accId,
sessionId: widget.sessionId,
);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
TextButton(
onPressed: () {
// Go back or navigate to home
Navigator.pop(context);
},
child: const Text(
"Go Back",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
),
),
),
],
),
),
),
);
}
if (data == null) {
return const Scaffold(
backgroundColor: AppColors.backgroundRegular,
......
......@@ -58,9 +58,115 @@ class _SelectOrderHelpScreenState extends State<SelectOrderHelpScreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final provider = Provider.of<HelpAndComplaintProvider>(
context,
listen: false,
);
provider.fetchGeneratorList(
accId: widget.accId,
sessionId: widget.sessionId,
);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
TextButton(
onPressed: () {
// Go back or navigate to home
Navigator.pop(context);
},
child: const Text(
"Go Back",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
),
),
),
],
),
),
),
);
......
......@@ -2,10 +2,14 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import '../../Notifiers/HelpAndComplaintProvider.dart';
import '../../Notifiers/PayAmountProvider.dart';
import '../../Notifiers/serviceAndJobCardListProvier.dart';
import '../../Utility/AppColors.dart';
import '../../Utility/CustomSnackbar.dart';
import '../../Utility/SharedpreferencesService.dart';
class Jobcardlistscreen extends StatefulWidget {
final accId;
......@@ -24,10 +28,19 @@ class Jobcardlistscreen extends StatefulWidget {
}
class _JobcardlistscreenState extends State<Jobcardlistscreen> {
late Razorpay _razorpay;
bool? isSuccess;
var paymentMethod = "";
var User_contact = "0";
bool bottomSheetButtonClicked = false;
final prefs = SharedPreferencesService.instance;
@override
void initState() {
// TODO: implement initState
super.initState();
_razorpay = Razorpay();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final provider = Provider.of<ServiceAndJobCardListProvider>(
context,
......@@ -41,6 +54,134 @@ class _JobcardlistscreenState extends State<Jobcardlistscreen> {
});
}
//_________________________________________________________
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 {
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
Widget build(BuildContext context) {
return Consumer2<ServiceAndJobCardListProvider, HelpAndComplaintProvider>(
......@@ -64,9 +205,116 @@ class _JobcardlistscreenState extends State<Jobcardlistscreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final provider = Provider.of<ServiceAndJobCardListProvider>(
context,
listen: false,
);
await provider.fetchAllJobCardsListAPI(
widget.accId,
widget.sessionId,
widget.complaintId,
);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
TextButton(
onPressed: () {
// Go back or navigate to home
Navigator.maybePop(context);
},
child: const Text(
"Go Back",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
),
),
),
],
),
),
),
);
......@@ -279,6 +527,7 @@ class _JobcardlistscreenState extends State<Jobcardlistscreen> {
color: AppColors.subtitleText,
),
InkResponse(
onTap: () => _openPaymentSheet(context, data[j].totalPrice.toString()),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 16,
......@@ -459,4 +708,248 @@ class _JobcardlistscreenState extends State<Jobcardlistscreen> {
});
});
}
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),
],
),
);
},
);
},
);
}
}
......@@ -257,7 +257,7 @@ class _serviceListScreenState extends State<serviceListScreen> {
),
),
Expanded(
flex: 3,
flex: 2,
child: SizedBox(
child: Column(
crossAxisAlignment:
......
......@@ -218,18 +218,130 @@ class _HomeScreenState extends State<HomeScreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final dashboardProvider =
Provider.of<DashboardProvider>(context, listen: false);
await dashboardProvider.fetchDashboard(
widget.accId,
widget.sessionId
);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
// TextButton(
// onPressed: () {
// // Go back or navigate to home
// Navigator.maybePop(context);
// },
// child: const Text(
// "Go Back",
// style: TextStyle(
// fontSize: 14,
// color: Colors.grey,
// fontFamily: "Poppins",
// ),
// ),
// ),
],
),
),
),
);
}
if (data == null) {
return const Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(child: Text("No data found.")),
return RefreshIndicator.adaptive(
color: AppColors.amountText,
onRefresh: () async {
await Future.delayed(const Duration(milliseconds: 600));
Provider.of<DashboardProvider>(context, listen: false);
dashboardProvider.fetchDashboard(widget.accId, widget.sessionId);
},
child: const Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(child: Text("No data found.")),
),
);
}
......
......@@ -316,9 +316,111 @@ class _ProfileScreenState extends State<ProfileScreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final dashboardProvider =
await Future.delayed(const Duration(milliseconds: 600));
Provider.of<DashboardProvider>(context, listen: false);
profileProvider.fetchDashboard(widget.accId, widget.sessionId);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
TextButton(
onPressed: () {
// Go back or navigate to home
Navigator.maybePop(context);
},
child: const Text(
"Go Back",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
),
),
),
],
),
),
),
);
......
......@@ -372,8 +372,8 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
height: 170,
width: 170,
child: SvgPicture.asset(
"assets/svg/genesis_logo_2io.svg",
color: Color(0xFF4076FF),
"assets/svg/gen_logo.svg",
color: Color(0xFFFFFFFF),
),
),
),
......
......@@ -271,8 +271,8 @@ class _BillDetailScreenState extends State<BillDetailScreen> {
padding: const EdgeInsets.symmetric(vertical: 2),
child: _buildProductItem(
product.partName.toString(),
product.price.toString(),
product.qty.toString(),
product.price.toString(),
product.totalPrice.toString()
)
),
......
......@@ -105,9 +105,116 @@ class _GeneratordetailsscreenState extends State<Generatordetailsscreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final detailsProvider = Provider.of<Generatordetailsprovider>(
context,
listen: false,
);
detailsProvider.fetchGeneratorDetails(
widget.accId,
widget.sessionId,
widget.genId,
);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
TextButton(
onPressed: () {
// Go back or navigate to home
Navigator.pop(context);
},
child: const Text(
"Go Back",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
),
),
),
],
),
),
),
);
......
......@@ -59,14 +59,116 @@ class _QuotationListScreenState extends State<QuotationListScreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final provider = Provider.of<Generatordetailsprovider>(
context,
listen: false,
);
await provider.fetchQuotationList(widget.accId, widget.sessionId, widget.genId);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
TextButton(
onPressed: () {
// Go back or navigate to home
Navigator.maybePop(context);
},
child: const Text(
"Go Back",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
),
),
),
],
),
),
),
);
}
if (data == null) {
return const Scaffold(
backgroundColor: AppColors.backgroundRegular,
......
......@@ -59,9 +59,112 @@ class _ScheduleListScreenState extends State<ScheduleListScreen> {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: Center(
child: Text(
error,
style: const TextStyle(color: Colors.red, fontSize: 16),
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Error Icon
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.error_outline_rounded,
size: 60,
color: Colors.red,
),
),
const SizedBox(height: 24),
// Error Title
const Text(
"Oops! Something went wrong",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: "Poppins",
),
),
const SizedBox(height: 12),
// Error Message
Text(
error,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
height: 1.4,
),
),
const SizedBox(height: 32),
// Retry Button
ElevatedButton.icon(
onPressed: () async {
// Show loading state
setState(() {});
await Future.delayed(const Duration(milliseconds: 300));
// Retry fetching data
final provider = Provider.of<Generatordetailsprovider>(
context,
listen: false,
);
await provider.fetchScheduleList(widget.accId, widget.sessionId,widget.genId);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 2,
),
icon: const Icon(Icons.refresh_rounded, size: 20),
label: const Text(
"Try Again",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
fontFamily: "Poppins",
),
),
),
const SizedBox(height: 16),
// Alternative Action
TextButton(
onPressed: () {
// Go back or navigate to home
Navigator.maybePop(context);
},
child: const Text(
"Go Back",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: "Poppins",
),
),
),
],
),
),
),
);
......