Commit df116895 authored by Sai Srinivas's avatar Sai Srinivas
Browse files

New Screen and api

parent 9462b0ba
......@@ -2,7 +2,8 @@
<application
android:label="Gen Rentals"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true"> <!-- Fixed: Removed extra quote and corrected placement -->
<activity
android:name=".MainActivity"
android:exported="true"
......
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
flutter.minSdkVersion=23
<svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.9809 37.9618C29.4637 37.9618 37.9618 29.4637 37.9618 18.9809C37.9618 8.49803 29.4637 0 18.9809 0C8.49803 0 0 8.49803 0 18.9809C0 29.4637 8.49803 37.9618 18.9809 37.9618Z" fill="url(#paint0_linear_383_1201)"/>
<path d="M18.8177 32.4369C17.2122 32.4369 15.8743 31.1325 15.8743 29.5271C15.8743 27.9216 17.2122 26.6172 18.8177 26.6172C20.4231 26.6172 21.761 27.9216 21.761 29.5271C21.761 31.1325 20.4231 32.4369 18.8177 32.4369Z" fill="white"/>
<path d="M20.7245 22.1017V24.6105H16.0086L15.2058 18.6567C19.186 18.6567 21.9954 17.7872 21.9954 15.2451C21.9954 13.6061 20.7915 12.3018 18.7178 12.3018C17.38 12.3018 15.6404 12.9037 14.102 13.9072L13.4663 9.15762C14.8712 8.18757 17.0789 7.48535 19.1525 7.48535C23.8349 7.48535 27.347 10.6628 27.347 14.8438C27.347 18.8908 24.0024 21.6671 20.7245 22.1017Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_383_1201" x1="25.4745" y1="36.8219" x2="12.4873" y2="1.13985" gradientUnits="userSpaceOnUse">
<stop offset="0.2486" stop-color="#948BF7"/>
<stop offset="0.9279" stop-color="#C7CBFF"/>
</linearGradient>
</defs>
</svg>
class DashboardResponse {
String? error;
String? mobNum;
String? raname;
String? balanceAmount;
int? balanceAmount;
String? message;
List<Products>? products;
List<Orders>? orders;
DashboardResponse(
{this.error,
this.mobNum,
this.raname,
this.balanceAmount,
this.message,
this.products});
this.orders});
DashboardResponse.fromJson(Map<String, dynamic> json) {
error = json['error'];
mobNum = json['mob_num'];
raname = json['raname'];
balanceAmount = json['balance_amount'];
message = json['message'];
if (json['products'] != null) {
products = <Products>[];
json['products'].forEach((v) {
products!.add(new Products.fromJson(v));
if (json['orders'] != null) {
orders = <Orders>[];
json['orders'].forEach((v) {
orders!.add(new Orders.fromJson(v));
});
}
}
......@@ -28,65 +31,62 @@ class DashboardResponse {
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['error'] = this.error;
data['mob_num'] = this.mobNum;
data['raname'] = this.raname;
data['balance_amount'] = this.balanceAmount;
data['message'] = this.message;
if (this.products != null) {
data['products'] = this.products!.map((v) => v.toJson()).toList();
if (this.orders != null) {
data['orders'] = this.orders!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Products {
class Orders {
String? orderid;
String? productName;
String? orderNum;
String? productImage;
String? plan;
String? rentedDate;
String? expiringInColor;
String? expiringText;
String? address;
bool? hasPendingPayment;
String? pendingPaymentText;
List<String>? products;
Products(
Orders(
{this.orderid,
this.productName,
this.orderNum,
this.productImage,
this.plan,
this.rentedDate,
this.expiringInColor,
this.expiringText,
this.address,
this.hasPendingPayment,
this.pendingPaymentText});
this.pendingPaymentText,
this.products});
Products.fromJson(Map<String, dynamic> json) {
Orders.fromJson(Map<String, dynamic> json) {
orderid = json['orderid'];
productName = json['productName'];
orderNum = json['order_num'];
productImage = json['productImage'];
plan = json['plan'];
rentedDate = json['rentedDate'];
expiringInColor = json['ExpiringInColor'];
expiringText = json['expiringText'];
address = json['address'];
hasPendingPayment = json['hasPendingPayment'];
pendingPaymentText = json['pendingPaymentText'];
products = json['products'].cast<String>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['orderid'] = this.orderid;
data['productName'] = this.productName;
data['order_num'] = this.orderNum;
data['productImage'] = this.productImage;
data['plan'] = this.plan;
data['rentedDate'] = this.rentedDate;
data['ExpiringInColor'] = this.expiringInColor;
data['expiringText'] = this.expiringText;
data['address'] = this.address;
data['hasPendingPayment'] = this.hasPendingPayment;
data['pendingPaymentText'] = this.pendingPaymentText;
data['products'] = this.products;
return data;
}
}
class SubscribeOrderDetailsResponse {
String? orderid;
String? orderNum;
String? rentedDate;
String? expiringInColor;
String? expiringText;
List<Products>? products;
String? error;
String? message;
SubscribeOrderDetailsResponse(
{this.orderid,
this.orderNum,
this.rentedDate,
this.expiringInColor,
this.expiringText,
this.products,
this.error,
this.message});
SubscribeOrderDetailsResponse.fromJson(Map<String, dynamic> json) {
orderid = json['orderid'];
orderNum = json['order_num'];
rentedDate = json['rentedDate'];
expiringInColor = json['ExpiringInColor'];
expiringText = json['expiringText'];
if (json['products'] != null) {
products = <Products>[];
json['products'].forEach((v) {
products!.add(new Products.fromJson(v));
});
}
error = json['error'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['orderid'] = this.orderid;
data['order_num'] = this.orderNum;
data['rentedDate'] = this.rentedDate;
data['ExpiringInColor'] = this.expiringInColor;
data['expiringText'] = this.expiringText;
if (this.products != null) {
data['products'] = this.products!.map((v) => v.toJson()).toList();
}
data['error'] = this.error;
data['message'] = this.message;
return data;
}
}
class Products {
String? id;
String? idName;
String? prodName;
String? totalPrice;
String? per;
String? dispatchDate;
String? receivedDate;
Products(
{this.id,
this.idName,
this.prodName,
this.totalPrice,
this.per,
this.dispatchDate,
this.receivedDate});
Products.fromJson(Map<String, dynamic> json) {
id = json['id'];
idName = json['id_name'];
prodName = json['prod_name'];
totalPrice = json['total_price'];
per = json['per'];
dispatchDate = json['dispatch_date'];
receivedDate = json['received_date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['id_name'] = this.idName;
data['prod_name'] = this.prodName;
data['total_price'] = this.totalPrice;
data['per'] = this.per;
data['dispatch_date'] = this.dispatchDate;
data['received_date'] = this.receivedDate;
return data;
}
}
class TransactionsResponse {
int? balanceAmount;
String? creditAmount;
String? debitAmount;
Map<String, List<TransactionItem>>? transactions;
String? error;
String? message;
TransactionsResponse({
this.balanceAmount,
this.creditAmount,
this.debitAmount,
this.transactions,
this.error,
this.message,
});
TransactionsResponse.fromJson(Map<String, dynamic> json) {
balanceAmount = json['balance_amount'];
creditAmount = json['credit_amount'];
debitAmount = json['debit_amount'];
error = json['error'];
message = json['message'];
if (json['transactions'] != null) {
transactions = {};
json['transactions'].forEach((key, value) {
transactions![key] = (value as List)
.map((v) => TransactionItem.fromJson(v))
.toList();
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['balance_amount'] = balanceAmount;
data['credit_amount'] = creditAmount;
data['debit_amount'] = debitAmount;
data['error'] = error;
data['message'] = message;
if (transactions != null) {
data['transactions'] = transactions!.map((key, value) =>
MapEntry(key, value.map((v) => v.toJson()).toList()));
}
return data;
}
}
class TransactionItem {
String? paymentId;
String? amount;
String? type;
String? purpose;
String? date;
TransactionItem({
this.paymentId,
this.amount,
this.type,
this.purpose,
this.date,
});
TransactionItem.fromJson(Map<String, dynamic> json) {
paymentId = json['payment_id'];
amount = json['amount'];
type = json['type'];
purpose = json['purpose'];
date = json['date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['payment_id'] = paymentId;
data['amount'] = amount;
data['type'] = type;
data['purpose'] = purpose;
data['date'] = date;
return data;
}
}
class OrderListResponse {
List<Order>? order;
int? error;
String? message;
OrderListResponse({this.order, this.error, this.message});
OrderListResponse.fromJson(Map<String, dynamic> json) {
if (json['order'] != null) {
order = <Order>[];
json['order'].forEach((v) {
order!.add(new Order.fromJson(v));
});
}
error = json['error'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.order != null) {
data['order'] = this.order!.map((v) => v.toJson()).toList();
}
data['error'] = this.error;
data['message'] = this.message;
return data;
}
}
class Order {
String? orderid;
String? datetime;
String? address;
Order({this.orderid, this.datetime, this.address});
Order.fromJson(Map<String, dynamic> json) {
orderid = json['orderid'];
datetime = json['datetime'];
address = json['address'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['orderid'] = this.orderid;
data['datetime'] = this.datetime;
data['address'] = this.address;
return data;
}
}
......@@ -15,6 +15,7 @@ class DashboardProvider with ChangeNotifier {
/// Fetch Dashboard API
Future<void> fetchDashboard({
required String accId,
required String sessionId,
}) async {
_isLoading = true;
_errorMessage = null;
......@@ -22,7 +23,7 @@ class DashboardProvider with ChangeNotifier {
try {
final response =
await ApiCalling.fetchDashboardApi(accId,);
await ApiCalling.fetchDashboardApi(accId, sessionId);
if (response != null) {
_dashboardData = response;
......
import 'package:flutter/material.dart';
import 'package:gen_rentals/Services/api_calling.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'dart:io';
class RentalProvider extends ChangeNotifier {
FetchMobileResponse? _response;
FetchMobileResponse? otpResponse;
bool _isLoading = false;
FetchMobileResponse? get response => _response;
bool get isLoading => _isLoading;
bool isOtpLoading = false;
......@@ -33,7 +36,8 @@ class RentalProvider extends ChangeNotifier {
notifyListeners();
try {
final result = await ApiCalling.fetchMobileOtpApi(mob, otp);
final deviceDetails = await getDeviceDetails();
final result = await ApiCalling.fetchMobileOtpApi(mob, otp, deviceDetails);
otpResponse = result;
} catch (e) {
debugPrint("❌ OTP API Error: $e");
......@@ -44,6 +48,41 @@ class RentalProvider extends ChangeNotifier {
}
}
Future<Map<String, String>> getDeviceDetails() async {
final deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) {
final androidInfo = await deviceInfo.androidInfo;
return {
"versionName": androidInfo.version.release ?? "",
"versionCode": androidInfo.version.codename ?? "",
"osVersion": androidInfo.version.release ?? "",
"sdkVersion": androidInfo.version.sdkInt.toString(),
"device": androidInfo.device ?? "",
"model": androidInfo.model ?? "",
"product": androidInfo.product ?? "",
"manufacturer": androidInfo.manufacturer ?? "",
"brand": androidInfo.brand ?? "",
"user": "",
"display": androidInfo.display ?? "",
"hardware": androidInfo.hardware ?? "",
"board": androidInfo.board ?? "",
"host": androidInfo.host ?? "",
"serial": androidInfo.serialNumber ?? "unknown",
"id": androidInfo.id ?? "",
"bootloader": androidInfo.bootloader ?? "",
"cpuAbi1": androidInfo.supportedAbis.isNotEmpty ? androidInfo.supportedAbis[0] : "",
"cpuAbi2": androidInfo.supportedAbis.length > 1 ? androidInfo.supportedAbis[1] : "",
"fingerprint": androidInfo.fingerprint ?? "",
};
}
return {};
}
}
......@@ -52,6 +91,7 @@ class FetchMobileResponse {
String? errorMsg;
String? accId;
String? message;
String? sessionId;
FetchMobileResponse({this.error, this.errorMsg});
......@@ -60,6 +100,7 @@ class FetchMobileResponse {
errorMsg = json['error_msg'];
accId = json['acc_id'];
message = json['message'];
sessionId = json['session_id'];
}
Map<String, dynamic> toJson() {
......@@ -68,7 +109,9 @@ class FetchMobileResponse {
data['error_msg'] = this.errorMsg;
data['acc_id'] = this.accId;
data['message'] = this.message;
data['session_id'] = this.sessionId;
return data;
}
}
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gen_rentals/Services/api_calling.dart';
import 'dart:convert';
import '../Models/SubscribeOrderDetailsResponse.dart';
class SubscribeOrderDetailsProvider with ChangeNotifier {
SubscribeOrderDetailsResponse? _orderDetails;
bool _isLoading = false;
String _errorMessage = '';
// Getters
SubscribeOrderDetailsResponse? get orderDetails => _orderDetails;
bool get isLoading => _isLoading;
String get errorMessage => _errorMessage;
/// Fetch Subscribe Order Details
Future<void> fetchSubscribeOrderDetails(
String sessionId,
String orderId,
String accId,
) async {
_isLoading = true;
_errorMessage = '';
notifyListeners();
try {
final response = await ApiCalling.fetchSubsOrderDetailApi(
sessionId,
orderId,
accId,
);
if (response != null) {
// Check if error is "0" which means success in your API
if (response.error == "0") {
_orderDetails = response;
_errorMessage = '';
}
// Handle other error cases
else if (response.error != null && response.error!.isNotEmpty && response.error != "0") {
_errorMessage = response.message ?? 'An error occurred';
_orderDetails = null;
}
// Handle message-based errors
else if (response.message != null &&
response.message!.isNotEmpty &&
!response.message!.toLowerCase().contains('success')) {
_errorMessage = response.message!;
_orderDetails = null;
}
// Default success case
else {
_orderDetails = response;
_errorMessage = '';
}
} else {
_errorMessage = 'Failed to load order details';
_orderDetails = null;
}
} catch (e) {
_errorMessage = 'An error occurred: $e';
_orderDetails = null;
debugPrint("❌ Provider Error (fetchSubscribeOrderDetails): $e");
} finally {
_isLoading = false;
notifyListeners();
}
}
// ... rest of your provider code
}
\ No newline at end of file
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:gen_rentals/Services/api_calling.dart';
import '../Models/TransactionsResponse.dart';
class TransactionsProvider with ChangeNotifier {
bool _isLoading = false;
TransactionsResponse? _transactionsResponse;
bool get isLoading => _isLoading;
TransactionsResponse? get transactionsResponse => _transactionsResponse;
/// For UI convenience
Map<String, List<TransactionItem>> get transactionsByMonth =>
_transactionsResponse?.transactions ?? {};
/// Fetch Rental Transactions API
Future<void> fetchRentalTransactions(String sessionId, String accId) async {
_isLoading = true;
notifyListeners();
try {
final response =
await ApiCalling.fetchRentalsTransactionsApi(sessionId, accId);
if (response != null && response.error == "0") {
_transactionsResponse = response;
log("✅ Transactions fetched successfully: ${response.transactions?.length ?? 0} months");
} else {
log("⚠️ Error in API response: ${response?.message}");
_transactionsResponse = null;
}
} catch (e) {
log("❌ Exception in fetchRentalTransactions: $e");
_transactionsResponse = null;
} finally {
_isLoading = false;
notifyListeners();
}
}
/// Optional: Clear data
void clearTransactions() {
_transactionsResponse = null;
notifyListeners();
}
}
......@@ -11,7 +11,8 @@ import 'authScreen/LoginScreen.dart';
class DashboardScreen extends StatefulWidget {
final String accId;
const DashboardScreen({super.key, required this.accId});
final String sessionId;
const DashboardScreen({super.key, required this.accId, required this.sessionId});
@override
State<DashboardScreen> createState() => _DashboardScreenState();
......@@ -25,7 +26,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
WidgetsBinding.instance.addPostFrameCallback((_) {
// Only fetch dashboard if accId is valid
if (widget.accId.isNotEmpty && widget.accId != "null") {
Provider.of<DashboardProvider>(context, listen: false).fetchDashboard(accId: widget.accId);
Provider.of<DashboardProvider>(context, listen: false).fetchDashboard(accId: widget.accId, sessionId: widget.sessionId);
} else {
// If accId is invalid, navigate back to login
WidgetsBinding.instance.addPostFrameCallback((_) {
......@@ -182,9 +183,11 @@ class _DashboardScreenState extends State<DashboardScreen> {
// Main content section
Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
// Balance Amount Card
Container(
width: double.infinity,
......@@ -222,7 +225,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
children: [
// Use provider data for balance amount - FIXED NULL CHECK
Text(
dashboardData?.balanceAmount ?? "0",
dashboardData?.balanceAmount.toString() ?? "0",
style: const TextStyle(
fontFamily: "Poppins",
color: Colors.black,
......@@ -260,6 +263,70 @@ class _DashboardScreenState extends State<DashboardScreen> {
const SizedBox(height: 20),
const SizedBox(height: 20),
// Subscribed Orders
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Section Title
Text(
"Subscribed Orders",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey.shade800,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
// Show loading or products list
if (dashboardProvider.isLoading && dashboardData == null)
const Center(
child: CircularProgressIndicator(),
)
else if (dashboardData?.orders == null || dashboardData!.orders!.isEmpty)
const Text(
"No products subscribed",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey,
fontSize: 14,
),
)
else
// List of subscribed products from API
Column(
children: dashboardData!.orders!.map((product) {
return Column(
children: [
InkResponse(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductsDetailScreen(
sessionId: widget.sessionId,
accId: widget.accId,
orderId: product.orderid.toString(),
)),
);
},
child: _buildProductItemFromApi(product),
),
const SizedBox(height: 16),
],
);
}).toList(),
),
],
),
),
// Feature cards grid
Container(
width: double.infinity,
......@@ -279,7 +346,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
......@@ -305,7 +372,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 8),
const SizedBox(height: 6),
Text(
"Submit your enquiry for requirement",
style: TextStyle(
......@@ -417,7 +484,10 @@ class _DashboardScreenState extends State<DashboardScreen> {
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => TransactionsScreen()),
MaterialPageRoute(builder: (context) => TransactionsScreen(
sessionId: widget.sessionId,
accId: widget.accId,
)),
);
},
child: Container(
......@@ -487,64 +557,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
],
),
),
const SizedBox(height: 20),
// Subscribed Products
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Section Title
Text(
"Subscribed Products",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey.shade800,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
// Show loading or products list
if (dashboardProvider.isLoading && dashboardData == null)
const Center(
child: CircularProgressIndicator(),
)
else if (dashboardData?.products == null || dashboardData!.products!.isEmpty)
const Text(
"No products subscribed",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey,
fontSize: 14,
),
)
else
// List of subscribed products from API
Column(
children: dashboardData!.products!.map((product) {
return Column(
children: [
InkResponse(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductsDetailScreen()),
);
},
child: _buildProductItemFromApi(product),
),
const SizedBox(height: 16),
],
);
}).toList(),
),
],
),
)
SizedBox(height: 10,),
],
),
),
......@@ -561,224 +574,267 @@ class _DashboardScreenState extends State<DashboardScreen> {
}
// Helper widget for product item from API data
Widget _buildProductItemFromApi(Products product) {
return Stack(
children: [
// Background strip for pending payment
if (product.hasPendingPayment == true)
Container(
height: 130 + 50,
padding: EdgeInsets.zero,
Widget _buildProductItemFromApi(Orders product) {
final bool hasPending = product.hasPendingPayment == true;
final productList = product.products ?? [];
return Container(
margin: const EdgeInsets.symmetric(vertical: 6),
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.6),
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: Colors.grey.shade200,
width: 1,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.15),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
child: Column(
child: Stack(
children: [
SizedBox(height: 144),
// Pending payment strip
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
decoration: BoxDecoration(
color: Colors.white38,
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
// ===== Red Strip (Behind Card) =====
if (hasPending)
Positioned.fill(
top: null,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 45,
decoration: const BoxDecoration(
color: Color(0xFFFFE2E0),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
),
),
child: Row(
children: [
Icon(
Icons.info_outline,
color: Colors.red,
size: 18,
),
const SizedBox(width: 12),
const Icon(Icons.info_outline, color: Colors.red, size: 18),
const SizedBox(width: 6),
Expanded(
child: Text(
product.pendingPaymentText ?? "Payment Pending",
style: TextStyle(
product.pendingPaymentText ??
"Payment Pending. Please Pay before incurring fines.",
style: const TextStyle(
fontFamily: "Poppins",
color: Colors.black87,
color: Colors.red,
fontSize: 12,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
),
),
),
const SizedBox(width: 12),
],
),
),
],
),
),
// Main content card
// ===== Main White Card =====
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey.shade200,
width: 1,
),
borderRadius: BorderRadius.circular(15),
),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Main content
/// Header Row (image, order id, date, badge)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 6,
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
Row(
children: [
// Expiring badge
if (product.expiringText != null && product.expiringText!.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
gradient: _getGradientByColor(product.expiringInColor),
),
child: Text(
product.expiringText!,
style: const TextStyle(
color: Colors.black87,
fontSize: 12,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
color: const Color(0xffF2F2F2),
borderRadius: BorderRadius.circular(16),
),
child: Image.network(
product.productImage ?? "",
height: 40,
width: 40,
fit: BoxFit.contain,
errorBuilder: (context, error, stack) =>
Image.asset('assets/images/gene_png.png',
height: 40, width: 40),
),
),
const SizedBox(height: 8),
// Product name and plan
const SizedBox(width: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.productName ?? "Unknown Product",
"#${product.orderid ?? "0"}",
style: const TextStyle(
color: Colors.black,
fontFamily: "Poppins",
color: Color(0xFF008CDE),
fontSize: 16,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
fontWeight: FontWeight.w500,
height: 1.2,
),
),
const SizedBox(height: 4),
Text(
"Plan",
product.rentedDate ?? "Rented date not available",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey.shade600,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 12,
height: 1,
),
),
Text(
"₹${product.plan ?? "0"}",
],
),
],
),
// ✅ Gradient expiry badge
if (product.expiringText != null &&
product.expiringText!.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 6),
decoration: BoxDecoration(
gradient: _getGradientByColor(product.expiringInColor),
borderRadius: BorderRadius.circular(8),
),
child: Text(
product.expiringText!,
style: const TextStyle(
fontFamily: "Poppins",
color: Color(0xFF008CDE),
fontSize: 18,
fontStyle: FontStyle.normal,
color: Colors.black87,
fontSize: 12,
fontWeight: FontWeight.w500,
height: 1.2
),
),
const SizedBox(height: 3),
),
],
),
// Rented date
Text(
product.rentedDate ?? "Rented date not available",
style: TextStyle(
fontFamily: "Poppins",
color: Colors.grey.shade500,
fontStyle: FontStyle.normal,
const SizedBox(height: 6),
const Divider(),
/// ===== Product List (with +3 More on same line) =====
Builder(
builder: (context) {
final visibleItems = productList.take(2).toList();
final remaining = productList.length - visibleItems.length;
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Left side → Product list (bulleted)
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < visibleItems.length; i++)
Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(width: 8),
const Text(
"• ",
style: TextStyle(color: Colors.black, fontSize: 16),
),
Expanded(
child: Text(
visibleItems[i],
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w400,
fontSize: 12,
),
),
),
],
),
),
],
),
),
Expanded(
flex: 3,
child: Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: const Color(0xffF2F2F2),
borderRadius: BorderRadius.circular(16),
// Right side → +x More (vertically centered)
if (remaining > 0)
Padding(
padding: const EdgeInsets.only(left: 8, right: 4),
child: Align(
alignment: Alignment.center,
child: Text(
"+$remaining More",
style: const TextStyle(
fontFamily: "Poppins",
color: Color(0xFF008CDE),
fontSize: 14,
fontWeight: FontWeight.w500,
),
child: product.productImage != null && product.productImage!.isNotEmpty
? Image.network(
product.productImage!,
height: 80,
width: 80,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
'assets/images/gene_png.png',
height: 80,
width: 80,
fit: BoxFit.contain,
);
},
)
: Image.asset(
'assets/images/gene_png.png',
height: 80,
width: 80,
fit: BoxFit.contain,
),
),
),
],
);
},
),
],
),
),
],
),
);
}
// Helper method to get gradient based on color from API
// Gradient helper
LinearGradient _getGradientByColor(String? color) {
switch (color) {
case "red":
case "Red":
return const LinearGradient(
colors: [Color(0xFFFFE0E0), Color(0xFFFFC0C0)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFFFDDDD),
Color(0xFFFFB5B5),
],
);
case "green":
case "Green":
default:
return const LinearGradient(
colors: [Color(0xFFE9FFDD), Color(0xFFB5FFD1)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFE9FFDD),
Color(0xFFB5FFD1),
],
);
}
}
// Helper method to get gradient based on color from API
// LinearGradient _getGradientByColor(String? color) {
// switch (color) {
// case "red":
// return const LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: [
// Color(0xFFFFDDDD),
// Color(0xFFFFB5B5),
// ],
// );
// case "green":
// default:
// return const LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: [
// Color(0xFFE9FFDD),
// Color(0xFFB5FFD1),
// ],
// );
// }
// }
void showPaymentBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
......
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 'package:provider/provider.dart';
import '../Models/SubscribeOrderDetailsResponse.dart';
import '../Notifier/SubscribeOrderDetailsProvider.dart';
import '../Utility/AppColors.dart';
import 'HelpScreens/CreateTicketScreen.dart';
class ProductsDetailScreen extends StatelessWidget {
const ProductsDetailScreen({super.key});
class ProductsDetailScreen extends StatefulWidget {
final String sessionId;
final String orderId;
final String accId;
const ProductsDetailScreen({
super.key,
required this.sessionId,
required this.orderId,
required this.accId,
});
@override
State<ProductsDetailScreen> createState() => _ProductsDetailScreenState();
}
class _ProductsDetailScreenState extends State<ProductsDetailScreen> {
final List<Map<String, dynamic>> createNewTickets = [
{
'title': 'Payment Issues',
'description': 'Get help with payment related problems',
'icon': "assets/svg/rupee_coin_ic.svg",
'color': Color(0xFFFFEFBE),
},
{
'title': 'Bill Related Issues',
'description': 'Resolve bill and invoice matters',
'icon': "assets/svg/know_pay.svg",
'color': Color(0xFFCEF9FF),
},
{
'title': 'Other Issues',
'description': 'Any other support you need',
'icon': "assets/svg/help_ic.svg",
'color': Color(0xFFE4E5FF),
},
];
@override
void initState() {
super.initState();
// Fetch order details when screen loads
WidgetsBinding.instance.addPostFrameCallback((_) {
_loadOrderDetails();
});
}
void _loadOrderDetails() {
final provider = Provider.of<SubscribeOrderDetailsProvider>(context, listen: false);
provider.fetchSubscribeOrderDetails(
widget.sessionId,
widget.orderId,
widget.accId,
);
}
@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 Consumer<SubscribeOrderDetailsProvider>(
builder: (context, provider, child) {
return SafeArea(
top: false,
child: Scaffold(
body: Container(
color: const Color(0xFFF3F3F3),
height: screenHeight,
child: SingleChildScrollView(
child: Column(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
title: Row(
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),
],
InkResponse(
onTap: () => Navigator.pop(context, true),
child: SvgPicture.asset(
"assets/svg/continue_left_ic.svg",
height: 25,
),
),
child: Image.asset(
'assets/images/sky_blue_bg.jpg',
width: double.infinity,
height: 400,
fit: BoxFit.cover,
const SizedBox(width: 10),
const Text(
"Bill List",
style: TextStyle(
fontSize: 16,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
// 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),
],
),
),
body: _buildBody(provider, screenHeight, bottomPadding),
),
);
},
);
}
Widget _buildBody(SubscribeOrderDetailsProvider provider, double screenHeight, double bottomPadding) {
if (provider.isLoading) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (provider.errorMessage.isNotEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
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,
),
Text(
provider.errorMessage,
style: const TextStyle(
fontSize: 16,
fontFamily: "Poppins",
color: Colors.red,
),
child: const Icon(
Icons.person,
color: Colors.white,
size: 30,
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _loadOrderDetails,
child: const Text('Retry'),
),
],
),
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),
],
),
),
if (provider.orderDetails == null) {
return const Center(
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",
'No order details found',
style: TextStyle(
fontSize: 16,
fontFamily: "Poppins",
color: Colors.grey,
fontSize: 16,
fontWeight: FontWeight.w400,
),
),
],
),
],
),
),
);
}
const SizedBox(height: 10),
final order = provider.orderDetails!;
// Main content section
Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
return Container(
color: const Color(0xFFF3F3F3),
height: screenHeight,
child: SingleChildScrollView(
child: Column(
children: [
// Balance Amount Card
// Order header (not in card)
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkResponse(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BillDetailListScreen()),
);
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
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,
mainAxisAlignment: MainAxisAlignment.center,
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",
"# Order ID ",
style: TextStyle(
fontSize: 24,
fontFamily: "Poppins",
color: AppColors.subtitleText,
fontSize: 12,
fontWeight: FontWeight.w400,
// fontStyle: FontStyle.italic,
),
color: Colors.black87,
),
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",
"#${order.orderNum ?? order.orderid ?? 'N/A'}",
style: TextStyle(
fontSize: 24,
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,
color: AppColors.amountText,
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Deposit",
style: TextStyle(
fontFamily: "Poppins",
color: AppColors.subtitleText,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 12,
),
),
const SizedBox(height: 8),
Text(
"₹5483",
order.rentedDate ?? 'Date not available',
style: const TextStyle(
fontSize: 14,
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,
color: Colors.grey,
),
),
Text(
"6 Months",
const SizedBox(height: 14),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: _getExpiringColor(order.expiringInColor),
borderRadius: BorderRadius.circular(16),
),
child: Text(
order.expiringText ?? 'Expiring info not available',
style: const TextStyle(
fontSize: 12,
fontFamily: "Poppins",
color: AppColors.cardAmountText,
fontSize: 18,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
),
],
)
],
)
],
),
),
const SizedBox(height: 18),
// Products section
if (order.products != null && order.products!.isNotEmpty)
Container(
width: double.infinity,
color: Colors.transparent,
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: const EdgeInsets.all(16),
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.",
const Text(
"Products",
style: TextStyle(
fontSize: 18,
fontFamily: "Poppins",
color: AppColors.subtitleText,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.normal,
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 16),
],
)
// Product list using ListView.builder
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: order.products!.length,
separatorBuilder: (context, index) => const SizedBox(height: 16),
itemBuilder: (context, index) {
return _buildProductItem(order.products![index]);
},
),
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(height: 16),
// Divider
const Divider(
color: Color(0xFFE5E5E5),
thickness: 1,
),
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),
// Help section
InkResponse(
onTap: () => _showReasonBottomSheet(),
child: Row(
children: [
Text(
"Need help with this order?",
style: TextStyle(
fontSize: 14,
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
color: Colors.grey,
),
),
],
),
),
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,
),
// View Bill button
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BillDetailListScreen())
);
// Handle view bill action
FocusScope.of(context).unfocus();
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.buttonColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
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,
elevation: 0,
),
child: const Text(
"View Bill",
style: TextStyle(
fontSize: 16,
fontFamily: "Plus Jakarta Sans",
fontWeight: FontWeight.w600,
),
],
),
const SizedBox(height: 20),
],
),
),
],
),
)
else
const Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'No products found',
style: TextStyle(
fontSize: 16,
fontFamily: "Poppins",
color: Colors.grey,
),
],
),
],
),
SizedBox(height: bottomPadding + 20),
],
),
),
),
),
);
}
Widget _buildFeatureCard({
required String title,
required String description,
required String icon,
required Color color,
}) {
Widget _buildProductItem(Products product) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
padding: const EdgeInsets.all(16),
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),
color: Colors.white,
borderRadius: BorderRadius.circular(18),
// border: Border.all(
// color: const Color(0xFFE5E5E5),
// width: 1,
// ),
// ],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
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),
// Product ID and Name
Text(
title,
style: TextStyle(
color: AppColors.nearDarkText,
product.idName ?? product.id ?? 'N/A',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
color: Colors.grey,
),
),
const SizedBox(height: 4),
// Description
Text(
description,
style: TextStyle(
color: AppColors.subtitleText,
product.prodName ?? 'Product name not available',
style: const TextStyle(
fontSize: 16,
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),
),
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 20),
const SizedBox(height: 12),
// Pay Amount Section
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
// Table-like layout for dates and price
Table(
columnWidths: const {
0: FlexColumnWidth(2),
1: FlexColumnWidth(1),
},
children: [
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
TableRow(
children: [
Text(
"Pay",
style: TextStyle(
fontSize: 16,
TableCell(
child: Text(
product.dispatchDate != null ?
"Dispatched On ${product.dispatchDate!}" :
"Dispatch date not available",
style: const TextStyle(
fontSize: 12,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
color: Color(0xFF777777),
color: Colors.grey,
),
),
SizedBox(height: 4),
Text(
"₹4218",
),
const TableCell(
child: Align(
alignment: Alignment.centerRight,
child: Text(
"Plan",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
color: Colors.black,
fontSize: 12,
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
),
),
],
),
// Rent Amount Section
Column(
crossAxisAlignment: CrossAxisAlignment.end,
TableRow(
children: [
const Text(
"Rent Amount",
style: TextStyle(
fontSize: 14,
TableCell(
child: Text(
product.receivedDate != null ?
"Received On ${product.receivedDate!}" :
"Receive date not available",
style: const TextStyle(
fontSize: 12,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
color: Color(0xFF777777),
color: Colors.grey,
),
),
const SizedBox(height: 4),
GestureDetector(
onTap: () {
// Handle view bill details
},
),
TableCell(
child: Align(
alignment: Alignment.centerRight,
child: Text(
"View Bill Details",
style: TextStyle(
product.totalPrice != null ?
"${product.totalPrice!}/${product.per ?? 'mo'}" :
'Price not available',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xFF008CDE),
fontFamily: "Poppins",
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
),
),
......@@ -603,58 +440,141 @@ class ProductsDetailScreen extends StatelessWidget {
),
],
),
],
),
);
}
const SizedBox(height: 10),
const Divider(height: 1, color: Color(0xFFEEEEEE)),
const SizedBox(height: 18),
Color _getExpiringColor(String? colorString) {
if (colorString == null || colorString.isEmpty) {
return const Color(0xFFFFEBEB); // Default color
}
// 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),
try {
// Assuming colorString is in format like "FFFF5757"
return Color(int.parse('FF$colorString', radix: 16));
} catch (e) {
return const Color(0xFFFFEFEF); // Default color on error
}
}
void _showReasonBottomSheet() {
// Your existing bottom sheet implementation
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 22),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
builder: (context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 14),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Continue Payment",
"Select Your Reason",
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 16,
fontSize: 18,
fontFamily: "Poppins",
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
SvgPicture.asset(
"assets/svg/continue_ic.svg",
color: Color(0xFFFFFFFF),
height: 25,
width: 25,
const SizedBox(height: 24),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.99,
),
itemCount: createNewTickets.length,
itemBuilder: (context, index) {
final ticket = createNewTickets[index];
final String title = ticket['title'] ?? 'Unknown';
final String description = ticket['description'] ?? '';
final String icon = ticket['icon'] ?? 'assets/svg/help_ic.svg';
final Color color = ticket['color'] ?? Colors.grey;
return _buildFeatureCard(
title: title,
description: description,
icon: icon,
color: color,
);
},
),
const SizedBox(height: 24),
],
),
);
},
);
}
Widget _buildFeatureCard({
required String title,
required String description,
required String icon,
required Color color,
}) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HelpTicketScreen(reason: title,))
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 1),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Icon container
Container(
width: 88,
height: 88,
decoration: BoxDecoration(
color: color.withOpacity(0.7),
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: SizedBox(
height: 40,
width: 40,
child: SvgPicture.asset(
icon,
fit: BoxFit.fitWidth,
),
),
),
],
),
const SizedBox(height: 8),
// Title
SizedBox(
child: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.nearDarkText,
fontSize: 14,
fontWeight: FontWeight.w400,
fontFamily: "Plus Jakarta Sans",
),
),
),
);
},
const SizedBox(height: 4),
],
),
),
);
}
}
\ No newline at end of file
......@@ -104,13 +104,14 @@ class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderSt
Future<void> _navigateToDashboard() async {
final String? savedAccId = await prefs.getString("accId");
final String? savedSessionId = await prefs.getString("session_id");
// Check if accId is not null and not empty
if (savedAccId != null && savedAccId.isNotEmpty) {
Navigator.pushReplacement(
context,
PageRouteBuilder(
pageBuilder: (_, __, ___) => DashboardScreen(accId: savedAccId),
pageBuilder: (_, __, ___) => DashboardScreen(accId: savedAccId, sessionId: savedSessionId.toString(),),
transitionsBuilder: (_, animation, __, child) {
return FadeTransition(
opacity: animation,
......
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import '../Notifier/TransactionsProvider.dart';
import '../Utility/AppColors.dart';
class TransactionsScreen extends StatefulWidget {
const TransactionsScreen({super.key});
final String sessionId;
final String accId;
const TransactionsScreen({
super.key,
required this.sessionId,
required this.accId,
});
@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
void initState() {
super.initState();
Future.microtask(() {
Provider.of<TransactionsProvider>(context, listen: false)
.fetchRentalTransactions(widget.sessionId, widget.accId);
});
}
@override
Widget build(BuildContext context) {
final provider = Provider.of<TransactionsProvider>(context);
final data = provider.transactionsResponse;
return SafeArea(
top: false,
child: Scaffold(
......@@ -72,11 +46,11 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
onTap: () => Navigator.pop(context, true),
child: SvgPicture.asset(
"assets/svg/continue_left_ic.svg",
height: 25
height: 25,
),
),
const SizedBox(width: 10),
Text(
const Text(
"Transactions",
style: TextStyle(
fontSize: 16,
......@@ -88,208 +62,341 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
],
),
),
// Main content
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
/// ✅ Main Content
body: provider.isLoading
? const Center(child: CircularProgressIndicator())
: data == null
? const Center(child: Text("No transactions available"))
: SingleChildScrollView(
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildBalanceCard(data),
const SizedBox(height: 16),
/// 🗓️ Monthly Grouped Transactions
...data.transactions!.entries.map((entry) {
final month = entry.key;
final items = entry.value;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 12),
Text(
month,
style: const TextStyle(
fontSize: 15,
fontFamily: "Poppins",
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
const SizedBox(height: 8),
...items.map((txn) => _buildTransactionItem(
type: txn.type ?? "",
title: txn.purpose ?? "-",
date: txn.date ?? "",
amount: "₹${txn.amount ?? "0.00"}",
)),
],
);
}),
],
),
),
),
);
}
/// 💰 Balance Card (Top Section)
Widget _buildBalanceCard(data) {
final balance = data.balanceAmount ?? "0";
final credit = data.creditAmount ?? "0";
final debit = data.debitAmount ?? "0";
return Stack(
children: [
SizedBox(height: 4,),
// Balance Card
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 18),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: const LinearGradient(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFE9FFEF),
Color(0xFFD6FFDF),
Color(0xFFF3F3F3),
Color(0xFFB5FFD1),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.03),
blurRadius: 8,
offset: const Offset(0, 2),
)
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"₹12,596",
/// Header
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Balance Amount",
style: TextStyle(
fontFamily: "Poppins",
fontSize: 13,
fontWeight: FontWeight.w500,
fontSize: 34,
color: AppColors.cardAmountText,
color: Colors.redAccent,
),
),
const SizedBox(height: 4),
Text(
"Balance Amount",
TextButton(
onPressed: () {},
child: const Text(
"Pay Now",
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 14,
color: AppColors.cardAmountText,
fontWeight: FontWeight.w500,
color: Color(0xFF007AFF),
),
),
const SizedBox(height: 10),
Container(
height: 1,
color: const Color(0xFF777777).withOpacity(0.3),
),
],
),
Text(
"₹$balance",
style: const TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w600,
fontSize: 30,
color: Colors.black,
),
),
const SizedBox(height: 4),
const Text(
"*Make sure to pay before you incur any fines.",
style: TextStyle(
fontFamily: "Poppins",
fontSize: 12,
color: Colors.grey,
),
),
const SizedBox(height: 14),
// Credited / Debited info
/// Credit / Debit Row
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",
// ✅ Bill Paid
Row(
children: [
Container(
height: 46,
width: 46,
decoration: BoxDecoration(
color: Colors.white,
amount: "₹26,300",
label: "Debited Amount",
borderRadius: BorderRadius.circular(22),
),
],
child: Center(
child: SvgPicture.asset(
"assets/svg/cross_down_arrow.svg",
height: 18,
width: 18,
fit: BoxFit.contain, // Ensures the SVG scales within bounds
),
],
),
),
const SizedBox(height: 16),
// Transaction list
const SizedBox(width: 10),
Column(
children: transactions.map((t) {
return _buildTransactionItem(
type: t["type"],
title: t["title"],
date: t["date"],
amount: t["amount"],
ref: t["ref"],
);
}).toList(),
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"₹$credit",
style: const TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
fontSize: 13,
color: Colors.black,
),
],
),
Text(
"Bill Paid",
style: TextStyle(
fontFamily: "Poppins",
fontSize: 11,
color: Colors.black54,
),
),
);
}
],
),
],
),
Widget _buildAmountSummary({
required String icon,
required Color color,
required String amount,
required String label,
}) {
return Row(
const SizedBox(width: 10),
// ❌ Bill Pending
Row(
children: [
// Icon and title row
Container(
width: 50,
height: 50,
height: 46,
width: 46,
decoration: BoxDecoration(
color: color.withOpacity(0.9),
borderRadius: BorderRadius.circular(30),
color: Colors.white,
borderRadius: BorderRadius.circular(22),
),
child: Center( // Add this Center widget
child: Center(
child: SvgPicture.asset(
icon,
height: 20,
width: 20,
// Remove fit: BoxFit.none
"assets/svg/cross_up_arrow.svg",
height: 18,
width: 18,
fit: BoxFit.contain, // Ensures the SVG scales within bounds
),
),
),
const SizedBox(width: 8),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
amount,
"₹$debit",
style: const TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w500,
fontSize: 13,
color: Colors.black,
),
),
Text(
"Bill Pending",
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 11,
color: Colors.black54,
),
)
],
),
],
),
],
),
],
),
),
/// White overlay card (unchanged)
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Text(
"Balance Amount",
style: TextStyle(
fontFamily: "Poppins",
color: Color(0xFFF00000),
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
const SizedBox(width: 4),
SvgPicture.asset(
"assets/svg/continue_ic.svg",
color: const Color(0xFFF00000),
height: 18,
width: 18,
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"₹$balance",
style: const TextStyle(
fontFamily: "Poppins",
color: Colors.black,
fontSize: 32,
fontWeight: FontWeight.w500,
),
),
InkResponse(
child: const Text(
"Pay Now",
style: TextStyle(
fontFamily: "Poppins",
color: Color(0xFF008CDE),
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
],
),
const SizedBox(height: 12),
Text(
label,
"*Make sure to pay before you incur any fines.",
style: TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
color: Colors.grey.shade500,
fontSize: 12,
color: Colors.grey.shade600,
fontWeight: FontWeight.w400,
),
),
],
),
),
],
);
}
/// 📋 Transaction Item
Widget _buildTransactionItem({
required String type,
required String title,
required String date,
required String amount,
required String ref,
}) {
final isCredit = type == "credit";
final isCredit = type.toLowerCase() == "credit";
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 14),
margin: const EdgeInsets.only(bottom: 10),
padding: const EdgeInsets.symmetric(vertical: 12, 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
CircleAvatar(
radius: 18,
backgroundColor:
isCredit ? Colors.green.shade50 : Colors.red.shade50,
child: SvgPicture.asset(
isCredit ? "assets/svg/cross_down_arrow.svg" : "assets/svg/cross_up_arrow.svg",
height: 20,
width: 20,
// Remove fit: BoxFit.none
),
isCredit
? "assets/svg/cross_down_arrow.svg"
: "assets/svg/cross_up_arrow.svg",
height: 18,
),
),
// 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(
......@@ -300,7 +407,6 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 14,
color: Colors.black,
),
......@@ -308,52 +414,24 @@ class _TransactionsScreenState extends State<TransactionsScreen> {
const SizedBox(height: 4),
Text(
date,
style: TextStyle(
style: const TextStyle(
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
fontSize: 12,
color: Colors.grey.shade600,
color: Colors.grey,
),
),
],
),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
amount,
style: TextStyle(
style: const 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
),
],
),
],
),
],
),
);
......
......@@ -91,12 +91,16 @@ class _OtpScreenState extends State<OtpScreen> {
// Added null check for accId
if (rentalProvider.otpResponse?.accId != null) {
await prefs.saveString("accId", rentalProvider.otpResponse!.accId!);
await prefs.saveString("session_id", rentalProvider.otpResponse!.sessionId!);
}
// Navigate to dashboard
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => DashboardScreen(accId: rentalProvider.otpResponse!.accId!,)),
MaterialPageRoute(builder: (_) => DashboardScreen(
accId: rentalProvider.otpResponse!.accId!,
sessionId: rentalProvider.otpResponse!.sessionId!,)
),
);
} else {
// ❌ Invalid OTP
......
/// base Url of api
const baseUrl = "https://erp.gengroup.in/ci/app/Inventory/";
const baseUrl = "https://erp.gengroup.in/ci/app/Rental/Rental_Home/";
const baseUrl2 = "https://erp.gengroup.in/ci/app/Rental/";
/// tokens url
const addFcmTokenUrl = "${baseUrl}add_fcm_token";
/// payments and bills
const addPaymentUrl = "${baseUrl}add_payment";
const rentalPaymentDetailsUrl = "${baseUrl}rental_payment_details";
const transactionsUrl = "${baseUrl}transactions";
const balanceUrl = "${baseUrl}balance";
const billDetailsUrl = "${baseUrl}bill_details";
const billListUrl = "${baseUrl}bill_list";
......@@ -21,7 +22,7 @@ const getRentalAccInfoUrl = "${baseUrl}get_rental_acc_info";
const orderDetailsBillUrl = "${baseUrl}order_details_bill";
const orderDetailsMainUrl = "${baseUrl}order_details_main";
const orderDetailsProductUrl = "${baseUrl}order_details_product";
const orderListUrl = "${baseUrl}order_list";
const subsOrderDetails = "${baseUrl}subs_order_details";
const tagOrderUrl = "${baseUrl}tag_order";
/// tickets
......@@ -33,6 +34,6 @@ const ticketListUrl = "${baseUrl}ticket_list";
/// dashboard and login
const fetchMobileUrl = "${baseUrl}fetch_mobile_number";
const fetchOtpUrl = "${baseUrl}login";
const dashboardUrl = "${baseUrl}dashboard";
\ No newline at end of file
const fetchMobileUrl = "${baseUrl2}Rental_Auth/fetch_mobile_number";
const fetchOtpUrl = "${baseUrl2}Rental_Auth/login";
const dashboardUrl = "${baseUrl2}Rental_Home/dashboard";
\ No newline at end of file
......@@ -7,11 +7,12 @@ import 'package:gen_rentals/Models/billProductResponse.dart';
import 'package:gen_rentals/Models/orderDetailsBillResponse.dart';
import 'package:gen_rentals/Models/orderDetailsMainResponse.dart';
import 'package:gen_rentals/Models/orderDetailsProductResponse.dart';
import 'package:gen_rentals/Models/orderListResponse.dart';
import 'package:gen_rentals/Models/SubscribeOrderDetailsResponse.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/TransactionsResponse.dart';
import '../Models/rentalAccountResponse.dart';
import '../Models/rentalContactResponse.dart';
import '../Notifier/RentalContactProvider .dart';
......@@ -47,13 +48,15 @@ class ApiCalling {
static Future<FetchMobileResponse?> fetchMobileOtpApi(
String mob,
String otp
String otp,
Map<String, String> deviceDetails
) async {
debugPrint("############################### Api calling ");
try {
Map<String, String> data = {
"mob": mob,
"otp": otp,
"device_details": deviceDetails.toString(),
};
final res = await post(data, fetchOtpUrl, {});
......@@ -204,23 +207,24 @@ class ApiCalling {
}
}
/// Fetch Order List
static Future<OrderListResponse?> fetchOrderListApi(
/// Fetch Subscribe Order Details
static Future<SubscribeOrderDetailsResponse?> fetchSubsOrderDetailApi(
String sessionId,
String empId,
String orderId,
String accId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"order_id": orderId,
"acc_id": accId,
};
final res = await post(data, orderListUrl, {});
final res = await post(data, subsOrderDetails, {});
debugPrint("Subscribe order details Response: ${res?.body}");
if (res != null) {
return OrderListResponse.fromJson(jsonDecode(res.body));
return SubscribeOrderDetailsResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
......@@ -286,23 +290,21 @@ class ApiCalling {
}
}
/// Fetch Rental Payment Details
static Future<RentalPaymentDetailsResponse?> fetchRentalPaymentDetailsApi(
/// Fetch Rental Transaction
static Future<TransactionsResponse?> fetchRentalsTransactionsApi(
String sessionId,
String empId,
String billId,
String accId,
) async {
try {
Map<String, String> data = {
"session_id": sessionId,
"emp_id": empId,
"bill_id": billId,
"acc_id": accId,
};
final res = await post(data, rentalPaymentDetailsUrl, {});
final res = await post(data, transactionsUrl, {});
if (res != null) {
return RentalPaymentDetailsResponse.fromJson(jsonDecode(res.body));
return TransactionsResponse.fromJson(jsonDecode(res.body));
} else {
debugPrint("Null Response");
return null;
......@@ -535,11 +537,13 @@ class ApiCalling {
/// Fetch Dashboard
static Future<DashboardResponse?> fetchDashboardApi(
String accId,
String sessionId,
) async {
debugPrint("Dashboard Api called ##############");
try {
Map<String, String> data = {
"acc_id": accId,
"session_id": sessionId,
};
debugPrint("Account Id : $accId");
......
import 'package:flutter/material.dart';
import 'package:gen_rentals/Notifier/DashboardProvider.dart';
import 'package:gen_rentals/Notifier/TransactionsProvider.dart';
import 'package:gen_rentals/Screens/SplashScreen.dart';
import 'package:provider/provider.dart';
import 'Notifier/RentalContactProvider .dart';
import 'Notifier/SubscribeOrderDetailsProvider.dart';
import 'Notifier/theme_provider.dart';
import 'Screens/authScreen/LoginScreen.dart';
......@@ -28,6 +30,8 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider<DashboardProvider>(create: (_) => DashboardProvider()),
ChangeNotifierProvider<RentalProvider>(create: (_) => RentalProvider(),),
ChangeNotifierProvider<ThemeProvider>(create: (_) => ThemeProvider(),),
ChangeNotifierProvider(create: (_) => SubscribeOrderDetailsProvider()),
ChangeNotifierProvider(create: (_) => TransactionsProvider()),
],
child: Consumer<ThemeProvider>(
builder: (context, themeProvider, child) {
......
......@@ -129,6 +129,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.11"
device_info_plus:
dependency: "direct dev"
description:
name: device_info_plus
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
url: "https://pub.dev"
source: hosted
version: "10.1.2"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
url: "https://pub.dev"
source: hosted
version: "7.0.3"
fake_async:
dependency: transitive
description:
......@@ -781,6 +797,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.13.0"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852"
url: "https://pub.dev"
source: hosted
version: "1.1.5"
xdg_directories:
dependency: transitive
description:
......
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