1)All files comments added
This commit is contained in:
parent
fadbad07bf
commit
545b43aef5
29
android/app/google-services.json
Normal file
29
android/app/google-services.json
Normal 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
1
firebase.json
Normal 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"}}}}}}
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
@ -4,20 +4,24 @@ 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,
|
||||
additionalHeaders: { // Pass the token here
|
||||
additionalHeaders: { // Pass the token here
|
||||
'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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
print("response of /api/kyc/getAll : ${response.data}");
|
||||
// Check if the response status code indicates success
|
||||
if (response.statusCode == 200) {
|
||||
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;
|
||||
// }
|
||||
// }
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
||||
@ -42,88 +43,4 @@ class OrderPlacedController extends GetxController {
|
||||
// } finally {
|
||||
// isLoading.value = false;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// import 'package:cheminova/controller/place_order_service.dart';
|
||||
// import 'package:cheminova/models/category_model.dart';
|
||||
// import 'package:get/get.dart';
|
||||
// import 'package:shared_preferences/shared_preferences.dart';
|
||||
// import '../models/oder_place_model.dart';
|
||||
// import 'cart_controller.dart';
|
||||
//
|
||||
//
|
||||
// class OrderPlacedController extends GetxController {
|
||||
// final OrderPlacedService _orderPlacedService = OrderPlacedService();
|
||||
// final CartController _cartController = Get.find();
|
||||
// Rx<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';
|
||||
// }
|
||||
// }
|
||||
}
|
@ -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: {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 [];
|
||||
}
|
||||
|
@ -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
75
lib/firebase_options.dart
Normal 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',
|
||||
);
|
||||
|
||||
}
|
@ -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(),
|
||||
|
@ -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,)';
|
||||
// }
|
||||
// }
|
@ -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;
|
||||
// }
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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()),
|
||||
|
@ -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),
|
||||
|
@ -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(
|
||||
@ -95,7 +95,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
HomeCard(
|
||||
title: 'Order Tracking',
|
||||
onTap: () => Get.to(
|
||||
() => const OrderTrackingScreen(),
|
||||
() => const OrderTrackingScreen(),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -107,13 +107,13 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
HomeCard(
|
||||
title: 'Order Management',
|
||||
onTap: () => Get.to(
|
||||
() => OrderManagementScreen(),
|
||||
() => OrderManagementScreen(),
|
||||
),
|
||||
),
|
||||
HomeCard(
|
||||
title: 'Shipping Management',
|
||||
onTap: () => Get.to(
|
||||
() => const ShippingManagementScreen(),
|
||||
() => const ShippingManagementScreen(),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -125,13 +125,13 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
HomeCard(
|
||||
title: 'Inventory Management',
|
||||
onTap: () => Get.to(
|
||||
() => const InventoryManagementScreen(),
|
||||
() => const InventoryManagementScreen(),
|
||||
),
|
||||
),
|
||||
HomeCard(
|
||||
title: 'Reporting & Analytics',
|
||||
onTap: () => Get.to(
|
||||
() => const ReportingAnalyticsScreen(),
|
||||
() => const ReportingAnalyticsScreen(),
|
||||
),
|
||||
),
|
||||
|
||||
@ -144,13 +144,13 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
HomeCard(
|
||||
title: 'Order Data Export',
|
||||
onTap: () => Get.to(
|
||||
() => const OrderHistoryReportScreen(),
|
||||
() => const OrderHistoryReportScreen(),
|
||||
),
|
||||
),
|
||||
HomeCard(
|
||||
title: 'Retail Distributors Onboarding',
|
||||
onTap: () => Get.to(
|
||||
() => const RetailDistributerOnBoardingScreen(),
|
||||
() => const RetailDistributerOnBoardingScreen(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -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 {
|
||||
_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
|
||||
// Update the status in the model before calling the controller method
|
||||
widget.kycModel!.status = "approved";
|
||||
_kycController.updateKycStatus(widget.kycModel!, "approved", "");
|
||||
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,
|
||||
|
@ -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)),
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// }),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
@ -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
|
||||
|
@ -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}",
|
||||
|
@ -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,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -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)),
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// }),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -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:
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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';
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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";
|
@ -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')))));
|
||||
// }
|
||||
// }
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user