Commit 23aaf199 authored by Sai Srinivas's avatar Sai Srinivas
Browse files

New Screen and Api added

parent eecc769f
import 'package:flutter/material.dart';
import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import '../Utility/AppColors.dart';
import 'package:flutter_svg/flutter_svg.dart';
class PaymentSuccessfulScreen extends StatefulWidget {
const PaymentSuccessfulScreen({super.key});
@override
State<PaymentSuccessfulScreen> createState() => _PaymentSuccessfulScreenState();
}
class _PaymentSuccessfulScreenState extends State<PaymentSuccessfulScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.backgroundRegular,
body: SafeArea(
child: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFFFFFFF),
Color(0xFFFFFFFF),
AppColors.backgroundRegular,
AppColors.backgroundRegular,
AppColors.backgroundRegular
],
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 40),
// Success Icon
Container(
width: double.infinity,
height: 140,
color: Colors.white,
child: Image.asset(
'assets/images/success_pay_gif.gif',
height: 80,
width: 80,
),
),
const SizedBox(height: 24),
// Success Title
const Text(
"Payment Successful",
style: TextStyle(
fontFamily: "Poppins",
fontSize: 24,
fontWeight: FontWeight.w500,
color: AppColors.normalText,
),
),
const SizedBox(height: 8),
// Success Message
Text(
"Now enjoy a seamless,\nuninterrupted rental service.",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Poppins",
fontSize: 16,
fontWeight: FontWeight.w400,
color: AppColors.subtitleText,
height: 1.5,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 25),
const SectionHeading(title: "Payment Details"),
// Payment Details Section
_buildSection(
children: [
_buildDetailRow(title: "Date", value: "8th Oct, 2025"),
_buildDetailRow(title: "Payment Mode", value: "Credit Card **56"),
_buildDetailRow(
title: "Payment Status",
value: "Paid",
valueStyle: const TextStyle(
color: Color(0xFF4CAF50),
fontWeight: FontWeight.w600,
),
),
],
),
const SizedBox(height: 10),
const SectionHeading(title: "Bill Details"),
// Bill Details Section
_buildSection(
children: [
_buildDetailRow(title: "Total Amount", value: "₹421"),
_buildDetailRow(title: "Bill Cycle", value: "7th Sep, 2025 – 7th Oct, 2025"),
_buildDetailRow(title: "Bill Generated Date", value: "8th Oct, 2025"),
_buildDetailRow(title: "Payable Amount", value: "₹421"),
_buildDetailRow(title: "Paid Date/Due Date", value: "7th Oct, 2025"),
],
),
],
),
const SizedBox(height: 25),
// Back to Home Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
// Add navigation logic here
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 22),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Back to Home",
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
),
const SizedBox(height: 20),
],
),
),
),
),
);
}
Widget _buildSection({
required List<Widget> children,
}) {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
decoration: BoxDecoration(
color: const Color(0xFFF8F9FA),
borderRadius: BorderRadius.circular(18),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
),
);
}
Widget _buildDetailRow({
required String title,
required String value,
TextStyle? valueStyle,
}) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: const TextStyle(
fontFamily: "Poppins",
fontSize: 14,
fontWeight: FontWeight.w400,
color: Color(0xFF777777),
),
),
Row(
children: [
if (value == "Paid")
SvgPicture.asset(
"assets/svg/success_ic.svg",
height: 18,
width: 18,
),
if (value == "Pending")
SvgPicture.asset(
"assets/svg/failed_ic.svg",
height: 18,
width: 18,
),
const SizedBox(width: 4),
Text(
value,
style: valueStyle ?? const TextStyle(
fontFamily: "Poppins",
fontSize: 14,
fontWeight: FontWeight.w400,
color: AppColors.normalText,
),
),
],
),
],
),
);
}
}
\ No newline at end of file
This diff is collapsed.
...@@ -3,6 +3,10 @@ import 'dart:io'; ...@@ -3,6 +3,10 @@ import 'dart:io';
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:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:gen_rentals/Screens/BillDetailListScreen.dart';
import 'package:gen_rentals/Screens/DashboardScreen.dart';
import 'package:gen_rentals/Screens/ProductsDetailScreen.dart';
import 'package:gen_rentals/Screens/TransactionsScreen.dart';
import '../Utility/CustomSnackbar.dart'; import '../Utility/CustomSnackbar.dart';
import 'authScreen/LoginScreen.dart'; import 'authScreen/LoginScreen.dart';
...@@ -76,7 +80,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt ...@@ -76,7 +80,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (_, __, ___) => const LoginScreen(), pageBuilder: (_, __, ___) => LoginScreen(),
transitionsBuilder: (_, animation, __, child) { transitionsBuilder: (_, animation, __, child) {
return FadeTransition( return FadeTransition(
opacity: animation, opacity: animation,
......
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../Utility/AppColors.dart';
class TransactionsScreen extends StatefulWidget {
const TransactionsScreen({super.key});
@override
State<TransactionsScreen> createState() => _TransactionsScreenState();
}
class _TransactionsScreenState extends State<TransactionsScreen> {
// Dummy data for transactions
final List<Map<String, dynamic>> transactions = [
{
"type": "debit",
"title": "Payment for June Rent",
"date": "25 Dec 2025",
"amount": "₹5,390.00",
"ref": "₹1,12,300"
},
{
"type": "debit",
"title": "Payment for June Rent",
"date": "25 Dec 2025",
"amount": "₹2,512.00",
"ref": "₹26,300"
},
{
"type": "credit",
"title": "Refund of Deposit Amount",
"date": "25 Dec 2025",
"amount": "₹19,790.00",
"ref": "₹1,26,300"
},
{
"type": "debit",
"title": "Payment for June Rent",
"date": "25 Dec 2025",
"amount": "₹5,390.00",
"ref": "₹1,12,300"
},
{
"type": "debit",
"title": "Payment for June Rent",
"date": "25 Dec 2025",
"amount": "₹2,512.00",
"ref": "₹26,300"
},
{
"type": "credit",
"title": "Refund of Deposit Amount",
"date": "25 Dec 2025",
"amount": "₹19,790.00",
"ref": "₹1,26,300"
},
];
@override
Widget build(BuildContext context) {
return SafeArea(
top: false,
child: Scaffold(
backgroundColor: AppColors.backgroundRegular,
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
titleSpacing: 0,
title: Row(
children: [
InkResponse(
onTap: () => Navigator.pop(context),
child: SvgPicture.asset(
"assets/svg/continue_left_ic.svg",
height: 25,
width: 25,
),
),
const SizedBox(width: 12),
const Text(
"Transactions",
style: TextStyle(
fontSize: 16,
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
],
),
),
// Main content
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Column(
children: [
SizedBox(height: 4,),
// Balance Card
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: const LinearGradient(
colors: [
Color(0xFFE9FFEF),
Color(0xFFD6FFDF),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Column(
children: [
Text(
"₹12,596",
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
fontSize: 34,
color: AppColors.cardAmountText,
),
),
const SizedBox(height: 4),
Text(
"Balance Amount",
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 14,
color: AppColors.cardAmountText,
),
),
const SizedBox(height: 10),
Container(
height: 1,
color: const Color(0xFF777777).withOpacity(0.3),
),
const SizedBox(height: 14),
// Credited / Debited info
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildAmountSummary(
icon: "assets/svg/cross_down_arrow.svg",
color: Colors.white,
amount: "₹26,300",
label: "Credited Amount",
),
_buildAmountSummary(
icon: "assets/svg/cross_up_arrow.svg",
color: Colors.white,
amount: "₹26,300",
label: "Debited Amount",
),
],
),
],
),
),
const SizedBox(height: 16),
// Transaction list
Column(
children: transactions.map((t) {
return _buildTransactionItem(
type: t["type"],
title: t["title"],
date: t["date"],
amount: t["amount"],
ref: t["ref"],
);
}).toList(),
),
],
),
),
),
);
}
Widget _buildAmountSummary({
required String icon,
required Color color,
required String amount,
required String label,
}) {
return Row(
children: [
// Icon and title row
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: color.withOpacity(0.9),
borderRadius: BorderRadius.circular(30),
),
child: Center( // Add this Center widget
child: SvgPicture.asset(
icon,
height: 20,
width: 20,
// Remove fit: BoxFit.none
),
),
),
const SizedBox(width: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
amount,
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 14,
color: Colors.black,
),
),
Text(
label,
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 12,
color: Colors.grey.shade600,
),
),
],
),
],
);
}
Widget _buildTransactionItem({
required String type,
required String title,
required String date,
required String amount,
required String ref,
}) {
final isCredit = type == "credit";
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 14),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14),
// border: Border.all(color: Colors.grey.shade200, width: 1),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withOpacity(0.02),
// blurRadius: 5,
// offset: const Offset(0, 1),
// ),
// ],
),
child: Row(
children: [
// Icon and title row
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: isCredit ? Colors.green.withOpacity(0.09) : Colors.red.withOpacity(0.09),
borderRadius: BorderRadius.circular(30),
),
child: Center( // Add this Center widget
child: SvgPicture.asset(
isCredit ? "assets/svg/cross_down_arrow.svg" : "assets/svg/cross_up_arrow.svg",
height: 20,
width: 20,
// Remove fit: BoxFit.none
),
),
),
// Container(
// padding: const EdgeInsets.all(8),
// decoration: BoxDecoration(
// color: isCredit
// ? const Color(0xFFE8F9EE)
// : const Color(0xFFFFEBEB),
// shape: BoxShape.circle,
// ),
// child: Icon(
// isCredit ? Icons.arrow_downward_rounded : Icons.arrow_upward_rounded,
// color: isCredit ? Colors.green : Colors.red,
// size: 20,
// ),
// ),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 14,
color: Colors.black,
),
),
const SizedBox(height: 4),
Text(
date,
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 12,
color: Colors.grey.shade600,
),
),
],
),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
amount,
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 14,
color: Colors.black,
),
),
const SizedBox(height: 4),
Row(
children: [
Text(
ref,
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 12,
color: Colors.grey.shade600,
),
),
const SizedBox(width: 4),//
SvgPicture.asset(
"assets/svg/rupee_coin_ic.svg",
height: 14,
width: 14,
// Remove fit: BoxFit.none
),
],
),
],
),
],
),
);
}
}
...@@ -26,58 +26,47 @@ class _LoginScreenState extends State<LoginScreen> { ...@@ -26,58 +26,47 @@ class _LoginScreenState extends State<LoginScreen> {
} }
Future<void> _login(BuildContext context) async { Future<void> _login(BuildContext context) async {
final rentalProvider = final rentalProvider = Provider.of<RentalProvider>(context, listen: false);
Provider.of<RentalContactProvider>(context, listen: false);
final mob = _phoneController.text.trim(); final mob = _phoneController.text.trim();
await rentalProvider.fetchRentalContactData( await rentalProvider.fetchRentalMobile(mob);
context,
"4d21382d9e1c4d6e0b7c426d53d89b6b7d48078877f185289092e6fa13bac4b11d417d37738b20b34151b8e638625b3ec013",
"5",
mob,
);
// ✅ Handle response // ✅ Handle response - Check if error is "0" (string comparison)
if (rentalProvider.rentalContact != null && if (rentalProvider.response != null && rentalProvider.response!.error == "0") {
rentalProvider.rentalContact!.error == 0) {
AnimatedSnackBar.success( AnimatedSnackBar.success(
context: context, context: context,
title: "Login Success", title: "OTP Sent",
message: "${rentalProvider.rentalContact?.message} OTP: ${rentalProvider.rentalContact?.otp}" ?? "Login Success", message: rentalProvider.response?.errorMsg ?? "OTP sent to your registered mobile number!",
); );
// Navigate to OTP screen // Navigate to OTP screen after a short delay
Navigator.pushReplacement( Future.delayed(const Duration(milliseconds: 1500), () {
context, if (mounted) {
PageRouteBuilder( Navigator.pushReplacement(
pageBuilder: (_, __, ___) => OtpScreen( context,
mob: mob, MaterialPageRoute(
otp: rentalProvider.rentalContact!.otp ?? 0, builder: (context) => OtpScreen(mob: mob),
), ),
transitionsBuilder: (_, animation, __, child) { );
return FadeTransition(opacity: animation, child: child); }
}, });
transitionDuration: const Duration(milliseconds: 600),
),
);
} else { } else {
CustomSnackBar.showWarning( CustomSnackBar.showWarning(
context: context, context: context,
message: rentalProvider.rentalContact?.message ?? title: "Login Failed",
rentalProvider.errorMessage ?? message: rentalProvider.response?.errorMsg ??
"Login failed", "Mobile number not registered or invalid",
title: "Login Status",
); );
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final rentalProvider = Provider.of<RentalContactProvider>(context); final rentalProvider = Provider.of<RentalProvider>(context);
return Scaffold( return Scaffold(
resizeToAvoidBottomInset: false, // prevents background image resize resizeToAvoidBottomInset: false,
body: Stack( body: Stack(
children: [ children: [
// 🏙️ Fixed background image // 🏙️ Fixed background image
...@@ -115,8 +104,7 @@ class _LoginScreenState extends State<LoginScreen> { ...@@ -115,8 +104,7 @@ class _LoginScreenState extends State<LoginScreen> {
], ],
), ),
), ),
padding: padding: const EdgeInsets.symmetric(horizontal: 22, vertical: 20),
const EdgeInsets.symmetric(horizontal: 22, vertical: 20),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
...@@ -155,12 +143,14 @@ class _LoginScreenState extends State<LoginScreen> { ...@@ -155,12 +143,14 @@ class _LoginScreenState extends State<LoginScreen> {
controller: _phoneController, controller: _phoneController,
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
onChanged: _validatePhone, onChanged: _validatePhone,
maxLength: 10,
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Enter Mobile No.", hintText: "Enter Mobile No.",
hintStyle: const TextStyle(color: Colors.grey), hintStyle: const TextStyle(color: Colors.grey),
filled: true, filled: true,
fillColor: Colors.white, fillColor: Colors.white,
counterText: "", // Remove character counter
contentPadding: const EdgeInsets.symmetric( contentPadding: const EdgeInsets.symmetric(
vertical: 16, horizontal: 20), vertical: 16, horizontal: 20),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
...@@ -172,8 +162,7 @@ class _LoginScreenState extends State<LoginScreen> { ...@@ -172,8 +162,7 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
borderSide: borderSide: const BorderSide(color: Colors.blue, width: 2),
const BorderSide(color: Colors.blue, width: 2),
), ),
), ),
), ),
...@@ -208,13 +197,11 @@ class _LoginScreenState extends State<LoginScreen> { ...@@ -208,13 +197,11 @@ class _LoginScreenState extends State<LoginScreen> {
? const Color(0xFF008CDE) ? const Color(0xFF008CDE)
: const Color(0xFF266E99), : const Color(0xFF266E99),
foregroundColor: Colors.white, foregroundColor: Colors.white,
disabledBackgroundColor: disabledBackgroundColor: const Color(0xFF266E99),
const Color(0xFF266E99),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
), ),
padding: padding: const EdgeInsets.symmetric(vertical: 16),
const EdgeInsets.symmetric(vertical: 16),
), ),
child: rentalProvider.isLoading child: rentalProvider.isLoading
? const SizedBox( ? const SizedBox(
...@@ -222,17 +209,14 @@ class _LoginScreenState extends State<LoginScreen> { ...@@ -222,17 +209,14 @@ class _LoginScreenState extends State<LoginScreen> {
width: 22, width: 22,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2, strokeWidth: 2,
valueColor: valueColor: AlwaysStoppedAnimation<Color>(
AlwaysStoppedAnimation<Color>(
Colors.white), Colors.white),
), ),
) )
: Padding( : Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 22),
horizontal: 22),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Continue", "Continue",
...@@ -266,4 +250,4 @@ class _LoginScreenState extends State<LoginScreen> { ...@@ -266,4 +250,4 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
); );
} }
} }
\ No newline at end of file
...@@ -7,13 +7,11 @@ import '../../Utility/AdvancedSnackbar.dart'; ...@@ -7,13 +7,11 @@ import '../../Utility/AdvancedSnackbar.dart';
import '../../Utility/CustomSnackbar.dart'; import '../../Utility/CustomSnackbar.dart';
class OtpScreen extends StatefulWidget { class OtpScreen extends StatefulWidget {
final String mob; // ✅ phone number final String mob; // phone number
final int otp; // ✅ backend OTP
const OtpScreen({ const OtpScreen({
super.key, super.key,
required this.mob, required this.mob,
required this.otp,
}); });
@override @override
...@@ -28,12 +26,10 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -28,12 +26,10 @@ class _OtpScreenState extends State<OtpScreen> {
bool _isVerifying = false; bool _isVerifying = false;
bool _isResending = false; bool _isResending = false;
int _secondsRemaining = 22; int _secondsRemaining = 22;
int _currentOtp = 0; // ✅ Store current OTP in state
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_currentOtp = widget.otp; // ✅ Initialize with passed OTP
_startTimer(); _startTimer();
} }
...@@ -69,66 +65,84 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -69,66 +65,84 @@ class _OtpScreenState extends State<OtpScreen> {
} }
Future<void> _verifyOtp() async { Future<void> _verifyOtp() async {
final rentalProvider = Provider.of<RentalProvider>(context, listen: false);
final enteredOtp = _controllers.map((c) => c.text).join(); final enteredOtp = _controllers.map((c) => c.text).join();
setState(() => _isVerifying = true); setState(() => _isVerifying = true);
await Future.delayed(const Duration(milliseconds: 800));
// Compare with current OTP (not widget.otp) try {
if (enteredOtp == _currentOtp.toString()) { await rentalProvider.fetchMobileOtp(widget.mob, enteredOtp);
// OTP verified successfully
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(" OTP Verified Successfully!"),
backgroundColor: Colors.green,
),
);
// navigation: if (rentalProvider.otpResponse != null) {
Navigator.pushReplacement(context, if (rentalProvider.otpResponse?.error == "0") {
MaterialPageRoute(builder: (_) => const DashboardScreen()) // ✅ OTP verified successfully
); if (!mounted) return;
} else { AnimatedSnackBar.success(
// ❌ Invalid OTP context: context,
ScaffoldMessenger.of(context).showSnackBar( title: "Success",
const SnackBar( message: rentalProvider.otpResponse?.message ?? "OTP Verified Successfully!",
content: Text("❌ Invalid OTP. Please try again."), );
backgroundColor: Colors.redAccent,
), // Navigate to dashboard
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const DashboardScreen()),
);
} else {
// ❌ Invalid OTP
CustomSnackBar.showError(
context: context,
title: "Error",
message: rentalProvider.otpResponse?.errorMsg ??
rentalProvider.otpResponse?.message ??
"Invalid OTP. Please try again.",
);
}
} else {
// ❌ API Error
CustomSnackBar.showError(
context: context,
title: "Error",
message: rentalProvider.otpResponse?.message ?? "Failed to verify OTP. Please try again.",
);
}
} catch (e) {
// ❌ Network Error
CustomSnackBar.showError(
context: context,
title: "Network Error",
message: e.toString(),
); );
} finally {
if (mounted) setState(() => _isVerifying = false);
} }
if (mounted) setState(() => _isVerifying = false);
} }
/// Resend OTP Function /// 🔁 Resend OTP Function
Future<void> _resendOtp(BuildContext context) async { Future<void> _resendOtp(BuildContext context) async {
setState(() => _isResending = true); setState(() => _isResending = true);
try { try {
final rentalProvider = final rentalProvider = Provider.of<RentalProvider>(context, listen: false);
Provider.of<RentalContactProvider>(context, listen: false);
await rentalProvider.fetchRentalContactData( // Call the mobile API again to get new OTP
context, await rentalProvider.fetchRentalMobile(widget.mob);
"4d21382d9e1c4d6e0b7c426d53d89b6b7d48078877f185289092e6fa13bac4b11d417d37738b20b34151b8e638625b3ec013",
"5",
widget.mob,
);
if (rentalProvider.rentalContact != null && if (rentalProvider.response != null && rentalProvider.response?.error == "0") {
rentalProvider.rentalContact!.error == 0) { // ✅ Successfully resent OTP
AnimatedSnackBar.success(
context: context,
title: "OTP Sent",
message: rentalProvider.response?.message ?? "OTP has been sent to your mobile number.",
);
// Update current OTP with the new one from API response // Reset timer and clear fields
final newOtp = rentalProvider.rentalContact!.otp!;
setState(() { setState(() {
_currentOtp = newOtp; // Update current OTP
_secondsRemaining = 22; _secondsRemaining = 22;
}); });
// Clear previous OTP fields // Clear previous OTP fields
for (var controller in _controllers) { for (var controller in _controllers) {
controller.clear(); controller.clear();
} }
...@@ -136,21 +150,16 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -136,21 +150,16 @@ class _OtpScreenState extends State<OtpScreen> {
_isValid = false; _isValid = false;
}); });
// Restart timer // Restart timer
_startTimer(); _startTimer();
AnimatedSnackBar.success(
context: context,
title: "OTP Sent",
message: "${rentalProvider.rentalContact?.message} (OTP: $newOtp)",
);
} else { } else {
// ❌ Failed to resend OTP
CustomSnackBar.showWarning( CustomSnackBar.showWarning(
context: context, context: context,
title: "Error", title: "Error",
message: rentalProvider.rentalContact?.message ?? message: rentalProvider.response?.errorMsg ??
rentalProvider.errorMessage ?? rentalProvider.response?.message ??
"Failed to resend OTP", "Failed to resend OTP",
); );
} }
...@@ -213,7 +222,7 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -213,7 +222,7 @@ class _OtpScreenState extends State<OtpScreen> {
onTap: () => FocusScope.of(context).unfocus(), onTap: () => FocusScope.of(context).unfocus(),
child: Stack( child: Stack(
children: [ children: [
// Background image // Background image
Positioned.fill( Positioned.fill(
child: Image.asset( child: Image.asset(
'assets/images/background.jpg', 'assets/images/background.jpg',
...@@ -221,7 +230,7 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -221,7 +230,7 @@ class _OtpScreenState extends State<OtpScreen> {
), ),
), ),
// Overlay // Overlay
Positioned.fill( Positioned.fill(
child: Container(color: Colors.black.withOpacity(0.5)), child: Container(color: Colors.black.withOpacity(0.5)),
), ),
...@@ -239,7 +248,7 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -239,7 +248,7 @@ class _OtpScreenState extends State<OtpScreen> {
), ),
), ),
// Foreground content // Foreground content
SingleChildScrollView( SingleChildScrollView(
padding: EdgeInsets.only( padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom + 20, bottom: MediaQuery.of(context).viewInsets.bottom + 20,
...@@ -318,7 +327,7 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -318,7 +327,7 @@ class _OtpScreenState extends State<OtpScreen> {
const SizedBox(height: 30), const SizedBox(height: 30),
// Continue Button // Continue Button
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 24), padding: const EdgeInsets.symmetric(horizontal: 24),
child: SizedBox( child: SizedBox(
...@@ -330,8 +339,7 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -330,8 +339,7 @@ class _OtpScreenState extends State<OtpScreen> {
? const Color(0xFF008CDE) ? const Color(0xFF008CDE)
: const Color(0xFF266E99), : const Color(0xFF266E99),
foregroundColor: Colors.white, foregroundColor: Colors.white,
disabledBackgroundColor: disabledBackgroundColor: const Color(0xFF266E99),
const Color(0xFF266E99),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
), ),
...@@ -347,11 +355,9 @@ class _OtpScreenState extends State<OtpScreen> { ...@@ -347,11 +355,9 @@ class _OtpScreenState extends State<OtpScreen> {
), ),
) )
: Padding( : Padding(
padding: padding: const EdgeInsets.symmetric(horizontal: 22),
const EdgeInsets.symmetric(horizontal: 22),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Continue", "Continue",
......
This diff is collapsed.
...@@ -29,4 +29,10 @@ const raiseTicketUrl = "${baseUrl}raise_ticket"; ...@@ -29,4 +29,10 @@ const raiseTicketUrl = "${baseUrl}raise_ticket";
const ticketChatUrl = "${baseUrl}ticket_chat"; const ticketChatUrl = "${baseUrl}ticket_chat";
const ticketChatDisplayUrl = "${baseUrl}ticket_chat_display"; const ticketChatDisplayUrl = "${baseUrl}ticket_chat_display";
const ticketCUrl = "${baseUrl}ticket_c"; const ticketCUrl = "${baseUrl}ticket_c";
const ticketListUrl = "${baseUrl}ticket_list"; const ticketListUrl = "${baseUrl}ticket_list";
\ No newline at end of file
/// dashboard and login
const fetchMobileUrl = "${baseUrl}fetch_mobile_number";
const fetchOtpUrl = "${baseUrl}login";
const dashboardUrl = "${baseUrl}ticket_list";
\ No newline at end of file
...@@ -10,9 +10,11 @@ import 'package:gen_rentals/Models/orderDetailsProductResponse.dart'; ...@@ -10,9 +10,11 @@ import 'package:gen_rentals/Models/orderDetailsProductResponse.dart';
import 'package:gen_rentals/Models/orderListResponse.dart'; import 'package:gen_rentals/Models/orderListResponse.dart';
import 'package:gen_rentals/Models/ticketListResponse.dart'; import 'package:gen_rentals/Models/ticketListResponse.dart';
import 'package:gen_rentals/Notifier/billDetailsResponse.dart'; import 'package:gen_rentals/Notifier/billDetailsResponse.dart';
import '../Models/DashboardResponse.dart';
import '../Models/RentalPaymentDetailsResponse.dart'; import '../Models/RentalPaymentDetailsResponse.dart';
import '../Models/rentalAccountResponse.dart'; import '../Models/rentalAccountResponse.dart';
import '../Models/rentalContactResponse.dart'; import '../Models/rentalContactResponse.dart';
import '../Notifier/RentalContactProvider .dart';
import 'api_URLs.dart'; import 'api_URLs.dart';
import 'api_post_request.dart'; import 'api_post_request.dart';
...@@ -21,22 +23,42 @@ class ApiCalling { ...@@ -21,22 +23,42 @@ class ApiCalling {
/// Fetch rental contact by mobile number /// Fetch rental contact by mobile number
static Future<RentalContactResponse?> fetchRentalContactApi( static Future<FetchMobileResponse?> fetchRentalMobileApi(
String sessionId,
String empId,
String mob, String mob,
) async { ) async {
debugPrint("############################### Api calling "); debugPrint("############################### Api calling ");
try { try {
Map<String, String> data = { Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"mob": mob, "mob": mob,
}; };
final res = await post(data, rentalContactUrl, {}); final res = await post(data, fetchMobileUrl, {});
if (res != null) {
return FetchMobileResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error: $e");
return null;
}
}
static Future<FetchMobileResponse?> fetchMobileOtpApi(
String mob,
String otp
) async {
debugPrint("############################### Api calling ");
try {
Map<String, String> data = {
"mob": mob,
"otp": otp,
};
final res = await post(data, fetchOtpUrl, {});
if (res != null) { if (res != null) {
return RentalContactResponse.fromJson(jsonDecode(res.body)); return FetchMobileResponse.fromJson(jsonDecode(res.body));
} else { } else {
debugPrint("Null Response"); debugPrint("Null Response");
return null; return null;
...@@ -510,5 +532,33 @@ class ApiCalling { ...@@ -510,5 +532,33 @@ class ApiCalling {
} }
} }
/// Fetch Dashboard
static Future<DashboardResponse?> fetchDashboardApi(
String sessionId,
String empId,
String mob,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"mob": mob,
};
final res = await post(data, dashboardUrl, {});
if (res != null) {
return DashboardResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
}
} catch (e) {
debugPrint("❌ API Error (fetch Balance): $e");
return null;
}
}
} }
...@@ -7,6 +7,14 @@ class AppColors { ...@@ -7,6 +7,14 @@ class AppColors {
static const Color secondary = Color(0xFF10B981); static const Color secondary = Color(0xFF10B981);
static const Color accent = Color(0xFFF59E0B); static const Color accent = Color(0xFFF59E0B);
// Text colors
static const Color amountText = Color(0xFF008CDE);
static const Color cardAmountText = Color(0xFF2D2D2D);
static const Color normalText = Color(0xFF2D2D2D);
static const Color subtitleText = Color(0xFF8E8E8E);
static const Color warningText = Color(0xFFF00000);
static const Color nearDarkText = Color(0xFF1E1E1E);
// Status colors // Status colors
static const Color success = Color(0xFF10B981); static const Color success = Color(0xFF10B981);
static const Color warning = Color(0xFFF59E0B); static const Color warning = Color(0xFFF59E0B);
...@@ -21,4 +29,8 @@ class AppColors { ...@@ -21,4 +29,8 @@ class AppColors {
// Background colors // Background colors
static const Color backgroundLight = Color(0xFFFFFFFF); static const Color backgroundLight = Color(0xFFFFFFFF);
static const Color backgroundDark = Color(0xFF111827); static const Color backgroundDark = Color(0xFF111827);
static const Color backgroundRegular = Color(0xFFF2F2F2);
//Button
static const Color buttonColor = Color(0xFF008CDE);
} }
\ No newline at end of file
import 'package:flutter/material.dart';
class SectionHeading extends StatelessWidget {
final String title;
final TextStyle? textStyle;
final EdgeInsetsGeometry padding;
const SectionHeading({
Key? key,
required this.title,
this.textStyle = const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, fontFamily: "Poppins"),
this.padding = const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: padding,
child: Text(
title,
style: textStyle ??
Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
);
}
}
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gen_rentals/Notifier/DashboardProvider.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/RentalContactProvider .dart'; import 'Notifier/RentalContactProvider .dart';
...@@ -24,10 +25,9 @@ class MyApp extends StatelessWidget { ...@@ -24,10 +25,9 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider<RentalContactProvider>(create: (_) => RentalContactProvider(), ChangeNotifierProvider<DashboardProvider>(create: (_) => DashboardProvider()),
), ChangeNotifierProvider<RentalProvider>(create: (_) => RentalProvider(),),
ChangeNotifierProvider<ThemeProvider>(create: (_) => ThemeProvider(), ChangeNotifierProvider<ThemeProvider>(create: (_) => ThemeProvider(),),
),
], ],
child: Consumer<ThemeProvider>( child: Consumer<ThemeProvider>(
builder: (context, themeProvider, child) { builder: (context, themeProvider, child) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment