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
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:gen_rentals/Screens/BillDetailListScreen.dart';
import 'package:gen_rentals/Utility/Reusablewidgets.dart';
import '../Utility/AppColors.dart';
class ProductsDetailScreen extends StatelessWidget {
const ProductsDetailScreen({super.key});
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
double bottomPadding = MediaQuery.of(context).padding.bottom;
return SafeArea(
top: false,
child: Scaffold(
body: Container(
color: const Color(0xFFF3F3F3),
height: screenHeight,
child: SingleChildScrollView(
child: Column(
children: [
// Top background image section
Stack(
children: [
// Background image
Container(
width: double.infinity,
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.white54,
Color(0xFFF3F3F3),
],
),
),
child: Image.asset(
'assets/images/sky_blue_bg.jpg',
width: double.infinity,
height: 400,
fit: BoxFit.cover,
),
),
// Content overlay
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header with profile
Container(
width: double.infinity,
height: 450,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0x22FFFFFF),
Color(0x33FFFFFF),
Color(0x88FFFFFF),
Color(0xFFF3F3F3),
Color(0xFFF3F3F3),
],
),
),
child: Column(
children: [
const SizedBox(height: 50),
// Instead of SizedBox(width: 280) - consider using Spacer()
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
"assets/svg/continue_left_ic.svg",
height: 50,
width: 50,
),
// Removed SizedBox(width: 280)
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.19),
shape: BoxShape.circle,
border: Border.all(
color: Colors.white.withOpacity(0.5),
width: 2,
),
),
child: const Icon(
Icons.person,
color: Colors.white,
size: 30,
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
'assets/images/gen2_img.png',
height: 250,
width: 250,
),
const Text(
"Genesis 85kVA",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.black,
fontSize: 30,
fontWeight: FontWeight.w500,
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFE9FFDD),
Color(0xFFB5FFD1),
],
),
),
child: Text(
"2 months left",
style: const TextStyle(
color: Colors.black87,
fontSize: 12,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
),
),
),
SizedBox(height: 4,),
const Text(
"Rented on 7th July, 2025",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey,
fontSize: 16,
fontWeight: FontWeight.w400,
),
),
],
),
],
),
),
const SizedBox(height: 10),
// Main content section
Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
// Balance Amount Card
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkResponse(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BillDetailListScreen()),
);
},
child: Row(
children: [
const Text(
"Balance Amount",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.warningText,
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
const SizedBox(width: 4),
SvgPicture.asset(
"assets/svg/continue_ic.svg",
color: AppColors.warningText,
height: 18,
width: 18,
),
],
),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"₹24,800",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.cardAmountText,
fontSize: 32,
fontWeight: FontWeight.w500,
),
),
InkResponse(
onTap: () => showPaymentBottomSheet(context),
child: Text(
"Pay Now",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.amountText,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
],
),
const SizedBox(height: 2),
Text(
"Last Paid on 12th Sep, 2025",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.subtitleText,
fontSize: 12,
fontWeight: FontWeight.w400,
// fontStyle: FontStyle.italic,
),
),
SvgPicture.asset(
"assets/svg/line_ic.svg",
color: AppColors.subtitleText,
height: 18,
width: 18,
),
// After spacer
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Plan",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.subtitleText,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 12,
),
),
Text(
"₹3600",
style: const TextStyle(
fontFamily: "Poppins",
color: Color(0xFF008CDE),
fontSize: 18,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w500,
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Deposit",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.subtitleText,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 12,
),
),
Text(
"₹5483",
style: const TextStyle(
fontFamily: "Poppins",
color: AppColors.cardAmountText,
fontSize: 18,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w500,
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Tenure",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.subtitleText,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 12,
),
),
Text(
"6 Months",
style: const TextStyle(
fontFamily: "Poppins",
color: AppColors.cardAmountText,
fontSize: 18,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w500,
),
),
],
)
],
)
],
),
),
const SizedBox(height: 18),
Container(
width: double.infinity,
color: Colors.transparent,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 2),
SectionHeading(title: "Generator Overview", padding: EdgeInsets.symmetric(vertical: 4),),
Text(
"A diesel generator converts fuel into electricity using an engine to drive an alternator. They provide backup power for homes and businesses and serve as primary sources in remote areas.",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.subtitleText,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 12,
),
),
],
)
),
const SizedBox(height: 20),
// Feature cards grid
Container(
width: double.infinity,
color: Colors.transparent,
child: Column(
children: [
// First row of feature cards
Row(
children: [
// Any Requirements Card
Expanded(
child: _buildFeatureCard(
title: "85 kVA",
description: "PRIME POWER",
icon: "assets/svg/power_ic.svg",
color: Colors.orange,
),
),
const SizedBox(width: 16),
// Subscribed Products Card
Expanded(
child: _buildFeatureCard(
title: "1500 RPM",
description: "ENGINE SPEED",
icon: "assets/svg/rpm_ic.svg",
color: Colors.blue,
),
),
],
),
const SizedBox(height: 16),
// Second row of feature cards
Row(
children: [
// Have Complaints Card
Expanded(
child: _buildFeatureCard(
title: "75 dB",
description: "LOW NOISE LEVEL",
icon: "assets/svg/noise_ic.svg",
color: Colors.green,
),
),
const SizedBox(width: 16),
// Know Your Payments Card
Expanded(
child: _buildFeatureCard(
title: "24 Hr",
description: "LONGER RUNTIME",
icon: "assets/svg/clock_ic.svg",
color: Colors.purple,
),
),
],
),
const SizedBox(height: 20),
],
),
),
],
),
),
],
),
],
),
],
),
),
),
),
);
}
Widget _buildFeatureCard({
required String title,
required String description,
required String icon,
required Color color,
}) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey.shade200,
width: 1,
),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withOpacity(0.05),
// blurRadius: 8,
// offset: const Offset(0, 2),
// ),
// ],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Icon and title row
Container(
width: 45,
height: 45,
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Center( // Add this Center widget
child: SvgPicture.asset(
icon,
height: 25,
width: 25,
// Remove fit: BoxFit.none
),
),
),
const SizedBox(height: 4),
Text(
title,
style: TextStyle(
color: AppColors.nearDarkText,
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 4),
// Description
Text(
description,
style: TextStyle(
color: AppColors.subtitleText,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 12,
),
),
],
),
);
}
void showPaymentBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (BuildContext context) {
return SafeArea(
bottom: true,
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header - Drag handle
Center(
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(2),
),
),
),
const SizedBox(height: 20),
// Pay Amount Section
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Pay",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Color(0xFF777777),
),
),
SizedBox(height: 4),
Text(
"₹4218",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
],
),
// Rent Amount Section
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const Text(
"Rent Amount",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Color(0xFF777777),
),
),
const SizedBox(height: 4),
GestureDetector(
onTap: () {
// Handle view bill details
},
child: Text(
"View Bill Details",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xFF008CDE),
),
),
),
],
),
],
),
const SizedBox(height: 10),
const Divider(height: 1, color: Color(0xFFEEEEEE)),
const SizedBox(height: 18),
// Continue Payment Button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
// Handle continue payment
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF008CDE),
foregroundColor: Colors.white,
disabledBackgroundColor: const Color(0xFF266E99),
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(
color: Color(0xFFFFFFFF),
fontSize: 16,
),
),
SvgPicture.asset(
"assets/svg/continue_ic.svg",
color: Color(0xFFFFFFFF),
height: 25,
width: 25,
),
],
),
),
),
),
],
),
),
),
);
},
);
}
}
\ No newline at end of file
......@@ -3,6 +3,10 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.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 'authScreen/LoginScreen.dart';
......@@ -76,7 +80,7 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
Navigator.pushReplacement(
context,
PageRouteBuilder(
pageBuilder: (_, __, ___) => const LoginScreen(),
pageBuilder: (_, __, ___) => LoginScreen(),
transitionsBuilder: (_, animation, __, child) {
return FadeTransition(
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> {
}
Future<void> _login(BuildContext context) async {
final rentalProvider =
Provider.of<RentalContactProvider>(context, listen: false);
final rentalProvider = Provider.of<RentalProvider>(context, listen: false);
final mob = _phoneController.text.trim();
await rentalProvider.fetchRentalContactData(
context,
"4d21382d9e1c4d6e0b7c426d53d89b6b7d48078877f185289092e6fa13bac4b11d417d37738b20b34151b8e638625b3ec013",
"5",
mob,
);
await rentalProvider.fetchRentalMobile(mob);
// ✅ Handle response
if (rentalProvider.rentalContact != null &&
rentalProvider.rentalContact!.error == 0) {
// ✅ Handle response - Check if error is "0" (string comparison)
if (rentalProvider.response != null && rentalProvider.response!.error == "0") {
AnimatedSnackBar.success(
context: context,
title: "Login Success",
message: "${rentalProvider.rentalContact?.message} OTP: ${rentalProvider.rentalContact?.otp}" ?? "Login Success",
title: "OTP Sent",
message: rentalProvider.response?.errorMsg ?? "OTP sent to your registered mobile number!",
);
// Navigate to OTP screen
// Navigate to OTP screen after a short delay
Future.delayed(const Duration(milliseconds: 1500), () {
if (mounted) {
Navigator.pushReplacement(
context,
PageRouteBuilder(
pageBuilder: (_, __, ___) => OtpScreen(
mob: mob,
otp: rentalProvider.rentalContact!.otp ?? 0,
),
transitionsBuilder: (_, animation, __, child) {
return FadeTransition(opacity: animation, child: child);
},
transitionDuration: const Duration(milliseconds: 600),
MaterialPageRoute(
builder: (context) => OtpScreen(mob: mob),
),
);
}
});
} else {
CustomSnackBar.showWarning(
context: context,
message: rentalProvider.rentalContact?.message ??
rentalProvider.errorMessage ??
"Login failed",
title: "Login Status",
title: "Login Failed",
message: rentalProvider.response?.errorMsg ??
"Mobile number not registered or invalid",
);
}
}
@override
Widget build(BuildContext context) {
final rentalProvider = Provider.of<RentalContactProvider>(context);
final rentalProvider = Provider.of<RentalProvider>(context);
return Scaffold(
resizeToAvoidBottomInset: false, // prevents background image resize
resizeToAvoidBottomInset: false,
body: Stack(
children: [
// 🏙️ Fixed background image
......@@ -115,8 +104,7 @@ class _LoginScreenState extends State<LoginScreen> {
],
),
),
padding:
const EdgeInsets.symmetric(horizontal: 22, vertical: 20),
padding: const EdgeInsets.symmetric(horizontal: 22, vertical: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
......@@ -155,12 +143,14 @@ class _LoginScreenState extends State<LoginScreen> {
controller: _phoneController,
keyboardType: TextInputType.phone,
onChanged: _validatePhone,
maxLength: 10,
style: const TextStyle(color: Colors.black),
decoration: InputDecoration(
hintText: "Enter Mobile No.",
hintStyle: const TextStyle(color: Colors.grey),
filled: true,
fillColor: Colors.white,
counterText: "", // Remove character counter
contentPadding: const EdgeInsets.symmetric(
vertical: 16, horizontal: 20),
enabledBorder: OutlineInputBorder(
......@@ -172,8 +162,7 @@ class _LoginScreenState extends State<LoginScreen> {
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide:
const BorderSide(color: Colors.blue, width: 2),
borderSide: const BorderSide(color: Colors.blue, width: 2),
),
),
),
......@@ -208,13 +197,11 @@ class _LoginScreenState extends State<LoginScreen> {
? const Color(0xFF008CDE)
: const Color(0xFF266E99),
foregroundColor: Colors.white,
disabledBackgroundColor:
const Color(0xFF266E99),
disabledBackgroundColor: const Color(0xFF266E99),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding:
const EdgeInsets.symmetric(vertical: 16),
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: rentalProvider.isLoading
? const SizedBox(
......@@ -222,17 +209,14 @@ class _LoginScreenState extends State<LoginScreen> {
width: 22,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(
valueColor: AlwaysStoppedAnimation<Color>(
Colors.white),
),
)
: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 22),
padding: const EdgeInsets.symmetric(horizontal: 22),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Continue",
......
......@@ -7,13 +7,11 @@ import '../../Utility/AdvancedSnackbar.dart';
import '../../Utility/CustomSnackbar.dart';
class OtpScreen extends StatefulWidget {
final String mob; // ✅ phone number
final int otp; // ✅ backend OTP
final String mob; // phone number
const OtpScreen({
super.key,
required this.mob,
required this.otp,
});
@override
......@@ -28,12 +26,10 @@ class _OtpScreenState extends State<OtpScreen> {
bool _isVerifying = false;
bool _isResending = false;
int _secondsRemaining = 22;
int _currentOtp = 0; // ✅ Store current OTP in state
@override
void initState() {
super.initState();
_currentOtp = widget.otp; // ✅ Initialize with passed OTP
_startTimer();
}
......@@ -69,62 +65,80 @@ class _OtpScreenState extends State<OtpScreen> {
}
Future<void> _verifyOtp() async {
final rentalProvider = Provider.of<RentalProvider>(context, listen: false);
final enteredOtp = _controllers.map((c) => c.text).join();
setState(() => _isVerifying = true);
await Future.delayed(const Duration(milliseconds: 800));
// Compare with current OTP (not widget.otp)
if (enteredOtp == _currentOtp.toString()) {
// OTP verified successfully
try {
await rentalProvider.fetchMobileOtp(widget.mob, enteredOtp);
if (rentalProvider.otpResponse != null) {
if (rentalProvider.otpResponse?.error == "0") {
// ✅ OTP verified successfully
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(" OTP Verified Successfully!"),
backgroundColor: Colors.green,
),
);
// navigation:
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (_) => const DashboardScreen())
AnimatedSnackBar.success(
context: context,
title: "Success",
message: rentalProvider.otpResponse?.message ?? "OTP Verified Successfully!",
);
// Navigate to dashboard
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const DashboardScreen()),
);
} else {
// ❌ Invalid OTP
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("❌ Invalid OTP. Please try again."),
backgroundColor: Colors.redAccent,
),
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);
}
}
/// Resend OTP Function
/// 🔁 Resend OTP Function
Future<void> _resendOtp(BuildContext context) async {
setState(() => _isResending = true);
try {
final rentalProvider =
Provider.of<RentalContactProvider>(context, listen: false);
final rentalProvider = Provider.of<RentalProvider>(context, listen: false);
await rentalProvider.fetchRentalContactData(
context,
"4d21382d9e1c4d6e0b7c426d53d89b6b7d48078877f185289092e6fa13bac4b11d417d37738b20b34151b8e638625b3ec013",
"5",
widget.mob,
);
// Call the mobile API again to get new OTP
await rentalProvider.fetchRentalMobile(widget.mob);
if (rentalProvider.rentalContact != null &&
rentalProvider.rentalContact!.error == 0) {
if (rentalProvider.response != null && rentalProvider.response?.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
final newOtp = rentalProvider.rentalContact!.otp!;
// Reset timer and clear fields
setState(() {
_currentOtp = newOtp; // Update current OTP
_secondsRemaining = 22;
});
......@@ -139,18 +153,13 @@ class _OtpScreenState extends State<OtpScreen> {
// Restart timer
_startTimer();
AnimatedSnackBar.success(
context: context,
title: "OTP Sent",
message: "${rentalProvider.rentalContact?.message} (OTP: $newOtp)",
);
} else {
// ❌ Failed to resend OTP
CustomSnackBar.showWarning(
context: context,
title: "Error",
message: rentalProvider.rentalContact?.message ??
rentalProvider.errorMessage ??
message: rentalProvider.response?.errorMsg ??
rentalProvider.response?.message ??
"Failed to resend OTP",
);
}
......@@ -330,8 +339,7 @@ class _OtpScreenState extends State<OtpScreen> {
? const Color(0xFF008CDE)
: const Color(0xFF266E99),
foregroundColor: Colors.white,
disabledBackgroundColor:
const Color(0xFF266E99),
disabledBackgroundColor: const Color(0xFF266E99),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
......@@ -347,11 +355,9 @@ class _OtpScreenState extends State<OtpScreen> {
),
)
: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 22),
padding: const EdgeInsets.symmetric(horizontal: 22),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Continue",
......
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../Notifier/RentalContactProvider .dart';
class MainScreen extends StatefulWidget {
RentalContactProvider provider;
MainScreen({super.key, required this.provider});
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateMixin {
int _selectedIndex = 0;
late AnimationController _animationController;
late Animation<double> _fadeAnimation;
late Animation<double> _scaleAnimation;
final List<String> _menuTitles = [
"Dashboard",
"View Orders",
"View Ledger",
"Make Payment",
"View Tickets",
];
final List<IconData> _menuIcons = [
Icons.dashboard_rounded,
Icons.shopping_bag_rounded,
Icons.account_balance_wallet_rounded,
Icons.payment_rounded,
Icons.support_agent_rounded,
];
final List<Color> _menuColors = [
const Color(0xFF26BAE7),
const Color(0xFF4CAF50),
const Color(0xFFFF9800),
const Color(0xFF9C27B0),
const Color(0xFFF44336),
];
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 800),
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
);
_scaleAnimation = Tween<double>(begin: 0.95, end: 1.0).animate(
CurvedAnimation(parent: _animationController, curve: Curves.elasticOut),
);
_animationController.forward();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final rentalProvider = Provider.of<RentalContactProvider>(context);
final contact = rentalProvider.rentalContact;
return Scaffold(
backgroundColor: const Color(0xFFF5F8FC),
appBar: AppBar(
title: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: Text(
_menuTitles[_selectedIndex],
key: ValueKey(_selectedIndex),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: Colors.white,
),
),
),
backgroundColor: const Color(0xFF273172),
elevation: 0,
iconTheme: const IconThemeData(color: Colors.white),
actions: [
IconButton(
icon: const Icon(Icons.notifications_none_rounded),
onPressed: () {},
),
const SizedBox(width: 8),
],
),
drawer: _buildDrawer(contact),
body: AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: _buildBody(contact),
),
);
}
Widget _buildDrawer(rentalContact) {
return Drawer(
width: 280,
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF273172),
Color(0xFF26BAE7),
],
),
),
child: Column(
children: [
// Header
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Logo and App Name
Row(
children: [
Container(
padding: const EdgeInsets.all(1),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
),
],
),
// child: SvgPicture.network(
// "https://genrentals.in/assets/img/logo-black.svg",
// height: 28,
// ),
),
const SizedBox(width: 12),
const Text(
"Gen Rentals",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w700,
),
),
],
),
const SizedBox(height: 20),
// User Info
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white.withOpacity(0.2)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Branch Name",
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 4),
Text(
"Branch Address",
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 12,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
"Balance: ₹ 0",
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
],
),
),
const SizedBox(height: 8),
// Menu items
Expanded(
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: ListView(
padding: const EdgeInsets.all(16),
children: [
...List.generate(_menuTitles.length, (index) =>
_buildDrawerItem(index, _menuTitles[index], _menuIcons[index], _menuColors[index])
),
const SizedBox(height: 16),
const Divider(height: 1),
const SizedBox(height: 16),
_buildDrawerItem(-1, "Logout", Icons.logout_rounded, const Color(0xFFF44336)),
],
),
),
),
],
),
),
);
}
Widget _buildDrawerItem(int index, String title, IconData icon, Color color) {
return Container(
margin: const EdgeInsets.only(bottom: 8),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
if (index == -1) {
// Logout
Navigator.pushReplacementNamed(context, "/login");
} else {
setState(() => _selectedIndex = index);
Navigator.pop(context); // close drawer
}
},
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: _selectedIndex == index ? color.withOpacity(0.1) : Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: _selectedIndex == index ? Border.all(color: color.withOpacity(0.3)) : null,
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
icon,
color: color,
size: 20,
),
),
const SizedBox(width: 16),
Expanded(
child: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: _selectedIndex == index ? FontWeight.w600 : FontWeight.w500,
color: _selectedIndex == index ? color : Colors.grey.shade700,
),
),
),
if (_selectedIndex == index)
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
),
),
],
),
),
),
),
);
}
Widget _buildBody(rentalContact) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Opacity(
opacity: _fadeAnimation.value,
child: Transform.scale(
scale: _scaleAnimation.value,
child: _getCurrentScreen(rentalContact),
),
);
},
);
}
Widget _getCurrentScreen(rentalContact) {
switch (_selectedIndex) {
case 0:
return _buildDashboard(rentalContact);
case 1:
return _buildPlaceholderScreen("View Orders", Icons.shopping_bag_rounded);
case 2:
return _buildPlaceholderScreen("View Ledger", Icons.account_balance_wallet_rounded);
case 3:
return _buildPlaceholderScreen("Make Payment", Icons.payment_rounded);
case 4:
return _buildPlaceholderScreen("View Tickets", Icons.support_agent_rounded);
default:
return _buildDashboard(rentalContact);
}
}
Widget _buildDashboard(rentalContact) {
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Welcome Section
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF273172), Color(0xFF26BAE7)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: const Color(0xFF273172).withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Welcome Back!",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w700,
color: Colors.white,
),
),
const SizedBox(height: 8),
Text(
"Here's your dashboard overview",
style: TextStyle(
fontSize: 16,
color: Colors.white.withOpacity(0.8),
),
),
const SizedBox(height: 20),
_buildInfoRow(Icons.phone_android_rounded, "Mobile", widget.provider.rentalContact!.mob.toString()),
_buildInfoRow(Icons.business_rounded, "Office", "N/A"),
_buildInfoRow(Icons.account_balance_wallet_rounded, "Balance", "₹ 0"),
],
),
),
const SizedBox(height: 24),
// Quick Stats
const Text(
"Quick Stats",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: Color(0xFF273172),
),
),
const SizedBox(height: 16),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
children: [
_buildStatCard("Active Orders", "12", Icons.shopping_bag_rounded, const Color(0xFF4CAF50)),
_buildStatCard("Pending Payments", "5", Icons.payment_rounded, const Color(0xFFFF9800)),
_buildStatCard("Open Tickets", "3", Icons.support_agent_rounded, const Color(0xFFF44336)),
_buildStatCard("Total Balance", "₹0", Icons.account_balance_wallet_rounded, const Color(0xFF26BAE7)),
],
),
const SizedBox(height: 24),
// Recent Activities
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Recent Activities",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Color(0xFF273172),
),
),
const SizedBox(height: 16),
_buildActivityItem("New order placed", "2 hours ago", Icons.shopping_bag_rounded),
_buildActivityItem("Payment received", "1 day ago", Icons.payment_rounded),
_buildActivityItem("Ticket resolved", "2 days ago", Icons.support_agent_rounded),
],
),
),
],
),
);
}
Widget _buildInfoRow(IconData icon, String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
Icon(icon, color: Colors.white.withOpacity(0.7), size: 18),
const SizedBox(width: 12),
Text(
"$label: ",
style: TextStyle(
color: Colors.white.withOpacity(0.7),
fontSize: 14,
),
),
Text(
value,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
],
),
);
}
Widget _buildStatCard(String title, String value, IconData icon, Color color) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(icon, color: color, size: 20),
),
const SizedBox(height: 12),
Text(
value,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: color,
),
),
const SizedBox(height: 4),
Text(
title,
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
),
),
],
),
);
}
Widget _buildActivityItem(String title, String time, IconData icon) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: const Color(0xFF26BAE7).withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(icon, color: const Color(0xFF26BAE7), size: 16),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
Text(
time,
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade500,
),
),
],
),
),
],
),
);
}
Widget _buildPlaceholderScreen(String title, IconData icon) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: const Color(0xFF26BAE7).withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
icon,
size: 64,
color: const Color(0xFF26BAE7),
),
),
const SizedBox(height: 24),
Text(
title,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
color: Color(0xFF273172),
),
),
const SizedBox(height: 12),
Text(
"This feature is coming soon",
style: TextStyle(
fontSize: 16,
color: Colors.grey.shade600,
),
),
],
),
);
}
}
\ No newline at end of file
......@@ -30,3 +30,9 @@ const ticketChatUrl = "${baseUrl}ticket_chat";
const ticketChatDisplayUrl = "${baseUrl}ticket_chat_display";
const ticketCUrl = "${baseUrl}ticket_c";
const ticketListUrl = "${baseUrl}ticket_list";
/// 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';
import 'package:gen_rentals/Models/orderListResponse.dart';
import 'package:gen_rentals/Models/ticketListResponse.dart';
import 'package:gen_rentals/Notifier/billDetailsResponse.dart';
import '../Models/DashboardResponse.dart';
import '../Models/RentalPaymentDetailsResponse.dart';
import '../Models/rentalAccountResponse.dart';
import '../Models/rentalContactResponse.dart';
import '../Notifier/RentalContactProvider .dart';
import 'api_URLs.dart';
import 'api_post_request.dart';
......@@ -21,22 +23,42 @@ class ApiCalling {
/// Fetch rental contact by mobile number
static Future<RentalContactResponse?> fetchRentalContactApi(
String sessionId,
String empId,
static Future<FetchMobileResponse?> fetchRentalMobileApi(
String mob,
) async {
debugPrint("############################### Api calling ");
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"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) {
return RentalContactResponse.fromJson(jsonDecode(res.body));
return FetchMobileResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
......@@ -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 {
static const Color secondary = Color(0xFF10B981);
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
static const Color success = Color(0xFF10B981);
static const Color warning = Color(0xFFF59E0B);
......@@ -21,4 +29,8 @@ class AppColors {
// Background colors
static const Color backgroundLight = Color(0xFFFFFFFF);
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:gen_rentals/Notifier/DashboardProvider.dart';
import 'package:gen_rentals/Screens/SplashScreen.dart';
import 'package:provider/provider.dart';
import 'Notifier/RentalContactProvider .dart';
......@@ -24,10 +25,9 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<RentalContactProvider>(create: (_) => RentalContactProvider(),
),
ChangeNotifierProvider<ThemeProvider>(create: (_) => ThemeProvider(),
),
ChangeNotifierProvider<DashboardProvider>(create: (_) => DashboardProvider()),
ChangeNotifierProvider<RentalProvider>(create: (_) => RentalProvider(),),
ChangeNotifierProvider<ThemeProvider>(create: (_) => ThemeProvider(),),
],
child: Consumer<ThemeProvider>(
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