diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3b67b1c..32cd1dd 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ + [].obs; + + int _currentPage = 1; + bool isLoading = false; + + @override + void onInit() { + super.onInit(); + + } + + Future getOrder(String id) async { + if (isLoading) return; + isLoading = true; + try { + + final fetchedProducts = await _getOrderPlacedServcie.getPlacedOrder(); + + + if (fetchedProducts != null) { + + products.addAll(fetchedProducts); + } + } catch (e) { + print("Error fetching products: $e"); + } finally { + isLoading = false; + update(); + } + } +} diff --git a/lib/controller/get_place_order_service.dart b/lib/controller/get_place_order_service.dart new file mode 100644 index 0000000..932317b --- /dev/null +++ b/lib/controller/get_place_order_service.dart @@ -0,0 +1,35 @@ +import 'package:cheminova/models/oder_place_model.dart'; + +import '../utils/common_api_service.dart'; +import '../utils/show_snackbar.dart'; + +class GetOrderPlacedServcie{ + Future?> getPlacedOrder() async { + try { + String url; + + url = "/api/get-placed-order-pd?id=66cc7869f02b935094127a27"; + + final response = await commonApiService>( + method: "GET", + url: url, + fromJson: (json) { + if (json['plcaedOrders'] != null) { + final List products = (json['plcaedOrders'] as List) + .map((productJson) => PlacedOrderModel.fromJson(productJson as Map)) + .toList(); + return products; + } else { + return []; + } + }, + ); + return response; + } catch (e) { + showSnackbar(e.toString()); + + return null; + } + } +} + diff --git a/lib/controller/home_controller.dart b/lib/controller/home_controller.dart index f6e9a0b..26f243c 100644 --- a/lib/controller/home_controller.dart +++ b/lib/controller/home_controller.dart @@ -1,9 +1,11 @@ import 'package:cheminova/controller/home_service.dart'; import 'package:cheminova/models/user_model.dart'; import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class HomeController extends GetxController { final HomeService homeService = HomeService(); + var user = Rxn(); @override @@ -12,8 +14,10 @@ class HomeController extends GetxController { super.onInit(); } - Future getUser() async { - user.value = await homeService.getUser(); - update(); + Future getUser() async + { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? token = prefs.getString('token'); + user.value = (await homeService.getUser(token: token)) as UserModel? ; } } diff --git a/lib/controller/home_service.dart b/lib/controller/home_service.dart index 332ca60..ba5ed41 100644 --- a/lib/controller/home_service.dart +++ b/lib/controller/home_service.dart @@ -3,12 +3,15 @@ import 'package:cheminova/utils/common_api_service.dart'; import 'package:cheminova/utils/show_snackbar.dart'; class HomeService { - Future getUser() async { + Future?> getUser({String? token}) async { try { - final response = await commonApiService( + final response = await commonApiService>( method: "GET", - url: "/api/territorymanager/my-profile", - fromJson: (json) => UserModel.fromJson(json), + url: "api/v1/user/details", + fromJson: (json) => json, + additionalHeaders: { // Pass the token here + 'Authorization': 'Bearer $token', + }, ); return response; @@ -17,4 +20,6 @@ class HomeService { } return null; } + + } diff --git a/lib/controller/place_order_controller.dart b/lib/controller/place_order_controller.dart new file mode 100644 index 0000000..a2e56c1 --- /dev/null +++ b/lib/controller/place_order_controller.dart @@ -0,0 +1,129 @@ +import 'dart:convert'; +import 'package:cheminova/controller/place_order_service.dart'; +import 'package:cheminova/models/product_model.dart'; +import 'package:dio/dio.dart'; +import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../models/oder_place_model.dart'; + + +class OrderPlacedController extends GetxController { + var placedOrder1 = PlacedOrderModel( + paymentMode: 'cheque', + shipTo: '456, Park Street, Kolkata, West Bengal - 700016', + billTo: '456, Park Street, Kolkata, West Bengal - 700016', + subtotal: 300, + gstTotal: 100, + grandTotal: 400, + orderItems: [ + ], + ).obs; + + var isLoading = false.obs; + + final OrderPlacedService _orderPlacedService = OrderPlacedService(); + + Future placeOrder() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? token = prefs.getString('token'); + isLoading.value = true; + //try { + // Construct order details + PlacedOrderModel orderDetails = placedOrder1.value; + print("Order Details: $orderDetails"); + + // Call the service to place the order + await _orderPlacedService.placeOrder(orderDetails, token!); + + } + // catch (e) { + // + // } finally { + // isLoading.value = false; + // } + } + + + + + + + + +// import 'package:cheminova/controller/place_order_service.dart'; +// import 'package:cheminova/models/category_model.dart'; +// import 'package:get/get.dart'; +// import 'package:shared_preferences/shared_preferences.dart'; +// import '../models/oder_place_model.dart'; +// import 'cart_controller.dart'; +// +// +// class OrderPlacedController extends GetxController { +// final OrderPlacedService _orderPlacedService = OrderPlacedService(); +// final CartController _cartController = Get.find(); +// Rx placedOrder1 = Rx(null); +// RxBool isLoading = false.obs; +// +// // Method to place an order with provided details +// Future placeOrder() async { +// SharedPreferences prefs = await SharedPreferences.getInstance(); +// String? token = prefs.getString('token'); +// +// // Prepare order details +// final order = PlacedOrderModel( +// paymentMode: 'cheque', +// shipTo: '456, Park Street, Kolkata, West Bengal - 700016', +// billTo: '456, Park Street, Kolkata, West Bengal - 700016', +// subtotal: 4000, +// gstTotal: 18, +// grandTotal: 4720, +// orderItems: [ +// OrderItem( +// id: "66cc7869f02b935094127a27", +// sku: "BJD", +// name: "Zycor 60m.l", +// price: 4000, +// gst: 18, +// hsnCode: 200, +// description: "", +// productStatus: "Active", +// addedBy: "ChemiNova", +// image: [], +// createdAt: DateTime.parse("2024-08-26T12:43:21.103Z"), +// updatedAt: DateTime.parse("2024-08-26T12:43:21.103Z"), +// count: 1, category:Category(id: "66cc7868f02b935094127a21", categoryName: "Insectiside") , +// brand: Brand(id: "66cc77fbf02b9350941279f5", brandName: "Old"), v: 0, +// ), +// ], +// ); +// +// try { +// isLoading.value = true; +// PlacedOrderModel? result = await _orderPlacedService.placeOrder(order, token); +// if (result != null) { +// placedOrder1.value = result; +// Get.snackbar('Success', 'Order placed successfully.'); +// // _cartController.clearCart(); // Clear cart items after order +// } else { +// Get.snackbar('Error', 'Failed to place order.'); +// } +// } catch (e) { +// Get.snackbar('Error', e.toString()); +// } finally { +// isLoading.value = false; +// } +// } +// +// String getShippingAddress() { +// return placedOrder1.value?.shipTo ?? 'No shipping address'; +// } +// +// String getBillingAddress() { +// return placedOrder1.value?.billTo ?? 'No billing address'; +// } +// +// String getPaymentMode() { +// return placedOrder1.value?.paymentMode ?? 'No payment mode'; +// } +// } diff --git a/lib/controller/place_order_service.dart b/lib/controller/place_order_service.dart new file mode 100644 index 0000000..418bade --- /dev/null +++ b/lib/controller/place_order_service.dart @@ -0,0 +1,41 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:cheminova/models/product_model.dart'; +import 'package:dio/dio.dart'; + +import '../models/oder_place_model.dart'; +import '../utils/log_service.dart'; + +class OrderPlacedService { + final Dio dio = Dio(); + + Future placeOrder(PlacedOrderModel orderDetails, String token) async { + //try { + logger.w("orderjson ${jsonEncode(orderDetails.toJson())}"); + final response = await dio.post( + 'https://cheminova-api-2.onrender.com/api/order-place', // Ensure this is your correct endpoint + data: jsonEncode(orderDetails.toJson()), + options: Options( + headers: { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }, + ), + ); + logger.w("Status code,${response.statusCode}"); + if (response.statusCode != 201) { + + throw Exception('Failed to place order'); + } + } + // on DioException catch (e) { + // print("DioException: ${e.message}"); + // throw Exception('Failed to place order: ${e.message}'); + // } + // catch (e) { + // print("General Exception: ${e.toString()}"); + // throw Exception('Failed to place order: ${e.toString()}'); + // } + } + diff --git a/lib/controller/product_controller.dart b/lib/controller/product_controller.dart index 5af5929..071458b 100644 --- a/lib/controller/product_controller.dart +++ b/lib/controller/product_controller.dart @@ -1,10 +1,11 @@ import 'package:cheminova/controller/product_service.dart'; +import 'package:cheminova/models/product_model1.dart'; import 'package:get/get.dart'; class ProductController extends GetxController { final ProductService productService = ProductService(); - var products = >[].obs; + var products = [].obs; var categories = [].obs; // Holds the list of categories var selectedCategory = Rxn(); // Holds the selected category int _currentPage = 1; @@ -28,7 +29,9 @@ class ProductController extends GetxController { ); if (fetchedProducts != null) { - products.addAll(fetchedProducts as Iterable>); + // Directly add the fetched products (which are of type List) to the list + products.addAll(fetchedProducts); + print("fetchedProducts ,$fetchedProducts"); } } catch (e) { print("Error fetching products: $e"); diff --git a/lib/controller/product_service.dart b/lib/controller/product_service.dart index 0b13240..b9796cb 100644 --- a/lib/controller/product_service.dart +++ b/lib/controller/product_service.dart @@ -1,8 +1,9 @@ +import '../models/product_model1.dart'; import '../utils/common_api_service.dart'; import '../utils/show_snackbar.dart'; class ProductService { - Future>?> getProduct(int page, {String? category}) async { + Future?> getProduct(int page, {String? category}) async { try { String url; if (category != null && category.isNotEmpty) { @@ -11,13 +12,13 @@ class ProductService { url = "/api/product/getAll/user?page=$page"; // URL without category filter } - final response = await commonApiService>>( + final response = await commonApiService>( method: "GET", url: url, fromJson: (json) { if (json['products'] != null) { - final List> products = (json['products'] as List) - .map((productJson) => productJson as Map) + final List products = (json['products'] as List) + .map((productJson) => Product.fromJson(productJson as Map)) .toList(); return products; } else { @@ -27,10 +28,10 @@ class ProductService { ); return response; } catch (e) { - showSnackbar(e.toString()); - //print("Error: $e"); + // showSnackbar(e.toString()); + + return null; } - return null; } diff --git a/lib/models/added_by_model.dart b/lib/models/added_by_model.dart new file mode 100644 index 0000000..dedcb72 --- /dev/null +++ b/lib/models/added_by_model.dart @@ -0,0 +1,23 @@ +class AddedBy { + String id; + String name; + + AddedBy({ + required this.id, + required this.name, + }); + + factory AddedBy.fromJson(Map json) => AddedBy( + id: json["_id"], + name: json["name"], + ); + + Map toJson() => { + "_id": id, + "name": name, + }; + @override + String toString() { + return 'AddedBy(id: $id, brandName: $AddedBy,)'; + } +} \ No newline at end of file diff --git a/lib/models/brand_model.dart b/lib/models/brand_model.dart new file mode 100644 index 0000000..f377412 --- /dev/null +++ b/lib/models/brand_model.dart @@ -0,0 +1,27 @@ +class Brand { + final String id; + final String brandName; + + Brand({ + required this.id, + required this.brandName, + }); + + factory Brand.fromJson(Map json) { + return Brand( + id: json['_id'], + brandName: json['brandName'], + ); + } + Map toJson() { + return { + '_id': id, + 'brandName': brandName, + + }; + } + @override + String toString() { + return 'Brand(id: $id, brandName: $brandName,)'; + } +} \ No newline at end of file diff --git a/lib/models/cart_item_model.dart b/lib/models/cart_item_model.dart new file mode 100644 index 0000000..2f392fe --- /dev/null +++ b/lib/models/cart_item_model.dart @@ -0,0 +1,27 @@ +// lib/models/cart_item.dart +import 'package:cheminova/models/product_model1.dart'; + +class CartItem { + final Product product; + int quantity; + + CartItem({ + required this.product, + this.quantity = 1, + }); + + // Method to increase quantity + void increaseQuantity() { + quantity++; + } + + // Method to decrease quantity + void decreaseQuantity() { + if (quantity > 1) { + quantity--; + } + } + + // Method to get total price of this item + int get totalPrice => product.price * quantity; +} diff --git a/lib/models/category_model.dart b/lib/models/category_model.dart new file mode 100644 index 0000000..5686628 --- /dev/null +++ b/lib/models/category_model.dart @@ -0,0 +1,27 @@ +class Category { + final String id; + final String categoryName; + + Category({ + required this.id, + required this.categoryName, + }); + + factory Category.fromJson(Map json) { + return Category( + id: json['_id'], + categoryName: json['categoryName'], + ); + } + Map toJson() { + return { + '_id': id, + 'categoryName': categoryName, + + }; + } + @override + String toString() { + return 'Category(id: $id, categoryName: $categoryName,)'; + } +} \ No newline at end of file diff --git a/lib/models/oder_place_model.dart b/lib/models/oder_place_model.dart new file mode 100644 index 0000000..112108f --- /dev/null +++ b/lib/models/oder_place_model.dart @@ -0,0 +1,183 @@ +import 'added_by_model.dart'; +import 'brand_model.dart'; +import 'category_model.dart'; + +class PlacedOrderModel { + String paymentMode; + String shipTo; + String billTo; + double subtotal; + double gstTotal; + double grandTotal; + List orderItems; + + PlacedOrderModel({ + required this.paymentMode, + required this.shipTo, + required this.billTo, + required this.subtotal, + required this.gstTotal, + required this.grandTotal, + required this.orderItems, + }); + + Map toJson() => { + 'paymentMode': paymentMode, + 'shipTo': shipTo, + 'billTo': billTo, + 'subtotal': subtotal, + 'gstTotal': gstTotal, + 'grandTotal': grandTotal, + 'orderItems': orderItems.map((item) => item.toJson()).toList(), + }; + + factory PlacedOrderModel.fromJson(Map json) => PlacedOrderModel( + paymentMode: json['paymentMode'], + shipTo: json['shipTo'], + billTo: json['billTo'], + subtotal: json['subtotal'].toDouble(), + gstTotal: json['gstTotal'].toDouble(), + grandTotal: json['grandTotal'].toDouble(), + orderItems: (json['orderItems'] as List).map((item) => OrderItem.fromJson(item)).toList(), + ); + + @override + String toString() { + return 'PlacedOrderModel{paymentMode: $paymentMode, ' + 'shipTo: $shipTo, ' + 'billTo: $billTo, ' + 'subtotal: $subtotal, ' + 'gstTotal: $gstTotal, ' + 'grandTotal: $grandTotal, ' + 'orderItems: ${orderItems.map((item) => item.toString()).join(', ')})'; + } +} + + +class OrderItem { + String id; + String sku; + String name; + double price; + double gst; + int hsnCode; + String description; + String productStatus; + final String addedBy; + List image; + DateTime createdAt; + DateTime updatedAt; + int count; + Category category; + Brand brand; + int v; + + OrderItem({ + required this.id, + required this.sku, + required this.name, + required this.price, + required this.gst, + required this.hsnCode, + required this.description, + required this.productStatus, + required this.addedBy, + required this.image, + required this.createdAt, + required this.updatedAt, + required this.count, + required this.category, + required this.brand, + required this.v, + }); + + // Adjusted toJson method to match the desired format + Map toJson() => { + '_id': id, + 'SKU': sku, + 'name': name, + 'category': category.toJson(), // Ensure Category has a proper toJson method + 'brand': brand.toJson(), // Ensure Brand has a proper toJson method + 'price': price, + 'GST': gst, + 'HSN_Code': hsnCode, + 'description': description, + 'product_Status': productStatus, + 'addedBy': { + '_id': id, // Assuming the addedBy is represented by the id + 'name': addedBy // If addedBy is just a name, use it directly here + }, + 'image': image, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + '__v': v, + 'count': count, + }; + + factory OrderItem.fromJson(Map json) => OrderItem( + id: json['_id'], + sku: json['SKU'], + name: json['name'], + price: json['price'].toDouble(), + gst: json['GST'].toDouble(), + hsnCode: json['HSN_Code'], + description: json['description'], + productStatus: json['product_Status'], + addedBy: json['addedBy']['name'], // Assuming addedBy has a 'name' key + image: List.from(json['image']), + createdAt: DateTime.parse(json['createdAt']), + updatedAt: DateTime.parse(json['updatedAt']), + count: json['count'], + category: Category.fromJson(json['category']), + brand: Brand.fromJson(json['brand']), + v: json['__v'], + ); + + @override + String toString() { + return 'OrderItem(id: $id, sku: $sku, name: $name, price: $price, gst: $gst, hsnCode: $hsnCode, description: $description, productStatus: $productStatus, addedBy: $addedBy, image: $image, createdAt: $createdAt, updatedAt: $updatedAt, count: $count, category: $category, brand: $brand, v: $v)'; + } +} + + + + +// class Brand { +// String id; +// String brandName; +// +// Brand({ +// required this.id, +// required this.brandName, +// }); +// +// factory Brand.fromJson(Map json) => Brand( +// id: json["_id"], +// brandName: json["brandName"], +// ); +// +// Map toJson() => { +// "_id": id, +// "brandName": brandName, +// }; +// } +// +// class Category { +// String id; +// String categoryName; +// +// Category({ +// required this.id, +// required this.categoryName, +// }); +// +// factory Category.fromJson(Map json) => Category( +// id: json["_id"], +// categoryName: json["categoryName"], +// ); +// +// Map toJson() => { +// "_id": id, +// "categoryName": categoryName, +// }; +// } diff --git a/lib/models/order_item_model.dart b/lib/models/order_item_model.dart new file mode 100644 index 0000000..70a198a --- /dev/null +++ b/lib/models/order_item_model.dart @@ -0,0 +1,130 @@ +// import 'brand_model.dart'; +// import 'category_model.dart'; +// +// class OrderItem { +// final String id; +// final String sku; +// final String name; +// final Category category; +// final Brand brand; +// final double price; +// final double gst; +// final int hsnCode; +// final String description; +// final String productStatus; +// final String addedBy; +// final List image; +// final DateTime createdAt; +// final DateTime updatedAt; +// final int count; +// +// OrderItem({ +// required this.id, +// required this.sku, +// required this.name, +// required this.category, +// required this.brand, +// required this.price, +// required this.gst, +// required this.hsnCode, +// required this.description, +// required this.productStatus, +// required this.addedBy, +// required this.image, +// required this.createdAt, +// required this.updatedAt, +// required this.count, +// }); +// +// factory OrderItem.fromJson(Map json) { +// return OrderItem( +// id: json['_id'], +// sku: json['SKU'], +// name: json['name'], +// category: Category.fromJson(json['category']), +// brand: Brand.fromJson(json['brand']), +// price: json['price'].toDouble(), +// gst: json['GST'].toDouble(), +// hsnCode: json['HSN_Code'], +// description: json['description'], +// productStatus: json['product_Status'], +// addedBy: json['addedBy'], +// image: List.from(json['image'] ?? []), +// createdAt: DateTime.parse(json['createdAt']), +// updatedAt: DateTime.parse(json['updatedAt']), +// count: json['count'], +// ); +// } +// +// Map toJson() { +// return { +// '_id': id, +// 'SKU': sku, +// 'name': name, +// 'category': category, +// 'brand': brand, +// 'price': price, +// 'GST': gst, +// 'HSN_Code': hsnCode, +// 'description': description, +// 'product_Status': productStatus, +// 'addedBy': addedBy, +// 'image': image, +// 'createdAt': createdAt.toIso8601String(), +// 'updatedAt': updatedAt.toIso8601String(), +// 'count': count, +// }; +// } +// } +// +// // +// class Category { +// final String id; +// final String categoryName; +// +// Category({ +// required this.id, +// required this.categoryName, +// }); +// +// factory Category.fromJson(Map json) { +// return Category( +// id: json['_id'], +// categoryName: json['categoryName'], +// ); +// } +// } +// +// class Brand { +// final String id; +// final String brandName; +// +// Brand({ +// required this.id, +// required this.brandName, +// }); +// +// factory Brand.fromJson(Map json) { +// return Brand( +// id: json['_id'], +// brandName: json['brandName'], +// ); +// } +// } +// // +// // class AddedBy { +// // final String id; +// // final String name; +// // +// // AddedBy({ +// // required this.id, +// // required this.name, +// // }); +// // +// // factory AddedBy.fromJson(Map json) { +// // return AddedBy( +// // id: json['_id'], +// // name: json['name'], +// // ); +// // } +// // } diff --git a/lib/models/product_model.dart b/lib/models/product_model.dart index e89525d..4ea0452 100644 --- a/lib/models/product_model.dart +++ b/lib/models/product_model.dart @@ -5,6 +5,8 @@ class ProductModel { final String image; final String description; final double price; + String? category1; + String? brandname; final ProductCategory category; final String id; int quantity; @@ -15,7 +17,39 @@ class ProductModel { required this.description, required this.price, required this.category, + this.category1, + this.brandname, required this.id, this.quantity = 1, }); + + // Factory constructor + factory ProductModel.fromJson(Map json) { + return ProductModel( + name: json['name']??"", + image: json['image']??"", + description: json['description']??"", + price: json['price']??"", + category: ProductCategory.values.firstWhere((e) => e.toString().split('.').last == json['category']), + category1: json['category1']??"", + brandname: json['brandname']??"", + id: json['id'], + quantity: json['quantity'] ?? 1, + ); + } + + // Optional: toJson method if you need to convert the model back to JSON + Map toJson() { + return { + 'name': name, + 'image': image, + 'description': description, + 'price': price, + 'category': category.toString().split('.').last, + 'category1': category1, + 'brandname': brandname, + 'id': id, + 'quantity': quantity, + }; + } } diff --git a/lib/models/product_model1.dart b/lib/models/product_model1.dart new file mode 100644 index 0000000..bfaa077 --- /dev/null +++ b/lib/models/product_model1.dart @@ -0,0 +1,116 @@ +import 'brand_model.dart'; +import 'category_model.dart'; + +class Product { + final String id; + final String sku; + final String name; + final Category category; + final Brand brand; + final int price; + int quantity; + final int gst; + final int hsnCode; + final String description; + final String productStatus; + final String addedBy; + final DateTime createdAt; + + Product({ + required this.id, + required this.sku, + required this.name, + required this.category, + required this.brand, + required this.price, + this.quantity =1, + required this.gst, + required this.hsnCode, + required this.description, + required this.productStatus, + required this.addedBy, + required this.createdAt, + }); + + factory Product.fromJson(Map json) { + return Product( + id: json['_id'] as String, + sku: json['SKU'] as String, + name: json['name'] as String, + category:Category.fromJson(json['category'] as Map), + brand: Brand.fromJson(json['brand'] as Map), + price: json['price'] as int, + gst: json['GST'] as int, + hsnCode: json['HSN_Code'] as int, + description: json['description'] ?? '', + productStatus: json['product_Status'] as String, + addedBy: json['addedBy']['name'] as String, + createdAt: DateTime.parse(json['createdAt'] as String), + ); + } + + + // Method to convert a Product to JSON + Map toJson() { + return { + '_id': id, + 'SKU': sku, + 'name': name, + 'category':toJson(), + 'brand':toJson(), + 'price': price, + 'GST': gst, + 'HSN_Code': hsnCode, + 'description': description, + 'product_Status': productStatus, + 'addedBy': { + 'name': addedBy, + }, + 'createdAt': createdAt.toIso8601String(), + }; + } + + // Override toString method for easy printing of Product details + @override + String toString() { + return 'Product(id: $id, sku: $sku, name: $name, category: $category, ' + 'brand: $brand, price: $price, quantity: $quantity, gst: $gst, ' + 'hsnCode: $hsnCode, description: $description, productStatus: $productStatus, ' + 'addedBy: $addedBy, createdAt: $createdAt)'; + } +} + + +// class Category { +// final String id; +// final String categoryName; +// +// Category({ +// required this.id, +// required this.categoryName, +// }); +// +// factory Category.fromJson(Map json) { +// return Category( +// id: json['_id'], +// categoryName: json['categoryName'], +// ); +// } +// } +// +// class Brand { +// final String id; +// final String brandName; +// +// Brand({ +// required this.id, +// required this.brandName, +// }); +// +// factory Brand.fromJson(Map json) { +// return Brand( +// id: json['_id'], +// brandName: json['brandName'], +// ); +// } +// } \ No newline at end of file diff --git a/lib/models/user_model.dart b/lib/models/user_model.dart index a4e5357..b079da9 100644 --- a/lib/models/user_model.dart +++ b/lib/models/user_model.dart @@ -16,11 +16,11 @@ class UserModel { // Factory constructor to create an instance of UserModel from a JSON map factory UserModel.fromJson(Map json) { return UserModel( - id: json['_id'] as String, - name: json['name'] as String, - uniqueId: json['uniqueId'] as String, - email: json['email'] as String, - isVerified: json['isVerified'] as bool, + id: json['_id'] ??"", + name: json['name'] ??"Sarita", + uniqueId: json['uniqueId'] ??"1234", + email: json['email'] ??"", + isVerified: json['isVerified'] as bool? ??false, ); } @@ -34,4 +34,10 @@ class UserModel { 'isVerified': isVerified, }; } + + // Override toString() to provide a readable output + @override + String toString() { + return 'UserModel{id: $id, name: $name, uniqueId: $uniqueId, email: $email, isVerified: $isVerified}'; + } } diff --git a/lib/screens/authentication/forget_password_screen.dart b/lib/screens/authentication/forget_password_screen.dart index 2a9cebf..6c18570 100644 --- a/lib/screens/authentication/forget_password_screen.dart +++ b/lib/screens/authentication/forget_password_screen.dart @@ -132,6 +132,7 @@ class _ForgetPasswordScreenState extends State { onPressed: () => authController.forgotpass(), isLoading: authController.isLoading.value, + ), ], ), diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 2eb9f2f..94167be 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -85,7 +85,7 @@ class _HomeScreenState extends State { HomeCard( title: 'Order Management', onTap: () => Get.to( - () => const OrderManagementScreen(), + () => OrderManagementScreen(), ), ), HomeCard( diff --git a/lib/screens/order/checkout_screen.dart b/lib/screens/order/checkout_screen.dart index 7fa3c14..a7c1fa0 100644 --- a/lib/screens/order/checkout_screen.dart +++ b/lib/screens/order/checkout_screen.dart @@ -1,36 +1,174 @@ -import 'package:cheminova/models/product_model.dart'; -import 'package:cheminova/screens/order/order_confermation_screen.dart'; -import 'package:cheminova/widgets/input_field.dart'; -import 'package:cheminova/widgets/my_drawer.dart'; -import 'package:cheminova/widgets/product_card.dart'; +import 'dart:ffi'; +import 'package:cheminova/controller/get_order_placed_controller.dart'; +import 'package:cheminova/models/added_by_model.dart'; +import 'package:cheminova/models/category_model.dart'; +import 'package:cheminova/utils/show_snackbar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../controller/cart_controller.dart'; +import '../../controller/place_order_controller.dart'; +import '../../controller/place_order_service.dart'; +import '../../controller/product_controller.dart'; +import '../../controller/product_service.dart'; +import '../../models/brand_model.dart'; +import '../../models/oder_place_model.dart'; +import '../../models/product_model1.dart'; +import '../../widgets/my_drawer.dart'; +import '../../widgets/product_card.dart'; +import 'order_confermation_screen.dart'; class CheckoutScreen extends StatefulWidget { - const CheckoutScreen({super.key}); + final Product? productModel; + + PlacedOrderModel? placeOrder; + + CheckoutScreen({super.key, this.productModel, this.placeOrder}); @override State createState() => _CheckoutScreenState(); } class _CheckoutScreenState extends State { - final TextEditingController _addressController = TextEditingController(); - final TextEditingController _contactController = TextEditingController(); + final CartController _cartController = Get.put(CartController()); + final ProductService _productService = ProductService(); + final ProductController _productController = Get.put(ProductController()); + final OrderPlacedController _orderPlacedController = + Get.put(OrderPlacedController()); + final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController()); - final List _checkoutList = [ - ProductModel( - id: "1", - image: 'assets/images/product.png', - name: "Product 1", - category: ProductCategory.food, - description: 'Product 1 description', - price: 100, - ), + int currentPage = 1; + String _groupValue = "cheque"; + + final List _addressList = [ + 'Home - 123 Street, City', + 'Office - 456 Avenue, City', + 'Warehouse - 789 Blvd, City', ]; - String _groupValue = "Credit Card"; + String? _selectedShippingAddress; + String? _selectedBillingAddress; + + @override + void initState() { + super.initState(); + // _getOrder(); + _loadSelectedAddress(); + _loadSelectedPaymentMode(); + + if (_addressList.isNotEmpty) { + _selectedShippingAddress = _addressList.first; + _selectedBillingAddress = _addressList.first; + } + } + + void _saveSelectedAddress() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('selectedShippingAddress', _selectedShippingAddress!); + await prefs.setString('selectedBillingAddress', _selectedBillingAddress!); + } + + void _onShippingAddressChanged(String? value) { + setState(() { + _selectedShippingAddress = value; + }); + _saveSelectedAddress(); + } + + void _onBillingAddressChanged(String? value) { + setState(() { + _selectedBillingAddress = value; + }); + _saveSelectedAddress(); + } + + void _loadSelectedAddress() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + setState(() { + _selectedShippingAddress = + prefs.getString('selectedShippingAddress') ?? _addressList.first; + _selectedBillingAddress = + prefs.getString('selectedBillingAddress') ?? _addressList.first; + }); + } + + void _onPaymentModeChanged(String? value) { + setState(() { + _groupValue = value!; + }); + _saveSelectedPaymentMode(); + } + + void _saveSelectedPaymentMode() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('selectedPaymentMode', _groupValue); + } + + void _loadSelectedPaymentMode() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + setState(() { + _groupValue = prefs.getString('selectedPaymentMode') ?? 'cheque'; + }); + } + + // void _getOrder(){ + // final details = _getPlacedOrderController.getOrder(widget.productModel!.id); + // print("dffgfg,$details"); + // } + void _onPlaceOrder() async { + try { + // Map the cart items (Product) to OrderItem objects + List orderItems = _cartController.cartList.map((product) { + return OrderItem( + id: product.id, + name: product.name, + price: product.price.toDouble(), + sku: product.sku, + gst: product.gst.toDouble(), + hsnCode: product.hsnCode, + description: product.description, + productStatus: product.productStatus, + image: [], + createdAt: product.createdAt, + updatedAt: product.createdAt, + count: product.quantity, + //category:product.category, + category:Category(id: product.category.id, categoryName: product.category.categoryName), + // brand:product.brand, + brand:Brand(id: product.brand.id, brandName: product.brand.brandName), + v: 0, addedBy: product.addedBy, + ); + }).toList(); + + // Update the placedOrder1 value + _orderPlacedController.placedOrder1.value= PlacedOrderModel( + paymentMode: _groupValue, + shipTo: _selectedShippingAddress!, + billTo: _selectedBillingAddress!, + orderItems: orderItems, + gstTotal: _cartController.gstTotal.value, + grandTotal: _cartController.grandTotal.value, + subtotal: _cartController.subtotal.value, + ); + + await _orderPlacedController.placeOrder(); + + if (_orderPlacedController.isLoading.value) { + showSnackbar("OderPlaced Successfully"); + Get.to(() => OrderConfermationScreen( + placedOrder: _orderPlacedController.placedOrder1.value, + )); + } + } catch (e) { + print("PlaceOrderScreen error: $e"); + } + } + + + @override Widget build(BuildContext context) { @@ -63,9 +201,7 @@ class _CheckoutScreenState extends State { ), ), ], - title: const Text( - "Checkout", - ), + title: const Text("Checkout"), ), drawer: const MyDrawer(), body: Stack( @@ -78,9 +214,7 @@ class _CheckoutScreenState extends State { SafeArea( child: Column( children: [ - SizedBox( - height: Get.height * 0.02, - ), + SizedBox(height: Get.height * 0.02), Card( margin: EdgeInsets.symmetric(horizontal: Get.width * 0.05), shape: RoundedRectangleBorder( @@ -106,15 +240,37 @@ class _CheckoutScreenState extends State { ), ), ), - InputField( - hintText: 'Address:', - labelText: 'Address:', - controller: _addressController, + SizedBox(height: 5,), + DropdownButtonFormField( + decoration: InputDecoration( + labelText: 'Shipping Address:', + hintText: 'Select Shipping Address', + border: OutlineInputBorder(), + ), + value: _selectedShippingAddress, + items: _addressList.map((String address) { + return DropdownMenuItem( + value: address, + child: Text(address), + ); + }).toList(), + onChanged: _onShippingAddressChanged, ), - InputField( - hintText: 'Contact:', - labelText: 'Contact:', - controller: _contactController, + SizedBox(height: Get.height * 0.02), + DropdownButtonFormField( + decoration: InputDecoration( + labelText: 'Billing Address:', + hintText: 'Select Billing Address', + border: OutlineInputBorder(), + ), + value: _selectedBillingAddress, + items: _addressList.map((String address) { + return DropdownMenuItem( + value: address, + child: Text(address), + ); + }).toList(), + onChanged: _onBillingAddressChanged, ), Padding( padding: EdgeInsets.symmetric( @@ -136,42 +292,30 @@ class _CheckoutScreenState extends State { SizedBox( height: Get.height * 0.035, child: RadioListTile( - title: const Text("Credit Card"), + title: const Text("cheque"), contentPadding: EdgeInsets.zero, - value: "Credit Card", + value: "cheque", groupValue: _groupValue, - onChanged: (value) { - setState(() { - _groupValue = value.toString(); - }); - }, + onChanged: _onPaymentModeChanged, ), ), SizedBox( height: Get.height * 0.035, child: RadioListTile( - title: const Text("Net Banking"), + title: const Text("online-transfer"), contentPadding: EdgeInsets.zero, - value: "Net Banking", + value: "online-transfer", groupValue: _groupValue, - onChanged: (value) { - setState(() { - _groupValue = value.toString(); - }); - }, + onChanged: _onPaymentModeChanged, ), ), SizedBox( child: RadioListTile( - title: const Text("Cash on Delivery"), + title: const Text("credit"), contentPadding: EdgeInsets.zero, - value: "Cash on Delivery", + value: "credit", groupValue: _groupValue, - onChanged: (value) { - setState(() { - _groupValue = value.toString(); - }); - }, + onChanged: _onPaymentModeChanged, ), ), ], @@ -198,58 +342,68 @@ class _CheckoutScreenState extends State { child: Padding( padding: EdgeInsets.all(Get.width * 0.02), child: ListView.builder( - padding: EdgeInsets.zero, - itemCount: 10, - itemBuilder: (context, index) => - ProductCard( - product: _checkoutList[0], - isCheckout: true, - ), + itemCount: _cartController.cartList.length, + itemBuilder: (context, index) { + final cartItem = + _cartController.cartList[index]; + return ProductCard( + productModel:_cartController.cartList[index] , + isCheckout: true, + quantity: _cartController.cartList[0].quantity, + + + // ListTile( + // title: Text(cartItem.name ?? 'N/A'), + // subtitle: Text( + // 'Quantity: ${cartItem.quantity}'), + // trailing: Text( + // 'Price: \₹${cartItem.price.toStringAsFixed(2)}'), + // ); + );}, ), ), ), Padding( - padding: EdgeInsets.all(Get.width * 0.04), - child: Text( - 'Total Price: ₹ 1000.00', - style: GoogleFonts.roboto( - fontSize: Get.width * 0.05, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + padding: EdgeInsets.all(Get.width * 0.02), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Subtotal: \₹${_cartController.subtotal.value.toStringAsFixed(2)}'), + Text( + 'GST: \₹${_cartController.gstTotal.value.toStringAsFixed(2)}'), + Text( + 'Grand Total: \₹${_cartController.grandTotal.value.toStringAsFixed(2)}'), + ], ), ), ], ), ), + ], ), ), ), - SizedBox( - height: Get.height * 0.025, - ), - SizedBox( - width: Get.width * 0.9, - height: Get.height * 0.06, - child: ElevatedButton( - onPressed: () => - Get.to(() => const OrderConfermationScreen()), - style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, - backgroundColor: const Color(0xFF00784C), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + SizedBox(height: 10.0,), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: _onPlaceOrder, + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: const Color(0xFF00784C), + padding: EdgeInsets.symmetric( + horizontal: Get.width * 0.20, + vertical: Get.height * 0.02), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), ), + child: const Text("Place Order"), ), - child: Text( - "Place Order", - style: GoogleFonts.roboto( - fontSize: Get.width * 0.04, - fontWeight: FontWeight.w600, - ), - ), - ), + ], ), ], ), diff --git a/lib/screens/order/order_confermation_screen.dart b/lib/screens/order/order_confermation_screen.dart index f999773..bce749a 100644 --- a/lib/screens/order/order_confermation_screen.dart +++ b/lib/screens/order/order_confermation_screen.dart @@ -1,4 +1,6 @@ +import 'package:cheminova/controller/get_order_placed_controller.dart'; import 'package:cheminova/models/product_model.dart'; +import 'package:cheminova/utils/show_snackbar.dart'; import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/product_card.dart'; import 'package:flutter/material.dart'; @@ -6,8 +8,15 @@ import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import '../../controller/cart_controller.dart'; +import '../../controller/place_order_controller.dart'; +import '../../models/oder_place_model.dart'; +import '../../models/product_model1.dart'; + class OrderConfermationScreen extends StatefulWidget { - const OrderConfermationScreen({super.key}); + Product? productModel; + PlacedOrderModel? placedOrder; + OrderConfermationScreen({super.key,this.productModel,this.placedOrder}); @override State createState() => @@ -15,18 +24,28 @@ class OrderConfermationScreen extends StatefulWidget { } class _OrderConfermationScreenState extends State { - final List _checkoutList = [ - ProductModel( - id: "1", - image: 'assets/images/product.png', - name: "Product 1", - category: ProductCategory.food, - description: 'Product 1 description', - price: 100.00, - ), - ]; + final CartController _cartController = Get.put(CartController()); + final OrderPlacedController _placedController = Get.put(OrderPlacedController()); + final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController()); + // final List _checkoutList = [ + // ProductModel( + // id: "1", + // image: 'assets/images/product.png', + // name: "Product 1", + // category: ProductCategory.food, + // description: 'Product 1 description', + // price: 100.00, + // ), + // ]; + + void _getOrder(){ + final details = _getPlacedOrderController.getOrder(_cartController.cartList[0].id); + showSnackbar("Get Placed Order Sucessfully"); + print("dffgfg,$details"); + } @override Widget build(BuildContext context) { + final orderItems = _placedController.placedOrder1; return Scaffold( extendBodyBehindAppBar: true, appBar: AppBar( @@ -94,7 +113,7 @@ class _OrderConfermationScreenState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Text( - "Order Number: 123456", + "Order Number:1234", style: GoogleFonts.roboto( fontSize: Get.width * 0.04, fontWeight: FontWeight.w400, @@ -124,24 +143,27 @@ class _OrderConfermationScreenState extends State { padding: EdgeInsets.all(Get.width * 0.02), child: ListView.builder( padding: EdgeInsets.zero, - itemCount: 10, + itemCount: _cartController.cartList.length, itemBuilder: (context, index) => ProductCard( - product: _checkoutList[0], + productModel:_cartController.cartList[index], isCheckout: true, ), ), ), ), Padding( - padding: EdgeInsets.all(Get.width * 0.04), - child: Text( - 'Total Price: ₹ 1000.00', - style: GoogleFonts.roboto( - fontSize: Get.width * 0.05, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + padding: EdgeInsets.all(Get.width * 0.02), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + 'Subtotal: \₹${_cartController.subtotal.value.toStringAsFixed(2)}'), + Text( + 'GST: \₹${_cartController.gstTotal.value.toStringAsFixed(2)}'), + Text( + 'Grand Total: \₹${_cartController.grandTotal.value.toStringAsFixed(2)}'), + ], ), ), ], @@ -161,30 +183,30 @@ class _OrderConfermationScreenState extends State { Card( child: SizedBox( width: Get.width, - height: Get.height * 0.2, + height: Get.height * 0.1, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(8.0), child: Text( - "Address: Lorem Ipsum is simply dummy text of the printing and typesetting industry", - style: GoogleFonts.roboto( - fontSize: Get.width * 0.04, - fontWeight: FontWeight.w400, - ), - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - "Contact: +91 9123456789", + "Address :${widget.placedOrder!.shipTo}", style: GoogleFonts.roboto( fontSize: Get.width * 0.04, fontWeight: FontWeight.w400, ), ), ), + // Padding( + // padding: const EdgeInsets.all(8.0), + // child: Text( + // "Contact: +91 9123456789", + // style: GoogleFonts.roboto( + // fontSize: Get.width * 0.04, + // fontWeight: FontWeight.w400, + // ), + // ), + // ), ], ), ), @@ -196,7 +218,7 @@ class _OrderConfermationScreenState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Text( - "Estimated Delivery Date: [Date]", + "Estimated Delivery Date: 20 Sep 2024", style: GoogleFonts.roboto( fontSize: Get.width * 0.04, fontWeight: FontWeight.w400, @@ -205,10 +227,30 @@ class _OrderConfermationScreenState extends State { ), ), ), + ], ), ), ), + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // ElevatedButton( + // onPressed:_getOrder, + // style: ElevatedButton.styleFrom( + // foregroundColor: Colors.white, + // backgroundColor: const Color(0xFF00784C), + // padding: EdgeInsets.symmetric( + // horizontal: Get.width * 0.20, + // vertical: Get.height * 0.02), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(10), + // ), + // ), + // child: const Text("Confirm Order"), + // ), + // ], + // ), ], ), ), diff --git a/lib/screens/order_management/order_fullfilment_screen.dart b/lib/screens/order_management/order_fullfilment_screen.dart index 70821ef..5475d79 100644 --- a/lib/screens/order_management/order_fullfilment_screen.dart +++ b/lib/screens/order_management/order_fullfilment_screen.dart @@ -6,24 +6,19 @@ import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import '../../controller/cart_controller.dart'; +import '../../models/product_model1.dart'; + class OrderFullfilmentScreen extends StatefulWidget { - const OrderFullfilmentScreen({super.key}); + final Product? productModel; + const OrderFullfilmentScreen({super.key,required this.productModel}); @override State createState() => _OrderFullfilmentScreenState(); } class _OrderFullfilmentScreenState extends State { - final List _checkoutList = [ - ProductModel( - id: "1", - image: 'assets/images/image_1.png', - name: "Product 1", - category: ProductCategory.food, - description: 'Product 1 description', - price: 100, - ), - ]; + final CartController _cartController = Get.put(CartController()); @override Widget build(BuildContext context) { return Scaffold( @@ -153,7 +148,7 @@ class _OrderFullfilmentScreenState extends State { padding: EdgeInsets.zero, itemCount: 10, itemBuilder: (context, index) => ProductCard( - product: _checkoutList[0], + productModel:widget.productModel, isCheckout: true, ), ), diff --git a/lib/screens/order_management/order_management_detail_screen.dart b/lib/screens/order_management/order_management_detail_screen.dart index 698ee92..a5ef30c 100644 --- a/lib/screens/order_management/order_management_detail_screen.dart +++ b/lib/screens/order_management/order_management_detail_screen.dart @@ -1,31 +1,38 @@ import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/screens/order_management/order_fullfilment_screen.dart'; import 'package:cheminova/widgets/product_card.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import '../../controller/cart_controller.dart'; +import '../../models/product_model1.dart'; + class OrderManagementDetailScreen extends StatefulWidget { - const OrderManagementDetailScreen({super.key}); + final Product? productModel; + const OrderManagementDetailScreen({super.key,required this.productModel}); @override State createState() => _OrderManagementDetailScreenState(); } + class _OrderManagementDetailScreenState extends State { - final List _checkoutList = [ - ProductModel( - id: "1", - image: 'assets/images/image_1.png', - name: "Product 1", - category: ProductCategory.food, - description: 'Product 1 description', - price: 100, - ), - ]; + final CartController _cartController = Get.put(CartController()); + // final List _checkoutList = [ + // ProductModel( + // id: "1", + // image: 'assets/images/image_1.png', + // name: "Product 1", + // category: ProductCategory.food, + // description: 'Product 1 description', + // price: 100, + // ), + // ]; @override Widget build(BuildContext context) { return Scaffold( @@ -155,7 +162,7 @@ class _OrderManagementDetailScreenState padding: EdgeInsets.zero, itemCount: 10, itemBuilder: (context, index) => ProductCard( - product: _checkoutList[0], + productModel: widget.productModel, isCheckout: true, ), ), @@ -236,7 +243,9 @@ class _OrderManagementDetailScreenState height: Get.height * 0.06, child: ElevatedButton( onPressed: () => Get.to( - () => const OrderFullfilmentScreen(), + () => OrderFullfilmentScreen( + productModel:widget.productModel , + ), ), style: ElevatedButton.styleFrom( foregroundColor: Colors.white, diff --git a/lib/screens/order_management/order_management_screen.dart b/lib/screens/order_management/order_management_screen.dart index f6341c7..a0dfda0 100644 --- a/lib/screens/order_management/order_management_screen.dart +++ b/lib/screens/order_management/order_management_screen.dart @@ -6,8 +6,11 @@ import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import '../../models/product_model1.dart'; + class OrderManagementScreen extends StatefulWidget { - const OrderManagementScreen({super.key}); + Product? productModel; + OrderManagementScreen({super.key,this.productModel}); @override State createState() => _OrderManagementScreenState(); @@ -177,7 +180,9 @@ class _OrderManagementScreenState extends State { child: ElevatedButton( onPressed: () => Get.to( () => - const OrderManagementDetailScreen(), + OrderManagementDetailScreen( + productModel:widget.productModel, + ), ), style: ElevatedButton.styleFrom( foregroundColor: Colors.white, diff --git a/lib/screens/product/cart_screen.dart b/lib/screens/product/cart_screen.dart index 4c7babb..f2022a7 100644 --- a/lib/screens/product/cart_screen.dart +++ b/lib/screens/product/cart_screen.dart @@ -1,3 +1,4 @@ +import 'package:cheminova/models/oder_place_model.dart'; import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/screens/order/checkout_screen.dart'; import 'package:cheminova/widgets/my_drawer.dart'; @@ -5,27 +6,31 @@ import 'package:cheminova/widgets/product_card.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; -import 'package:get/get_core/get_core.dart'; import 'package:google_fonts/google_fonts.dart'; +import '../../controller/cart_controller.dart'; +import '../../models/product_model1.dart'; + class CartScreen extends StatefulWidget { - const CartScreen({super.key}); + Product? productModel; + PlacedOrderModel? placedOrder; + CartScreen({super.key, this.productModel,this.placedOrder}); @override State createState() => _CartScreenState(); } class _CartScreenState extends State { - final List _cartList = [ - ProductModel( - id: "1", - image: 'assets/images/product.png', - name: "Product 1", - category: ProductCategory.food, - description: 'Product 1 description', - price: 100, - ), - ]; + final CartController _cartController = Get.find(); + + // @override + void initState() { + super.initState(); + if (widget.productModel != null) { + _cartController.addToCart(widget.productModel); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -89,29 +94,59 @@ class _CartScreenState extends State { children: [ SizedBox( height: Get.height * 0.6, - child: ListView.builder( - padding: EdgeInsets.zero, - itemCount: 10, - itemBuilder: (context, index) => ProductCard( - product: _cartList[0], - isInCart: true, - ), - ), + child: Obx(() { + return ListView.builder( + padding: EdgeInsets.zero, + itemCount: _cartController.cartList.length, + itemBuilder: (context, index) => ProductCard( + productModel: _cartController.cartList[index], + isInCart: true, + placedOrder:widget.placedOrder, + ), + ); + }), ), const SizedBox( height: 10, ), - Text( - "Total Price: ₹ Total", - style: GoogleFonts.roboto( - fontSize: 20, - fontWeight: FontWeight.w700, - color: Colors.white, - ), - ), - const SizedBox( - height: 16, - ), + Obx(() { + return Text( + "Subtotal Price: ₹ ${_cartController.subtotal.value}", + style: GoogleFonts.roboto( + fontSize: 15, + fontWeight: FontWeight.w700, + color: Colors.white, + ), + ); + + }), + + + // const SizedBox( + // height: 16, + // ), + Obx(() { + return Text( + "gstTotal Price: ₹ ${_cartController.gstTotal.value}", + style: GoogleFonts.roboto( + fontSize: 15, + fontWeight: FontWeight.w700, + color: Colors.white, + ), + ); + + }), + Obx(() { + return Text( + "grandTotal Price: ₹ ${_cartController.grandTotal.value}", + style: GoogleFonts.roboto( + fontSize: 15, + fontWeight: FontWeight.w700, + color: Colors.white, + ), + ); + + }), ], ), ), @@ -123,7 +158,10 @@ class _CartScreenState extends State { width: Get.width * 0.9, height: Get.height * 0.06, child: ElevatedButton( - onPressed: () => Get.to(() => const CheckoutScreen()), + onPressed: () => Get.to(() => CheckoutScreen( + + productModel:widget.productModel + )), style: ElevatedButton.styleFrom( foregroundColor: Colors.white, backgroundColor: const Color(0xFF00784C), diff --git a/lib/screens/product/product_catalog_screen.dart b/lib/screens/product/product_catalog_screen.dart index 6a35d9e..5a27415 100644 --- a/lib/screens/product/product_catalog_screen.dart +++ b/lib/screens/product/product_catalog_screen.dart @@ -1,10 +1,14 @@ +import 'package:cheminova/models/product_model1.dart'; +import 'package:cheminova/screens/product/cart_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import '../../controller/cart_controller.dart'; import '../../widgets/my_drawer.dart'; import '../../widgets/product_card.dart'; import '../../controller/product_service.dart'; +import '../../models/product_model.dart'; // Import your ProductModel class ProductCatalogScreen extends StatefulWidget { const ProductCatalogScreen({super.key}); @@ -16,24 +20,27 @@ class ProductCatalogScreen extends StatefulWidget { class _ProductCatalogScreenState extends State { final ProductService _productService = ProductService(); final ScrollController _scrollController = ScrollController(); - List> _products = []; + final CartController cartController = Get.put(CartController()); + + List _products = []; // Use ProductModel here List> _categories = []; int _currentPage = 1; bool _isLoading = false; bool _hasMoreData = true; - String? _selectedCategory; // Default to null to handle 'All' explicitly + String? _selectedCategory; String? _selectedPriceRange; String? _selectedAvailability; @override void initState() { super.initState(); - _fetchCategories(); // Fetch categories first to set initial filter - _fetchProducts(); // Fetch products after setting initial filters + _fetchCategories(); + _fetchProducts(); _scrollController.addListener(() { - if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent && + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent && !_isLoading && _hasMoreData) { _fetchMoreProducts(); @@ -46,13 +53,13 @@ class _ProductCatalogScreenState extends State { _isLoading = true; }); - // Adjust the category parameter based on the selected category final category = _selectedCategory == 'All' ? null : _selectedCategory; - final products = await _productService.getProduct(_currentPage, category: category); + final products = await _productService.getProduct( + _currentPage, category: category); setState(() { if (products != null) { - _products.addAll(products); + _products.addAll(products); // Assuming products is a List _hasMoreData = products.isNotEmpty; } _isLoading = false; @@ -64,9 +71,8 @@ class _ProductCatalogScreenState extends State { if (categories != null) { setState(() { _categories = categories; - // Add "All" option _categories.insert(1, {'categoryName': 'All'}); - _selectedCategory = 'All'; // Set initial selected category to "All" + _selectedCategory = 'All'; }); } } @@ -131,11 +137,34 @@ class _ProductCatalogScreenState extends State { ), actions: [ GestureDetector( - onTap: () => Get.back(), + onTap: () => Get.to(CartScreen()), child: Padding( padding: const EdgeInsets.all(8.0), - child: SvgPicture.asset( - 'assets/svg/back_arrow.svg', + child: Stack( + children: [ + Icon(Icons.shopping_cart, size: 30,), + // Cart count display + Positioned( + right: 0, + child: Obx(() => + cartController.cartCount.value > 0 + ? Container( + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Colors.red, + shape: BoxShape.circle, + ), + child: Text( + '${cartController.cartCount.value}', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + ) + : SizedBox.shrink()), + ), + ], ), ), ), @@ -157,7 +186,6 @@ class _ProductCatalogScreenState extends State { child: Column( children: [ SizedBox(height: Get.height * 0.02), - // Search Bar Padding( padding: const EdgeInsets.symmetric(horizontal: 18.0), child: TextField( @@ -212,10 +240,8 @@ class _ProductCatalogScreenState extends State { shrinkWrap: true, scrollDirection: Axis.horizontal, itemCount: 3, - itemBuilder: (context, index) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: _buildFilterDropdown(index), - ), + itemBuilder: (context, index) => + _buildFilterDropdown(index), ), ), SizedBox( @@ -223,16 +249,20 @@ class _ProductCatalogScreenState extends State { child: ListView.builder( controller: _scrollController, padding: EdgeInsets.zero, - itemCount: _products.length + (_isLoading ? 1 : 0), + itemCount: _products.length + + (_isLoading ? 1 : 0), itemBuilder: (context, index) { if (index >= _products.length) { print("Product length $_products"); - return const Center(child: CircularProgressIndicator()); + return const Center( + child: CircularProgressIndicator()); } return Padding( - padding: const EdgeInsets.symmetric(vertical: 8), + padding: const EdgeInsets.symmetric( + vertical: 8), child: ProductCard( productModel: _products[index], + // Use ProductModel here ), ); }, @@ -254,57 +284,89 @@ class _ProductCatalogScreenState extends State { Widget _buildFilterDropdown(int index) { switch (index) { case 0: - return DropdownButton( + return _buildStyledDropdown( value: _selectedCategory, - hint: const Text("Category"), - onChanged: (value) { - if (value != null) { - _onCategoryChanged(value); - } - }, - items: _categories.map>((category) { + onChanged: _onCategoryChanged, + items: _categories.map((category) { return DropdownMenuItem( value: category['categoryName'], child: Text(category['categoryName']), ); }).toList(), + hint: "Category", ); - case 1: - return DropdownButton( - value: _selectedPriceRange, - hint: const Text("Price Range"), - onChanged: (value) { - setState(() { - _selectedPriceRange = value; - }); - }, - items: ['\$0-\$50', '\$51-\$100', '\$101-\$150'] - .map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - ); - case 2: - return DropdownButton( - value: _selectedAvailability, - hint: const Text("Availability"), - onChanged: (value) { - setState(() { - _selectedAvailability = value; - }); - }, - items: ['In Stock', 'Out of Stock'] - .map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - ); + // case 1: + // return _buildStyledDropdown( + // value: _selectedPriceRange, + // onChanged: (value) { + // setState(() { + // _selectedPriceRange = value; + // }); + // }, + // items: [ + // const DropdownMenuItem( + // value: "Under ₹50", + // child: Text("Under ₹50"), + // ), + // const DropdownMenuItem( + // value: "₹50 - ₹100", + // child: Text("₹50 - ₹100"), + // ), + // const DropdownMenuItem( + // value: "Above ₹100", + // child: Text("Above ₹100"), + // ), + // ], + // hint: "Price Range", + // ); + // case 2: + // return _buildStyledDropdown( + // value: _selectedAvailability, + // onChanged: (value) { + // setState(() { + // _selectedAvailability = value; + // }); + // }, + // items: [ + // const DropdownMenuItem( + // value: "In Stock", + // child: Text("In Stock"), + // ), + // const DropdownMenuItem( + // value: "Out of Stock", + // child: Text("Out of Stock"), + // ), + // ], + // hint: "Availability", + // ); default: - return Container(); + return const SizedBox(); } } + + Widget _buildStyledDropdown({ + required String? value, + required ValueChanged onChanged, + required List> items, + required String hint, + }) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: Colors.grey.shade300), + color: Colors.white, + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: value, + onChanged: onChanged, + items: items, + hint: Text(hint), + icon: const Icon(Icons.arrow_drop_down), + ), + ), + ); + } + } diff --git a/lib/screens/product/product_detail_screen.dart b/lib/screens/product/product_detail_screen.dart index edd8574..f725649 100644 --- a/lib/screens/product/product_detail_screen.dart +++ b/lib/screens/product/product_detail_screen.dart @@ -1,5 +1,7 @@ import 'package:cheminova/models/product_model.dart'; +import 'package:cheminova/models/product_model1.dart'; import 'package:cheminova/screens/order/checkout_screen.dart'; +import 'package:cheminova/utils/show_snackbar.dart'; import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/product_card.dart'; import 'package:flutter/material.dart'; @@ -7,10 +9,11 @@ import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import '../../controller/cart_controller.dart'; import 'cart_screen.dart'; class ProductDetailScreen extends StatefulWidget { - final Map? productModel; + Product? productModel; ProductModel? product; ProductDetailScreen({super.key, this.product, this.productModel}); @@ -20,6 +23,7 @@ class ProductDetailScreen extends StatefulWidget { } class _ProductDetailScreenState extends State { + final CartController _cartController = Get.put(CartController()); @override Widget build(BuildContext context) { return Scaffold( @@ -109,7 +113,7 @@ class _ProductDetailScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( - widget.productModel!['name'], + widget.productModel!.name, style: GoogleFonts.roboto( fontSize: 20, fontWeight: FontWeight.w600, @@ -120,7 +124,7 @@ class _ProductDetailScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( - "₹ ${widget.productModel!['price'].toString()}", + "₹ ${widget.productModel!.price.toString()}", style: GoogleFonts.roboto( fontSize: 24, fontWeight: FontWeight.w800, @@ -131,7 +135,7 @@ class _ProductDetailScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( - widget.productModel!['category']['categoryName'], + widget.productModel!.category!.categoryName, style: GoogleFonts.roboto( fontSize: 16, fontWeight: FontWeight.w400, @@ -143,7 +147,7 @@ class _ProductDetailScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( - widget.productModel!['description'], + widget.productModel!.description, style: GoogleFonts.roboto( fontSize: 16, fontWeight: FontWeight.w400, @@ -162,9 +166,8 @@ class _ProductDetailScreenState extends State { child: ElevatedButton( onPressed: () { // Pass the product data to the CartScreen - Get.to(() => CartScreen( - // Pass the product in a list - )); + _cartController.addToCart(widget.productModel!); + showSnackbar("Product Added to cart"); }, style: ElevatedButton.styleFrom( foregroundColor: Colors.white, diff --git a/lib/utils/common_api_service.dart b/lib/utils/common_api_service.dart index 76f054f..caa8abe 100644 --- a/lib/utils/common_api_service.dart +++ b/lib/utils/common_api_service.dart @@ -85,7 +85,7 @@ Future commonApiService({ errorMessage = e.response?.data; } - showSnackbar(errorMessage); + //showSnackbar(errorMessage); } catch (e) { print("exception $url $e"); } diff --git a/lib/utils/log_service.dart b/lib/utils/log_service.dart new file mode 100644 index 0000000..df7de21 --- /dev/null +++ b/lib/utils/log_service.dart @@ -0,0 +1,7 @@ +import 'package:logger/logger.dart'; + +final logger = Logger( + printer: PrettyPrinter( + lineLength: 500 + ) +); \ No newline at end of file diff --git a/lib/widgets/my_drawer.dart b/lib/widgets/my_drawer.dart index 830705b..7dcdc48 100644 --- a/lib/widgets/my_drawer.dart +++ b/lib/widgets/my_drawer.dart @@ -23,31 +23,33 @@ class _MyDrawerState extends State { SizedBox( height: 150, child: Obx( - () => DrawerHeader( - decoration: const BoxDecoration( - color: Colors.black87, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - homeController.user.value?.name ?? "username", - style: const TextStyle( - color: Colors.white, - fontSize: 18, + (){ + return DrawerHeader( + decoration: const BoxDecoration( + color: Colors.black87, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + homeController.user.value?.name?? "username", + style: const TextStyle( + color: Colors.white, + fontSize: 18, + ), ), - ), - Text( - homeController.user.value?.uniqueId ?? 'Employee ID', - style: const TextStyle( - color: Colors.white, - fontSize: 20, + Text( + homeController.user.value?.uniqueId?? 'Employee ID', + style: const TextStyle( + color: Colors.white, + fontSize: 20, + ), ), - ), - ], - ), - ), + ], + ), + ); + }, ), ), ListTile( diff --git a/lib/widgets/product_card.dart b/lib/widgets/product_card.dart index aea5019..dab5b0e 100644 --- a/lib/widgets/product_card.dart +++ b/lib/widgets/product_card.dart @@ -1,30 +1,52 @@ +import 'package:cheminova/controller/cart_controller.dart'; +import 'package:cheminova/models/oder_place_model.dart'; import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/screens/product/product_detail_screen.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; -class ProductCard extends StatelessWidget { - final Map? productModel; +import '../models/product_model1.dart'; +import '../screens/product/cart_screen.dart'; +import '../utils/show_snackbar.dart'; + +class ProductCard extends StatefulWidget { + final Product? productModel; + PlacedOrderModel? placedOrder; 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.isInCart = false, this.isCheckout = false, + this.isConfirmation = false, }); + @override + State createState() => _ProductCardState(); +} + + +class _ProductCardState extends State { + @override + @override Widget build(BuildContext context) { + final CartController _cartController = Get.put(CartController()); + bool showQuantity = widget.isInCart || widget.isCheckout || widget.isConfirmation; + bool isProductInCart = _cartController.cartList.contains(widget.productModel); return GestureDetector( - onTap: () => isInCart || isCheckout + onTap: () => widget.isInCart || widget.isCheckout ? null : Get.to(() => - ProductDetailScreen(productModel: productModel)), + ProductDetailScreen(productModel: widget.productModel)), child: Card( child: Row( children: [ @@ -52,29 +74,38 @@ class ProductCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - productModel!['name'], + widget.productModel!.name, style: GoogleFonts.roboto( fontSize: 16, fontWeight: FontWeight.w500, ), ), Text( - productModel!['category']['categoryName'], + widget.productModel!.category!.categoryName, style: GoogleFonts.roboto( fontSize: 14, fontWeight: FontWeight.w400, ), ), Text( - "₹ ${ productModel!['price'].toString()}0", + "₹ ${ widget.productModel!.price.toString()}", style: GoogleFonts.roboto( fontSize: 22, fontWeight: FontWeight.w700, ), ), - isCheckout + showQuantity + ? Text( + "Quantity: ${widget.productModel!.quantity.toString()}", + style: GoogleFonts.roboto( + fontSize: 15, + fontWeight: FontWeight.w700, + ), + ) + : const SizedBox(), + widget.isCheckout ? const SizedBox() - : isInCart + : widget.isInCart ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -93,7 +124,13 @@ class ProductCard extends StatelessWidget { height: 24, width: 24, child: ElevatedButton( - onPressed: () {}, + onPressed: () { + _cartController.increaseQuantity(widget.productModel!); + setState(() { + widget.quantity = widget.productModel!.quantity; + + }); + }, style: ElevatedButton.styleFrom( padding: EdgeInsets.zero, shape: RoundedRectangleBorder( @@ -111,7 +148,7 @@ class ProductCard extends StatelessWidget { ), ), Text( - productModel!['brand']['brandName'], + "${widget.quantity}", style: const TextStyle( color: Colors.white, fontSize: 16, @@ -121,7 +158,13 @@ class ProductCard extends StatelessWidget { height: 24, width: 24, child: ElevatedButton( - onPressed: () {}, + onPressed: () { + _cartController.decreaseQuantity(widget.productModel!); + setState(() { + widget.quantity = widget.productModel!.quantity; + }); + + }, style: ElevatedButton.styleFrom( padding: EdgeInsets.zero, shape: RoundedRectangleBorder( @@ -141,8 +184,11 @@ class ProductCard extends StatelessWidget { ], ), ), + SizedBox(width: 20.0,), IconButton( - onPressed: () {}, + onPressed: () { + _cartController.removeFromCart(widget.productModel); + }, icon: const Icon( Icons.delete_outline_rounded, color: Colors.red, @@ -152,7 +198,12 @@ class ProductCard extends StatelessWidget { ) : ElevatedButton( onPressed: () { - + if (isProductInCart) { + showSnackbar("Product already added to cart"); + } else { + _cartController.addToCart(widget.productModel!); + showSnackbar("Product added to cart successfully"); + } }, style: ElevatedButton.styleFrom( foregroundColor: Colors.white, diff --git a/pubspec.lock b/pubspec.lock index 3b6069e..398fb94 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -200,6 +200,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + logger: + dependency: "direct main" + description: + name: logger + sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" + url: "https://pub.dev" + source: hosted + version: "2.4.0" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fa2758a..8f22a41 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: dio: ^5.5.0+1 http: ^1.2.2 shared_preferences: ^2.2.3 + logger: ^2.4.0 dev_dependencies: flutter_test: