new changes done

This commit is contained in:
saritabirare 2025-04-28 13:34:34 +05:30
parent 2c0797b687
commit e985fd194b
38 changed files with 1806 additions and 1054 deletions

View File

@ -16,7 +16,7 @@ class AnnouncementController extends GetxController {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
final List<AnnouncementModel>? fetchedAnnouncements =
await _announcementService.fetchAnnouncements(token!);
await _announcementService.fetchAnnouncements();
announcements.assignAll(fetchedAnnouncements as Iterable<AnnouncementModel>);
} catch (e) {
errorMessage.value = e.toString();

View File

@ -8,16 +8,16 @@ class AnnouncementService {
final Dio _dio = Dio();
Future<List<AnnouncementModel>?> fetchAnnouncements(String token) async {
Future<List<AnnouncementModel>?> fetchAnnouncements() async {
try {
String url = ApiUrls.AnnaouncementUrl; // Base URL to fetch product manuals
final response = await commonApiService<List<AnnouncementModel>>(
method: "GET",
url: url,
additionalHeaders: { // Pass the token here
'Authorization': 'Bearer $token',
},
// additionalHeaders: { // Pass the token here
// 'Authorization': 'Bearer $token',
// },
fromJson: (json) {
if (json['announcements'] != null) {
// If the productManuals key is present, map the response to a list of ProductManualModel objects

View File

@ -2,13 +2,21 @@ import 'package:cheminova/models/kyc_model.dart';
import 'package:cheminova/utils/api_urls.dart';
import 'package:dio/dio.dart';
import '../utils/app_interceptor.dart';
class KycService {
// Function to fetch KYC data from the API
Future<List<dynamic>> getKycData(String token) async {
try {
// Make a GET request to the KYC API endpoint with authorization token
var response = await Dio().get(
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
var response = await dio.get(
ApiUrls.getKycUrl,
// 'https://api.cnapp.co.in/api/kyc/getAll',
options: Options(
@ -31,6 +39,8 @@ class KycService {
}
Future<bool> approveKycStatus(String token, String kycId,String status) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
try {
// Prepare the payload for approval directly
var payload = {
@ -41,7 +51,7 @@ class KycService {
// print("Payload: $payload");
// Make a PATCH request to update the KYC status
var response = await Dio().patch(
var response = await dio.patch(
'https://api.cnapp.co.in/api/kyc/update/$kycId', // URL with the KYC ID
data: payload, // Payload with the status
options: Options(
@ -74,6 +84,8 @@ class KycService {
}
Future<bool> rejectKycStatus(
String token, String kycId, String? rejectionReason, String? user, String status) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
try {
// Prepare the payload for the PATCH request
var data = {
@ -92,7 +104,7 @@ class KycService {
print("Payload: $data");
// Make a PATCH request to update the KYC status
var response = await Dio().patch(
var response = await dio.patch(
'https://api.cnapp.co.in/api/kyc/update/$kycId',
data: data,
options: Options(

View File

@ -2,15 +2,17 @@ import 'package:dio/dio.dart';
import 'package:cheminova/models/notification_model.dart';
import '../utils/api_urls.dart';
import '../utils/app_interceptor.dart';
class NotificationService {
final Dio _dio = Dio();
// final Dio _dio = Dio();
Future<List<NotificationModel>?> fetchNotifications(String token, String date) async {
final String url = ApiUrls.getNotificationUrl;
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
try {
final response = await _dio.get(
final response = await dio.get(
url,
options: Options(
headers: {

View File

@ -6,12 +6,18 @@ import 'package:cheminova/utils/api_urls.dart';
import 'package:dio/dio.dart';
import '../models/oder_place_model.dart';
import '../utils/app_interceptor.dart';
import '../utils/log_service.dart';
class OrderPlacedService {
final Dio dio = Dio();
//final Dio dio = Dio();
// OrderPlacedService() : _dio = Dio(BaseOptions(baseUrl: 'https://api.cnapp.co.in')) {
// _dio.interceptors.add(AuthInterceptor());
// _dio.interceptors.add(PrettyDioLogger());
// }
Future<void> placeOrder(PlacedOrderModel orderDetails, String token) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
//try {
// logger.w("orderjson ${jsonEncode(orderDetails.toJson())}");
final response = await dio.post(

View File

@ -6,16 +6,23 @@ import 'package:cheminova/utils/show_snackbar.dart';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import '../models/rd_order_item_model.dart';
import '../utils/app_interceptor.dart';
class RDOrderPlacedService {
final Dio _dio = Dio(); // Create Dio instance
// RDOrderPlacedService() : _dio = Dio(BaseOptions(baseUrl: 'https://api.cnapp.co.in')) {
// _dio.interceptors.add(AuthInterceptor());
// _dio.interceptors.add(PrettyDioLogger());
// }
Future<void> placRDeOrder(PlacedOrdersProcessing orderDetails,
String token) async {
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
//try {
// logger.w("orderjson ${jsonEncode(orderDetails.toJson())}");
final response = await _dio.post(
final response = await dio.post(
'https://api.cnapp.co.in/api/pd-process-order',
// Ensure this is your correct endpoint
data: jsonEncode(orderDetails.toJson()),

View File

@ -4,6 +4,7 @@ import 'package:cheminova/models/product_stock_model.dart';
import 'package:dio/dio.dart';
import '../utils/api_urls.dart';
import '../utils/app_interceptor.dart';
import '../utils/common_api_service.dart';
import '../utils/show_snackbar.dart';
@ -14,9 +15,10 @@ class UpdateStockService{
try {
// Correct API URL with orderId passed in the URL
final String url = ApiUrls.ProductUpdateStockUrl;
final dio = Dio();
dio.interceptors.add(AuthInterceptor());
// Make the PUT request
final response = await Dio().put(
final response = await dio.put(
url, // Use the correct URL here
data: {
"products": stock, // Send the cancellation reason as JSON

View File

@ -13,8 +13,13 @@ class Brand {
return Brand(
id: json['_id'],
brandName: json['brandName'],
images: json["image"] != null
? (json["image"] as List).map((e) => BrandImage.fromJson(e)).toList()
// images: json["image"] != null
// ? (json["image"] as List).map((e) => BrandImage.fromJson(e)).toList()
// : [],
images: json["image"] != null // Ensure you use the correct key
? (json["image"] as List)
.map((e) => BrandImage.fromJson(e))
.toList()
: [],
);
@ -49,7 +54,7 @@ class BrandImage {
factory BrandImage.fromJson(Map<String, dynamic> json) {
return BrandImage(
publicId: json["public_id"] ?? "",
url: json["url"] ?? "",
url: json["url"]?.toString() ?? "",
imageId: json["_id"] ?? "",
);
}

View File

@ -1,9 +1,15 @@
import 'package:cheminova/models/rd_order_item_model.dart';
import 'brand_model.dart';
class GetRdCancelledModel {
final String id;
final String paymentMode;
final String shipTo;
final String billTo;
final List<OrderItem> orderItems;
final List<RDOrderItem> orderItems;
final double subtotal;
final double gstTotal;
final double grandTotal;
@ -51,8 +57,8 @@ class GetRdCancelledModel {
paymentMode: json['paymentMode'],
shipTo: json['shipTo'],
billTo: json['billTo'],
orderItems: (json['orderItem'] as List<dynamic>)
.map((item) => OrderItem.fromJson(item))
orderItems: (json['orderItem'] as List)
.map((item) => RDOrderItem.fromJson(item))
.toList(),
subtotal: json['subtotal'].toDouble(),
gstTotal: json['gstTotal'].toDouble(),
@ -122,7 +128,7 @@ class OrderItem {
final double gst;
final int hsnCode;
final String description;
final List<String> images;
final List<BrandImage> images;
final int quantity;
final int remainingQuantity;
final String id;
@ -154,7 +160,9 @@ class OrderItem {
gst: json['GST'].toDouble(),
hsnCode: json['HSN_Code'],
description: json['description'] ?? '',
images: List<String>.from(json['image']),
images : (json["image"] as List)
.map((item) => BrandImage.fromJson(item))
.toList(),
quantity: json['quantity'],
remainingQuantity: json['remainingQuantity'],
id: json['_id'],

View File

@ -64,7 +64,7 @@ class OrderItem {
String description;
String productStatus;
final String addedBy;
List<String> image;
List<BrandImage> image;
DateTime createdAt;
DateTime updatedAt;
int count;
@ -124,7 +124,9 @@ class OrderItem {
description: json['description'],
productStatus: json['product_Status'],
addedBy: json['addedBy']['name'], // Assuming addedBy has a 'name' key
image: List<String>.from(json['image']),
image: json['image'] is List
? (json['image'] as List).map((e) => BrandImage.fromJson(e)).toList()
: [BrandImage.fromJson(json['image'])],
createdAt: DateTime.parse(json['createdAt']),
updatedAt: DateTime.parse(json['updatedAt']),
count: json['count'],

View File

@ -1,3 +1,5 @@
import 'brand_model.dart';
class PlacedOrderList {
final String id;
final String paymentMode;
@ -95,6 +97,7 @@ class OrderItem1 {
final String brandName;
final double price;
final int quantity;
List<BrandImage>? image;
OrderItem1({
required this.sku,
@ -102,6 +105,7 @@ class OrderItem1 {
required this.categoryName,
required this.brandName,
required this.price,
this.image,
required this.quantity,
});
@ -112,6 +116,9 @@ class OrderItem1 {
categoryName: json['categoryName'],
brandName: json['brandName'],
price: json['price'].toDouble(),
image : (json["image"] as List)
.map((item) => BrandImage.fromJson(item))
.toList(),
quantity: json['quantity'],
);
}
@ -124,13 +131,14 @@ class OrderItem1 {
'brandName': brandName,
'price': price,
'quantity': quantity,
'image':image
};
}
@override
String toString() {
return 'OrderItem(sku: $sku, name: $name, categoryName: $categoryName, '
'brandName: $brandName, price: $price, quantity: $quantity)';
'brandName: $brandName, price: $price, quantity: $quantity,image:$image)';
}
}

View File

@ -1,4 +1,6 @@
import 'brand_model.dart';
class RDOrderItem {
final String productId;
final String sku;
@ -9,7 +11,7 @@
final int gst; // Ensure GST is int
final int hsnCode; // Ensure HSN_Code is int
final String description;
final List<String> image;
final List<BrandImage> image;
int? quantity;
int? remainingQuantity;
int? processquantity;
@ -43,10 +45,13 @@
hsnCode: json['HSN_Code'] ?? 0,
// Handle HSN_Code as int
description: json['description'] ?? '',
image: List<String>.from(json['image'] ?? []),
//image: List<String>.from(json['image'] ?? []),
image : (json["image"] as List)
.map((item) => BrandImage.fromJson(item))
.toList(),
quantity: json['quantity'] ?? 0,
// Handle quantity as int
processquantity: json['processquantity']??1,
processquantity: json['processQuantity']??1,
remainingQuantity: json['remainingQuantity'] ??
0, // Handle remainingQuantity as int
);

View File

@ -20,13 +20,13 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
final authController = Get.put(AuthController());
void dispose() {
// Dispose of the text controllers when the screen is closed to free up resources
authController.currentpassController.dispose();
authController.newpassController.dispose();
authController.confirmpassController.dispose();
super.dispose();
}
// void dispose() {
// // Dispose of the text controllers when the screen is closed to free up resources
// authController.currentpassController.dispose();
// authController.newpassController.dispose();
// authController.confirmpassController.dispose();
// super.dispose();
// }
// Function to validate user input and initiate password change
void validateAndChangePassword() async {

View File

@ -24,6 +24,12 @@ class _ProfileScreenState extends State<ProfileScreen> {
// Initialize the HomeController using GetX
final homecontroller = Get.put(HomeController());
@override
void initState() {
// TODO: implement initState
super.initState();
homecontroller.getUser();
}
@override
Widget build(BuildContext context) {
// Accessing the user details from the HomeController
final user = homecontroller.user;
@ -52,7 +58,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
],
),
// Main content of the profile screen
body: SingleChildScrollView(
body: user == null
? const Center(child: CircularProgressIndicator())
:
SingleChildScrollView(
child: Column(
children: [
Container(
@ -70,7 +79,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
children: [
const SizedBox(height: 20),
// Displaying individual profile items
_buildProfileItem('Name', user!.name),
_buildProfileItem('Name', user.name),
_buildProfileItem('ID', user.uniqueId),
_buildProfileItem('Email ID', user.email),
_buildProfileItem('Mobile Number', user.phone),

View File

@ -184,7 +184,7 @@ class _HomeScreenState extends State<HomeScreen> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
HomeCard(
title: 'RD Orders',
title: 'Retailer Orders',
onTap: () => Get.to(
() => RdOrderScreen(),
),

View File

@ -179,13 +179,18 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
),
SizedBox(
height: Get.height * 0.6,
child: Obx(() {
child:
Obx(() {
// Filter the list based on the selected status
List<KycModel> filteredOrders =
selectedStatus == "All"
? _kycController.kycList
: _kycController.kycList.where((kyc) => kyc.status == selectedStatus).toList();
filteredOrders.sort((a, b) {
DateTime dateA = DateTime.parse(filteredOrders[0].createdAt.toString()); // Assuming createdAt is a string
DateTime dateB = DateTime.parse(filteredOrders[0].createdAt.toString());
return dateB.compareTo(dateA); // Sort in descending order
});
return ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,

View File

@ -67,7 +67,8 @@ class NotificationScreen extends StatelessWidget {
),
),
drawer: MyDrawer(),
body: Obx(() {
body:
Obx(() {
// Show a loading indicator while data is being fetched
if (notificationController.isLoading.value) {
return const Center(child: CircularProgressIndicator());

View File

@ -96,16 +96,34 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
_saveSelectedAddress();
}
// void _loadSelectedAddress() async {
// SharedPreferences prefs = await SharedPreferences.getInstance();
// setState(() {
// _selectedShippingAddress =
// prefs.getString('selectedShippingAddress') ?? _addressList.first;
// _selectedBillingAddress =
// prefs.getString('selectedBillingAddress') ?? _addressList.first;
// });
// }
void _loadSelectedAddress() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
_addressController
.fetchAddresses(); // Ensure address list is updated
setState(() {
_selectedShippingAddress =
prefs.getString('selectedShippingAddress') ?? _addressList.first;
(prefs.getString('selectedShippingAddress') ??
(_addressController.addressList.isNotEmpty ? _addressController.addressList.first : null)) as String?;
_selectedBillingAddress =
prefs.getString('selectedBillingAddress') ?? _addressList.first;
(prefs.getString('selectedBillingAddress') ??
(_addressController.addressList.isNotEmpty ? _addressController.addressList.first : null)) as String?;
});
}
void _onPaymentModeChanged(String? value) {
setState(() {
_groupValue = value!;
@ -138,7 +156,14 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
hsnCode: product.hsnCode,
description: product.description,
productStatus: product.productStatus,
image: [],
// image:[],
image: product.brand.images.isNotEmpty
? product.brand.images.map((image) => BrandImage(
publicId: image.publicId, // or any other identifier
imageId: image.imageId, url: image.url,
)).toList()
:[],
createdAt: product.createdAt,
updatedAt: product.createdAt,
count: product.quantity,

View File

@ -1,4 +1,5 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/controller/shiptobilltoController.dart';
import 'package:cheminova/models/oder_place_model.dart';
@ -72,7 +73,7 @@ Future<void> adduni()async {
.map((item) => (item.quantity))
.join(', ');
}
//String? imageurl;
@override
Widget build(BuildContext context) {
@ -223,6 +224,7 @@ Future<void> adduni()async {
itemCount: widget.placedOrderList?.orderItem.length ?? 0,
itemBuilder: (context, index) {
final orderItem = widget.placedOrderList!.orderItem[index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
return orderItem != null
? Card(
margin: const EdgeInsets.symmetric(vertical: 5.0),
@ -233,9 +235,26 @@ Future<void> adduni()async {
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/new_product.jpeg",
// "assets/images/product.png", // Add the image URL here
// Image.asset(
// "assets/images/new_product.jpeg",
// // "assets/images/product.png", // Add the image URL here
// height: 50,
// width: 50,
// fit: BoxFit.cover,
// ),
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
// imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50,
width: 50,
fit: BoxFit.cover,

View File

@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/models/product_model1.dart';
import 'package:cheminova/screens/order/checkout_screen.dart';
@ -24,6 +25,7 @@ class ProductDetailScreen extends StatefulWidget {
class _ProductDetailScreenState extends State<ProductDetailScreen> {
final CartController _cartController = Get.put(CartController());// Initialize CartController
String? imageurl;
// Function to capitalize the first letter of a string
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
@ -31,6 +33,9 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
}
@override
Widget build(BuildContext context) {
imageurl = widget.productModel!.brand.images.isNotEmpty
? widget.productModel!.brand.images[0].url
: 'assets/images/no_image_available.jpg'; // Use a fallback image URL or handle it accordingly
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
@ -105,16 +110,21 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
),
borderRadius: BorderRadius.circular(15),
),
child: ClipRRect(
child:
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset(
"assets/images/new_product.jpeg",
// "assets/images/product.png",
fit: BoxFit.cover,),
// Image.asset(
// widget.product.image,
// fit: BoxFit.cover,
// ),
child:
imageurl!.startsWith('http') // Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageurl!,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
imageurl!,
fit: BoxFit.cover,
),
),
),
),

View File

@ -368,7 +368,7 @@ class _PartialProcessingDialogScreenState extends State<PartialProcessingDialogS
TextButton(
onPressed: () {
//Get.back();
Navigator.of(context).pop();
Navigator.pop(context);
},
child: const Text("Cancel"),
),

View File

@ -836,6 +836,7 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/controller/get_rd_cancle_controller.dart';
import 'package:cheminova/controller/get_rd_pending_controller.dart';
@ -874,12 +875,14 @@ class RdOrderCancelledScreenDetailScreen extends StatefulWidget {
// PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen
final SingleGetOrderModel? placedOrderList;
// GetRdPendingModel? productpendingModel;
final String orderId;
//final String orderId;
// GetInvoiceModel? placeInvoiceList;
// PlacedOrderModel? placedOrderModel;
// Constructor for initializing the screen with placed order details
RdOrderCancelledScreenDetailScreen({super.key,this.placedOrderList,required this.orderId});
RdOrderCancelledScreenDetailScreen({super.key,this.placedOrderList,
// required this.orderId
});
@override
State<RdOrderCancelledScreenDetailScreen> createState() =>
@ -1055,7 +1058,7 @@ class _RdOrderCancelledScreenDetailScreenState
),
],
title: const Text(
"RD Cancelled Order Details",
"Retailer Cancelled Order Details",
),
),
body: Stack(
@ -1276,6 +1279,7 @@ class _RdOrderCancelledScreenDetailScreenState
itemCount: order.orderItem!.length ?? 0,
itemBuilder: (context, index) {
final orderItem =order.orderItem![index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotal = orderItem.price * orderItem.quantity!.toInt();
final GstTotalAmount = (orderItem.price * orderItem.quantity!.toInt()) *(orderItem.gst/100 );
final grandTotal = subTotal + GstTotalAmount;
@ -1289,13 +1293,32 @@ class _RdOrderCancelledScreenDetailScreenState
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/new_product.jpeg",
// "assets/images/product.png",
// Image.asset(
// "assets/images/new_product.jpeg",
// // "assets/images/product.png",
// height: 50,
// width: 50,
// fit: BoxFit.cover,
// ),
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
//imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50,
width: 50,
fit: BoxFit.cover,
),
const SizedBox(width: 10),
Expanded(
child: Column(
@ -1373,6 +1396,7 @@ class _RdOrderCancelledScreenDetailScreenState
.toList();
final orderItem = filteredItems[index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotalProcesssItem = orderItem.price! * orderItem.remainingQuantity!.toInt();
final GstTotalAmounProcessItem = (orderItem.price! * orderItem.remainingQuantity!.toInt()) *(orderItem.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
@ -1386,13 +1410,32 @@ class _RdOrderCancelledScreenDetailScreenState
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/new_product.jpeg",
// "assets/images/product.png",
// Image.asset(
// "assets/images/new_product.jpeg",
// // "assets/images/product.png",
// height: 50,
// width: 50,
// fit: BoxFit.cover,
// ),
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
//imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50,
width: 50,
fit: BoxFit.cover,
),
const SizedBox(width: 10),
Expanded(
child: Column(

View File

@ -101,8 +101,8 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
if (index >= 0 && index < _getRDCancleController.productRDList.length) {
// Get the order ID from the list based on the index
final orderId = _getRDCancleController.productRDList[index].id;
final invoiceId = _getRDCancleController.productRDList[index].invoices[0];
// final invoiceId = _getRDCancleController.productRDList[index].invoices;
print("orderId canceeled,$orderId");
// Retrieve the token from SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
@ -117,7 +117,7 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
// Navigate to the details screen with the fetched order
Get.to(() => RdOrderCancelledScreenDetailScreen(
placedOrderList: singleOrder, // Pass the single order instance
orderId: orderId,
//orderId: orderId,
));
} else {
@ -144,6 +144,68 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
}
// void onOrderTap(int index) async {
// try {
// // Fetch orders and wait for it to complete
// await _getRDCancleController.getRDCancleProduct();
//
// // Debugging: Check if data is actually fetched
// print('Fetched orders count: ${_getRDCancleController.productRDList.length}');
//
// // Ensure the list is not empty after fetching
// if (_getRDCancleController.productRDList.isEmpty) {
// Get.snackbar("Error", "No orders available to display.");
// return;
// }
//
// // Ensure index is within range
// if (index < 0 || index >= _getRDCancleController.productRDList.length) {
// Get.snackbar("Error", "Invalid order selection.");
// return;
// }
//
// // Retrieve order details
// final order = _getRDCancleController.productRDList[index].id;
// // final invoice = _getRDCancleController.productRDList[index].invoices[index];
// // Ensure invoices are available
// if (order.isEmpty) {
// Get.snackbar("Error", "No invoice found for this order.");
// return;
// }
//
// final orderId = order;
// //final invoiceId = invoice;
//
// print("Cancelled Order ID: $orderId");
//
// // Retrieve token
// SharedPreferences prefs = await SharedPreferences.getInstance();
// String? token = prefs.getString('token');
//
// if (token == null) {
// Get.snackbar("Error", "User not authenticated.");
// return;
// }
//
// // Fetch single order details
// final SingleGetOrderModel? singleOrder =
// await GetSingleProductService().getSingleOrder(token, orderId);
//
// if (singleOrder == null) {
// Get.snackbar("Error", "Unable to fetch order details.");
// return;
// }
//
// // Navigate to details screen
// await Get.to(() => RdOrderCancelledScreenDetailScreen(
// placedOrderList: singleOrder, // Pass fetched order
// orderId: orderId,
// ));
// } catch (e) {
// print('Error in onOrderTap: $e');
// Get.snackbar("Error", "An unexpected error occurred.");
// }
// }
@override
@ -174,7 +236,7 @@ class _RdCancelledScreenState extends State<RdCancelledScreen> {
),
),
],
title: const Text("RD Cancelled Order"),
title: const Text("Retailer Cancelled Order"),
),
drawer: MyDrawer(),
body: Stack(

View File

@ -150,7 +150,7 @@ class _RdDeliveredDetailsScreenState
),
],
title: const Text(
"RD Delivered Order Details",
"Retailer Delivered Order Details",
),
),
body: Stack(

View File

@ -163,7 +163,7 @@ class _RdDeliveredScreenState extends State<RdDeliveredScreen> {
),
),
],
title: const Text("RD Delivered Order"),
title: const Text("Retailer Delivered Order"),
),
drawer: MyDrawer(),
body: Stack(

View File

@ -198,7 +198,10 @@ class _RdDispatchedDetailsDetailScreenState
SnackBar(content: Text('Please select a delivery date.')),
);
}
Navigator.of(context).pop(); // Close the dialog after submission
Navigator.push(context, MaterialPageRoute(builder: (context){
return RdDeliveredScreen();
}));
// Navigator.of(context).pop(); // Close the dialog after submission
},
child: Text('Confirm'),
),
@ -312,7 +315,7 @@ class _RdDispatchedDetailsDetailScreenState
),
],
title: const Text(
"RD Dispatched Order Details",
"Retailer Dispatched Order Details",
),
),
body: Stack(

View File

@ -172,7 +172,7 @@ class _RdDispatchedScreenState extends State<RdDispatchedScreen> {
),
),
],
title: const Text("RD Dispatched Order"),
title: const Text("Retailer Dispatched Order"),
),
drawer: MyDrawer(),
body: Stack(

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/rd_single_order_controller.dart';
import 'package:cheminova/models/rd_order_item_model.dart';
@ -26,12 +27,14 @@ class RdOrderDetailUpdateScreen extends StatefulWidget {
//final Product? productModel;
// PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen
SingleGetOrderModel? placedOrderList;
final String orderId;
//final String orderId;
//final int orderIndex; // New parameter to receive the index
// PlacedOrderModel? placedOrderModel;
// Constructor for initializing the screen with placed order details
RdOrderDetailUpdateScreen({super.key,this.placedOrderList,required this.orderId});
RdOrderDetailUpdateScreen({super.key,this.placedOrderList,
//required this.orderId
});
@override
State<RdOrderDetailUpdateScreen> createState() =>
@ -46,6 +49,7 @@ class _RdOrderDetailUpdateScreenState
final RdSingleOrderController _getPlacedOrderController = Get.put(RdSingleOrderController());
final GetProductRDController _getProductRDController = Get.put(GetProductRDController());
final RDOrderPlacedController controller = Get.put(RDOrderPlacedController());
bool isDialogClosed = false; // Flag to track if dialog is already closed
String? orderId;
@ -226,6 +230,9 @@ class _RdOrderDetailUpdateScreenState
actions: [
TextButton(
onPressed: () async {
if (isDialogClosed) return; // Prevent reopening the dialog
isDialogClosed = true; // Mark dialog as closed
if (selectedStatus == "cancelled") {
// Ensure the reason is provided for cancellation
if (reasonController.text.isEmpty) {
@ -245,9 +252,9 @@ class _RdOrderDetailUpdateScreenState
});
// Close the dialog after a short delay
Future.delayed(Duration(seconds: 1), () {
// Navigator.of(context).pop(); // Close the dialog
});
// Future.delayed(Duration(seconds: 1), () {
// // Navigator.of(context).pop(); // Close the dialog
// });
return; // Exit here to prevent further processing
}
@ -262,31 +269,33 @@ class _RdOrderDetailUpdateScreenState
Map<String, RDOrderItem> orderItemMap = {};
// Populate the map with items and their quantities
for (var item in _getProductRDController.productRDList) {
var productId = item.orderItem[0].productId;
for (var item in widget.placedOrderList!.orderItem) {
var productId = item.productId;
if (orderItemMap.containsKey(productId)) {
// If the product already exists, aggregate the quantity
var existingItem = orderItemMap[productId]!;
existingItem.quantity = (existingItem.quantity ?? 0) + (item.orderItem[0].quantity ?? 0);
existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.orderItem[0].remainingQuantity ?? 0);
existingItem.processquantity = (existingItem.processquantity ?? 0) + (item.orderItem[0].processquantity ?? 0);
// var existingItem = orderItemMap[productId]!;
existingItem.quantity = ((existingItem.quantity ?? 0) + (item.quantity ?? 0));
// existingItem.quantity = (existingItem.quantity ?? 0) + (item.orderItem[0].quantity ?? 0);
// existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.orderItem[0].remainingQuantity ?? 0);
// existingItem.processquantity = (existingItem.processquantity ?? 0) + (item.orderItem[0].processquantity ?? 0);
} else {
// If it's a new product, add it to the map
orderItemMap[productId] = RDOrderItem(
productId: productId,
sku: item.orderItem[0].sku,
name: item.orderItem[0].name,
categoryName: item.orderItem[0].categoryName,
brandName: item.orderItem[0].brandName,
price: item.orderItem[0].price,
gst: item.orderItem[0].gst.toInt(),
hsnCode: item.orderItem[0].hsnCode,
description: item.orderItem[0].description,
sku: item.sku,
name: item.name,
categoryName: item.categoryName,
brandName: item.brandName,
price: item.price,
gst: item.gst.toInt(),
hsnCode: item.hsnCode,
description: item.description,
image: [], // Handle images appropriately
quantity: item.orderItem[0].quantity ?? 0,
remainingQuantity: item.orderItem[0].remainingQuantity ?? 0,
processquantity: item.orderItem[0].processquantity ?? 0,
quantity: item.quantity ?? 0,
remainingQuantity: item.remainingQuantity ?? 0,
processquantity: item.remainingQuantity ?? 0,
);
}
}
@ -309,7 +318,7 @@ class _RdOrderDetailUpdateScreenState
showSnackbar("Order processed and invoice created successfully");
Get.to(RdOrderProcessingScreen());
Navigator.of(context).pop();
// Navigator.of(context).pop();
// Close the dialog after a short delay
// Close the dialog
@ -458,6 +467,7 @@ class _RdOrderDetailUpdateScreenState
itemCount: widget.placedOrderList!.orderItem!.length ?? 0,
itemBuilder: (context, index) {
final orderItem = widget.placedOrderList!.orderItem![index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotalProcesssItem = orderItem.price! * orderItem.quantity!.toInt();
final GstTotalAmounProcessItem = (orderItem.price! * orderItem.quantity!.toInt()) *(orderItem.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
@ -471,9 +481,27 @@ class _RdOrderDetailUpdateScreenState
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/new_product.jpeg",
// "assets/images/product.png",
// Image.asset(
// "assets/images/new_product.jpeg",
// // "assets/images/product.png",
// height: 50,
// width: 50,
// fit: BoxFit.cover,
// ),
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
//imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50,
width: 50,
fit: BoxFit.cover,

View File

@ -165,7 +165,7 @@ class _RdOrderScreenState extends State<RdOrderScreen> {
// Navigate to the details screen with the fetched order
Get.to(() => RdOrderDetailUpdateScreen(
placedOrderList: singleOrder,
orderId: orderId,
// orderId: orderId,
));
} else {
// Handle the case where the single order could not be fetched
@ -224,7 +224,7 @@ class _RdOrderScreenState extends State<RdOrderScreen> {
),
),
],
title: const Text("RD Order"),
title: const Text("Retailer Order"),
),
drawer: MyDrawer(),
body: Stack(

View File

@ -1,4 +1,5 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/controller/get_rd_pending_controller.dart';
import 'package:cheminova/controller/rd_get_order_controller.dart';
@ -24,6 +25,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import '../../controller/cart_controller.dart';
import '../../controller/get_single_invoice_controller.dart';
import '../../controller/rd_processing_order_controller.dart';
import '../../controller/rd_single_order_controller.dart';
import '../../models/get_invoice_model.dart';
import '../../models/product_model1.dart';
import '../../models/rd_order_item_model.dart';
@ -35,12 +37,14 @@ class RdOrderPendingScreenDetailScreen extends StatefulWidget {
// PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen
final SingleGetOrderModel? placedOrderList;
// GetRdPendingModel? productpendingModel;
final String orderId;
//final String orderId;
// GetInvoiceModel? placeInvoiceList;
// PlacedOrderModel? placedOrderModel;
// Constructor for initializing the screen with placed order details
RdOrderPendingScreenDetailScreen({super.key,this.placedOrderList,required this.orderId});
RdOrderPendingScreenDetailScreen({super.key,this.placedOrderList,
// required this.orderId
});
@override
State<RdOrderPendingScreenDetailScreen> createState() =>
@ -52,11 +56,12 @@ class _RdOrderPendingScreenDetailScreenState
extends State<RdOrderPendingScreenDetailScreen> {
// Controllers for managing cart and placed orders
final CartController _cartController = Get.put(CartController());
final RdSingleOrderController _getPlacedOrderController = Get.put(RdSingleOrderController());
final GetRdPendingController _getRdPendingController = Get.put(GetRdPendingController());
final GetSingleInvoiceController _getSingleInvoiceController = Get.put(GetSingleInvoiceController());
final GetProductRDController _getProductRDController = Get.put(GetProductRDController());
final RDOrderPlacedController controller = Get.put(RDOrderPlacedController());
bool isDialogClosed = false; // Flag to track if dialog is already closed
final List<String> statusOptions = [
"new",
"pending",
@ -201,6 +206,9 @@ class _RdOrderPendingScreenDetailScreenState
actions: [
TextButton(
onPressed: () async {
if (isDialogClosed) return; // Prevent reopening the dialog
isDialogClosed = true; // Mark dialog as closed
{
if (selectedStatus == "cancelled") {
// Ensure the reason is provided for cancellation
@ -235,35 +243,47 @@ class _RdOrderPendingScreenDetailScreenState
Map<String, RDOrderItem> orderItemMap = {};
// Populate the map with items and their quantities
for (var item in _getProductRDController.productRDList) {
var productId = item.orderItem[0].productId;
for (var item in widget.placedOrderList!.orderItem) {
var productId = item.productId;
if (item.remainingQuantity != null && item.remainingQuantity! > 0) {
if (orderItemMap.containsKey(productId)) {
// If the product already exists, aggregate the quantity
// If the product already exists, aggregate the remaining quantity
var existingItem = orderItemMap[productId]!;
existingItem.quantity = (existingItem.quantity ?? 0) + (item.orderItem[0].quantity ?? 0);
existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.orderItem[0].remainingQuantity ?? 0);
existingItem.processquantity = (existingItem.processquantity ?? 0) + (item.orderItem[0].processquantity ?? 0);
} else {
existingItem.quantity = (existingItem.quantity ?? 0) + (item.quantity ?? 0);
existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.remainingQuantity ?? 0);
existingItem.processquantity = existingItem.remainingQuantity; // Process all remaining stock
}
// if (orderItemMap.containsKey(productId)) {
// // If the product already exists, aggregate the quantity
// var existingItem = orderItemMap[productId]!;
// // var existingItem = orderItemMap[productId]!;
// existingItem.quantity = ((existingItem.quantity ?? 0) + (item.quantity ?? 0));
// existingItem.quantity = (existingItem.quantity ?? 0) + (item.orderItem[0].quantity ?? 0);
// existingItem.remainingQuantity = (existingItem.remainingQuantity ?? 0) + (item.orderItem[0].remainingQuantity ?? 0);
// existingItem.processquantity = (existingItem.processquantity ?? 0) + (item.orderItem[0].processquantity ?? 0);
else {
// If it's a new product, add it to the map
orderItemMap[productId] = RDOrderItem(
productId: productId,
sku: item.orderItem[0].sku,
name: item.orderItem[0].name,
categoryName: item.orderItem[0].categoryName,
brandName: item.orderItem[0].brandName,
price: item.orderItem[0].price,
gst: item.orderItem[0].gst.toInt(),
hsnCode: item.orderItem[0].hsnCode,
description: item.orderItem[0].description,
sku: item.sku,
name: item.name,
categoryName: item.categoryName,
brandName: item.brandName,
price: item.price,
gst: item.gst.toInt(),
hsnCode: item.hsnCode,
description: item.description,
image: [], // Handle images appropriately
quantity: item.orderItem[0].quantity ?? 0,
remainingQuantity: item.orderItem[0].remainingQuantity ?? 0,
processquantity: item.orderItem[0].processquantity ?? 0,
quantity: item.quantity ?? 0,
remainingQuantity: item.remainingQuantity ?? 0,
processquantity: item.remainingQuantity ?? 0,
);
}
}
}
// Convert the map to a list
List<RDOrderItem> orderItems = orderItemMap.values.toList();
@ -372,7 +392,7 @@ class _RdOrderPendingScreenDetailScreenState
),
],
title: const Text(
"RDPending Order Details",
"RetailerPending Order Details",
),
),
body: Stack(
@ -593,6 +613,7 @@ class _RdOrderPendingScreenDetailScreenState
itemCount: order.orderItem!.length ?? 0,
itemBuilder: (context, index) {
final orderItem =order.orderItem![index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotal = orderItem.price * orderItem.quantity!.toInt();
final GstTotalAmount = (orderItem.price * orderItem.quantity!.toInt()) *(orderItem.gst/100 );
final grandTotal = subTotal + GstTotalAmount;
@ -606,9 +627,26 @@ class _RdOrderPendingScreenDetailScreenState
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/new_product.jpeg",
// "assets/images/product.png",
// Image.asset(
// "assets/images/new_product.jpeg",
// // "assets/images/product.png",
// height: 50,
// width: 50,
// fit: BoxFit.cover,
// ),
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
//imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50,
width: 50,
fit: BoxFit.cover,
@ -690,6 +728,7 @@ class _RdOrderPendingScreenDetailScreenState
.toList();
final orderItem = filteredItems[index];
final imageUrl = orderItem.image?.isNotEmpty == true ? orderItem.image![0].url : null;
final subTotalProcesssItem = orderItem.price! * orderItem.remainingQuantity!.toInt();
final GstTotalAmounProcessItem = (orderItem.price! * orderItem.remainingQuantity!.toInt()) *(orderItem.gst!/100 );
final grandTotalProcessItem = subTotalProcesssItem + GstTotalAmounProcessItem;
@ -703,12 +742,30 @@ class _RdOrderPendingScreenDetailScreenState
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
/* Image.asset(
"assets/images/new_product.jpeg",
// "assets/images/product.png",
height: 50,
width: 50,
fit: BoxFit.cover,
),*/
imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('http') // Check if it's a network URL/ Check if it's a network URL
? CachedNetworkImage(
imageUrl: imageUrl,
height: 50,
width: 50,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(), // Optional placeholder
errorWidget: (context, url, error) => const Icon(Icons.error), // Optional error widget
)
: Image.asset(
//imageUrl!,
'assets/images/no_image_available.jpg', // Placeholder image when URL is empty
height: 50,
width: 50,
fit: BoxFit.cover,
),
const SizedBox(width: 10),
Expanded(

View File

@ -114,7 +114,7 @@ class _RdOrderPendingScreenState extends State<RdOrderPendingScreen> {
// Navigate to the details screen with the fetched order
Get.to(() => RdOrderPendingScreenDetailScreen(
placedOrderList: singleOrder, // Pass the single order instance
orderId: orderId,
// orderId: orderId,
));
} else {
@ -171,7 +171,7 @@ class _RdOrderPendingScreenState extends State<RdOrderPendingScreen> {
),
),
],
title: const Text("RD Pending Order"),
title: const Text("Retailer Pending Order"),
),
drawer: MyDrawer(),
body: Stack(

View File

@ -123,8 +123,10 @@ class _RdOrderProcessingDetailScreenState extends State<RdOrderProcessingDetailS
// Call the API to submit data
_getDispatchController.RDProcessingToDispatchProduct(widget.placeInvoiceList!.id.toString(), courierName, courierTrackingId);
showSnackbar("Order Status updated Order Dispatched");
Navigator.of(context).pop(); // Close the dialog after submission
Navigator.push(context, MaterialPageRoute(builder: (context){
return RdDispatchedScreen();
}));
//Navigator.of(context).pop(); // Close the dialog after submission
},
child: Text('Submit'),
),

View File

@ -172,7 +172,7 @@ class _RdOrderProcessingScreenState extends State<RdOrderProcessingScreen> {
),
),
],
title: const Text("RD Processing Order"),
title: const Text("Retailer Processing Order"),
),
drawer: MyDrawer(),
body: Stack(

View File

@ -5,7 +5,18 @@ import 'package:cheminova/utils/constants.dart';
import 'package:cheminova/utils/show_snackbar.dart';
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'app_interceptor.dart';
Dio createDio() {
final dio = Dio();
dio.interceptors.add((AuthInterceptor()));
return dio;
}
// Generic API service function that handles API requests with optional file uploads
Future<BodyType?> commonApiService<BodyType>({
required String url,
required String method,
@ -18,7 +29,7 @@ Future<BodyType?> commonApiService<BodyType>({
}) async {
try {
// Initialize Dio for making HTTP requests
Dio dio = Dio();
Dio dio = createDio();
final Response response;
print("body : $body");

View File

@ -1,8 +1,10 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/cart_controller.dart';
import 'package:cheminova/models/oder_place_model.dart';
import 'package:cheminova/models/order_item_model.dart';
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/models/rd_get_order_model.dart';
import 'package:cheminova/screens/product/product_detail_screen.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@ -16,6 +18,7 @@ class ProductCard extends StatefulWidget {
PlacedOrderModel? placedOrder;
PlacedOrderList? placedOrderList;
PlaceOrderItem1? placeorderItem;
PlacedOrdersResponse ? placeRDOrder;
ProductModel? product;
final bool isInCart;
final bool isCheckout;
@ -30,6 +33,7 @@ class ProductCard extends StatefulWidget {
this.placedOrder,
this.placedOrderList,
this.placeorderItem,
this.placeRDOrder,
this.isInCart = false,
this.isCheckout = false,
this.isConfirmation = false,
@ -44,6 +48,7 @@ class _ProductCardState extends State<ProductCard> {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
String? imageurl;
@override
Widget build(BuildContext context) {
@ -53,13 +58,20 @@ class _ProductCardState extends State<ProductCard> {
// Get the current quantity of the product, either from the cart or the default value
int currentQuantity = isProductInCart
? _cartController.cartList.firstWhere((p) => p.id == widget.productModel!.id).quantity
: widget.productModel!.quantity;
: widget.productModel!.quantity ??1;
TextEditingController quantityController =
TextEditingController(text: currentQuantity.toString());
imageurl = widget.productModel!.brand.images.isNotEmpty
? widget.productModel!.brand.images[0].url
: 'assets/images/no_image_available.jpg'; // Use a fallback image URL or handle it accordingly
return GestureDetector(
// Navigate to the ProductDetailScreen on tap unless the product is in cart or checkout
onTap: () => widget.isInCart || widget.isCheckout
? null
: Get.to(() => ProductDetailScreen(productModel: widget.productModel)),
child: SizedBox(
// height: Get.height * 0.21,
// width: Get.width *0.20,
child: Card(
child: Row(
children: [
@ -67,21 +79,26 @@ class _ProductCardState extends State<ProductCard> {
padding: const EdgeInsets.all(8.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(15.0),
child: Container(
height: Get.height * 0.15,
width: Get.width * 0.31,
child:
Container(
height: Get.height * 0.18,
width: Get.width * 0.32,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/product.png"),
image: imageurl!.startsWith('http')
? CachedNetworkImageProvider(imageurl!) as ImageProvider
: AssetImage(imageurl!),
fit: BoxFit.cover,
),
),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
padding: const EdgeInsets.symmetric(horizontal: 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -102,106 +119,22 @@ class _ProductCardState extends State<ProductCard> {
),
),
// Display the price of the product
if (!widget.isCheckout)
widget.isInCart
?
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${widget.productModel!.price.toString()}",
style: GoogleFonts.roboto(
fontSize: 22,
fontSize: 20,
fontWeight: FontWeight.w700,
),
),
if (showQuantity)
Text(
"Quantity: ${currentQuantity}",
style: GoogleFonts.roboto(
fontSize: 15,
fontWeight: FontWeight.w700,
),
),
// Display quantity adjustment buttons and remove button if the product is in cart
if (!widget.isCheckout)
widget.isInCart
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: Get.height * 0.04,
width: Get.width * 0.21,
decoration: BoxDecoration(
color: const Color(0xFF004791),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
height: 24,
width: 24,
child: ElevatedButton(
onPressed: () {
_cartController.decreaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'-',
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
),
),
Text(
"${currentQuantity}",
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
),
SizedBox(
height: 22,
width: 22,
child: ElevatedButton(
onPressed: () {
_cartController.increaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'+',
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
),
),
],
),
),
SizedBox(
width: 2.0,
),
// SizedBox(
// width: 60,
// ),
IconButton(
onPressed: () {
_cartController.removeFromCart(widget.productModel!);
@ -216,6 +149,225 @@ class _ProductCardState extends State<ProductCard> {
),
),
],
)
:SizedBox(),
if (showQuantity)
SizedBox(
height: Get.height * 0.04,
child: Text(
"Quantity: ${currentQuantity}",
style: GoogleFonts.roboto(
color: Color(0xFF004791),
fontSize: 15,
fontWeight: FontWeight.w700,
),
),
),
// Display quantity adjustment buttons and remove button if the product is in cart
if (!widget.isCheckout)
widget.isInCart
?
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: Get.height * 0.05,
width: Get.width * 0.40,
decoration: BoxDecoration(
color: const Color(0xFF004791),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
height: 25,
width: 25,
child: ElevatedButton(
onPressed: () {
_cartController.decreaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
backgroundColor:Color(0xFF004791),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'-',
style: GoogleFonts.roboto(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
// Text(
// "${currentQuantity}",
// style: const TextStyle(
// color: Colors.white,
// fontSize: 16,
// ),
// Expanded(
// child: TextFormField(
// // decoration:InputDecoration(
// // border: InputBorder.none,
// // ),
//
// controller: quantityController,
// style: TextStyle(color: Color(0xFF004791),fontWeight: FontWeight.bold),
// keyboardType: TextInputType.number,
//
// textAlign: TextAlign.center,
// onFieldSubmitted: (value) {
// int enteredQuantity = int.tryParse(value) ?? currentQuantity;
// if (enteredQuantity <= 0) {
// showSnackbar("Quantity must be at least 1");
// enteredQuantity = 1;
// }
// setState(() {
// currentQuantity = enteredQuantity;
// _cartController.updateQuantity(
// widget.productModel!, currentQuantity);
// });
// },
// decoration: const InputDecoration(
//
// contentPadding: EdgeInsets.only(left: 8.0,right: 8.0,bottom: 8.0),
// border: OutlineInputBorder(
// //
// ),
// ),
// ),
// ),
SizedBox(width: 5,),
Expanded(
child: TextFormField(
controller: quantityController,
style: const TextStyle(
color: Color(0xFF004791),
fontWeight: FontWeight.bold,
fontSize: 16,
),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
onFieldSubmitted: (value) {
int enteredQuantity = int.tryParse(value) ?? currentQuantity;
if (enteredQuantity <= 0) {
showSnackbar("Quantity must be at least 1");
enteredQuantity = 1;
}
setState(() {
currentQuantity = enteredQuantity;
_cartController.updateQuantity(widget.productModel!, currentQuantity);
});
},
decoration: InputDecoration(
labelText: "Enter Quantity",
labelStyle: const TextStyle(
color: Color(0xFF004791),
fontWeight: FontWeight.w600,
fontSize: 14,
),
hintText: "",
hintStyle: const TextStyle(
color: Colors.grey,
fontWeight: FontWeight.w400,
fontSize: 14,
),
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Color(0xFF004791),
width: 1.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Color(0xFF004791),
width: 2,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Colors.red,
width: 1.5,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Colors.red,
width: 2,
),
),
),
),
),
SizedBox(width: 5,),
SizedBox(
height: 25,
width: 25,
child: ElevatedButton(
onPressed: () {
_cartController.increaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF004791),
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'+',
style: GoogleFonts.roboto(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
SizedBox(
width: 1.0,
),
// IconButton(
// onPressed: () {
// _cartController.removeFromCart(widget.productModel!);
// showSnackbar("Product has been removed successfully!");
// setState(() {
// currentQuantity = 1;
// });
// },
// icon: const Icon(
// Icons.delete_outline_rounded,
// color: Colors.red,
// ),
// ),
],
)
: ElevatedButton(
onPressed: () {
@ -249,6 +401,211 @@ class _ProductCardState extends State<ProductCard> {
],
),
),
),
);
}
}
//
// class ProductCard extends StatefulWidget {
// final Product? productModel;
// PlacedOrderModel? placedOrder;
// PlacedOrderList? placedOrderList;
// PlaceOrderItem1? placeorderItem;
// PlacedOrdersResponse ? placeRDOrder;
// ProductModel? product;
// final bool isInCart;
// final bool isCheckout;
// final bool isConfirmation;
// int? quantity;
//
// ProductCard({
// super.key,
// this.product,
// this.quantity = 1,
// this.productModel,
// this.placedOrder,
// this.placedOrderList,
// this.placeorderItem,
// this.placeRDOrder,
// this.isInCart = false,
// this.isCheckout = false,
// this.isConfirmation = false,
// });
//
// @override
// State<ProductCard> createState() => _ProductCardState();
// }
//
// class _ProductCardState extends State<ProductCard> {
// final CartController _cartController = Get.put(CartController());
//
// String capitalizeFirstLetter(String text) {
// if (text.isEmpty) return text;
// return text[0].toUpperCase() + text.substring(1).toLowerCase();
// }
//
// @override
// Widget build(BuildContext context) {
// bool showQuantity = widget.isInCart || widget.isCheckout || widget.isConfirmation;
// bool isProductInCart = _cartController.cartList.any((p) => p.id == widget.productModel!.id);
//
// // Get the current quantity of the product
// int currentQuantity = isProductInCart
// ? _cartController.cartList.firstWhere((p) => p.id == widget.productModel!.id).quantity
// : widget.productModel!.quantity ?? 1;
//
// TextEditingController quantityController =
// TextEditingController(text: currentQuantity.toString());
//
// return GestureDetector(
// onTap: () => widget.isInCart || widget.isCheckout
// ? null
// : Get.to(() => ProductDetailScreen(productModel: widget.productModel)),
// child: Card(
// child: Row(
// children: [
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: ClipRRect(
// borderRadius: BorderRadius.circular(15.0),
// child: Container(
// height: Get.height * 0.15,
// width: Get.width * 0.31,
// decoration: const BoxDecoration(
// image: DecorationImage(
// image: AssetImage("assets/images/product.png"),
// fit: BoxFit.cover,
// ),
// ),
// ),
// ),
// ),
// Expanded(
// child: Padding(
// padding: const EdgeInsets.symmetric(horizontal: 3.0),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// capitalizeFirstLetter(widget.productModel!.name),
// style: GoogleFonts.roboto(
// fontSize: 16,
// fontWeight: FontWeight.w500,
// ),
// ),
// Text(
// capitalizeFirstLetter(widget.productModel!.category!.categoryName),
// style: GoogleFonts.roboto(
// fontSize: 14,
// fontWeight: FontWeight.w400,
// ),
// ),
// Text(
// "${widget.productModel!.price.toString()}",
// style: GoogleFonts.roboto(
// fontSize: 22,
// fontWeight: FontWeight.w700,
// ),
// ),
// if (showQuantity)
// Row(
// children: [
// SizedBox(
// width: 50,
// child: TextFormField(
// controller: quantityController,
// keyboardType: TextInputType.number,
// textAlign: TextAlign.center,
// onFieldSubmitted: (value) {
// int enteredQuantity = int.tryParse(value) ?? currentQuantity;
// if (enteredQuantity <= 0) {
// showSnackbar("Quantity must be at least 1");
// enteredQuantity = 1;
// }
// setState(() {
// currentQuantity = enteredQuantity;
// _cartController.updateQuantity(
// widget.productModel!, currentQuantity);
// });
// },
// decoration: const InputDecoration(
// contentPadding: EdgeInsets.all(8),
// border: OutlineInputBorder(),
// ),
// ),
// ),
// IconButton(
// onPressed: () {
// _cartController.decreaseQuantity(widget.productModel!);
// setState(() {
// currentQuantity = _cartController
// .cartList
// .firstWhere((p) => p.id == widget.productModel!.id)
// .quantity;
// quantityController.text = currentQuantity.toString();
// });
// },
// icon: const Icon(Icons.remove),
// ),
// IconButton(
// onPressed: () {
// _cartController.increaseQuantity(widget.productModel!);
// setState(() {
// currentQuantity = _cartController
// .cartList
// .firstWhere((p) => p.id == widget.productModel!.id)
// .quantity;
// quantityController.text = currentQuantity.toString();
// });
// },
// icon: const Icon(Icons.add),
// ),
// ],
// ),
// if (!widget.isCheckout)
// widget.isInCart
// ? Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// ElevatedButton(
// onPressed: () {
// _cartController.removeFromCart(widget.productModel!);
// showSnackbar("Product removed successfully!");
// setState(() {
// currentQuantity = 1;
// quantityController.text = currentQuantity.toString();
// });
// },
// style: ElevatedButton.styleFrom(
// backgroundColor: Colors.red,
// ),
// child: const Text("Remove"),
// ),
// ],
// )
// : ElevatedButton(
// onPressed: () {
// if (isProductInCart) {
// showSnackbar("Product already added to cart");
// } else {
// _cartController.addToCart(widget.productModel!);
// showSnackbar("Product added to cart successfully!");
// }
// },
// child: const Text("Add To Cart"),
// ),
// ],
// ),
// ),
// ),
// ],
// ),
// ),
// );
// }
// }

View File

@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cheminova/controller/cart_controller.dart';
import 'package:cheminova/controller/rd_get_order_controller.dart';
import 'package:cheminova/models/rd_get_order_model.dart';
@ -5,6 +6,8 @@ import 'package:cheminova/models/rd_order_item_model.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import '../utils/show_snackbar.dart';
class ProductCard1 extends StatefulWidget {
final RDOrderItem productModel; // The specific product to be displayed
int? quantity;
@ -24,16 +27,20 @@ class _ProductCard1State extends State<ProductCard1> {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
String? imageurl;
@override
Widget build(BuildContext context) {
final CartController _cartController = Get.put(CartController());
TextEditingController quantityController =
TextEditingController();
// Current quantity the user wants to process
int processQuantity = widget.productModel.processquantity ?? 1;
// Total available quantity
int availableQuantity = widget.productModel.remainingQuantity ?? 1;
imageurl = widget.productModel.image.isNotEmpty
? widget.productModel.image[0].url
: 'assets/images/no_image_available.jpg';
return Card(
child: Row(
@ -45,9 +52,12 @@ class _ProductCard1State extends State<ProductCard1> {
child: Container(
height: Get.height * 0.15,
width: Get.width * 0.31,
decoration: const BoxDecoration(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/product.png"),
image:
imageurl!.startsWith('http')
? CachedNetworkImageProvider(imageurl!) as ImageProvider
: AssetImage(imageurl!),
fit: BoxFit.cover,
),
),
@ -158,6 +168,39 @@ class _ProductCard1State extends State<ProductCard1> {
fontSize: 16,
),
),
// Expanded(
// child: TextFormField(
// // decoration:InputDecoration(
// // border: InputBorder.none,
// // ),
//
// controller: quantityController,
// style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold),
// keyboardType: TextInputType.number,
//
// textAlign: TextAlign.center,
// onFieldSubmitted: (value) {
// int enteredQuantity = int.tryParse(value) ?? processQuantity;
// if (enteredQuantity <= 0) {
// showSnackbar("Quantity must be at least 1");
// enteredQuantity = 1;
// }
// // setState(() {
// // // widget.productModel.processquantity = enteredQuantity;
// // // // _cartController.updateQuantity(
// // // // widget.productModel.processquantity!, processQuantity);
// // processQuantity = enteredQuantity;
// // widget.productModel.processquantity = processQuantity;
// // });
// },
// decoration: const InputDecoration(
//
// contentPadding: EdgeInsets.only(left: 8.0,right: 8.0,bottom: 8.0),
// // border: OutlineInputBorder(),
// ),
// ),
// ),
// Increase quantity button
SizedBox(
height: 22,

View File

@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 2.0.1+1
version: 2.0.2+1
environment:
sdk: ">=3.4.1 <4.0.0"