1)All files comments added

This commit is contained in:
saritabirare 2024-09-27 17:17:26 +05:30
parent fadbad07bf
commit 545b43aef5
46 changed files with 676 additions and 1168 deletions

View File

@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "242950171023",
"project_id": "cheminova-1fcf0",
"storage_bucket": "cheminova-1fcf0.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:242950171023:android:7fdc614b0429b52445c3fa",
"android_client_info": {
"package_name": "com.example.cheminova"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyDfgOZAwDgUnzQYnIHm8ObxrDtTutmAoAE"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

1
firebase.json Normal file
View File

@ -0,0 +1 @@
{"flutter":{"platforms":{"android":{"default":{"projectId":"cheminova-1fcf0","appId":"1:242950171023:android:7fdc614b0429b52445c3fa","fileOutput":"android/app/google-services.json"}},"dart":{"lib/firebase_options.dart":{"projectId":"cheminova-1fcf0","configurations":{"android":"1:242950171023:android:7fdc614b0429b52445c3fa","ios":"1:242950171023:ios:f4aba8c6c2d8f5ec45c3fa","macos":"1:242950171023:ios:f4aba8c6c2d8f5ec45c3fa"}}}}}}

View File

@ -3,13 +3,17 @@ import '../models/product_model.dart';
import '../models/product_model1.dart';
class CartController extends GetxController {
// Observable list to store products added to the cart
var cartList = <Product>[].obs;
// Observable variable to track the total count of items in the cart
var cartCount = 0.obs;
var subtotal = 0.0.obs;
var gstTotal = 0.0.obs;
var grandTotal = 0.0.obs;
// Observable variables to calculate price details
var subtotal = 0.0.obs; // The total price of items without tax
var gstTotal = 0.0.obs; // The total GST amount
var grandTotal = 0.0.obs;// The total amount including GST
// Track the selected products
// Observable list to track selected products for price calculation
var selectedProducts = <Product>[].obs;
@override
@ -18,79 +22,97 @@ class CartController extends GetxController {
// Initialize the cart list or other initializations if needed
initializeSelections();
}
// Function to add a product to the cart
void addToCart(Product product) {
// Check if the product already exists in the cart
var existingProduct = cartList.firstWhereOrNull((p) => p.id == product.id);
if (existingProduct != null) {
// If the product exists, increase its quantity
existingProduct.quantity++;
} else {
// If it's a new product, add it to the cart
cartList.add(product);
}
// Update the cart count
cartCount.value = cartList.length;
// Recalculate the total price
updateTotalPrice();
}
// Function to update the total price, subtotal, and GST total
void updateTotalPrice() {
double subTotal = 0.0;
double gstTotalAmount = 0.0;
// Calculate subtotal and GST for selected products only
for (var product in selectedProducts) {
subTotal += product.price * product.quantity;
gstTotalAmount += (product.price * product.quantity * (product.gst / 100));
}
// Update observable values
subtotal.value = subTotal;
gstTotal.value = gstTotalAmount;
grandTotal.value = subtotal.value + gstTotal.value;
}
// Function to increase the quantity of a product in the cart
void increaseQuantity(Product product) {
final index = cartList.indexWhere((item) => item.id == product.id);
if (index != -1) {
// Increment the quantity of the product
cartList[index].quantity++;
// If the product is selected, update the total price
if (selectedProducts.contains(cartList[index])) {
updateTotalPrice();
}
}
}
// Function to decrease the quantity of a product in the cart
void decreaseQuantity(Product product) {
final index = cartList.indexWhere((item) => item.id == product.id);
if (index != -1 && cartList[index].quantity > 1) {
// Decrement the quantity of the product
cartList[index].quantity--;
// If the product is selected, update the total price
if (selectedProducts.contains(cartList[index])) {
updateTotalPrice();
}
}
}
// Function to remove a product from the cart
void removeFromCart(Product product) {
// Remove the product from the cart list
cartList.removeWhere((item) => item.id == product.id);
// Remove the product from the selected list if it's there
selectedProducts.remove(product);
// Update the cart count and total price
cartCount.value = cartList.length;
updateTotalPrice();
}
// Function to toggle the selection of a product
void toggleProductSelection(Product product, bool isSelected) {
if (isSelected) {
// Add the product to the selected list if it's not already selected
if (!selectedProducts.contains(product)) {
selectedProducts.add(product);
}
} else {
// Remove the product from the selected list
selectedProducts.remove(product);
}
// Update the total price after selection change
updateTotalPrice();
}
// Function to select or deselect all products
void selectAllProducts(bool selectAll) {
if (selectAll) {
// Select all products in the cart
selectedProducts.assignAll(cartList);
} else {
// Clear all selections
selectedProducts.clear();
}
// Update the total price after selection change
updateTotalPrice();
}
// Function to initialize product selections; selects all by default
void initializeSelections() {
selectAllProducts(true);
}

View File

@ -9,12 +9,18 @@ import '../utils/log_service.dart';
import 'get_place_order_service.dart';
class GetPlacedOrderController extends GetxController {
// Service to fetch all placed orders
final GetOrderPlacedService _getOrderPlacedService = GetOrderPlacedService();
// Controller to manage order placement functionality
final OrderPlacedController _orderPlacedController = Get.put(OrderPlacedController());
// Service to fetch a single placed order
final GetSingleOrderPlacedService _getSingleOrderPlacedService = GetSingleOrderPlacedService();
var placedOrders = <PlacedOrderList>[].obs;
var products = <Product>[].obs;
// Observable list to store fetched placed orders
var placedOrders = <PlacedOrderList>[].obs;
// Observable list to track products related to placed orders
var products = <Product>[].obs;
// Observable to handle loading state
var isLoading = false.obs;
@override
@ -22,12 +28,13 @@ class GetPlacedOrderController extends GetxController {
super.onInit();
getOrders(); // Fetch the orders immediately on initialization
}
// Function to fetch all placed orders
Future<void> getOrders() async {
// Call the service to fetch placed orders
final fetchedOrders = await _getOrderPlacedService.getPlacedOrders();
if (fetchedOrders != null && fetchedOrders.isNotEmpty) {
// Add fetched orders to the observable list
placedOrders.addAll(fetchedOrders);
//logger.w("Fetched orders: $fetchedOrders");
@ -36,10 +43,11 @@ class GetPlacedOrderController extends GetxController {
}
}
// Function to search and fetch a single placed order by ID
Future<void> searchOrder() async {
try {
isLoading.value = true;
// Fetch a single order based on the first order's ID in the list
final order = await _getSingleOrderPlacedService.getSinglePlacedOrder(placedOrders[0].id);
if (order != null) {
placedOrders.clear(); // Clear existing orders if needed
@ -54,10 +62,11 @@ class GetPlacedOrderController extends GetxController {
}
}
// Optional: Reset the pagination if needed
// Optional function to reset pagination and fetch fresh data
void resetPagination() {
// Reset pagination in the service
_getOrderPlacedService.resetPagination();
placedOrders.clear(); // Clear existing data
getOrders(); // Fetch fresh data
getOrders(); // Fetch fresh orders after resetting
}
}

View File

@ -1,4 +1,5 @@
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:cheminova/utils/api_urls.dart';
import '../models/oder_place_model.dart';
import '../utils/common_api_service.dart';
import '../utils/show_snackbar.dart';
@ -9,24 +10,28 @@ class GetOrderPlacedService {
final List<PlacedOrderList> _allOrders = []; // To store all fetched orders
bool _hasMoreOrders = true; // To check if there are more orders to fetch
// Function to fetch placed orders from the server
Future<List<PlacedOrderList>?> getPlacedOrders() async {
try {
// Continue fetching as long as there are more orders available
while (_hasMoreOrders) {
// Construct the API URL with pagination parameters
String url = "/api/get-placed-order-pd?page=$_currentPage";
String url = "${ApiUrls.getPlacedOrderUrl}?page=$_currentPage";
// Call the common API service to fetch orders
final response = await commonApiService<List<PlacedOrderList>>(
method: "GET",
url: url,
fromJson: (json) {
// Parse the JSON response if it contains the 'plcaedOrders' key
if (json['plcaedOrders'] != null) {
// Convert the JSON list to a list of PlacedOrderList objects
final List<PlacedOrderList> orders = (json['plcaedOrders'] as List)
.map((orderJson) => PlacedOrderList.fromJson(orderJson as Map<String, dynamic>))
.toList();
// Check if the fetched orders list is not empty
if (orders.isNotEmpty) {
_allOrders.addAll(orders);
_currentPage++;
_allOrders.addAll(orders); // Add the fetched orders to the main list
_currentPage++; // Increment the page number for the next fetch
// _limit += orders.length; // Adjust limit based on the number of fetched orders
} else {
_hasMoreOrders = false; // Stop fetching if no more orders are returned
@ -39,20 +44,21 @@ class GetOrderPlacedService {
}
},
);
// Stop fetching if the response is null or empty
if (response == null || response.isEmpty) {
_hasMoreOrders = false; // Stop fetching if the response is empty
}
}
// Return all fetched orders after completing the fetch process
return _allOrders;
} catch (e) {
// Show an error message in a snackbar if an exception occurs
showSnackbar(e.toString());
return null;
}
}
// Optional: Reset the pagination and orders when needed
// Function to reset the pagination and clear the orders list
void resetPagination() {
_currentPage = 1;
//_limit = 100; // Reset the limit to the initial value

View File

@ -1,30 +1,35 @@
import 'package:cheminova/models/place_order_list_model.dart'; // Import your model
import 'package:cheminova/utils/api_urls.dart';
import '../utils/common_api_service.dart';
import '../utils/show_snackbar.dart';
class GetSingleOrderPlacedService {
// Function to fetch a single placed order by its ID
Future<PlacedOrderList?> getSinglePlacedOrder(String orderId) async {
try {
// Construct the API URL for the single placed order
String url = "/api/get-single-placed-order-pd/$orderId";
String url = "${ApiUrls.getSinglePlacedOrderUrl}$orderId";
final response = await commonApiService<PlacedOrderList>(
method: "GET",
url: url,
fromJson: (json) {
// Check if the JSON response contains the 'singleOrder' key
if (json['singleOrder'] != null) {
// Convert the JSON response to a PlacedOrderList model
return PlacedOrderList.fromJson(json['singleOrder'] as Map<String, dynamic>);
} else {
// Throw an exception if the order is not found in the response
throw Exception("Order not found"); // Throw an exception if not found
}
},
);
return response;
return response; // Return the fetched order if successful
} catch (e) {
// Show an error message in a snackbar if an exception occurs
showSnackbar(e.toString());
return null;
return null; // Return null to indicate an error occurred
}
}
}

View File

@ -6,46 +6,41 @@ import 'package:shared_preferences/shared_preferences.dart';
import '../notification_service.dart';
class HomeController extends GetxController {
// Instance of HomeService to handle API requests
final HomeService homeService = HomeService();
// Instance of NotificationServices for handling notifications
NotificationServices notificationServices = NotificationServices();
UserModel? user;
// var userModel = UserModel(
// id: '',
// uniqueId: '',
// name: '',
// email: '',
// phone: '',
// role: '',
// sbu: '',
// createdAt: '',
// updatedAt: '',
// ).obs; // Observable for UserModel
UserModel? user; // Variable to store user details
@override
void onInit() {
getUser();
super.onInit();
notificationServices.requestNotificationPermission();
// Called when the controller is initialized
getUser(); // Fetch user data
super.onInit(); // Call parent class's onInit method
notificationServices.requestNotificationPermission(); // Request permission for notifications
notificationServices.getDeviceToken().then((value) {
// Retrieve the FCM device token
print('Device Token: $value');
fcmToken();
fcmToken(); // Call the function to send the FCM token to the server
});
}
// Function to handle FCM token retrieval and sending it to the server
Future<void> fcmToken() async {
// Get SharedPreferences instance
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
final fcmToken = await NotificationServices().getDeviceToken();
String? token = prefs.getString('token'); // Retrieve the saved user token
final fcmToken = await NotificationServices().getDeviceToken(); // Get the FCM device token
print('fcmToken: $fcmToken');
homeService.fcmToken({"fcmToken": fcmToken}, token!);
homeService.fcmToken({"fcmToken": fcmToken}, token); // Send the FCM token to the server
}
// Function to fetch user details from the server
Future<void> getUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
// Create an instance of HomeService
HomeService homeService = HomeService();
// Fetch user details using the token
user = await homeService.getUser(token: token);
if (user != null) {
@ -57,59 +52,3 @@ class HomeController extends GetxController {
}
// 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';
//
// import '../notification_service.dart';
//
// class HomeController extends GetxController {
// final HomeService homeService = HomeService();
// NotificationServices notificationServices = NotificationServices();
//
//
//
// var userModel = UserModel(id: '', uniqueId: '', name: '', email: '', phone: '', role: '', sbu: '', createdAt: '', updatedAt: ''
//
// ).obs; // Observable for UserModel
//
// @override
// void onInit() {
// getUser();
// super.onInit();
// notificationServices.requestNotificationPermission();
// notificationServices.getDeviceToken().then((value) {
// print('Device Token: $value');
// fcmToken();
// });
// }
//
// Future<void> fcmToken() async {
// SharedPreferences prefs = await SharedPreferences.getInstance();
// String? token = prefs.getString('token');
// final fcmToken = await NotificationServices().getDeviceToken();
// print('fcmToken: $fcmToken');
// homeService.fcmToken({"fcmToken": fcmToken}, token!);
// }
//
// Future<void> getUser() async {
// SharedPreferences prefs = await SharedPreferences.getInstance();
//
// String? token = prefs.getString('token');
//
// userModel = (await homeService.getUser(token: token)) as dynamic;
//
//
// // if (userModel != null) {
// // if (userModel != null) {ddddd
// // userModel.value = userResponse as UserModel; // Update the userModel with API response
// // update(); // Notify GetX to rebuild widgets using GetBuilder/Obx
// // }
// }
// }
//

View File

@ -4,8 +4,10 @@ import 'package:cheminova/utils/common_api_service.dart';
import 'package:cheminova/utils/show_snackbar.dart';
class HomeService {
// Function to fetch user details from the API
Future<UserModel?> getUser({String? token}) async {
try {
// Making a GET request to fetch user profile data
final response = await commonApiService<UserModel>(
method: "GET",
url: ApiUrls.profileUrl,
@ -13,11 +15,13 @@ class HomeService {
'Authorization': 'Bearer $token',
},
fromJson: (json) {
// Callback to parse the JSON response into a UserModel
if (json['user'] != null) {
// Parse the user data from the API response
return UserModel.fromJson(json['user']);
return UserModel.fromJson(
json['user']); // Convert JSON to UserModel
}
return json as UserModel;
return json as UserModel; // Return the response as UserModel if no 'user' key found
},
);
return response;
@ -28,21 +32,26 @@ class HomeService {
}
}
// Function to send FCM token to the server
Future<Map<String, dynamic>?> fcmToken(Map<String, dynamic> data,
String? token) async {
try {
final response = await commonApiService<String>(
// Making a POST request to send the FCM token
url: ApiUrls.fcmUrl,
method: 'POST',
body: data,
// Body data to be sent in the request
fromJson: (json) => json as String,
// Just return the string response
additionalHeaders: { // Pass the token here
additionalHeaders: {
// Pass the token here
'Authorization': 'Bearer $token',
// Bearer token for authenticated requests
},
);
if (response != null) {
// Since the response is a string, wrap it in a Map to avoid type issues
return {

View File

@ -1,9 +1,8 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/kyc_model.dart';
import 'kyc_service.dart';
@ -11,6 +10,12 @@ class KycController extends GetxController {
var kycList = <KycModel>[].obs; // Using an observable list to store KYC data
var isLoading = false.obs;
@override
void onInit() {
super.onInit();
loadKycFromLocalStorage(); // Load KYC data from local storage when initialized
}
Future<void> fetchKycData() async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
@ -23,6 +28,7 @@ class KycController extends GetxController {
if (data != null && data.isNotEmpty) {
// Parse the list of KYC objects
kycList.value = KycModel.fromJsonList(data); // Convert to List<KycModel>
saveKycToLocalStorage(); // Save the fetched KYC data to local storage
} else {
print("No KYC data found or API response is empty.");
}
@ -36,10 +42,10 @@ class KycController extends GetxController {
// Update KYC status locally and persist the changes
Future<void> updateKycStatus(KycModel kycModel, String status, String comment) async {
final index = kycList.indexOf(kycModel);
if (index != -1) {
kycList[index].status = status; // Update status locally
saveKycToLocalStorage(); // Persist the changes locally
update(); // Notify listeners about the change
// Show a success message after updating
Get.snackbar(
@ -59,23 +65,19 @@ class KycController extends GetxController {
prefs.setStringList('kycList', kycListJson); // Save the updated list locally
}
// Load the KYC list from SharedPreferences
// Load KYC data from SharedPreferences
Future<void> loadKycFromLocalStorage() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String>? storedKycList = prefs.getStringList('kycList');
List<String>? kycListJson = prefs.getStringList('kycList');
if (storedKycList != null) {
// If local data is found, update the KYC list with the locally saved data
List<KycModel> localKycList = storedKycList.map((kycJson) => KycModel.fromJson(jsonDecode(kycJson))).toList();
if (kycListJson != null) {
kycList.value = kycListJson.map((jsonStr) => KycModel.fromJson(jsonDecode(jsonStr))).toList();
print("Loaded KYC data from local storage.");
} else {
// If no data found, fetch from API
fetchKycData();
// Merge local data with the API data (if any exists in kycList)
for (var localKyc in localKycList) {
int index = kycList.indexWhere((kyc) => kyc.id == localKyc.id);
if (index != -1) {
// Update the status with the locally saved status
kycList[index].status = localKyc.status;
}
}
}
}
}

View File

@ -1,21 +1,24 @@
import 'package:cheminova/utils/api_urls.dart';
import 'package:dio/dio.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(
'https://api.cnapp.co.in/api/kyc/getAll',
ApiUrls.getKycUrl,
// 'https://api.cnapp.co.in/api/kyc/getAll',
options: Options(
headers: {
'Authorization': 'Bearer $token',
},
),
);
// Check if the response status code indicates success
if (response.statusCode == 200) {
print("response of /api/kyc/getAll : ${response.data}");
print("response of ApiUrls.getKycUrl: ${response.data}");
return response.data; // Return the data as a List<dynamic>
} else {
throw Exception("Failed to load KYC data");
@ -28,39 +31,3 @@ class KycService {
}
// import 'dart:convert';
// import 'package:cheminova/utils/api_urls.dart';
// import '../models/kyc_model.dart';
// import '../utils/common_api_service.dart';
//
// class KycService {
// Future<List<KycModel>?> getKycData(String token) async {
// String url = ApiUrls.getKyc; // API endpoint for KYC data
//
// // Use the commonApiService for making the API request
// final response = await commonApiService<List<KycModel>>(
// method: "GET",
// url: url,
// additionalHeaders: {
// 'Authorization': 'Bearer $token', // Add the token in headers
// },
// fromJson: (json)
// {
// if (json != null && json['data'] != null) {
// List<dynamic> dataList = json['data']; // Access 'data' array
// return dataList.map((item) => KycModel.fromJson(item)).toList();
// } else {
// print('Invalid KYC response or data is null');
// return [];
// }
//
//
//
// },
// );
//
// // Return the parsed KYC data list, or an empty list in case of failure
// return response;
// }
// }

View File

@ -4,10 +4,12 @@ import 'package:cheminova/utils/api_urls.dart';
import '../utils/common_api_service.dart';
class NotificationApiService {
// Function to fetch notifications from the API
Future<List<NotificationModel>?> getNotification(String token) async {
try {
// Set the URL for fetching notifications
String url =ApiUrls.getNotificationUrl; // Base URL to fetch product manuals
// Make a GET request to the notification API
final response = await commonApiService<List<NotificationModel>>(
method: "GET",
url: url,
@ -16,7 +18,7 @@ class NotificationApiService {
},
fromJson: (json) {
if (json['notifications'] != null) {
// Map the list of product manuals from the response
// If notifications are present in the response, map them to NotificationModel objects
final List<NotificationModel> notification = (json['notifications'] as List)
.map((manualJson) => NotificationModel.fromJson(manualJson as Map<String, dynamic>))
.toList();

View File

@ -9,6 +9,7 @@ import '../models/oder_place_model.dart';
class OrderPlacedController extends GetxController {
// Observable variable to hold the details of the placed order
var placedOrder1 = PlacedOrderModel(
paymentMode: 'cheque',
shipTo: '456, Park Street, Kolkata, West Bengal - 700016',
@ -23,13 +24,13 @@ class OrderPlacedController extends GetxController {
var isLoading = false.obs;
final OrderPlacedService _orderPlacedService = OrderPlacedService();
// Method to place an order
Future<void> placeOrder() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
isLoading.value = true;
//try {
// Construct order details
// Construct order details from the observable variable
PlacedOrderModel orderDetails = placedOrder1.value;
print("Order Details: $orderDetails");
@ -43,87 +44,3 @@ class OrderPlacedController extends GetxController {
// 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<PlacedOrderModel?> placedOrder1 = Rx<PlacedOrderModel?>(null);
// RxBool isLoading = false.obs;
//
// // Method to place an order with provided details
// Future<void> 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';
// }
// }

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:developer';
import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/utils/api_urls.dart';
import 'package:dio/dio.dart';
import '../models/oder_place_model.dart';
@ -14,7 +15,7 @@ class OrderPlacedService {
//try {
// logger.w("orderjson ${jsonEncode(orderDetails.toJson())}");
final response = await dio.post(
'https://api.cnapp.co.in/api/order-place', // Ensure this is your correct endpoint
'${ApiUrls.placedOrderUrl}', // Ensure this is your correct endpoint
data: jsonEncode(orderDetails.toJson()),
options: Options(
headers: {

View File

@ -4,6 +4,7 @@ import 'package:get/get.dart';
class ProductController extends GetxController {
// Instantiate the product service
final ProductService productService = ProductService();
var products = <Product>[].obs;
var categories = <String>[].obs; // Holds the list of categories
@ -14,12 +15,14 @@ class ProductController extends GetxController {
@override
void onInit() {
super.onInit();
// Fetch categories when the controller initializes
getCategory();
// Fetch products when the controller initializes
getUser();
}
// Method to fetch products based on the selected category and current page
Future<void> getUser() async {
if (isLoading) return;
if (isLoading) return; // Prevent duplicate calls if already loading
isLoading = true;
try {
final category = selectedCategory.value; // Get the selected category
@ -29,7 +32,7 @@ class ProductController extends GetxController {
);
if (fetchedProducts != null) {
// Directly add the fetched products (which are of type List<Product>) to the list
// If products were fetched, add them to the observable list
products.addAll(fetchedProducts);
print("fetchedProducts ,$fetchedProducts");
}
@ -40,28 +43,29 @@ class ProductController extends GetxController {
update();
}
}
// Method to fetch categories from the product service
Future<void> getCategory() async {
try {
final fetchedCategories = await productService.getCategory();
if (fetchedCategories != null) {
// If categories were fetched, map them to the observable list
categories.assignAll(fetchedCategories.map((category) => category['categoryName'] as String));
categories.insert(0, 'All'); // Add "All" option
categories.insert(0, 'All'); // Add "All" option as the first category
}
} catch (e) {
print("Error fetching categories: $e");
}
}
// Method to set the selected category and fetch products
void setCategory(String category) {
selectedCategory.value = category == 'All' ? null : category;
_currentPage = 1;
products.clear();
getUser();
products.clear(); // Clear the existing products
getUser(); // Fetch products based on the new category
}
// Method to load more products when reaching the end of the list
void loadMoreProducts() {
_currentPage++;
getUser();
getUser(); // Fetch products for the next page
}
}

View File

@ -6,6 +6,7 @@ import '../models/product_mannual_model.dart';
import '../utils/common_api_service.dart'; // Replace with your actual common API service import
class ProductMannualService {
// Method to fetch product manuals using an authorization token
Future<List<ProductManualModel>?> getProductManuals(String token) async {
try {
String url = ApiUrls.getProductManualUrl; // Base URL to fetch product manuals
@ -18,11 +19,11 @@ class ProductMannualService {
},
fromJson: (json) {
if (json['productManuals'] != null) {
// Map the list of product manuals from the response
// If the productManuals key is present, map the response to a list of ProductManualModel objects
final List<ProductManualModel> productManuals = (json['productManuals'] as List)
.map((manualJson) => ProductManualModel.fromJson(manualJson as Map<String, dynamic>))
.toList();
return productManuals;
return productManuals; // Return the list of product manuals
} else {
return [];
}

View File

@ -5,20 +5,23 @@ import '../utils/common_api_service.dart';
import '../utils/show_snackbar.dart';
class ProductService {
// Method to fetch products based on the page number and optional category
Future<List<Product>?> getProduct(int page, {String? category}) async {
try {
String url;
// Determine the URL based on the presence of a category filter
if (category != null && category.isNotEmpty) {
url = "ApiUrls.getProductUrl?page=$page&category=$category";
url = "${ApiUrls.getCategoryUrl}?page=$page&category=$category";
} else {
url = "/api/product/getAll/user?page=$page"; // URL without category filter
url = "${ApiUrls.getallProductUrl}?page=$page"; // URL without category filter
}
// Make the API call using the common API service
final response = await commonApiService<List<Product>>(
method: "GET",
url: url,
fromJson: (json) {
if (json['products'] != null) {
// If the 'products' key exists, map it to a list of Product objects
final List<Product> products = (json['products'] as List)
.map((productJson) => Product.fromJson(productJson as Map<String, dynamic>))
.toList();
@ -36,9 +39,10 @@ class ProductService {
}
}
// Method to fetch product categories
Future<List<Map<String, dynamic>>?> getCategory() async {
try {
// Make the API call to fetch categories
final response = await commonApiService<List<Map<String, dynamic>>>(
method: "GET",
url: ApiUrls.getCategoryUrl,
@ -47,9 +51,9 @@ class ProductService {
final List<Map<String, dynamic>> category = (json['categories'] as List)
.map((productJson) => productJson as Map<String, dynamic>)
.toList();
return category;
return category; // Return the list of categories
} else {
return [];
return []; // Return an empty list if no categories are found
}
},
);

75
lib/firebase_options.dart Normal file
View File

@ -0,0 +1,75 @@
// File generated by FlutterFire CLI.
// ignore_for_file: type=lint
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for web - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyDfgOZAwDgUnzQYnIHm8ObxrDtTutmAoAE',
appId: '1:242950171023:android:7fdc614b0429b52445c3fa',
messagingSenderId: '242950171023',
projectId: 'cheminova-1fcf0',
storageBucket: 'cheminova-1fcf0.appspot.com',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyCukVtk1vpdHcO1ayiPMz1wLQGfRGzEXxk',
appId: '1:242950171023:ios:f4aba8c6c2d8f5ec45c3fa',
messagingSenderId: '242950171023',
projectId: 'cheminova-1fcf0',
storageBucket: 'cheminova-1fcf0.appspot.com',
iosBundleId: 'com.example.cheminova',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyCukVtk1vpdHcO1ayiPMz1wLQGfRGzEXxk',
appId: '1:242950171023:ios:f4aba8c6c2d8f5ec45c3fa',
messagingSenderId: '242950171023',
projectId: 'cheminova-1fcf0',
storageBucket: 'cheminova-1fcf0.appspot.com',
iosBundleId: 'com.example.cheminova',
);
}

View File

@ -10,13 +10,13 @@ var box;
void main()async{
WidgetsFlutterBinding.ensureInitialized();
// Ensure that Flutter's binding is initialized before running the app, necessary for async operations before runApp
// Initialize Firebase with the current platform's configuration
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
await Hive.initFlutter();
await Hive.initFlutter(); // Initialize Hive for Flutter
await Hive.openBox('cartBox');
runApp(const MyApp());
}
@ -26,6 +26,7 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Use GetMaterialApp for navigation and state management with GetX
return const GetMaterialApp(
debugShowCheckedModeBanner: false,
home: SplashScreen(),

View File

@ -1,23 +1,23 @@
class AddedBy {
String id;
String name;
AddedBy({
required this.id,
required this.name,
});
factory AddedBy.fromJson(Map<String, dynamic> json) => AddedBy(
id: json["_id"],
name: json["name"],
);
Map<String, dynamic> toJson() => {
"_id": id,
"name": name,
};
@override
String toString() {
return 'AddedBy(id: $id, brandName: $AddedBy,)';
}
}
// class AddedBy {
// String id;
// String name;
//
// AddedBy({
// required this.id,
// required this.name,
// });
//
// factory AddedBy.fromJson(Map<String, dynamic> json) => AddedBy(
// id: json["_id"],
// name: json["name"],
// );
//
// Map<String, dynamic> toJson() => {
// "_id": id,
// "name": name,
// };
// @override
// String toString() {
// return 'AddedBy(id: $id, brandName: $AddedBy,)';
// }
// }

View File

@ -1,27 +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;
}
// // 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;
// }

View File

@ -16,43 +16,47 @@ class ChangePasswordScreen extends StatefulWidget {
}
class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
// Initialize the AuthController using GetX dependency injection
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();
}
// Function to validate user input and initiate password change
void validateAndChangePassword() async {
String oldPassword = authController.currentpassController.text.trim();
String newPassword = authController.newpassController.text.trim();
String confirmPassword = authController.confirmpassController.text.trim();
// Check if any of the fields are empty
if (newPassword.isEmpty || confirmPassword.isEmpty || oldPassword.isEmpty) {
showSnackbar('All fields are required');
return;
}
// Check if the new password meets the minimum length requirement
if (newPassword.length < 8) {
showSnackbar('Password must be at least 8 characters long');
return;
}
// Check if the new password contains at least one special character
if (!RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(newPassword)) {
showSnackbar('Password must contain at least one special character');
return;
}
// Check if new password and confirm password fields match
if (newPassword != confirmPassword) {
showSnackbar('New Password and Confirm Password do not match');
return;
}
// Call the changePassword method from AuthController
authController.changePassword();
}
@ -107,6 +111,7 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
height: Get.height * 0.7,
),
),
// Main content area with a scrollable card
Center(
child: SingleChildScrollView(
child: Card(
@ -120,7 +125,7 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// Title for the Change Password screen
Container(
padding: const EdgeInsets.only(bottom: 10),
alignment: Alignment.centerLeft,
@ -134,6 +139,7 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
),
),
),
// Input field for current password
InputField(
hintText: "Current Password",
labelText: "Current Password",
@ -143,6 +149,7 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
),
const SizedBox(height: 15),
// Input field for new password
InputField(
hintText: "New Password",
labelText: "New Password",
@ -151,6 +158,7 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
keyboardType: TextInputType.text,
),
const SizedBox(height: 15),
// Input field for confirm password
InputField(
hintText: "Confirm Password",
labelText: "Confirm Password",

View File

@ -9,14 +9,14 @@ import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../notification_service.dart';
import '../../../utils/api_client.dart';
import '../../../utils/api_urls.dart';
import '../../../utils/secure__storage_service.dart';
class AuthController extends GetxController {
final authService = AuthService();
final _apiClient = ApiClient();
final _storageService = SecureStorageService();
TextEditingController emailController = TextEditingController();
@ -31,10 +31,13 @@ class AuthController extends GetxController {
@override
void onInit(){
super.onInit();
// Request notification permissions on initialization
NotificationServices().requestNotificationPermission();
}
// Function to handle user login
Future<void> login() async {
isLoading.value = true;
// Call the login service with email and password
final response = await authService.login({
'email': emailController.text,
'password': passwordController.text,
@ -98,7 +101,7 @@ class AuthController extends GetxController {
// }
// Function to handle forgotten password
Future<void> forgotpass() async{
isLoading.value = true;
final response = await authService.forgotPassword(
@ -112,7 +115,7 @@ Future<void> forgotpass() async{
showSnackbar("Email sent successfully");
}
}
// Function to handle password change
Future<void> changePassword() async {
isLoading.value = true;

View File

@ -2,12 +2,13 @@ import 'package:cheminova/utils/api_urls.dart';
import 'package:cheminova/utils/common_api_service.dart';
import 'package:cheminova/utils/show_snackbar.dart';
import '../../../utils/api_client.dart';
class AuthService {
// Function to handle user login
Future<Map<String, dynamic>?> login(Map<String, dynamic> data) async {
try {
// Making a POST request to the login URL using the common API service
final response = await commonApiService<Map<String, dynamic>>(
url: ApiUrls.loginUrl,
method: 'POST',
@ -20,10 +21,10 @@ class AuthService {
}
return null;
}
// Function to handle forgot password functionality // Function to handle password change functionality
Future<Map<String, dynamic>?> forgotPassword(Map<String, dynamic> data) async {
try {
// Making a POST request to the forgot password URL using the common API service
final response = await commonApiService<Map<String, dynamic>>(
url: ApiUrls.forgetPasswordUrl,
method: 'POST',
@ -38,8 +39,10 @@ class AuthService {
}
// Function to handle password change functionality
Future<Map<String, dynamic>?> changePassword(Map<String, dynamic> data, {required String token}) async {
try {
// Making a PUT request to the change password URL using the common API service
final response = await commonApiService<Map<String, dynamic>>(
url: ApiUrls.changePasswordUrl,
method: 'PUT',

View File

@ -15,6 +15,7 @@ class ForgetPasswordScreen extends StatefulWidget {
}
class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
// Controllers for handling user input and managing state
final userNameController = TextEditingController();
final passwordController = TextEditingController();
final authController = Get.put(AuthController());
@ -60,6 +61,7 @@ class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
height: Get.height * 0.7,
),
),
// Main content of the screen
Center(
child: SingleChildScrollView(
child: Card(
@ -94,6 +96,7 @@ class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
),
),
),
// Instructional text for the user
Container(
padding: const EdgeInsets.only(bottom: 10),
alignment: Alignment.centerLeft,
@ -107,6 +110,7 @@ class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
),
),
),
// Input field for the user to enter their email
InputField(
hintText: "Email",
labelText: "Email",
@ -115,7 +119,7 @@ class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
),
const SizedBox(height: 30),
GestureDetector(
onTap: () => Get.back(),
onTap: () => Get.back(), // Navigate back to login screen
child: Text(
'Back to Login',
style: GoogleFonts.getFont(
@ -129,7 +133,7 @@ class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
),
const SizedBox(height: 30),
CustomButton(text: "Send",
// Trigger forgot password function
onPressed: () => authController.forgotpass(),
isLoading: authController.isLoading.value,

View File

@ -16,9 +16,13 @@ class LoginScreen extends StatefulWidget {
}
class _LoginScreenState extends State<LoginScreen> {
// Global key for the form to validate user inputs
final formKey = GlobalKey<FormState>();
// Controller for handling authentication logic
final authController = Get.put(AuthController());
// Email validation pattern
final String emailPattern = r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$';
// Password validation pattern (at least 6 characters)
final String passwordPattern = r'^.{6,}$'; // At least 6 characters
@override
@ -43,6 +47,7 @@ class _LoginScreenState extends State<LoginScreen> {
height: Get.height * 0.7,
),
),
// Main content of the login screen wrapped in a scroll view
SingleChildScrollView(
child: Form(
key: formKey,
@ -131,6 +136,7 @@ class _LoginScreenState extends State<LoginScreen> {
),
),
),
// Email input field with validation
CommonTextFormField(
controller: authController.emailController,
keyboardType: TextInputType.emailAddress,
@ -147,6 +153,7 @@ class _LoginScreenState extends State<LoginScreen> {
label: "Email",
),
const SizedBox(height: 15),
// Password input field with validation
CommonTextFormField(
controller: authController.passwordController,
validator: (value) {
@ -164,6 +171,7 @@ class _LoginScreenState extends State<LoginScreen> {
label: "Password",
),
const SizedBox(height: 30),
// Navigation to the forgot password screen
GestureDetector(
onTap: () =>
Get.to(() => const ForgetPasswordScreen()),

View File

@ -9,11 +9,7 @@ import '../../widgets/comman_background.dart';
import '../../widgets/common_appbar.dart';
class ProfileScreen extends StatefulWidget {
// String? name;
// final String uniqueId;
// final String email;
// final String mobileNumber;
// final String designation;
const ProfileScreen({
Key? key,
@ -25,10 +21,11 @@ class ProfileScreen extends StatefulWidget {
}
class _ProfileScreenState extends State<ProfileScreen> {
// Initialize the HomeController using GetX
final homecontroller = Get.put(HomeController());
@override
Widget build(BuildContext context) {
// Accessing the user details from the HomeController
final user = homecontroller!.user;
return Stack(
children: [
@ -44,6 +41,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
actions: [
IconButton(
onPressed: () {
// Navigates back to the previous screen
Navigator.pop(context);
},
icon: SvgPicture.asset(
@ -53,6 +51,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
],
),
// Main content of the profile screen
body: SingleChildScrollView(
child: Column(
children: [
@ -70,6 +69,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
// Displaying individual profile items
_buildProfileItem('Name', user!.name),
_buildProfileItem('ID', user.uniqueId),
_buildProfileItem('Email ID', user.email),

View File

@ -54,7 +54,7 @@ class _HomeScreenState extends State<HomeScreen> {
actions: [
GestureDetector(
onTap: () {
// Action for notification icon tap
// Navigate to NotificationScreen when the notification icon is tapped
Get.to(() => NotificationScreen());
},
child: Padding(

View File

@ -1,4 +1,4 @@
import 'package:cheminova/screens/retail/kyc_verification_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
@ -26,47 +26,95 @@ class _KycRetailerDetailScreenState
void _approveKyc() {
if (widget.kycModel!.status == "approved") {
Get.snackbar("Error", "The KYC has already been approved.", snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red, colorText: Colors.white);
Get.snackbar(
"Error",
"The KYC has already been approved.",
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
} else {
// Update the status in the model before calling the controller method
widget.kycModel!.status = "approved";
_kycController.updateKycStatus(widget.kycModel!, "approved", "");
Get.snackbar("Success", "KYC approved successfully.", snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.green, colorText: Colors.white);
Get.back(); // Go back after approval
setState(() {
});
Get.snackbar(
"Success",
"KYC approved successfully.",
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
colorText: Colors.white,
);
// Pass the updated model back to the previous screen
Get.back(result: widget.kycModel);
}
}
void _rejectKyc() {
if (widget.kycModel!.status == "reject") {
Get.snackbar("Error", "The KYC has already been rejected.", snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red, colorText: Colors.white);
Get.snackbar(
"Error",
"The KYC has already been rejected.",
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
} else {
// Show dialog to enter a comment
Get.dialog(
AlertDialog(
title: Text("Reject KYC"),
title: const Text("Reject KYC"),
content: TextField(
controller: commentController, // TextEditingController for comment
decoration: InputDecoration(hintText: "Enter rejection comment"),
controller: commentController,
decoration: const InputDecoration(hintText: "Enter rejection comment"),
),
actions: [
TextButton(
onPressed: () {
Get.back(); // Close dialog without action
},
child: Text("Cancel"),
child: const Text("Cancel"),
),
TextButton(
onPressed: () {
String comment = commentController.text;
if (comment.isNotEmpty) {
// Call reject method with comment
// Update the status in the model before calling the controller method
widget.kycModel!.status = "reject";
// Append the comment to the notes list
widget.kycModel!.notes ??= []; // Initialize if null
widget.kycModel!.notes!.add(comment);
_kycController.updateKycStatus(widget.kycModel!, "reject", comment);
Get.snackbar("Success", "KYC rejected with comment: $comment", snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.green, colorText: Colors.white);
setState(() {});
Get.snackbar(
"Success",
"KYC rejected with comment: $comment",
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
colorText: Colors.white,
);
// Pass the updated model back to the previous screen
Get.back(); // Close the dialog
Get.back(); // Go back to the previous screen
Get.back(result: widget.kycModel); // Pass the result back
} else {
Get.snackbar("Error", "Comment is required", snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red, colorText: Colors.white);
Get.snackbar(
"Error",
"Comment is required",
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
},
child: Text("Reject"),
child: const Text("Reject"),
),
],
),
@ -78,6 +126,8 @@ class _KycRetailerDetailScreenState
@override
Widget build(BuildContext context) {
return Scaffold(
@ -270,7 +320,7 @@ class _KycRetailerDetailScreenState
child: Padding(
padding: const EdgeInsets.all(12),
child: Text(
"Comment:",
"Comment:${widget.kycModel!.notes}",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w700,

View File

@ -32,16 +32,19 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
@override
void initState() {
super.initState();
_kycController.loadKycFromLocalStorage();
getKycData();
}
Future<void> _onRefresh() async {
await getKycData();
// await getKycData();
//navigateToKycDetail(_kycController.kycList as KycModel);
await Future.delayed(Duration(seconds: 1));
}
Future<void> getKycData() async {
await _kycController.fetchKycData();
print("kyc successfully");
}
@ -56,6 +59,25 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
return formattedDate;
}
Future<void> navigateToKycDetail(KycModel kycModel) async {
var result = await Get.to(() => KycRetailerDetailScreen(kycModel: kycModel));
if (result != null) {
// Update the list or filter based on the result
KycModel updatedKycModel = result;
setState(() {
// Find and update the KYC in your list
int index = _kycController.kycList.indexWhere((kyc) => kyc.status == updatedKycModel.status);
if (index != -1) {
_kycController.kycList[index] = updatedKycModel;
_kycController.saveKycToLocalStorage(); // Persist updates
}
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -177,11 +199,7 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
List<KycModel> filteredOrders =
selectedStatus == "All"
? _kycController.kycList
: _kycController.kycList
.where((order) =>
order.status ==
selectedStatus)
.toList();
: _kycController.kycList.where((kyc) => kyc.status == selectedStatus).toList();
return ListView.builder(
padding: EdgeInsets.zero,
@ -189,6 +207,7 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
itemCount: filteredOrders.length,
itemBuilder: (context, index) {
final order = filteredOrders[index];
final kyc = _kycController.kycList[index];
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 8),
@ -302,12 +321,12 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
padding:
const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () => Get.to(() =>
KycRetailerDetailScreen(
kycModel:
_kycController
.kycList[
index])),
onPressed: () => navigateToKycDetail(kyc), // KycRetailerDetailScreen(
// kycModel:
// _kycController
// .kycList[
// index])
style:
ElevatedButton.styleFrom(
foregroundColor:
@ -349,279 +368,3 @@ class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
);
}
}
// import 'package:cheminova/controller/kyc_controller.dart';
// import 'package:cheminova/models/kyc_model.dart';
// import 'package:cheminova/widgets/input_field.dart';
// import 'package:cheminova/widgets/my_drawer.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:intl/intl.dart';
// import '../../controller/cart_controller.dart';
// import 'kyc_retailer_details_screen.dart';
//
//
// class KycRetailerInfoScreen extends StatefulWidget {
//
// KycModel? kycModel;
// KycRetailerInfoScreen({super.key, this.kycModel});
//
// @override
// State<KycRetailerInfoScreen> createState() => _KycRetailerInfoScreenState();
// }
//
// class _KycRetailerInfoScreenState extends State<KycRetailerInfoScreen> {
// final _searchController = TextEditingController();
// final List<String> _filterList = ["Order Status", "Date Range"];
//
// final KycController _kycController = Get.put(KycController());
// final CartController _cartController = Get.put(CartController());
// final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
// GlobalKey<RefreshIndicatorState>();
//
// @override
// void initState() {
// super.initState();
// getKycData();
// }
//
// Future<void> _onRefresh() async {
// await getKycData();
// await Future.delayed(Duration(seconds: 1));
// }
//
// Future<void> getKycData() async {
// await _kycController.fetchKycData();
// print("kyc successfully");
// }
//
// String capitalizeFirstLetter(String text) {
// if (text.isEmpty) return text;
// return text[0].toUpperCase() + text.substring(1).toLowerCase();
// }
//
// String formatDate(String apiDate) {
// DateTime parsedDate = DateTime.parse(apiDate);
// String formattedDate = DateFormat('dd-MMM-yyyy').format(parsedDate);
// return formattedDate;
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// extendBodyBehindAppBar: true,
// appBar: AppBar(
// centerTitle: true,
// backgroundColor: Colors.transparent,
// elevation: 0,
// leading: Builder(
// builder: (context) {
// return GestureDetector(
// onTap: () => Scaffold.of(context).openDrawer(),
// child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: SvgPicture.asset('assets/svg/menu.svg'),
// ),
// );
// },
// ),
// actions: [
// GestureDetector(
// onTap: () => Get.back(),
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: SvgPicture.asset('assets/svg/back_arrow.svg'),
// ),
// ),
// ],
// title: const Text("Kyc Management"),
// ),
// drawer: MyDrawer(),
// body: Stack(
// fit: StackFit.expand,
// children: [
// Image.asset('assets/images/image_1.png', fit: BoxFit.cover),
// SafeArea(
// child: SingleChildScrollView(
// child: Padding(
// padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
// child: RefreshIndicator(
// key: _refreshIndicatorKey,
// onRefresh: _onRefresh,
// color: Colors.black,
// backgroundColor: Colors.white,
// child: Column(
// mainAxisSize: MainAxisSize.min,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// InputField(
// hintText: "Search Order",
// labelText: "Search Order",
// controller: _searchController,
// ),
// SizedBox(height: Get.height * 0.035),
// Card(
// margin: const EdgeInsets.symmetric(horizontal: 18),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(19),
// side: const BorderSide(color: Color(0xFFFDFDFD)),
// ),
// color: const Color(0xFFB4D1E5).withOpacity(0.9),
// child: Padding(
// padding: const EdgeInsets.all(12.0),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// SizedBox(
// height: Get.height * 0.05,
// child: ListView.builder(
// shrinkWrap: true,
// scrollDirection: Axis.horizontal,
// itemCount: _filterList.length,
// itemBuilder: (context, index) => Padding(
// padding: const EdgeInsets.symmetric(horizontal: 4),
// child: Chip(
// label: Text(
// _filterList[index],
// style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w500),
// ),
// ),
// ),
// ),
// ),
// SizedBox(
// height: Get.height * 0.6,
// child: Obx(() {
// // // Use a set to keep track of unique order IDs
// // final Set<String> uniqueOrderIds = {};
// // final List<PlacedOrderList> uniqueOrders = [];
// //
// // for (var order in _kycController.kycList) {
// // if (uniqueOrderIds.add(order.id)) {
// // uniqueOrders.add(order);
// // }
// // }
//
// return ListView.builder(
// padding: EdgeInsets.zero,
// shrinkWrap: true,
// itemCount: _kycController.kycList.length,
// itemBuilder: (context, index) {
// final order = _kycController.kycList[index];
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 8),
// child: Card(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// Text("Order ID: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text("${order.id}")
// ],
// ),
// ),
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.start, // Aligns the Column to the top of the Text
// children: [
// Text(
// "Product Names: ",
// style: GoogleFonts.roboto(
// fontSize: 14,
// fontWeight: FontWeight.bold,
// ),
// ),
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start, // Aligns text to the right within the Column
// children: [
//
// Text(
// '${capitalizeFirstLetter(order!.tradeName.toString())}', // Adds index and trims whitespace
// textAlign: TextAlign.left, // Aligns text to the right
// style: GoogleFonts.roboto(
// fontSize: 14,
// ),
// ),
// ],
// ),
// ),
// ],
// ),
// ),
//
//
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// Text("Order Date: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text(formatDate("${order.createdAt}"))
// ],
// ),
// ),
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 8),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// Text("Status: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text(capitalizeFirstLetter("${order.status}"))
// ],
// ),
// ),
// SizedBox(
// width: Get.width * 0.4,
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: ElevatedButton(
// onPressed: ()=>
// Get.to(() => KycRetailerDetailScreen(
// kycModel: _kycController.kycList[index])),
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
// backgroundColor: const Color(0xFF004791),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(10)),
// ),
// child: Text("View Details", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w400)),
// ),
// ),
// )
// ],
// ),
// ),
// );
// },
// );
// }),
// )
// ],
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// ),
// ],
// ),
// );
// }
// }
//

View File

@ -114,10 +114,6 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
});
}
// void _getOrder(){
// final details = _getPlacedOrderController.getOrder(widget.productModel!.id);
// print("dffgfg,$details");
// }
void _onPlaceOrder() async {
try {
// Map the cart items (Product) to OrderItem objects

View File

@ -14,9 +14,11 @@ import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart';
class OrderConfermationScreen extends StatefulWidget {
Product? productModel;
PlacedOrderModel? placedOrder;
List<Product>? selectedProducts;
Product? productModel; // The selected product model
PlacedOrderModel? placedOrder; // The order details after placement
List<Product>? selectedProducts; // List of selected products for the order
// Constructor to initialize the class with optional parameters
OrderConfermationScreen({super.key,this.productModel,this.placedOrder,this.selectedProducts});
@override
@ -25,28 +27,15 @@ class OrderConfermationScreen extends StatefulWidget {
}
class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
final CartController _cartController = Get.put(CartController());
final CartController _cartController = Get.put(CartController()); // Instance of CartController
// Instance of OrderPlacedController
final OrderPlacedController _placedController = Get.put(OrderPlacedController());
// Instance of GetPlacedOrderController
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
// final List<ProductModel> _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();
// showSnackbar("Get Placed Order Sucessfully");
// print("dffgfg,$details");
// }
@override
Widget build(BuildContext context) {
final orderItems = _placedController.placedOrder1;
final orderItems = _placedController.placedOrder1; // Fetching the placed order details
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
@ -55,7 +44,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
leading: Builder(
builder: (context) {
return GestureDetector(
onTap: () => Scaffold.of(context).openDrawer(),
onTap: () => Scaffold.of(context).openDrawer(), // Open the drawer on tap
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset(
@ -67,7 +56,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
),
actions: [
GestureDetector(
onTap: () => Get.back(),
onTap: () => Get.back(), // Go back on tap
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
@ -92,7 +81,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
child: Column(
children: [
SizedBox(
height: Get.height * 0.02,
height: Get.height * 0.02, // Spacing from the top
),
Card(
margin: const EdgeInsets.symmetric(horizontal: 18),
@ -208,7 +197,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: TextEditingController(
text: widget.placedOrder!.shipTo,
text: widget.placedOrder!.shipTo, // Pre-filling the address
),
decoration: InputDecoration(
hintText: "Address : ${widget.placedOrder!.shipTo}",

View File

@ -16,8 +16,10 @@ import '../../models/product_model1.dart';
class OrderManagementDetailScreen extends StatefulWidget {
//final Product? productModel;
// PlacedOrderList and PlacedOrderModel are optional parameters passed to this screen
PlacedOrderList? placedOrderList;
PlacedOrderModel? placedOrderModel;
// Constructor for initializing the screen with placed order details
OrderManagementDetailScreen({super.key,this.placedOrderList,this.placedOrderModel});
@override
@ -28,8 +30,10 @@ class OrderManagementDetailScreen extends StatefulWidget {
class _OrderManagementDetailScreenState
extends State<OrderManagementDetailScreen> {
// Controllers for managing cart and placed orders
final CartController _cartController = Get.put(CartController());
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
// Function to format date from the API to a more readable format
String formatDate(String apiDate) {
DateTime parsedDate = DateTime.parse(apiDate);
@ -38,15 +42,16 @@ class _OrderManagementDetailScreenState
return formattedDate;
}
// Function to capitalize the first letter of a string
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
// Function to collect unique order IDs and corresponding order details
Future<void> adduni()async {
final Set<String> uniqueOrderIds = {};
final List<PlacedOrderList> uniqueOrders = [];
// Loop through placed orders and add unique orders to the list
for (var order in _getPlacedOrderController.placedOrders) {
if (uniqueOrderIds.add(order.uniqueId)) {
uniqueOrders.add(order);
@ -54,7 +59,7 @@ Future<void> adduni()async {
}
final order = uniqueOrders[0];
// Combine product names into a single string
// Combine product names, categories, and quantities into strings
final productNames = order.orderItem
.map((item) => (item.name))
.join(', ');
@ -125,6 +130,7 @@ Future<void> adduni()async {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
child: Column(
children: [
@ -263,6 +269,7 @@ Future<void> adduni()async {
),
),
const SizedBox(height: 8),
// Card for displaying shipping information
Card(
child: Column(
children: [
@ -301,19 +308,7 @@ Future<void> adduni()async {
),
),
),
// SizedBox(
// width: Get.width,
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: Text(
// "Contact: +91 9123456789",
// style: GoogleFonts.roboto(
// fontSize: Get.width * 0.04,
// fontWeight: FontWeight.w400,
// ),
// ),
// ),
// ),
],
),
),
@ -343,31 +338,7 @@ Future<void> adduni()async {
),
),
SizedBox(height: Get.height * 0.04),
// SizedBox(
// width: Get.width * 0.9,
// height: Get.height * 0.06,
// child: ElevatedButton(
// onPressed: () => Get.to(
// () => OrderFullfilmentScreen(
// placedOrderList:widget.placedOrderList ,
// ),
// ),
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
// backgroundColor: const Color(0xFF00784C),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(10),
// ),
// ),
// child: Text(
// "Fulfill Order",
// style: GoogleFonts.roboto(
// fontSize: Get.width * 0.04,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// ),
],
),
),

View File

@ -33,24 +33,24 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
@override
void initState() {
super.initState();
getOrder1();
getOrder1(); // Fetch orders when the screen initializes
}
Future<void> _onRefresh() async {
await getOrder1();
await Future.delayed(Duration(seconds: 1));
}
// Fetches orders from the API
Future<void> getOrder1() async {
await _getPlacedOrderController.getOrders();
print("Order fetched successfully");
}
// Capitalizes the first letter of the string
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
// Formats the date received from the API
String formatDate(String apiDate) {
DateTime parsedDate = DateTime.parse(apiDate);
String formattedDate = DateFormat('dd-MMM-yyyy').format(parsedDate);
@ -146,13 +146,13 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
// Use a set to keep track of unique order IDs
final Set<String> uniqueOrderIds = {};
final List<PlacedOrderList> uniqueOrders = [];
// Loop through the fetched orders to filter unique orders
for (var order in _getPlacedOrderController.placedOrders) {
if (uniqueOrderIds.add(order.id)) {
uniqueOrders.add(order);
}
}
// Displaying unique orders in a ListView
return ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
@ -240,7 +240,7 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () => Get.to(() => OrderManagementDetailScreen(
placedOrderList: uniqueOrders[index])),
placedOrderList: uniqueOrders[index])), // Navigate to detail screen
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF004791),
@ -275,252 +275,3 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
}
}
// import 'package:cheminova/controller/get_place_order_service.dart';
// import 'package:cheminova/controller/place_order_controller.dart';
// import 'package:cheminova/models/place_order_list_model.dart';
// import 'package:cheminova/screens/order_management/order_management_detail_screen.dart';
// import 'package:cheminova/widgets/input_field.dart';
// import 'package:cheminova/widgets/my_drawer.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:intl/intl.dart';
//
// import '../../controller/cart_controller.dart';
// import '../../controller/get_order_placed_controller.dart';
// import '../../models/product_model1.dart';
// import '../../models/oder_place_model.dart';
// import '../../utils/show_snackbar.dart'; // Ensure this import is correct
//
// class OrderManagementScreen extends StatefulWidget {
// final Product? productModel;
// PlacedOrderList? placeOrder;
// OrderManagementScreen({super.key, this.productModel, this.placeOrder});
//
// @override
// State<OrderManagementScreen> createState() => _OrderManagementScreenState();
// }
//
// class _OrderManagementScreenState extends State<OrderManagementScreen> {
// final _searchController = TextEditingController();
// final List<String> _filterList = ["Order Status", "Date Range"];
//
// final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
// final CartController _cartController = Get.put(CartController());
//
// @override
// void initState() {
// super.initState();
// getOrder1();
// }
//
// Future<void> getOrder1() async {
// await _getPlacedOrderController.getOrders();
// print("Order fetched successfully");
// }
//
// String capitalizeFirstLetter(String text) {
// if (text.isEmpty) return text;
// return text[0].toUpperCase() + text.substring(1).toLowerCase();
// }
//
// String formatDate(String apiDate) {
// DateTime parsedDate = DateTime.parse(apiDate);
// String formattedDate = DateFormat('dd-MMM-yyyy hh:mm:ss a').format(parsedDate);
// return formattedDate;
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// extendBodyBehindAppBar: true,
// appBar: AppBar(
// centerTitle: true,
// backgroundColor: Colors.transparent,
// elevation: 0,
// leading: Builder(
// builder: (context) {
// return GestureDetector(
// onTap: () => Scaffold.of(context).openDrawer(),
// child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: SvgPicture.asset('assets/svg/menu.svg'),
// ),
// );
// },
// ),
// actions: [
// GestureDetector(
// onTap: () => Get.back(),
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: SvgPicture.asset('assets/svg/back_arrow.svg'),
// ),
// ),
// ],
// title: const Text("Order Management"),
// ),
// drawer: const MyDrawer(),
// body: Stack(
// fit: StackFit.expand,
// children: [
// Image.asset('assets/images/image_1.png', fit: BoxFit.cover),
// SafeArea(
// child: SingleChildScrollView(
// child: Padding(
// padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// InputField(
// hintText: "Search Order",
// labelText: "Search Order",
// controller: _searchController,
// ),
// SizedBox(height: Get.height * 0.035),
// Card(
// margin: const EdgeInsets.symmetric(horizontal: 18),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(19),
// side: const BorderSide(color: Color(0xFFFDFDFD)),
// ),
// color: const Color(0xFFB4D1E5).withOpacity(0.9),
// child: Padding(
// padding: const EdgeInsets.all(12.0),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// SizedBox(
// height: Get.height * 0.05,
// child: ListView.builder(
// shrinkWrap: true,
// scrollDirection: Axis.horizontal,
// itemCount: _filterList.length,
// itemBuilder: (context, index) => Padding(
// padding: const EdgeInsets.symmetric(horizontal: 4),
// child: Chip(
// label: Text(
// _filterList[index],
// style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w500),
// ),
// ),
// ),
// ),
// ),
// SizedBox(
// height: Get.height * 0.6,
// child: Obx(() {
// return ListView.builder(
// padding: EdgeInsets.zero,
// shrinkWrap: true,
// itemCount: _getPlacedOrderController.placedOrders.length,
// itemBuilder: (context, index) {
// final order = _getPlacedOrderController.placedOrders[index];
//
// // Combine product names into a single string
// final productNames = order.orderItem
// .map((item) => capitalizeFirstLetter(item.name))
// .join(', ');
//
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 8),
// child: Card(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Order ID: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text("${order.id}")
// ],
// ),
// ),
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Product Names: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Expanded(
// child: Text(productNames,
// style: GoogleFonts.roboto(
// fontSize: 14,
// )),
// ),
// ],
// ),
// ),
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Order Date: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text(formatDate("${order.createdAt}"))
// ],
// ),
// ),
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 8),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Status: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text(capitalizeFirstLetter("${order.status}"))
// ],
// ),
// ),
// SizedBox(
// width: Get.width * 0.4,
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: ElevatedButton(
// onPressed: () => Get.to(() => OrderManagementDetailScreen(
// placedOrderList: _getPlacedOrderController.placedOrders[index])),
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
// backgroundColor: const Color(0xFF004791),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(10)),
// ),
// child: Text("View Details", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w400)),
// ),
// ),
// )
// ],
// ),
// ),
// );
// },
// );
// }),
// )
// ],
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// ],
// ),
// );
// }
// }
//

View File

@ -40,7 +40,7 @@ class _CartScreenState extends State<CartScreen> {
void _toggleSelectAll(bool? value) {
setState(() {
_selectAll = value ?? false;
_cartController.selectAllProducts(_selectAll);
_cartController.selectAllProducts(_selectAll); // Select or deselect all products
});
}
@ -148,7 +148,7 @@ class _CartScreenState extends State<CartScreen> {
onChanged: _toggleSelectAll,
),
Text(
"Select All",
"Select All", // Label for the select all checkbox
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w500,
@ -166,7 +166,7 @@ class _CartScreenState extends State<CartScreen> {
children: [
Checkbox(
value: _cartController.selectedProducts.contains(
_cartController.cartList[index]),
_cartController.cartList[index]), // Checkbox for individual product selection
onChanged: (value) {
_cartController.toggleProductSelection(
_cartController.cartList[index],
@ -244,7 +244,7 @@ class _CartScreenState extends State<CartScreen> {
height: Get.height * 0.06,
child: ElevatedButton(
onPressed: () => Get.to(() => CheckoutScreen(
selectedProducts: _cartController.selectedProducts,
selectedProducts: _cartController.selectedProducts, // Pass selected products to checkout
)),
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,

View File

@ -3,22 +3,23 @@ import 'package:cheminova/models/product_mannual_model.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
// The ViewPdfScreen widget to display a PDF document
class ViewPdfScreen extends StatefulWidget {
final ProductManualModel productManualModel;
// Constructor for ViewPdfScreen, requires a ProductManualModel
const ViewPdfScreen({super.key, required this.productManualModel});
@override
State<ViewPdfScreen> createState() => _ViewPdfScreenState();
}
// State class for ViewPdfScreen
class _ViewPdfScreenState extends State<ViewPdfScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SfPdfViewer.network(
widget.productManualModel.productManual.url,
widget.productManualModel.productManual.url, // Fetch the PDF URL from the model
),
),
);

View File

@ -18,14 +18,14 @@ class ProductCatalogScreen extends StatefulWidget {
}
class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
final ProductService _productService = ProductService();
final ProductService _productService = ProductService(); // Service for fetching products
final ScrollController _scrollController = ScrollController();
final CartController cartController = Get.put(CartController());
final CartController cartController = Get.put(CartController()); // Cart controller for managing cart state
List<Product> _products = []; // Use ProductModel here
List<Product> _products = []; // List to hold fetched products
List<Map<String, dynamic>> _categories = [];
int _currentPage = 1;
int _currentPage = 1; // Current page for pagination
bool _isLoading = false;
bool _hasMoreData = true;
@ -36,9 +36,10 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
@override
void initState() {
super.initState();
_fetchCategories();
_fetchProducts();
_fetchCategories(); // Fetch categories on initialization
_fetchProducts(); // Fetch initial products
_scrollController.addListener(() {
// Listener to fetch more products when scrolling to the bottom
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent &&
!_isLoading &&
@ -47,25 +48,26 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
}
});
}
// Function to fetch products based on current filters and pagination
Future<void> _fetchProducts() async {
setState(() {
_isLoading = true;
});
// Set the category based on the selected category; use null for 'All'
final category = _selectedCategory == 'All' ? null : _selectedCategory;
// Fetch products from the service
final products = await _productService.getProduct(
_currentPage, category: category);
setState(() {
if (products != null) {
_products.addAll(products); // Assuming products is a List<ProductModel>
_products.addAll(products); // Add fetched products to the list
_hasMoreData = products.isNotEmpty;
}
_isLoading = false;
});
}
// Function to fetch categories from the service
Future<void> _fetchCategories() async {
final categories = await _productService.getCategory();
if (categories != null) {
@ -76,7 +78,7 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
});
}
}
// Function to handle category change
void _onCategoryChanged(String? newCategory) {
if (newCategory != null) {
setState(() {
@ -84,34 +86,34 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
_products.clear();
_currentPage = 1;
});
_fetchProducts();
_fetchProducts(); // Fetch products for the new category
}
}
// Function to fetch more products for pagination
Future<void> _fetchMoreProducts() async {
if (!_isLoading && _hasMoreData) {
setState(() {
_isLoading = true;
_currentPage++;
});
await _fetchProducts();
await _fetchProducts(); // Fetch more products
}
}
// Function to clear all filters
void _clearFilters() {
setState(() {
_selectedCategory = null;
_selectedPriceRange = null;
_selectedAvailability = null;
_products.clear();
_products.clear(); // Clear existing products
_currentPage = 1;
});
_fetchProducts();
_fetchProducts(); // Fetch products without filters
}
@override
void dispose() {
_scrollController.dispose();
_scrollController.dispose(); // Dispose of the scroll controller
super.dispose();
}
@ -263,7 +265,7 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
padding: const EdgeInsets.symmetric(
vertical: 8),
child: ProductCard(
productModel: _products[index],
productModel: _products[index], // Product card for each product
// Use ProductModel here
),
);
@ -282,7 +284,7 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
),
);
}
// Function to build filter dropdowns
Widget _buildFilterDropdown(int index) {
switch (index) {
case 0:

View File

@ -23,7 +23,8 @@ class ProductDetailScreen extends StatefulWidget {
}
class _ProductDetailScreenState extends State<ProductDetailScreen> {
final CartController _cartController = Get.put(CartController());
final CartController _cartController = Get.put(CartController());// Initialize CartController
// Function to capitalize the first letter of a string
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
@ -114,6 +115,7 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
),
),
),
// Displaying product name
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
@ -131,6 +133,7 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
],
),
),
// Displaying product price
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
@ -148,6 +151,7 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
],
),
),
// Displaying product category
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
@ -166,6 +170,7 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
),
),
const SizedBox(height: 8),
// Displaying product description
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
@ -187,13 +192,14 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
),
),
SizedBox(height: Get.height * 0.04),
// Add to Cart button
SizedBox(
width: Get.width * 0.9,
height: Get.height * 0.06,
child: ElevatedButton(
onPressed: () {
// Pass the product data to the CartScreen
_cartController.addToCart(widget.productModel!);
_cartController.addToCart(widget.productModel!); // Add product to cart
showSnackbar("Product successfully added to your cart");
},
style: ElevatedButton.styleFrom(

View File

@ -14,12 +14,14 @@ class ProductsManualScreen extends StatefulWidget {
}
class _ProductsManualScreenState extends State<ProductsManualScreen> {
// Initialize the ProductManualController using GetX for managing state
final ProductManualController _productManualController = Get.put(ProductManualController());
@override
void initState() {
super.initState();
_productManualController.fetchProductManuals(); // Fetch product manual list from API
// Fetch product manual list from API when the screen initializes
_productManualController.fetchProductManuals();
}
@override
@ -83,17 +85,17 @@ class _ProductsManualScreenState extends State<ProductsManualScreen> {
);
}
// Build the card content
// Method to build the main card content with the list of product manuals
Widget _buildCardContent() {
return Obx(() {
if (_productManualController.isLoading.value) {
return const CircularProgressIndicator(); // Loading state
}
// Check if the product manual list is empty
if (_productManualController.productManualList.isEmpty) {
return const Text("No product manuals available"); // Empty state
}
// Display the card with a list of product manual buttons
return Card(
margin: const EdgeInsets.symmetric(horizontal: 24),
shape: RoundedRectangleBorder(
@ -104,7 +106,7 @@ class _ProductsManualScreenState extends State<ProductsManualScreen> {
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: _buildProductButtons(),
children: _buildProductButtons(), // Dynamically build buttons from API data
),
),
);
@ -116,18 +118,18 @@ class _ProductsManualScreenState extends State<ProductsManualScreen> {
return _productManualController.productManualList.map((productManual) {
return CustomButton(
text: productManual.title ?? "No Title", // Dynamically fetch product name
onPressed: () => _navigateToPdfScreen(productManual),
onPressed: () => _navigateToPdfScreen(productManual), // Navigate to PDF screen on button press
);
}).toList();
}
// Method to handle navigation to PDF screen
// Method to handle navigation to the PDF screen with the selected product manual
void _navigateToPdfScreen(ProductManualModel productManual) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ViewPdfScreen(
productManualModel: productManual,
productManualModel: productManual, // Pass the selected product manual data to the PDF screen
),
),
);

View File

@ -1,60 +0,0 @@
import 'package:cheminova/utils/secure__storage_service.dart';
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'api_urls.dart';
class ApiClient {
final Dio _dio;
final SecureStorageService _storageService = SecureStorageService();
ApiClient({String? baseUrl})
: _dio = Dio(BaseOptions(
baseUrl: baseUrl ?? ApiUrls.baseUrl,
connectTimeout: const Duration(seconds: 120),
receiveTimeout: const Duration(seconds: 120))) {
_dio.interceptors
.add(LogInterceptor(responseBody: true, requestBody: true));
_dio.interceptors
.add(InterceptorsWrapper(onRequest: (options, handler) async {
String? token = await _storageService.read(key: 'access_token');
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
_dio.interceptors
.add(LogInterceptor(responseBody: true, requestBody: true));
_dio.interceptors.add(PrettyDioLogger(
requestHeader: true,
requestBody: true,
responseBody: true,
responseHeader: false,
error: true,
compact: true,
maxWidth: 90,
));
return handler.next(options);
}, onResponse: (response, handler) {
return handler.next(response);
}, onError: (DioException e, handler) {
return handler.next(e);
}));
}
Future<dynamic> get(String path, {Map<String, dynamic>? queryParameters}) {
return _dio.get(path, queryParameters: queryParameters);
}
Future<Response> post(String path, {dynamic data}) {
return _dio.post(path, data: data);
}
Future<Response> put(String path, {Map<String, dynamic>? data}) {
return _dio.put(path, data: data);
}
Future<Response> delete(String path, {Map<String, dynamic>? data}) {
return _dio.delete(path, data: data);
}
}

View File

@ -1,18 +1,40 @@
class ApiUrls {
// static const String baseUrl = 'https://cheminova-api-2.onrender.com/api/';
//============================== Base Url =========================================//
static const String baseUrl = 'https://api.cnapp.co.in';
//============================== Login =========================================//
static const String loginUrl = '/api/v1/user/login/';
static const String profileUrl = '/api/v1/user/details';
static const String forgetPasswordUrl = '/api/v1/user/password/forgot';
static const String changePasswordUrl = '/api/v1/user/password/update';
static const String fcmUrl = '/api/v1/user/fcm-token';
//============================== User Details ==============================//
static const String profileUrl = '/api/v1/user/details';
//============================== Product Details ==============================//
static const String getCategoryUrl = '/api/category/getCategories';
static const String getProductUrl = '/api/category/getCategories';
static const String getProductManualUrl = '/api/productmanual/getall';
static const String getKycUrl = '/api/kyc/getAll';
static const String getNotificationUrl = '/api/get-notification-pd';
// static const String getProductUrl = '/api/category/getCategories';
static const String getallProductUrl = '/api/product/getAll/user';
//============================== Placed Order Details ==============================//
static const String getPlacedOrderUrl ='/api/get-placed-order-pd';
static const String getSinglePlacedOrderUrl ='/api/get-single-placed-order-pd';
static const String placedOrderUrl ='${baseUrl}/api/order-place';
//============================== Product Manual ==============================//
static const String getProductManualUrl = '/api/productmanual/getall';
//============================== Notification Details ==============================//
static const String getNotificationUrl = '/api/get-notification-pd';
//============================== Kyc Details ==============================//
static const String getKycUrl = '${baseUrl}/api/kyc/getAll';
}

View File

@ -1,20 +1,22 @@
import 'dart:io';
import 'package:cheminova/utils/api_urls.dart';
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';
// Generic API service function that handles API requests with optional file uploads
Future<BodyType?> commonApiService<BodyType>({
required String url,
required String method,
Map<String, dynamic> body = const {},
File? imageFile,
Map<String, dynamic> body = const {}, // Request body
File? imageFile, // Optional image file for upload
bool isformData = true,
Map<String, String>? additionalHeaders,
required BodyType Function(Map<String, dynamic>) fromJson,
Map<String, String>? additionalHeaders, // Additional headers for the request
required BodyType Function(Map<String, dynamic>) fromJson,// Function to parse the response data
}) async {
try {
// Initialize Dio for making HTTP requests
Dio dio = Dio();
final Response response;
@ -23,22 +25,23 @@ Future<BodyType?> commonApiService<BodyType>({
// Fetch the token from SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
// Setting default headers, including Content-Type and Authorization if token is present
Map<String, String> headers = {
'Content-Type': isformData ? 'multipart/form-data' : 'application/json',
};
// Adding the token to the headers if available
if (token != null) {
headers['Authorization'] = 'Bearer $token';
}
// Adding any additional headers provided in the request
if (additionalHeaders != null) {
headers.addAll(additionalHeaders);
}
// Setting options with the headers
Options options = Options(headers: headers);
// Preparing form data for requests, especially if files are involved
FormData formData = FormData.fromMap(body);
// Adding the image file to the form data if present
if (imageFile != null) {
String fileName = imageFile.path.split('/').last;
formData.files.add(MapEntry(
@ -46,25 +49,26 @@ Future<BodyType?> commonApiService<BodyType>({
await MultipartFile.fromFile(imageFile.path, filename: fileName),
));
}
// Handling different HTTP methods based on the provided method parameter
if (method == "POST") {
response = await dio.post("$baseUrl$url",
response = await dio.post("${ApiUrls.baseUrl}$url",
data: isformData ? formData : body, options: options);
} else if (method == "PUT") {
response = await dio.put("$baseUrl$url",
response = await dio.put("${ApiUrls.baseUrl}$url",
data: isformData ? formData : body, options: options);
} else if (method == "DELETE") {
response = await dio.delete("$baseUrl$url", options: options);
response = await dio.delete("${ApiUrls.baseUrl}$url", options: options);
} else if (method == "PATCH") {
response = await dio.patch("$baseUrl$url",
response = await dio.patch("${ApiUrls.baseUrl}$url",
data: isformData ? formData : body, options: options);
} else {
response = await dio.get("$baseUrl$url", options: options);
// Default to GET method if no specific method is matched
response = await dio.get("${ApiUrls.baseUrl}$url", options: options);
}
print("response of $url : $response");
// Special handling for login endpoint to store token in SharedPreferences
if (url == "/api/v1/user/login/" &&
response.data['token'] != null) {
prefs.setString('token', response.data['token']);
@ -73,14 +77,14 @@ Future<BodyType?> commonApiService<BodyType>({
// if (url == "/api/territorymanager/my-profile") {
// return fromJson(response.data['myData']);
// }
// Returning parsed response data using the fromJson function provided
return fromJson(response.data);
} on DioException catch (e) {
print("dio exception $url ${e.response?.data}}");
print("dio exception details: ${e.message} ${e.response?.statusCode}");
String errorMessage = "An error occurred";
// Extracting error message from the response if available
if (e.response?.data is Map<String, dynamic>) {
errorMessage = e.response?.data['message'] ?? errorMessage;
} else if (e.response?.data is String) {
@ -91,5 +95,6 @@ Future<BodyType?> commonApiService<BodyType>({
} catch (e) {
print("exception $url $e");
}
// Returning null in case of any exception
return null;
}

View File

@ -1,3 +1,3 @@
//String baseUrl = "https://cheminova-api-2.onrender.com";
String baseUrl = "https://api.cnapp.co.in";
//String baseUrl = "https://api.cnapp.co.in";

View File

@ -1,46 +1,46 @@
import 'package:flutter/material.dart';
class CommonElevatedButton extends StatelessWidget {
final String text;
final void Function()? onPressed;
final double? height;
final double? width;
final double? borderRadius;
final Color? backgroundColor;
final bool isLoading;
const CommonElevatedButton(
{super.key,
required this.text,
this.onPressed,
this.borderRadius,
this.backgroundColor,
this.height,
this.width,
this.isLoading = false});
@override
Widget build(BuildContext context) {
return SizedBox(
height: height ?? kToolbarHeight - 25,
width: width ?? 200,
child: ElevatedButton(
onPressed: isLoading ? null : onPressed,
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius ?? 6)),
backgroundColor: backgroundColor ?? const Color(0xff1E1E1E),
side: const BorderSide(color: Colors.transparent)),
child: Center(
child: isLoading
? const CircularProgressIndicator(
backgroundColor: Colors.white,
valueColor: AlwaysStoppedAnimation<Color>(Colors.black))
: Text(text,
style: const TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.w400,
fontFamily: 'Anek')))));
}
}
// import 'package:flutter/material.dart';
//
// class CommonElevatedButton extends StatelessWidget {
// final String text;
// final void Function()? onPressed;
// final double? height;
// final double? width;
// final double? borderRadius;
// final Color? backgroundColor;
// final bool isLoading;
//
// const CommonElevatedButton(
// {super.key,
// required this.text,
// this.onPressed,
// this.borderRadius,
// this.backgroundColor,
// this.height,
// this.width,
// this.isLoading = false});
//
// @override
// Widget build(BuildContext context) {
// return SizedBox(
// height: height ?? kToolbarHeight - 25,
// width: width ?? 200,
// child: ElevatedButton(
// onPressed: isLoading ? null : onPressed,
// style: ElevatedButton.styleFrom(
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(borderRadius ?? 6)),
// backgroundColor: backgroundColor ?? const Color(0xff1E1E1E),
// side: const BorderSide(color: Colors.transparent)),
// child: Center(
// child: isLoading
// ? const CircularProgressIndicator(
// backgroundColor: Colors.white,
// valueColor: AlwaysStoppedAnimation<Color>(Colors.black))
// : Text(text,
// style: const TextStyle(
// fontSize: 15,
// color: Colors.white,
// fontWeight: FontWeight.w400,
// fontFamily: 'Anek')))));
// }
// }

View File

@ -5,8 +5,8 @@ import 'package:google_fonts/google_fonts.dart';
class HomeCard extends StatelessWidget {
final String title;
final VoidCallback onTap;
final VoidCallback onTap; // Function to execute when the card is tapped
// Constructor to initialize the card with title and onTap action
const HomeCard({
super.key,
required this.title,
@ -16,7 +16,7 @@ class HomeCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
onTap: onTap, // Handling tap event on the card
child: Container(
margin: const EdgeInsets.fromLTRB(0, 0, 20, 0),
child: ClipRect(

View File

@ -17,16 +17,17 @@ class MyDrawer extends StatefulWidget {
}
class _MyDrawerState extends State<MyDrawer> {
final homecontroller = Get.put(HomeController());
final homecontroller = Get.put(HomeController()); // Initialize HomeController
@override
Widget build(BuildContext context) {
final user = homecontroller.user;
final user = homecontroller.user; // Get the current user from HomeController
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
SizedBox(
height: 150,
// Drawer header displaying user information
child: DrawerHeader(
decoration: const BoxDecoration(
color: Colors.black87,
@ -53,6 +54,7 @@ class _MyDrawerState extends State<MyDrawer> {
),
),
),
// Navigation tile for Home
ListTile(
leading: const Icon(Icons.home),
title: const Text('Home'),
@ -60,10 +62,11 @@ class _MyDrawerState extends State<MyDrawer> {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const HomeScreen()),
(route) => false,
(route) => false, // Remove all previous routes
);
},
),
// Navigation tile for Profile
ListTile(
leading: const Icon(Icons.account_circle),
title: const Text('Profile'),
@ -74,6 +77,7 @@ class _MyDrawerState extends State<MyDrawer> {
);
},
),
// Navigation tile for Change Password
ListTile(
leading: const Icon(Icons.settings),
title: const Text('Change Password'),
@ -84,6 +88,7 @@ class _MyDrawerState extends State<MyDrawer> {
);
},
),
// Navigation tile for Logout
ListTile(
leading: const Icon(Icons.exit_to_app),
title: const Text('Logout'),
@ -96,7 +101,7 @@ class _MyDrawerState extends State<MyDrawer> {
);
}
}
// Function to display logout confirmation dialog
Future logoutBox(BuildContext context) {
Size size = MediaQuery.of(context).size;
return showDialog(

View File

@ -50,12 +50,13 @@ class _ProductCardState extends State<ProductCard> {
final CartController _cartController = Get.put(CartController());
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, either from the cart or the default value
int currentQuantity = isProductInCart
? _cartController.cartList.firstWhere((p) => p.id == widget.productModel!.id).quantity
: widget.productModel!.quantity;
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)),
@ -84,6 +85,7 @@ class _ProductCardState extends State<ProductCard> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Display the product name with the first letter capitalized
Text(
capitalizeFirstLetter(widget.productModel!.name),
style: GoogleFonts.roboto(
@ -91,6 +93,7 @@ class _ProductCardState extends State<ProductCard> {
fontWeight: FontWeight.w500,
),
),
// Display the category name of the product
Text(
capitalizeFirstLetter(widget.productModel!.category!.categoryName),
style: GoogleFonts.roboto(
@ -98,6 +101,7 @@ class _ProductCardState extends State<ProductCard> {
fontWeight: FontWeight.w400,
),
),
// Display the price of the product
Text(
"${widget.productModel!.price.toString()}",
style: GoogleFonts.roboto(
@ -113,6 +117,7 @@ class _ProductCardState extends State<ProductCard> {
fontWeight: FontWeight.w700,
),
),
// Display quantity adjustment buttons and remove button if the product is in cart
if (!widget.isCheckout)
widget.isInCart
? Row(