diff --git a/android/app/build.gradle b/android/app/build.gradle
index e2ee37a..fcfd7eb 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,5 +1,9 @@
plugins {
id "com.android.application"
+ // START: FlutterFire Configuration
+ id 'com.google.gms.google-services'
+ id 'com.google.firebase.crashlytics'
+ // END: FlutterFire Configuration
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
@@ -24,7 +28,7 @@ if (flutterVersionName == null) {
}
android {
- namespace = "com.example.cheminova"
+ namespace = "com.example.cheminova_rd"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@@ -35,7 +39,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
- applicationId = "com.example.cheminova"
+ applicationId = "com.example.cheminova_rd"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdk = flutter.minSdkVersion
@@ -56,3 +60,10 @@ android {
flutter {
source = "../.."
}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.10.0'
+ implementation 'androidx.activity:activity:1.8.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+}
diff --git a/android/app/google-services.json b/android/app/google-services.json
new file mode 100644
index 0000000..eb1938e
--- /dev/null
+++ b/android/app/google-services.json
@@ -0,0 +1,29 @@
+{
+ "project_info": {
+ "project_number": "181536932687",
+ "project_id": "cheminova-rd",
+ "storage_bucket": "cheminova-rd.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:181536932687:android:8f3b0977f4b4dcc56f7b3a",
+ "android_client_info": {
+ "package_name": "com.example.cheminova_rd"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyAYZUuqmSoE9MrTvOaavYYjdRoQFD-XnFc"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 7c7f3d0..ae729ce 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,49 +1,62 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+ android:icon="@mipmap/ic_launcher"
+ android:label="cheminova">
-
+ to determine the Window background behind the Flutter UI.
+ -->
+ android:name="io.flutter.embedding.android.NormalTheme"
+ android:resource="@style/NormalTheme" />
+
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/example/cheminova/MainActivity.kt b/android/app/src/main/kotlin/com/example/cheminova_rd/MainActivity.kt
similarity index 73%
rename from android/app/src/main/kotlin/com/example/cheminova/MainActivity.kt
rename to android/app/src/main/kotlin/com/example/cheminova_rd/MainActivity.kt
index 548a7cf..6a5d304 100644
--- a/android/app/src/main/kotlin/com/example/cheminova/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/example/cheminova_rd/MainActivity.kt
@@ -1,4 +1,4 @@
-package com.example.cheminova
+package com.example.cheminova_rd
import io.flutter.embedding.android.FlutterActivity
diff --git a/android/build.gradle b/android/build.gradle
index d2ffbff..a054dd4 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,3 +1,8 @@
+buildscript {
+ dependencies {
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10'
+ }
+}
allprojects {
repositories {
google()
diff --git a/android/settings.gradle b/android/settings.gradle
index 536165d..5959482 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -19,6 +19,10 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
+ // START: FlutterFire Configuration
+ id "com.google.gms.google-services" version "4.3.15" apply false
+ id "com.google.firebase.crashlytics" version "2.8.1" apply false
+ // END: FlutterFire Configuration
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}
diff --git a/lib/controller/get_order_placed_controller.dart b/lib/controller/get_order_placed_controller.dart
index 911a9e7..44b2fe3 100644
--- a/lib/controller/get_order_placed_controller.dart
+++ b/lib/controller/get_order_placed_controller.dart
@@ -17,7 +17,8 @@ class GetPlacedOrderController extends GetxController {
Get.put(OrderPlacedController());
final GetSingleOrderPlacedService _getSingleOrderPlacedService =
GetSingleOrderPlacedService();
- var placedOrders = [].obs;
+ List placedOrders = [].obs;
+ List filterOrder = [].obs;
var products = [].obs;
var isLoading = false.obs;
@@ -31,6 +32,8 @@ class GetPlacedOrderController extends GetxController {
RxInt currentPage = 1.obs;
RxBool hasMoreOrders = true.obs;
+ RxString productStatus = 'All'.obs;
+
Future getOrders() async {
if (isLoading.value || !hasMoreOrders.value) return;
@@ -44,7 +47,6 @@ class GetPlacedOrderController extends GetxController {
if (response.statusCode == 200) {
placedOrders.addAll(data.placedOrders ?? []);
- debugPrint('allOrders.length: ${placedOrders.toJson()}');
currentPage++;
hasMoreOrders.value = placedOrders.length < data.totalOrders!.toInt();
} else {
@@ -82,6 +84,18 @@ class GetPlacedOrderController extends GetxController {
}
}
+ void updateProductStatus(dynamic newValue) {
+ productStatus.value = newValue;
+ filterOrder.clear();
+ if (productStatus.value == 'All') {
+ filterOrder.addAll(placedOrders);
+ } else {
+ filterOrder.addAll(placedOrders
+ .where((order) => order.status.toString().toLowerCase() == productStatus.value.toLowerCase())
+ .toList());
+ }
+ }
+
// // Optional: Reset the pagination if needed
// void resetPagination() {
// _getOrderPlacedService.resetPagination();
diff --git a/lib/controller/inventory_management_controller.dart b/lib/controller/inventory_management_controller.dart
new file mode 100644
index 0000000..bc8e008
--- /dev/null
+++ b/lib/controller/inventory_management_controller.dart
@@ -0,0 +1 @@
+import 'dart:convert';
import 'package:cheminova/services/api_service.dart';
import 'package:cheminova/utils/api_urls.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import '../models/InventoryManagementResponse.dart';
class InventoryManagementController extends GetxController {
final apiService = ApiService();
Future getProducts() async {
final response =
await apiService.get(ApiUrls.inventoryManangementOrdersStock);
if (response.statusCode == 200) {
return InventoryManagementResponse.fromJson(response.data);
}else{
return InventoryManagementResponse();
}
}
}
\ No newline at end of file
diff --git a/lib/controller/notification_controller.dart b/lib/controller/notification_controller.dart
new file mode 100644
index 0000000..2c910db
--- /dev/null
+++ b/lib/controller/notification_controller.dart
@@ -0,0 +1,32 @@
+import 'package:cheminova/services/api_service.dart';
+import 'package:get/get.dart';
+import '../models/NotificationListResponse.dart';
+
+import '../utils/api_urls.dart';
+
+class NotificationController extends GetxController {
+ final ApiService _apiClient = ApiService();
+ RxList notificationsList = [].obs;
+ RxBool isLoading = false.obs;
+
+ @override
+ void onInit() {
+ super.onInit();
+ getNotification();
+ }
+
+ Future getNotification() async {
+ isLoading.value = true;
+ try {
+ final response = await _apiClient.get(ApiUrls.getNotificationUrl);
+ isLoading.value = false;
+ if (response.statusCode == 200) {
+ final data = NotificationListResponse.fromJson(response.data);
+ notificationsList.value = data.notifications ?? [];
+ }
+ } catch (e) {
+ isLoading.value = false;
+ Get.snackbar('Error', 'Failed to fetch notifications');
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart
new file mode 100644
index 0000000..75b157f
--- /dev/null
+++ b/lib/firebase_options.dart
@@ -0,0 +1,69 @@
+// 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:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for macos - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ 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: 'AIzaSyAYZUuqmSoE9MrTvOaavYYjdRoQFD-XnFc',
+ appId: '1:181536932687:android:8f3b0977f4b4dcc56f7b3a',
+ messagingSenderId: '181536932687',
+ projectId: 'cheminova-rd',
+ storageBucket: 'cheminova-rd.appspot.com',
+ );
+
+ static const FirebaseOptions ios = FirebaseOptions(
+ apiKey: 'AIzaSyCerSkU_YMUkOhz5uM7t8pCOFi6mvkLpOw',
+ appId: '1:181536932687:ios:a4866cdefdcb5cf06f7b3a',
+ messagingSenderId: '181536932687',
+ projectId: 'cheminova-rd',
+ storageBucket: 'cheminova-rd.appspot.com',
+ iosBundleId: 'com.example.cheminova',
+ );
+
+}
\ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
index 57040fd..5bbb7e5 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,8 +1,94 @@
+import 'dart:developer';
+import 'dart:io';
+
import 'package:cheminova/screens/splash_screen.dart';
+import 'package:firebase_core/firebase_core.dart';
+import 'package:firebase_crashlytics/firebase_crashlytics.dart';
+import 'package:firebase_messaging/firebase_messaging.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:get/get.dart';
+import 'firebase_options.dart';
+
+
+
+@pragma('vm:entry-point')
+Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
+ await Firebase.initializeApp();
+ log("Handling a background message: ${message.data["data"]}");
+}
+
+AndroidNotificationChannel channel = const AndroidNotificationChannel(
+ 'High Importance Channel', 'High Importance Notifications',
+ importance: Importance.high);
+
+late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
void main()async{
+
+ WidgetsFlutterBinding.ensureInitialized();
+
+ await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
+ FlutterError.onError = (errorDetails) {
+ FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
+ };
+ PlatformDispatcher.instance.onError = (error, stack) {
+ FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
+ return true;
+ };
+
+ if (!kIsWeb) {
+ flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
+
+ FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
+
+ await FirebaseMessaging.instance.getInitialMessage().then((message) {});
+
+ FirebaseMessaging.onMessage.listen((RemoteMessage message) {
+ RemoteNotification? notification = message.notification;
+ AndroidNotification? android = message.notification?.android;
+ if (notification != null && android != null) {
+ flutterLocalNotificationsPlugin.show(
+ notification.hashCode,
+ notification.title,
+ notification.body,
+ NotificationDetails(
+ android: AndroidNotificationDetails(channel.id, channel.name,
+ icon: '@mipmap/ic_launcher', importance: Importance.max),
+ iOS: const DarwinNotificationDetails()));
+ const AndroidInitializationSettings initializationSettingsAndroid =
+ AndroidInitializationSettings('@mipmap/ic_launcher');
+ const DarwinInitializationSettings darwinInitializationSettings =
+ DarwinInitializationSettings();
+ var initSettings = const InitializationSettings(
+ android: initializationSettingsAndroid,
+ iOS: darwinInitializationSettings);
+ flutterLocalNotificationsPlugin.initialize(initSettings);
+ }
+ });
+
+ if (Platform.isAndroid) {
+ await flutterLocalNotificationsPlugin
+ .resolvePlatformSpecificImplementation<
+ AndroidFlutterLocalNotificationsPlugin>()
+ ?.requestNotificationsPermission();
+ await flutterLocalNotificationsPlugin
+ .resolvePlatformSpecificImplementation<
+ AndroidFlutterLocalNotificationsPlugin>()
+ ?.createNotificationChannel(channel);
+ }
+ if (Platform.isIOS) {
+ await flutterLocalNotificationsPlugin
+ .resolvePlatformSpecificImplementation<
+ IOSFlutterLocalNotificationsPlugin>()
+ ?.requestPermissions(alert: true, badge: true, sound: true);
+ }
+
+ await FirebaseMessaging.instance
+ .setForegroundNotificationPresentationOptions(
+ alert: true, badge: true, sound: true);
+ }
runApp(const MyApp());
}
diff --git a/lib/models/InventoryManagementResponse.dart b/lib/models/InventoryManagementResponse.dart
new file mode 100644
index 0000000..4a9519d
--- /dev/null
+++ b/lib/models/InventoryManagementResponse.dart
@@ -0,0 +1,100 @@
+class InventoryManagementResponse {
+ bool? success;
+ int? totalProducts;
+ List? products;
+
+ InventoryManagementResponse(
+ {this.success, this.totalProducts, this.products});
+
+ InventoryManagementResponse.fromJson(Map json) {
+ success = json['success'];
+ totalProducts = json['totalProducts'];
+ if (json['products'] != null) {
+ products = [];
+ json['products'].forEach((v) {
+ products!.add(new Products.fromJson(v));
+ });
+ }
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['success'] = this.success;
+ data['totalProducts'] = this.totalProducts;
+ if (this.products != null) {
+ data['products'] = this.products!.map((v) => v.toJson()).toList();
+ }
+ return data;
+ }
+}
+
+class Products {
+ String? sId;
+ String? sKU;
+ String? name;
+ int? price;
+ int? gST;
+ int? hSNCode;
+ String? description;
+ String? productStatus;
+ String? addedBy;
+ List? image;
+ String? createdAt;
+ String? updatedAt;
+ String? category;
+ String? brand;
+ int? stock;
+
+ Products(
+ {this.sId,
+ this.sKU,
+ this.name,
+ this.price,
+ this.gST,
+ this.hSNCode,
+ this.description,
+ this.productStatus,
+ this.addedBy,
+ this.image,
+ this.createdAt,
+ this.updatedAt,
+ this.category,
+ this.brand,
+ this.stock});
+
+ Products.fromJson(Map json) {
+ sId = json['_id'];
+ sKU = json['SKU'];
+ name = json['name'];
+ price = json['price'];
+ gST = json['GST'];
+ hSNCode = json['HSN_Code'];
+ description = json['description'];
+ productStatus = json['product_Status'];
+ addedBy = json['addedBy'];
+ createdAt = json['createdAt'];
+ updatedAt = json['updatedAt'];
+ category = json['category'];
+ brand = json['brand'];
+ stock = json['stock'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['_id'] = this.sId;
+ data['SKU'] = this.sKU;
+ data['name'] = this.name;
+ data['price'] = this.price;
+ data['GST'] = this.gST;
+ data['HSN_Code'] = this.hSNCode;
+ data['description'] = this.description;
+ data['product_Status'] = this.productStatus;
+ data['addedBy'] = this.addedBy;
+ data['createdAt'] = this.createdAt;
+ data['updatedAt'] = this.updatedAt;
+ data['category'] = this.category;
+ data['brand'] = this.brand;
+ data['stock'] = this.stock;
+ return data;
+ }
+}
diff --git a/lib/models/NotificationListResponse.dart b/lib/models/NotificationListResponse.dart
new file mode 100644
index 0000000..90199a8
--- /dev/null
+++ b/lib/models/NotificationListResponse.dart
@@ -0,0 +1,67 @@
+class NotificationListResponse {
+ String? returnMessage;
+ List? notifications;
+
+ NotificationListResponse({this.returnMessage, this.notifications});
+
+ NotificationListResponse.fromJson(Map json) {
+ returnMessage = json['return_message'];
+ if (json['notifications'] != null) {
+ notifications = [];
+ json['notifications'].forEach((v) {
+ notifications!.add(Notifications.fromJson(v));
+ });
+ }
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['return_message'] = returnMessage;
+ if (notifications != null) {
+ data['notifications'] =
+ notifications!.map((v) => v.toJson()).toList();
+ }
+ return data;
+ }
+}
+
+class Notifications {
+ String? sId;
+ String? title;
+ String? msg;
+ String? addedFor;
+ String? createdAt;
+ String? updatedAt;
+ int? iV;
+
+ Notifications(
+ {this.sId,
+ this.title,
+ this.msg,
+ this.addedFor,
+ this.createdAt,
+ this.updatedAt,
+ this.iV});
+
+ Notifications.fromJson(Map json) {
+ sId = json['_id'];
+ title = json['title'];
+ msg = json['msg'];
+ addedFor = json['added_for'];
+ createdAt = json['createdAt'];
+ updatedAt = json['updatedAt'];
+ iV = json['__v'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['_id'] = sId;
+ data['title'] = title;
+ data['msg'] = msg;
+ data['added_for'] = addedFor;
+ data['createdAt'] = createdAt;
+ data['updatedAt'] = updatedAt;
+ data['__v'] = iV;
+ return data;
+ }
+}
diff --git a/lib/notification_services.dart b/lib/notification_services.dart
new file mode 100644
index 0000000..6777ade
--- /dev/null
+++ b/lib/notification_services.dart
@@ -0,0 +1,165 @@
+import 'dart:io';
+
+import 'package:firebase_messaging/firebase_messaging.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_local_notifications/flutter_local_notifications.dart';
+
+class NotificationServices {
+ //initialising firebase message plugin
+ FirebaseMessaging messaging = FirebaseMessaging.instance;
+
+ //initialising firebase message plugin
+ final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
+ FlutterLocalNotificationsPlugin();
+
+ //function to initialise flutter local notification plugin to show notifications for android when app is active
+ void initLocalNotifications(
+ BuildContext context, RemoteMessage message) async {
+ var androidInitializationSettings =
+ const AndroidInitializationSettings('@mipmap/ic_launcher');
+ var iosInitializationSettings = const DarwinInitializationSettings();
+
+ var initializationSetting = InitializationSettings(
+ android: androidInitializationSettings, iOS: iosInitializationSettings);
+
+ await _flutterLocalNotificationsPlugin.initialize(initializationSetting,
+ onDidReceiveNotificationResponse: (payload) {
+ // handle interaction when app is active for android
+ handleMessage(context, message);
+ });
+ }
+
+ void firebaseInit(BuildContext context) {
+ FirebaseMessaging.onMessage.listen((message) {
+ RemoteNotification? notification = message.notification;
+ AndroidNotification? android = message.notification!.android;
+
+ if (kDebugMode) {
+ print("notifications title:${notification!.title}");
+ print("notifications body:${notification.body}");
+ print('count:${android!.count}');
+ print('data:${message.data.toString()}');
+ }
+
+ if (Platform.isIOS) {
+ forgroundMessage();
+ }
+
+ if (Platform.isAndroid) {
+ initLocalNotifications(context, message);
+ showNotification(message);
+ }
+ });
+ }
+
+ void requestNotificationPermission() async {
+ NotificationSettings settings = await messaging.requestPermission(
+ alert: true,
+ announcement: true,
+ badge: true,
+ carPlay: true,
+ criticalAlert: true,
+ provisional: true,
+ sound: true,
+ );
+
+ if (settings.authorizationStatus == AuthorizationStatus.authorized) {
+ if (kDebugMode) {
+ print('user granted permission');
+ }
+ } else if (settings.authorizationStatus ==
+ AuthorizationStatus.provisional) {
+ if (kDebugMode) {
+ print('user granted provisional permission');
+ }
+ } else {
+ //appsetting.AppSettings.openNotificationSettings();
+ if (kDebugMode) {
+ print('user denied permission');
+ }
+ }
+ }
+
+ // function to show visible notification when app is active
+ Future showNotification(RemoteMessage message) async {
+ AndroidNotificationChannel channel = AndroidNotificationChannel(
+ message.notification!.android!.channelId.toString(),
+ message.notification!.android!.channelId.toString(),
+ importance: Importance.max,
+ showBadge: true,
+ playSound: true,
+ sound: const RawResourceAndroidNotificationSound('jetsons_doorbell'));
+
+ AndroidNotificationDetails androidNotificationDetails =
+ AndroidNotificationDetails(
+ channel.id.toString(), channel.name.toString(),
+ channelDescription: 'your channel description',
+ importance: Importance.high,
+ priority: Priority.high,
+ playSound: true,
+ ticker: 'ticker',
+ sound: channel.sound
+ // sound: RawResourceAndroidNotificationSound('jetsons_doorbell')
+ // icon: largeIconPath
+ );
+
+ const DarwinNotificationDetails darwinNotificationDetails =
+ DarwinNotificationDetails(
+ presentAlert: true, presentBadge: true, presentSound: true);
+
+ NotificationDetails notificationDetails = NotificationDetails(
+ android: androidNotificationDetails, iOS: darwinNotificationDetails);
+
+ Future.delayed(Duration.zero, () {
+ _flutterLocalNotificationsPlugin.show(
+ 0,
+ message.notification!.title.toString(),
+ message.notification!.body.toString(),
+ notificationDetails,
+ );
+ });
+ }
+
+ //function to get device token on which we will send the notifications
+ Future getDeviceToken() async {
+ String? token = await messaging.getToken();
+ return token!;
+ }
+
+ void isTokenRefresh() async {
+ messaging.onTokenRefresh.listen((event) {
+ event.toString();
+ if (kDebugMode) {
+ print('refresh');
+ }
+ });
+ }
+
+ //handle tap on notification when app is in background or terminated
+ Future setupInteractMessage(BuildContext context) async {
+ // when app is terminated
+ RemoteMessage? initialMessage =
+ await FirebaseMessaging.instance.getInitialMessage();
+
+ if (initialMessage != null) {
+ handleMessage(context, initialMessage);
+ }
+
+ //when app ins background
+ FirebaseMessaging.onMessageOpenedApp.listen((event) {
+ handleMessage(context, event);
+ });
+ }
+
+ void handleMessage(BuildContext context, RemoteMessage message) {}
+
+ Future forgroundMessage() async {
+ await FirebaseMessaging.instance
+ .setForegroundNotificationPresentationOptions(
+ alert: true,
+ badge: true,
+ sound: true,
+ );
+ }
+}
diff --git a/lib/screens/authentication/controller/auth_controller.dart b/lib/screens/authentication/controller/auth_controller.dart
index ab08871..77a9100 100644
--- a/lib/screens/authentication/controller/auth_controller.dart
+++ b/lib/screens/authentication/controller/auth_controller.dart
@@ -1,12 +1,17 @@
import 'package:cheminova/screens/authentication/controller/auth_service.dart';
import 'package:cheminova/screens/home_screen.dart';
+import 'package:cheminova/services/api_service.dart';
import 'package:cheminova/utils/show_snackbar.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
+import '../../../notification_services.dart';
+import '../../../utils/api_urls.dart';
+
class AuthController extends GetxController {
final authService = AuthService();
+ final _apiClient = ApiService();
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
@@ -26,6 +31,9 @@ class AuthController extends GetxController {
isLoading.value = false;
update();
if (response != null) {
+ final fcmToken = await NotificationServices().getDeviceToken();
+ print('fcmToken: $fcmToken');
+ await _apiClient.post(ApiUrls.fcmUrl, data: {'fcmToken': fcmToken});
showSnackbar("Your Successfully logged In!");
Get.offAll(() => const HomeScreen());
}
diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart
index 61f309b..072526e 100644
--- a/lib/screens/home_screen.dart
+++ b/lib/screens/home_screen.dart
@@ -3,10 +3,8 @@ import 'package:cheminova/screens/inventory/inventory_management_screen.dart';
import 'package:cheminova/screens/order/order_tracking_screen.dart';
import 'package:cheminova/screens/order_management/order_management_screen.dart';
import 'package:cheminova/screens/product/product_catalog_screen.dart';
-import 'package:cheminova/screens/report/order_history_report_screen.dart';
-import 'package:cheminova/screens/report/reporting_analytics_screen.dart';
+import 'package:cheminova/screens/report/notification_screen.dart';
import 'package:cheminova/screens/retail/retail_distributer_on_boarding_screen.dart';
-import 'package:cheminova/screens/shipping/shipping_management_screen.dart';
import 'package:cheminova/widgets/home_card.dart';
import 'package:cheminova/widgets/my_drawer.dart';
import 'package:flutter/material.dart';
@@ -29,19 +27,23 @@ class _HomeScreenState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- extendBodyBehindAppBar: true, // The app bar extends behind the body content.
+ extendBodyBehindAppBar: true,
+ // The app bar extends behind the body content.
// AppBar configuration with transparent background and a custom menu icon
appBar: AppBar(
centerTitle: true,
- backgroundColor: Colors.transparent, // AppBar background is transparent to blend with the background image.
- elevation: 0, // No shadow under the AppBar.
+ backgroundColor: Colors.transparent,
+ // AppBar background is transparent to blend with the background image.
+ elevation: 0,
+ // No shadow under the AppBar.
// Leading widget is a custom menu icon that opens the drawer when tapped.
leading: Builder(
builder: (context) {
return GestureDetector(
- onTap: () => Scaffold.of(context).openDrawer(), // Opens the drawer.
+ onTap: () => Scaffold.of(context).openDrawer(),
+ // Opens the drawer.
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset(
@@ -79,30 +81,34 @@ class _HomeScreenState extends State {
// SingleChildScrollView allows scrolling if the content is larger than the screen.
child: SingleChildScrollView(
child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly, // Evenly spaces the rows of cards.
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ // Evenly spaces the rows of cards.
children: [
// Row with two HomeCard widgets for Product Catalogue and Order Tracking.
Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly, // Cards are spaced evenly across the row.
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ // Cards are spaced evenly across the row.
children: [
// HomeCard widget with the title and navigation to the Product Catalog screen.
HomeCard(
- title: 'Product Catalogue',
- onTap: () =>
- Get.to(() => const ProductCatalogScreen()), // Navigates to ProductCatalogScreen using GetX.
+ title: 'Products',
+ onTap: () => Get.to(() =>
+ const ProductCatalogScreen()), // Navigates to ProductCatalogScreen using GetX.
),
// HomeCard widget with the title and navigation to the Order Tracking screen.
HomeCard(
title: 'Order Tracking',
onTap: () => Get.to(
- () => const OrderTrackingScreen(), // Navigates to OrderTrackingScreen using GetX.
+ () =>
+ const OrderTrackingScreen(), // Navigates to OrderTrackingScreen using GetX.
),
),
],
),
- const SizedBox(height: 10), // Adds vertical spacing between rows.
+ const SizedBox(height: 30),
+ // Adds vertical spacing between rows.
// Row with two HomeCard widgets for Order Management and Shipping Management.
Row(
@@ -111,55 +117,41 @@ class _HomeScreenState extends State {
HomeCard(
title: 'Order Management',
onTap: () => Get.to(
- () => OrderManagementScreen(), // Navigates to OrderManagementScreen.
+ () =>
+ OrderManagementScreen(), // Navigates to OrderManagementScreen.
),
),
- HomeCard(
- title: 'Shipping Management',
- onTap: () => Get.to(
- () => const ShippingManagementScreen(), // Navigates to ShippingManagementScreen.
- ),
- ),
- ],
- ),
-
- const SizedBox(height: 10),
-
- // Row with two HomeCard widgets for Inventory Management and Reporting & Analytics.
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
HomeCard(
title: 'Inventory Management',
onTap: () => Get.to(
- () => const InventoryManagementScreen(), // Navigates to InventoryManagementScreen.
- ),
- ),
- HomeCard(
- title: 'Reporting & Analytics',
- onTap: () => Get.to(
- () => const ReportingAnalyticsScreen(), // Navigates to ReportingAnalyticsScreen.
+ () =>
+ const InventoryManagementScreen(), // Navigates to InventoryManagementScreen.
),
),
+ // HomeCard(
+ // title: 'Shipping Management',
+ // onTap: () => Get.to(
+ // () =>
+ // const ShippingManagementScreen(), // Navigates to ShippingManagementScreen.
+ // ),
+ // ),
],
),
- const SizedBox(height: 10),
+ const SizedBox(height: 30),
// Row with two HomeCard widgets for Order Data Export and Retail Distributors Onboarding.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
HomeCard(
- title: 'Order Data Export',
- onTap: () => Get.to(
- () => const OrderHistoryReportScreen(), // Navigates to OrderHistoryReportScreen.
- ),
- ),
+ title: 'Notifications',
+ onTap: () => Get.to(() => NotificationScreen())),
HomeCard(
- title: 'Retail Distributors Onboarding',
+ title: 'Announcement',
onTap: () => Get.to(
- () => const RetailDistributerOnBoardingScreen(), // Navigates to RetailDistributerOnBoardingScreen.
+ () =>
+ const RetailDistributerOnBoardingScreen(), // Navigates to RetailDistributerOnBoardingScreen.
),
),
],
diff --git a/lib/screens/inventory/inventory_management_screen.dart b/lib/screens/inventory/inventory_management_screen.dart
index 9d4e385..60c5372 100644
--- a/lib/screens/inventory/inventory_management_screen.dart
+++ b/lib/screens/inventory/inventory_management_screen.dart
@@ -1,10 +1,11 @@
-import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/widgets/inventory_product_card.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:cheminova/widgets/my_drawer.dart';
+import '../../controller/inventory_management_controller.dart';
+import '../../models/InventoryManagementResponse.dart';
class InventoryManagementScreen extends StatefulWidget {
const InventoryManagementScreen({super.key});
@@ -15,22 +16,23 @@ class InventoryManagementScreen extends StatefulWidget {
}
class _InventoryManagementScreenState extends State {
- final List _productList = [
- ProductModel(
- id: '1',
- name: 'Product 1',
- price: 100,
- quantity: 100,
- description: 'Description 1',
- category: ProductCategory.food,
- image: 'assets/images/product.png',
- )
- ];
+ late Future _productsFuture;
+
+ final InventoryManagementController _controller =
+ Get.put(InventoryManagementController());
+
final List _filterList = [
"Category",
"Price Range",
"Availability",
];
+
+ @override
+ void initState() {
+ super.initState();
+ _productsFuture = _controller.getProducts();
+ }
+
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -45,9 +47,7 @@ class _InventoryManagementScreenState extends State {
onTap: () => Scaffold.of(context).openDrawer(),
child: Padding(
padding: const EdgeInsets.all(16.0),
- child: SvgPicture.asset(
- 'assets/svg/menu.svg',
- ),
+ child: SvgPicture.asset('assets/svg/menu.svg'),
),
);
},
@@ -57,15 +57,11 @@ class _InventoryManagementScreenState extends State {
onTap: () => Get.back(),
child: Padding(
padding: const EdgeInsets.all(8.0),
- child: SvgPicture.asset(
- 'assets/svg/back_arrow.svg',
- ),
+ child: SvgPicture.asset('assets/svg/back_arrow.svg'),
),
),
],
- title: const Text(
- "Inventory Management",
- ),
+ title: const Text("Inventory Management"),
),
drawer: const MyDrawer(),
body: Stack(
@@ -78,9 +74,7 @@ class _InventoryManagementScreenState extends State {
SafeArea(
child: Column(
children: [
- SizedBox(
- height: Get.height * 0.02,
- ),
+ SizedBox(height: Get.height * 0.02),
Card(
margin: const EdgeInsets.symmetric(horizontal: 18),
shape: RoundedRectangleBorder(
@@ -116,16 +110,32 @@ class _InventoryManagementScreenState extends State {
),
SizedBox(
height: Get.height * 0.6,
- child: ListView.builder(
- padding: EdgeInsets.zero,
- shrinkWrap: true,
- itemCount: 10,
- itemBuilder: (context, index) => Padding(
- padding: const EdgeInsets.symmetric(vertical: 8),
- child: InventoryProductCard(
- product: _productList[0],
- ),
- ),
+ child: FutureBuilder(
+ future: _productsFuture,
+ builder: (context, snapshot) {
+ if (snapshot.connectionState ==
+ ConnectionState.waiting) {
+ return const Center(
+ child: CircularProgressIndicator());
+ } else if (snapshot.hasError) {
+ return Center(
+ child: Text('Error: ${snapshot.error}'));
+ } else if (snapshot.hasData) {
+ final products = snapshot.data!.products ?? [];
+ return ListView.builder(
+ padding: EdgeInsets.zero,
+ shrinkWrap: true,
+ itemCount: products.length,
+ itemBuilder: (context, index) {
+ final data = products[index];
+ return InventoryProductCard(product: data);
+ },
+ );
+ } else {
+ return const Center(
+ child: Text('No products found'));
+ }
+ },
),
)
],
diff --git a/lib/screens/inventory/inventory_product_detail_screen.dart b/lib/screens/inventory/inventory_product_detail_screen.dart
index 2d59cff..bee9af9 100644
--- a/lib/screens/inventory/inventory_product_detail_screen.dart
+++ b/lib/screens/inventory/inventory_product_detail_screen.dart
@@ -1,3 +1,4 @@
+import 'package:cheminova/models/InventoryManagementResponse.dart';
import 'package:cheminova/models/product_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
@@ -5,7 +6,7 @@ import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
class InventoryProductDetailScreen extends StatefulWidget {
- final ProductModel product;
+ final Products product;
const InventoryProductDetailScreen({
super.key,
@@ -95,7 +96,7 @@ class _InventoryProductDetailScreenState
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset(
- widget.product.image,
+ 'assets/images/product.png',
fit: BoxFit.cover,
),
),
@@ -159,7 +160,7 @@ class _InventoryProductDetailScreenState
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Text(
- "Current Stock: ${widget.product.quantity}",
+ "Current Stock: ${widget.product.stock}",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w400,
diff --git a/lib/screens/inventory/update_stock_screen.dart b/lib/screens/inventory/update_stock_screen.dart
index 2e0f0ba..6fdb9c1 100644
--- a/lib/screens/inventory/update_stock_screen.dart
+++ b/lib/screens/inventory/update_stock_screen.dart
@@ -1,3 +1,4 @@
+import 'package:cheminova/models/InventoryManagementResponse.dart';
import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/widgets/input_field.dart';
import 'package:flutter/material.dart';
@@ -6,7 +7,7 @@ import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
class UpdateStockScreen extends StatefulWidget {
- final ProductModel product;
+ final Products product;
const UpdateStockScreen({
super.key,
@@ -48,7 +49,7 @@ class _UpdateStockScreenState extends State {
),
],
title: const Text(
- "Product Detail",
+ "Product update",
),
),
body: Stack(
@@ -95,7 +96,7 @@ class _UpdateStockScreenState extends State {
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset(
- widget.product.image,
+ 'assets/images/product.png',
fit: BoxFit.cover,
),
),
@@ -123,7 +124,7 @@ class _UpdateStockScreenState extends State {
child: Padding(
padding: const EdgeInsets.all(12),
child: Text(
- "Current Stock: ${widget.product.quantity}",
+ "Current Stock: ${widget.product.stock}",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w700,
diff --git a/lib/screens/order_management/order_management_screen.dart b/lib/screens/order_management/order_management_screen.dart
index 56dbfc7..3cf62b8 100644
--- a/lib/screens/order_management/order_management_screen.dart
+++ b/lib/screens/order_management/order_management_screen.dart
@@ -7,14 +7,15 @@ 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';
-
class OrderManagementScreen extends StatefulWidget {
final Product? productModel;
PlacedOrderList? placeOrder;
+
OrderManagementScreen({super.key, this.productModel, this.placeOrder});
@override
@@ -25,10 +26,11 @@ class _OrderManagementScreenState extends State {
final _searchController = TextEditingController();
final List _filterList = ["Order Status", "Date Range"];
- final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
+ final GetPlacedOrderController _getPlacedOrderController =
+ Get.put(GetPlacedOrderController());
final CartController _cartController = Get.put(CartController());
final GlobalKey _refreshIndicatorKey =
- GlobalKey();
+ GlobalKey();
@override
void initState() {
@@ -38,7 +40,7 @@ class _OrderManagementScreenState extends State {
Future _onRefresh() async {
await getOrder1();
- await Future.delayed(Duration(seconds: 1));
+ await Future.delayed(const Duration(seconds: 1));
}
Future getOrder1() async {
@@ -96,13 +98,14 @@ class _OrderManagementScreenState extends State {
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: Padding(
+ padding: EdgeInsets.only(
+ bottom: MediaQuery.of(context).viewInsets.bottom),
child: RefreshIndicator(
- key: _refreshIndicatorKey,
- onRefresh: _onRefresh,
- color: Colors.black,
- backgroundColor: Colors.white,
+ key: _refreshIndicatorKey,
+ onRefresh: _onRefresh,
+ color: Colors.black,
+ backgroundColor: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
@@ -125,20 +128,36 @@ class _OrderManagementScreenState extends State {
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),
- ),
- ),
+ Obx(
+ () => Container(
+ height: Get.height * 0.05,
+ padding: const EdgeInsets.all(8),
+ margin: const EdgeInsets.only(bottom: 8),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius:
+ BorderRadius.circular(5)),
+ child: DropdownButton(
+ value: _getPlacedOrderController
+ .productStatus.value,
+ onChanged: (dynamic newValue) {
+ if (newValue != null) {
+ _getPlacedOrderController
+ .updateProductStatus(newValue);
+ }
+ },
+ items: [
+ 'All',
+ 'Delivered',
+ 'Processing',
+ 'Cancelled'
+ ].map>(
+ (String value) {
+ return DropdownMenuItem(
+ value: value,
+ child: Text(value),
+ );
+ }).toList(),
),
),
),
@@ -147,10 +166,19 @@ class _OrderManagementScreenState extends State {
child: Obx(() {
// Use a set to keep track of unique order IDs
final Set uniqueOrderIds = {};
- final List uniqueOrders = [];
+ final List uniqueOrders =
+ [];
- for (var order in _getPlacedOrderController.placedOrders) {
- if (uniqueOrderIds.add(order.sId??'')) {
+ final orders = _getPlacedOrderController
+ .filterOrder.isNotEmpty
+ ? _getPlacedOrderController
+ .filterOrder
+ : _getPlacedOrderController
+ .placedOrders;
+
+ for (var order in orders) {
+ if (uniqueOrderIds
+ .add(order.sId ?? '')) {
uniqueOrders.add(order);
}
}
@@ -164,48 +192,85 @@ class _OrderManagementScreenState extends State {
// Combine product names into a single string
final productNames = order.orderItem!
- .map((item) => capitalizeFirstLetter(item.name??''))
+ .map((item) =>
+ capitalizeFirstLetter(
+ item.name ?? ''))
.join(', ');
return Padding(
- padding: const EdgeInsets.symmetric(vertical: 8),
+ padding: const EdgeInsets.symmetric(
+ vertical: 8),
child: Card(
child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
children: [
Padding(
- padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
+ padding: const EdgeInsets
+ .fromLTRB(16, 8, 8, 0),
child: Row(
- mainAxisAlignment: MainAxisAlignment.start,
+ mainAxisAlignment:
+ MainAxisAlignment
+ .start,
children: [
- Text("Order ID: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
- Text("${order.uniqueId}")
+ Text("Order ID: ",
+ style: GoogleFonts.roboto(
+ fontSize: 14,
+ fontWeight:
+ FontWeight
+ .bold)),
+ Text(
+ "${order.uniqueId}")
],
),
),
Padding(
- padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
+ padding: const EdgeInsets
+ .fromLTRB(16, 8, 8, 0),
child: Row(
- crossAxisAlignment: CrossAxisAlignment.start, // Aligns the Column to the top of the Text
+ crossAxisAlignment:
+ CrossAxisAlignment
+ .start,
+ // Aligns the Column to the top of the Text
children: [
Text(
"Product Names: ",
- style: GoogleFonts.roboto(
+ style: GoogleFonts
+ .roboto(
fontSize: 14,
- fontWeight: FontWeight.bold,
+ fontWeight:
+ FontWeight.bold,
),
),
Expanded(
child: Column(
- crossAxisAlignment: CrossAxisAlignment.start, // Aligns text to the right within the Column
+ crossAxisAlignment:
+ CrossAxisAlignment
+ .start,
+ // Aligns text to the right within the Column
children: [
- const SizedBox(height: 4), // Adds a small space between the label and the product names
- for (int i = 0; i < productNames.split(",").length; i++)
+ const SizedBox(
+ height: 4),
+ // Adds a small space between the label and the product names
+ for (int i = 0;
+ i <
+ productNames
+ .split(
+ ",")
+ .length;
+ i++)
Text(
- '${i + 1}. ${productNames.split(",")[i].trim()}', // Adds index and trims whitespace
- textAlign: TextAlign.left, // Aligns text to the right
- style: GoogleFonts.roboto(
- fontSize: 14,
+ '${i + 1}. ${productNames.split(",")[i].trim()}',
+ // Adds index and trims whitespace
+ textAlign:
+ TextAlign
+ .left,
+ // Aligns text to the right
+ style:
+ GoogleFonts
+ .roboto(
+ fontSize:
+ 14,
),
),
],
@@ -214,42 +279,76 @@ class _OrderManagementScreenState extends State {
],
),
),
-
-
Padding(
- padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
+ padding: const EdgeInsets
+ .fromLTRB(16, 8, 8, 0),
child: Row(
- mainAxisAlignment: MainAxisAlignment.start,
+ mainAxisAlignment:
+ MainAxisAlignment
+ .start,
children: [
- Text("Order Date: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
- Text(formatDate("${order.createdAt}"))
+ Text("Order Date: ",
+ style: GoogleFonts.roboto(
+ fontSize: 14,
+ fontWeight:
+ FontWeight
+ .bold)),
+ Text(formatDate(
+ "${order.createdAt}"))
],
),
),
Padding(
- padding: const EdgeInsets.fromLTRB(16, 8, 8, 8),
+ padding: const EdgeInsets
+ .fromLTRB(16, 8, 8, 8),
child: Row(
- mainAxisAlignment: MainAxisAlignment.start,
+ mainAxisAlignment:
+ MainAxisAlignment
+ .start,
children: [
- Text("Status: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
- Text(capitalizeFirstLetter("${order.status}"))
+ 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),
+ padding:
+ const EdgeInsets.all(
+ 8.0),
child: ElevatedButton(
- onPressed: () => Get.to(() => OrderManagementDetailScreen(
- placedOrderList: uniqueOrders[index])),
- style: ElevatedButton.styleFrom(
- foregroundColor: Colors.white,
- backgroundColor: const Color(0xFF004791),
+ onPressed: () => Get.to(() =>
+ OrderManagementDetailScreen(
+ placedOrderList:
+ uniqueOrders[
+ index])),
+ style: ElevatedButton
+ .styleFrom(
+ foregroundColor:
+ Colors.white,
+ backgroundColor:
+ const Color(
+ 0xFF004791),
shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10)),
+ borderRadius:
+ BorderRadius
+ .circular(
+ 10)),
),
- child: Text("View Details", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w400)),
+ child: Text(
+ "View Details",
+ style: GoogleFonts.roboto(
+ fontSize: 14,
+ fontWeight:
+ FontWeight
+ .w400)),
),
),
)
@@ -274,31 +373,24 @@ class _OrderManagementScreenState extends State {
],
),
),
- Obx(() {
- if (_getPlacedOrderController.isLoading.value) {
- return Container(
- color: Colors.black.withOpacity(0.5),
- child: const Center(
- child: CircularProgressIndicator(strokeWidth: 1),
- ),
- );
- }
- return const SizedBox.shrink();
- },)
+ Obx(
+ () {
+ if (_getPlacedOrderController.isLoading.value) {
+ return Container(
+ color: Colors.black.withOpacity(0.5),
+ child: const Center(
+ child: CircularProgressIndicator(strokeWidth: 1),
+ ),
+ );
+ }
+ return const SizedBox.shrink();
+ },
+ )
],
);
}
}
-
-
-
-
-
-
-
-
-
// 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';
diff --git a/lib/screens/report/notification_screen.dart b/lib/screens/report/notification_screen.dart
new file mode 100644
index 0000000..68e7e5c
--- /dev/null
+++ b/lib/screens/report/notification_screen.dart
@@ -0,0 +1,118 @@
+import 'package:cheminova/widgets/my_drawer.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:get/get.dart';
+import 'package:intl/intl.dart';
+import '../../controller/notification_controller.dart';
+import '../../models/NotificationListResponse.dart';
+import '../../widgets/comman_background.dart';
+import '../../widgets/common_appbar.dart';
+import '../../widgets/common_elevated_button.dart';
+
+class NotificationScreen extends StatelessWidget {
+ final NotificationController controller = Get.put(NotificationController());
+
+ NotificationScreen({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return CommonBackground(
+ child: Scaffold(
+ backgroundColor: Colors.transparent,
+ appBar: CommonAppBar(
+ title: const Text('Notification',
+ style: TextStyle(
+ fontSize: 20,
+ color: Colors.black,
+ fontWeight: FontWeight.w400,
+ fontFamily: 'Anek')),
+ backgroundColor: Colors.transparent,
+ elevation: 0,
+ actions: [
+ IconButton(
+ onPressed: () => Navigator.pop(context),
+ icon: SvgPicture.asset('assets/svg/back_arrow.svg'),
+ padding: const EdgeInsets.only(right: 20))
+ ],
+ ),
+ drawer: const MyDrawer(),
+ body: Obx(() => controller.isLoading.value
+ ? const Center(child: CircularProgressIndicator())
+ : MyListView(notificationList: controller.notificationsList)),
+ ),
+ );
+ }
+}
+
+Widget buildProductButton(String productName) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 15),
+ child: CommonElevatedButton(
+ borderRadius: 30,
+ width: double.infinity,
+ height: kToolbarHeight - 10,
+ text: productName,
+ backgroundColor: const Color(0xff004791),
+ onPressed: () {
+ debugPrint('$productName pressed');
+ },
+ ),
+ );
+}
+
+class MyListView extends StatelessWidget {
+ final List notificationList;
+
+ const MyListView({super.key, required this.notificationList});
+
+ @override
+ Widget build(BuildContext context) {
+ Map> groupedNotifications = {};
+
+ for (var notification in notificationList) {
+ String date = DateFormat("dd MMM yyyy").format(DateTime.parse(notification.createdAt ?? ''));
+ if (!groupedNotifications.containsKey(date)) {
+ groupedNotifications[date] = [];
+ }
+ groupedNotifications[date]!.add(notification);
+ }
+
+ return ListView.builder(
+ padding: const EdgeInsets.only(top: 15),
+ itemCount: groupedNotifications.length,
+ itemBuilder: (context, index) {
+ String date = groupedNotifications.keys.elementAt(index);
+ List notificationsForDate = groupedNotifications[date]!;
+
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 10, left: 10, right: 10),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(bottom: 8.0),
+ child: Text(
+ date,
+ style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
+ ),
+ ),
+ ...notificationsForDate.map((item) => Padding(
+ padding: const EdgeInsets.only(bottom: 10),
+ child: ExpansionTile(
+ collapsedBackgroundColor: Colors.white,
+ backgroundColor: Colors.white,
+ trailing: const SizedBox.shrink(),
+ title: Text(
+ item.title ?? '',
+ style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
+ ),
+ subtitle: Text(item.msg ?? ''),
+ ),
+ )),
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/screens/report/order_history_report_screen.dart b/lib/screens/report/order_history_report_screen.dart
deleted file mode 100644
index c146e9c..0000000
--- a/lib/screens/report/order_history_report_screen.dart
+++ /dev/null
@@ -1,191 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_svg/svg.dart';
-import 'package:get/get.dart';
-import 'package:google_fonts/google_fonts.dart';
-
-class OrderHistoryReportScreen extends StatefulWidget {
- const OrderHistoryReportScreen({super.key});
-
- @override
- State createState() =>
- _OrderHistoryReportScreenState();
-}
-
-class _OrderHistoryReportScreenState extends State {
- final List _filterList = [
- "Order Status",
- "Date Range",
- ];
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- extendBodyBehindAppBar: true,
- appBar: AppBar(
- centerTitle: true,
- backgroundColor: Colors.transparent,
- elevation: 0,
- leading: GestureDetector(
- onTap: () {},
- 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 History Report",
- ),
- ),
- body: Stack(
- fit: StackFit.expand,
- children: [
- Image.asset(
- 'assets/images/image_1.png',
- fit: BoxFit.cover,
- ),
- SafeArea(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- SizedBox(height: Get.height * 0.02),
- 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.02),
- SizedBox(
- width: Get.width,
- child: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Container(
- height: Get.height * 0.4,
- width: Get.width * 0.7,
- decoration: BoxDecoration(
- border: Border.all(
- width: 4,
- color: Colors.white,
- ),
- borderRadius: BorderRadius.circular(15),
- ),
- child: ClipRRect(
- borderRadius: BorderRadius.circular(10),
- child: Image.asset(
- "assets/images/chart.png",
- fit: BoxFit.cover,
- ),
- ),
- ),
- ),
- ),
- SizedBox(height: Get.height * 0.02),
- SizedBox(
- width: Get.width,
- child: Card(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Padding(
- padding:
- const EdgeInsets.fromLTRB(16, 8, 8, 0),
- child: Text(
- "Report Title: Sales Data Report",
- style: GoogleFonts.roboto(
- fontSize: 14,
- fontWeight: FontWeight.w400,
- ),
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.fromLTRB(16, 8, 8, 8),
- child: Text(
- "Description: Overview of sales data",
- style: GoogleFonts.roboto(
- fontSize: 14,
- fontWeight: FontWeight.w400,
- ),
- ),
- ),
- SizedBox(
- width: Get.width * 0.5,
- child: Padding(
- padding: const EdgeInsets.all(8.0),
- child: ElevatedButton(
- onPressed: () {},
- style: ElevatedButton.styleFrom(
- foregroundColor: Colors.white,
- backgroundColor:
- const Color(0xFF004791),
- shape: RoundedRectangleBorder(
- borderRadius:
- BorderRadius.circular(10),
- ),
- ),
- child: Text(
- "Generate Report",
- style: GoogleFonts.roboto(
- fontSize: 14,
- fontWeight: FontWeight.w400,
- ),
- ),
- ),
- ),
- )
- ],
- ),
- ),
- ),
- ],
- ),
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- );
- }
-}
diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart
index f07c320..d727f01 100644
--- a/lib/services/api_service.dart
+++ b/lib/services/api_service.dart
@@ -28,4 +28,7 @@ class ApiService {
data: {'message': 'An unexpected error occurred'});
}
}
-}
+
+ Future post(String path, {dynamic data}) {
+ return _dio.post(path, data: data); // Send POST request
+ }}
\ No newline at end of file
diff --git a/lib/utils/api_urls.dart b/lib/utils/api_urls.dart
index 336c6bf..a35af11 100644
--- a/lib/utils/api_urls.dart
+++ b/lib/utils/api_urls.dart
@@ -5,14 +5,15 @@ class ApiUrls {
static const String profileUrl = '/api/rd-get-me';
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';
+ static const String fcmUrl = '/api/rd-save-fcm-token';
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 getNotificationUrl = '/api/get-notification-rd';
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';
+ static const String inventoryManangementOrdersStock ='${baseUrl}/api/stock';
}
diff --git a/lib/widgets/inventory_product_card.dart b/lib/widgets/inventory_product_card.dart
index 73e337b..5369f10 100644
--- a/lib/widgets/inventory_product_card.dart
+++ b/lib/widgets/inventory_product_card.dart
@@ -1,3 +1,4 @@
+import 'package:cheminova/models/InventoryManagementResponse.dart';
import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/screens/inventory/inventory_product_detail_screen.dart';
import 'package:cheminova/screens/inventory/update_stock_screen.dart';
@@ -6,7 +7,8 @@ import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
class InventoryProductCard extends StatelessWidget {
- final ProductModel product;
+ final Products product;
+
const InventoryProductCard({
super.key,
required this.product,
@@ -26,7 +28,7 @@ class InventoryProductCard extends StatelessWidget {
width: Get.width * 0.30,
decoration: BoxDecoration(
image: DecorationImage(
- image: Image.asset(product.image).image,
+ image: Image.asset('assets/images/product.png').image,
fit: BoxFit.cover,
),
),
@@ -36,70 +38,74 @@ class InventoryProductCard extends StatelessWidget {
const SizedBox(
width: 10,
),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- product.name,
- style: GoogleFonts.roboto(
- fontSize: 16,
- fontWeight: FontWeight.w500,
- ),
- ),
- Text(
- "Stock: ${product.quantity}",
- style: GoogleFonts.roboto(
- fontSize: 16,
- fontWeight: FontWeight.w500,
- ),
- ),
- ElevatedButton(
- onPressed: () => Get.to(
- () => InventoryProductDetailScreen(
- product: product,
- ),
- ),
- style: ElevatedButton.styleFrom(
- foregroundColor: Colors.white,
- backgroundColor: const Color(0xFF004791),
- padding:
- const EdgeInsets.symmetric(horizontal: 18, vertical: 8),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- ),
- child: Text(
- "Details",
+ Flexible(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ product.name ?? '',
+ maxLines: 2,
+ overflow: TextOverflow.ellipsis,
style: GoogleFonts.roboto(
- fontSize: 14,
- fontWeight: FontWeight.w600,
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
),
),
- ),
- ElevatedButton(
- onPressed: () => Get.to(
- () => UpdateStockScreen(
- product: product,
- ),
- ),
- style: ElevatedButton.styleFrom(
- foregroundColor: Colors.white,
- backgroundColor: const Color(0xFF00784C),
- padding:
- const EdgeInsets.symmetric(horizontal: 18, vertical: 8),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- ),
- child: Text(
- "Update",
+ Text(
+ "Stock: ${product.stock ?? 0}",
style: GoogleFonts.roboto(
- fontSize: 14,
- fontWeight: FontWeight.w600,
+ fontSize: 16,
+ fontWeight: FontWeight.w500,
),
),
- ),
- ],
+ ElevatedButton(
+ onPressed: () => Get.to(
+ () => InventoryProductDetailScreen(
+ product: product,
+ ),
+ ),
+ style: ElevatedButton.styleFrom(
+ foregroundColor: Colors.white,
+ backgroundColor: const Color(0xFF004791),
+ padding:
+ const EdgeInsets.symmetric(horizontal: 18, vertical: 8),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(10),
+ ),
+ ),
+ child: Text(
+ "Details",
+ style: GoogleFonts.roboto(
+ fontSize: 14,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ ),
+ ElevatedButton(
+ onPressed: () => Get.to(
+ () => UpdateStockScreen(
+ product: product,
+ ),
+ ),
+ style: ElevatedButton.styleFrom(
+ foregroundColor: Colors.white,
+ backgroundColor: const Color(0xFF00784C),
+ padding:
+ const EdgeInsets.symmetric(horizontal: 18, vertical: 8),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(10),
+ ),
+ ),
+ child: Text(
+ "Update",
+ style: GoogleFonts.roboto(
+ fontSize: 14,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ ),
+ ],
+ ),
)
],
),