Compare commits
10 Commits
96aa3e8549
...
2d393a9885
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2d393a9885 | ||
![]() |
ec339c48ba | ||
![]() |
12af640bae | ||
![]() |
1436aa0131 | ||
![]() |
7cce7db73c | ||
![]() |
aa04f39fca | ||
![]() |
60ae618071 | ||
![]() |
5391d953a7 | ||
![]() |
de188372d9 | ||
![]() |
7e86e93c8e |
@ -1,7 +1,10 @@
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'package:cheminova/provider/collect_kyc_provider.dart';
|
||||
import 'package:cheminova/provider/pd_rd_provider.dart';
|
||||
import 'package:cheminova/provider/product_manual_provider.dart';
|
||||
import 'package:cheminova/provider/product_provider.dart';
|
||||
import 'package:cheminova/provider/task_provider.dart';
|
||||
import 'package:cheminova/provider/user_provider.dart';
|
||||
import 'package:cheminova/screens/splash_screen.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
@ -20,8 +23,10 @@ Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
}
|
||||
|
||||
AndroidNotificationChannel channel = const AndroidNotificationChannel(
|
||||
'High Importance Channel', 'High Importance Notifications',
|
||||
importance: Importance.high);
|
||||
'High Importance Channel',
|
||||
'High Importance Notifications',
|
||||
importance: Importance.high,
|
||||
);
|
||||
|
||||
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
|
||||
|
||||
@ -98,6 +103,9 @@ Future<void> main() async {
|
||||
ChangeNotifierProvider(create: (context) => CollectKycProvider()),
|
||||
ChangeNotifierProvider(create: (_) => UserProvider()),
|
||||
ChangeNotifierProvider(create: (_) => ProductProvider()),
|
||||
ChangeNotifierProvider(create: (_) => PdRdProvider()),
|
||||
ChangeNotifierProvider(create: (_) => TaskProvider()),
|
||||
ChangeNotifierProvider(create: (_) => ProductManualProvider()),
|
||||
],
|
||||
child: const MyApp(),
|
||||
),
|
||||
@ -115,12 +123,16 @@ class _MyAppState extends State<MyApp> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
// scaffoldMessengerKey: SnackBarService().scaffoldMessengerKey,
|
||||
title: 'cheminova',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true),
|
||||
home: const SplashScreen());
|
||||
debugShowCheckedModeBanner: false,
|
||||
// scaffoldMessengerKey: SnackBarService().scaffoldMessengerKey,
|
||||
title: 'cheminova',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: const Color(0xff004791),
|
||||
),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const SplashScreen(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
72
lib/models/pd_rd_response_model.dart
Normal file
72
lib/models/pd_rd_response_model.dart
Normal file
@ -0,0 +1,72 @@
|
||||
class PdRdResponseModel {
|
||||
String? id;
|
||||
String? uniqueId;
|
||||
String? name;
|
||||
String? tradeNameRd;
|
||||
ShippingAddress? shippingAddress;
|
||||
String? salesCoordinator; // Nullable property for SalesCoordinator
|
||||
|
||||
PdRdResponseModel({
|
||||
this.id,
|
||||
this.uniqueId,
|
||||
this.name,
|
||||
this.tradeNameRd,
|
||||
this.shippingAddress,
|
||||
this.salesCoordinator, // Initialize SalesCoordinator
|
||||
});
|
||||
|
||||
factory PdRdResponseModel.fromJson(Map<String, dynamic> json) =>
|
||||
PdRdResponseModel(
|
||||
id: json["_id"],
|
||||
name: json["name"],
|
||||
uniqueId: json["uniqueId"],
|
||||
tradeNameRd: json["trade_name"],
|
||||
shippingAddress: json['shippingAddress'] != null
|
||||
? ShippingAddress.fromJson(json['shippingAddress'])
|
||||
: null,
|
||||
salesCoordinator: json.containsKey('salesCoordinator')
|
||||
? json['salesCoordinator']
|
||||
: null, // Handle missing field
|
||||
);
|
||||
}
|
||||
|
||||
class ShippingAddress {
|
||||
final String id;
|
||||
final String street;
|
||||
final String city;
|
||||
final String state;
|
||||
final String postalCode;
|
||||
final String country;
|
||||
final String panNumber;
|
||||
final String tradeName;
|
||||
final String gstNumber;
|
||||
final bool isDefault;
|
||||
|
||||
ShippingAddress({
|
||||
required this.id,
|
||||
required this.street,
|
||||
required this.city,
|
||||
required this.state,
|
||||
required this.postalCode,
|
||||
required this.country,
|
||||
required this.panNumber,
|
||||
required this.tradeName,
|
||||
required this.gstNumber,
|
||||
required this.isDefault,
|
||||
});
|
||||
|
||||
factory ShippingAddress.fromJson(Map<String, dynamic> json) {
|
||||
return ShippingAddress(
|
||||
id: json['_id'] ?? '',
|
||||
street: json['street'] ?? '',
|
||||
city: json['city'] ?? '',
|
||||
state: json['state'] ?? '',
|
||||
postalCode: json['postalCode'] ?? '',
|
||||
country: json['country'] ?? '',
|
||||
panNumber: json['panNumber'] ?? '',
|
||||
tradeName: json['tradeName'] ?? '',
|
||||
gstNumber: json['gstNumber'] ?? '',
|
||||
isDefault: json['isDefault'] ?? false,
|
||||
);
|
||||
}
|
||||
}
|
48
lib/models/product_manual_model.dart
Normal file
48
lib/models/product_manual_model.dart
Normal file
@ -0,0 +1,48 @@
|
||||
class ProductManualModel {
|
||||
final ProductManualDetail productManualDetail;
|
||||
final String id;
|
||||
final String title;
|
||||
final String createdAt;
|
||||
final String updatedAt;
|
||||
final int version;
|
||||
|
||||
ProductManualModel({
|
||||
required this.productManualDetail,
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.version,
|
||||
});
|
||||
|
||||
factory ProductManualModel.fromJson(Map<String, dynamic> json) {
|
||||
return ProductManualModel(
|
||||
productManualDetail: ProductManualDetail.fromJson(json['product_manual']),
|
||||
id: json['_id'],
|
||||
title: json['title'],
|
||||
createdAt: json['createdAt'],
|
||||
updatedAt: json['updatedAt'],
|
||||
version: json['__v'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ProductManualDetail {
|
||||
final String publicId;
|
||||
final String url;
|
||||
final String filename;
|
||||
|
||||
ProductManualDetail({
|
||||
required this.publicId,
|
||||
required this.url,
|
||||
required this.filename,
|
||||
});
|
||||
|
||||
factory ProductManualDetail.fromJson(Map<String, dynamic> json) {
|
||||
return ProductManualDetail(
|
||||
publicId: json['public_id'],
|
||||
url: json['url'],
|
||||
filename: json['filename'],
|
||||
);
|
||||
}
|
||||
}
|
@ -2,13 +2,13 @@ class ProductResponse {
|
||||
final bool success;
|
||||
final int totalData;
|
||||
final int totalPages;
|
||||
final List<Product> product;
|
||||
final List<Product> products;
|
||||
|
||||
ProductResponse({
|
||||
required this.success,
|
||||
required this.totalData,
|
||||
required this.totalPages,
|
||||
required this.product,
|
||||
required this.products,
|
||||
});
|
||||
|
||||
factory ProductResponse.fromJson(Map<String, dynamic> json) {
|
||||
@ -16,7 +16,7 @@ class ProductResponse {
|
||||
success: json['success'],
|
||||
totalData: json['total_data'],
|
||||
totalPages: json['total_pages'],
|
||||
product: (json['product'] as List)
|
||||
products: (json['products'] as List)
|
||||
.map((item) => Product.fromJson(item))
|
||||
.toList(),
|
||||
);
|
||||
@ -27,7 +27,7 @@ class ProductResponse {
|
||||
'success': success,
|
||||
'total_data': totalData,
|
||||
'total_pages': totalPages,
|
||||
'product': product.map((item) => item.toJson()).toList(),
|
||||
'products': products.map((item) => item.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -37,32 +37,38 @@ class Product {
|
||||
final String SKU;
|
||||
final String name;
|
||||
final Category category;
|
||||
final Brand brand;
|
||||
final double price;
|
||||
final GST gst;
|
||||
final int GST;
|
||||
final int HSNCode;
|
||||
final String description;
|
||||
final String specialInstructions;
|
||||
final String productStatus;
|
||||
final AddedBy addedBy;
|
||||
final List<dynamic> image;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
final int v;
|
||||
int? sale;
|
||||
int? inventory;
|
||||
|
||||
Product({
|
||||
required this.id,
|
||||
required this.SKU,
|
||||
required this.name,
|
||||
required this.category,
|
||||
required this.brand,
|
||||
required this.price,
|
||||
required this.gst,
|
||||
required this.GST,
|
||||
required this.HSNCode,
|
||||
required this.description,
|
||||
required this.specialInstructions,
|
||||
required this.productStatus,
|
||||
required this.addedBy,
|
||||
required this.image,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.v,
|
||||
this.sale,
|
||||
this.inventory,
|
||||
});
|
||||
|
||||
factory Product.fromJson(Map<String, dynamic> json) {
|
||||
@ -71,16 +77,19 @@ class Product {
|
||||
SKU: json['SKU'],
|
||||
name: json['name'],
|
||||
category: Category.fromJson(json['category']),
|
||||
brand: Brand.fromJson(json['brand']),
|
||||
price: (json['price'] as num).toDouble(),
|
||||
gst: GST.fromJson(json['GST']),
|
||||
description: json['description'],
|
||||
specialInstructions: json['special_instructions'],
|
||||
GST: json['GST'],
|
||||
HSNCode: json['HSN_Code'],
|
||||
description: json['description'] ?? '',
|
||||
productStatus: json['product_Status'],
|
||||
addedBy: AddedBy.fromJson(json['addedBy']),
|
||||
image: json['image'] as List<dynamic>,
|
||||
createdAt: DateTime.parse(json['createdAt']),
|
||||
updatedAt: DateTime.parse(json['updatedAt']),
|
||||
v: json['__v'],
|
||||
sale: json['sale'], // Nullable field
|
||||
inventory: json['inventory'], // Nullable field
|
||||
);
|
||||
}
|
||||
|
||||
@ -90,16 +99,19 @@ class Product {
|
||||
'SKU': SKU,
|
||||
'name': name,
|
||||
'category': category.toJson(),
|
||||
'brand': brand.toJson(),
|
||||
'price': price,
|
||||
'GST': gst.toJson(),
|
||||
'GST': GST,
|
||||
'HSN_Code': HSNCode,
|
||||
'description': description,
|
||||
'special_instructions': specialInstructions,
|
||||
'product_Status': productStatus,
|
||||
'addedBy': addedBy.toJson(),
|
||||
'image': image,
|
||||
'createdAt': createdAt.toIso8601String(),
|
||||
'updatedAt': updatedAt.toIso8601String(),
|
||||
'__v': v,
|
||||
'sale': sale, // Nullable field
|
||||
'inventory': inventory, // Nullable field
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -128,30 +140,26 @@ class Category {
|
||||
}
|
||||
}
|
||||
|
||||
class GST {
|
||||
class Brand {
|
||||
final String id;
|
||||
final String name;
|
||||
final int tax;
|
||||
final String brandName;
|
||||
|
||||
GST({
|
||||
Brand({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.tax,
|
||||
required this.brandName,
|
||||
});
|
||||
|
||||
factory GST.fromJson(Map<String, dynamic> json) {
|
||||
return GST(
|
||||
factory Brand.fromJson(Map<String, dynamic> json) {
|
||||
return Brand(
|
||||
id: json['_id'],
|
||||
name: json['name'],
|
||||
tax: json['tax'],
|
||||
brandName: json['brandName'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'_id': id,
|
||||
'name': name,
|
||||
'tax': tax,
|
||||
'brandName': brandName,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
78
lib/models/task_model.dart
Normal file
78
lib/models/task_model.dart
Normal file
@ -0,0 +1,78 @@
|
||||
class TaskModel {
|
||||
final String id;
|
||||
final String taskId;
|
||||
final String task;
|
||||
final String? note;
|
||||
final String taskStatus;
|
||||
final String? taskPriority;
|
||||
final DateTime taskDueDate;
|
||||
final TaskAssignedTo taskAssignedTo;
|
||||
final String? taskAssignedBy;
|
||||
final String? addedFor;
|
||||
final String? addedForId;
|
||||
final String? tradename;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
final int? version;
|
||||
|
||||
TaskModel({
|
||||
required this.id,
|
||||
required this.taskId,
|
||||
required this.task,
|
||||
this.note,
|
||||
required this.taskStatus,
|
||||
this.taskPriority,
|
||||
required this.taskDueDate,
|
||||
required this.taskAssignedTo,
|
||||
this.taskAssignedBy,
|
||||
this.addedFor,
|
||||
this.addedForId,
|
||||
this.tradename,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.version,
|
||||
});
|
||||
|
||||
factory TaskModel.fromJson(Map<String, dynamic> json) {
|
||||
return TaskModel(
|
||||
id: json['_id'],
|
||||
taskId: json['taskId'],
|
||||
task: json['task'],
|
||||
note: json['note'],
|
||||
taskStatus: json['taskStatus'],
|
||||
taskPriority: json['taskPriority'],
|
||||
taskDueDate: DateTime.parse(json['taskDueDate']),
|
||||
taskAssignedTo: TaskAssignedTo.fromJson(json['taskAssignedTo']),
|
||||
taskAssignedBy: json['taskAssignedBy'],
|
||||
addedFor: json['addedFor'],
|
||||
addedForId: json['addedForId'],
|
||||
tradename: json['tradename'],
|
||||
createdAt: DateTime.parse(json['createdAt']),
|
||||
updatedAt: DateTime.parse(json['updatedAt']),
|
||||
version: json['__v'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TaskAssignedTo {
|
||||
final String id;
|
||||
final String name;
|
||||
final String mobileNumber;
|
||||
final String email;
|
||||
|
||||
TaskAssignedTo({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.mobileNumber,
|
||||
required this.email,
|
||||
});
|
||||
|
||||
factory TaskAssignedTo.fromJson(Map<String, dynamic> json) {
|
||||
return TaskAssignedTo(
|
||||
id: json['_id'],
|
||||
name: json['name'],
|
||||
mobileNumber: json['mobileNumber'],
|
||||
email: json['email'],
|
||||
);
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ class UserModel {
|
||||
String name;
|
||||
String email;
|
||||
String uniqueId;
|
||||
String mobileNumber;
|
||||
String designation;
|
||||
bool isVerified;
|
||||
|
||||
UserModel({
|
||||
@ -10,6 +12,8 @@ class UserModel {
|
||||
required this.name,
|
||||
required this.email,
|
||||
required this.uniqueId,
|
||||
required this.mobileNumber,
|
||||
required this.designation,
|
||||
required this.isVerified,
|
||||
});
|
||||
|
||||
@ -19,8 +23,9 @@ class UserModel {
|
||||
name: json['name'],
|
||||
email: json['email'],
|
||||
uniqueId: json['uniqueId'],
|
||||
mobileNumber: json['mobileNumber'],
|
||||
designation: json['designation'],
|
||||
isVerified: json['isVerified'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
68
lib/provider/pd_rd_provider.dart
Normal file
68
lib/provider/pd_rd_provider.dart
Normal file
@ -0,0 +1,68 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:cheminova/models/pd_rd_response_model.dart';
|
||||
import 'package:cheminova/services/api_client.dart';
|
||||
import 'package:cheminova/services/api_urls.dart';
|
||||
|
||||
class PdRdProvider extends ChangeNotifier {
|
||||
bool _isLoading = false;
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
List<PdRdResponseModel> _pdList = [];
|
||||
List<PdRdResponseModel> get pdList => _pdList;
|
||||
List<PdRdResponseModel> _rdList = [];
|
||||
List<PdRdResponseModel> get rdList => _rdList;
|
||||
|
||||
final _apiClient = ApiClient();
|
||||
|
||||
void setLoading(bool loading) {
|
||||
_isLoading = loading;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void clearLists() {
|
||||
_pdList.clear();
|
||||
_rdList.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getPd() async {
|
||||
setLoading(true);
|
||||
clearLists(); // Clear the list before fetching new data
|
||||
try {
|
||||
Response response = await _apiClient.get(ApiUrls.getPd);
|
||||
if (response.statusCode == 200) {
|
||||
List<PdRdResponseModel> data = (response.data as List)
|
||||
.map((json) => PdRdResponseModel.fromJson(json))
|
||||
.toList();
|
||||
_pdList = data;
|
||||
} else {
|
||||
print("Failed to load data: ${response.statusCode}");
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getRd() async {
|
||||
setLoading(true);
|
||||
clearLists(); // Clear the list before fetching new data
|
||||
try {
|
||||
Response response = await _apiClient.get(ApiUrls.getRd);
|
||||
if (response.statusCode == 200) {
|
||||
List<PdRdResponseModel> data = (response.data as List)
|
||||
.map((json) => PdRdResponseModel.fromJson(json))
|
||||
.toList();
|
||||
_rdList = data;
|
||||
} else {
|
||||
print("Failed to load data: ${response.statusCode}");
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
39
lib/provider/product_manual_provider.dart
Normal file
39
lib/provider/product_manual_provider.dart
Normal file
@ -0,0 +1,39 @@
|
||||
import 'package:cheminova/models/product_manual_model.dart';
|
||||
import 'package:cheminova/services/api_urls.dart';
|
||||
import 'package:cheminova/services/api_client.dart';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ProductManualProvider extends ChangeNotifier {
|
||||
bool _isLoading = false;
|
||||
List<ProductManualModel> _productManualList = [];
|
||||
final _apiClient = ApiClient();
|
||||
|
||||
List<ProductManualModel> get productManualList => _productManualList;
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
void setLoading(bool loading) {
|
||||
_isLoading = loading;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getProductManualList() async {
|
||||
setLoading(true);
|
||||
try {
|
||||
Response response = await _apiClient.get(ApiUrls.getProductsManual);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
List<ProductManualModel> data =
|
||||
(response.data['productManuals'] as List)
|
||||
.map((json) => ProductManualModel.fromJson(json))
|
||||
.toList();
|
||||
_productManualList = data;
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,11 +12,14 @@ class ProductProvider extends ChangeNotifier {
|
||||
final _apiClient = ApiClient();
|
||||
ProductResponse? productResponse;
|
||||
List<Product> productList = [];
|
||||
final List<Product> _selectedProducts = [];
|
||||
|
||||
bool _isLoading = false;
|
||||
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
List<Product> get selectedProducts => _selectedProducts;
|
||||
|
||||
void setLoading(bool loading) {
|
||||
_isLoading = loading;
|
||||
notifyListeners();
|
||||
@ -29,7 +32,7 @@ class ProductProvider extends ChangeNotifier {
|
||||
setLoading(false);
|
||||
if (response.statusCode == 200) {
|
||||
productResponse = ProductResponse.fromJson(response.data);
|
||||
productList = productResponse!.product;
|
||||
productList = productResponse!.products;
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e) {
|
||||
@ -37,4 +40,36 @@ class ProductProvider extends ChangeNotifier {
|
||||
print("Error: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> submitSelectedProducts(
|
||||
String addedFor, String addedForId) async {
|
||||
setLoading(true);
|
||||
try {
|
||||
final data = {
|
||||
"products": selectedProducts.map((product) {
|
||||
return {
|
||||
"SKU": product.SKU,
|
||||
"ProductName": product.name,
|
||||
"Sale": product.sale,
|
||||
"Inventory": product.inventory,
|
||||
};
|
||||
}).toList(),
|
||||
"addedFor": addedFor,
|
||||
"addedForId": addedForId,
|
||||
};
|
||||
|
||||
Response response =
|
||||
await _apiClient.post(ApiUrls.submitProducts, data: data);
|
||||
setLoading(false);
|
||||
if (response.statusCode == 201) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
print("Error: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
248
lib/provider/task_provider.dart
Normal file
248
lib/provider/task_provider.dart
Normal file
@ -0,0 +1,248 @@
|
||||
import 'package:cheminova/models/pd_rd_response_model.dart';
|
||||
import 'package:cheminova/models/task_model.dart';
|
||||
import 'package:cheminova/screens/data_submit_successfull.dart';
|
||||
import 'package:cheminova/services/api_client.dart';
|
||||
import 'package:cheminova/services/api_urls.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class TaskProvider extends ChangeNotifier {
|
||||
bool _isLoading = false;
|
||||
PdRdResponseModel? _selectedSalesCoordinator;
|
||||
String? _selectedTask;
|
||||
String? _selectedPriority;
|
||||
String _selectedDate = DateFormat('dd/MM/yyyy').format(DateTime.now());
|
||||
List<PdRdResponseModel> _salesCoordinators = [];
|
||||
List<PdRdResponseModel> _pdList = [];
|
||||
List<PdRdResponseModel> _rdList = [];
|
||||
List<TaskModel> _taskModelList = [];
|
||||
PdRdResponseModel? _selectedDistributor;
|
||||
final TextEditingController _noteController = TextEditingController();
|
||||
final _apiClient = ApiClient();
|
||||
|
||||
bool get isLoading => _isLoading;
|
||||
PdRdResponseModel? get selectedSalesCoordinator => _selectedSalesCoordinator;
|
||||
String? get selectedTask => _selectedTask;
|
||||
String? get selectedPriority => _selectedPriority;
|
||||
String get selectedDate => _selectedDate;
|
||||
List<PdRdResponseModel> get salesCoordinators => _salesCoordinators;
|
||||
TextEditingController get noteController => _noteController;
|
||||
List<PdRdResponseModel> get pdList => _pdList;
|
||||
List<PdRdResponseModel> get rdList => _rdList;
|
||||
List<TaskModel> get taskModelList => _taskModelList;
|
||||
PdRdResponseModel? get selectedDistributor => _selectedDistributor;
|
||||
|
||||
void setLoading(bool loading) {
|
||||
_isLoading = loading;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setSelectedSalesCoordinator(PdRdResponseModel coordinator) {
|
||||
_selectedSalesCoordinator = coordinator;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setSelectedTask(String? task) {
|
||||
_selectedTask = task;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setSelectedPriority(String priority) {
|
||||
_selectedPriority = priority;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setDate(String date) {
|
||||
_selectedDate = date;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_selectedSalesCoordinator = null;
|
||||
_selectedTask = null;
|
||||
_selectedPriority = null;
|
||||
_selectedDate = DateFormat('dd/MM/yyyy').format(DateTime.now());
|
||||
_noteController.clear();
|
||||
_taskModelList.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getSalesCoordinators() async {
|
||||
setLoading(true);
|
||||
try {
|
||||
Response response = await _apiClient.get(ApiUrls.getSalesCoordinators);
|
||||
if (response.statusCode == 200) {
|
||||
List<PdRdResponseModel> data =
|
||||
(response.data['salesCoOrinators'] as List)
|
||||
.map((json) => PdRdResponseModel.fromJson(json))
|
||||
.toList();
|
||||
_salesCoordinators = data;
|
||||
} else {
|
||||
print("Failed to load data: ${response.statusCode}");
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
setLoading(false);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> assignTask({
|
||||
required BuildContext context,
|
||||
String? selectedDistributorType,
|
||||
}) async {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
final data = {
|
||||
'taskAssignedTo': _selectedSalesCoordinator!.id,
|
||||
'task': _selectedTask,
|
||||
'taskPriority': _selectedPriority,
|
||||
'taskDueDate': _selectedDate,
|
||||
if (_selectedTask == 'Collect KYC' || _selectedTask == 'Visit RD/PD')
|
||||
'note': _noteController.text,
|
||||
};
|
||||
|
||||
if (selectedDistributorType != null &&
|
||||
selectedDistributorType.isNotEmpty) {
|
||||
data.addAll({
|
||||
'addedFor': selectedDistributorType,
|
||||
'addedForId': _selectedDistributor!.id,
|
||||
'tradename': selectedDistributorType == 'PrincipalDistributor'
|
||||
? _selectedDistributor!.shippingAddress!.tradeName
|
||||
: _selectedDistributor!.tradeNameRd,
|
||||
});
|
||||
}
|
||||
|
||||
Response response = await _apiClient.post(
|
||||
ApiUrls.assignTask,
|
||||
data: data,
|
||||
);
|
||||
|
||||
if (response.statusCode == 201) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const DataSubmitSuccessfull(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
print("Failed to assign task: ${response.statusCode}");
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
void clearLists() {
|
||||
_pdList.clear();
|
||||
_rdList.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setSelectedDistributor(PdRdResponseModel? distributor) {
|
||||
_selectedDistributor = distributor;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getPd() async {
|
||||
setLoading(true);
|
||||
clearLists(); // Clear the list before fetching new data
|
||||
try {
|
||||
Response response = await _apiClient.get(ApiUrls.getPd);
|
||||
if (response.statusCode == 200) {
|
||||
List<PdRdResponseModel> data = (response.data as List)
|
||||
.map((json) => PdRdResponseModel.fromJson(json))
|
||||
.toList();
|
||||
_pdList = data;
|
||||
print("PDTradeName ${data[0].shippingAddress!.tradeName}");
|
||||
} else {
|
||||
print("Failed to load data: ${response.statusCode}");
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getRd() async {
|
||||
setLoading(true);
|
||||
clearLists(); // Clear the list before fetching new data
|
||||
try {
|
||||
Response response = await _apiClient.get(ApiUrls.getRd);
|
||||
if (response.statusCode == 200) {
|
||||
List<PdRdResponseModel> data = (response.data as List)
|
||||
.map((json) => PdRdResponseModel.fromJson(json))
|
||||
.toList();
|
||||
_rdList = data;
|
||||
print("RDTradeName ${data[0].tradeNameRd}");
|
||||
} else {
|
||||
print("Failed to load data: ${response.statusCode}");
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getNewTasks() async {
|
||||
setLoading(true);
|
||||
clearLists();
|
||||
try {
|
||||
Response response = await _apiClient.get("${ApiUrls.getAllTasks}New");
|
||||
if (response.statusCode == 200) {
|
||||
List<TaskModel> data = (response.data['tasks'] as List)
|
||||
.map((json) => TaskModel.fromJson(json))
|
||||
.toList();
|
||||
_taskModelList = data;
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getPendingTasks() async {
|
||||
setLoading(true);
|
||||
clearLists();
|
||||
try {
|
||||
Response response = await _apiClient.get("${ApiUrls.getAllTasks}Pending");
|
||||
if (response.statusCode == 200) {
|
||||
List<TaskModel> data = (response.data['tasks'] as List)
|
||||
.map((json) => TaskModel.fromJson(json))
|
||||
.toList();
|
||||
_taskModelList = data;
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getCompletedTasks() async {
|
||||
setLoading(true);
|
||||
clearLists();
|
||||
try {
|
||||
Response response =
|
||||
await _apiClient.get("${ApiUrls.getAllTasks}Completed");
|
||||
if (response.statusCode == 200) {
|
||||
List<TaskModel> data = (response.data['tasks'] as List)
|
||||
.map((json) => TaskModel.fromJson(json))
|
||||
.toList();
|
||||
_taskModelList = data;
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error occurred: $e");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
36
lib/provider/visit_pdrd_provider.dart
Normal file
36
lib/provider/visit_pdrd_provider.dart
Normal file
@ -0,0 +1,36 @@
|
||||
import 'package:cheminova/screens/data_submit_successfull.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../services/api_client.dart';
|
||||
import '../services/api_urls.dart';
|
||||
|
||||
class VisitPdRdProvider with ChangeNotifier {
|
||||
final _apiClient = ApiClient();
|
||||
bool _isLoading = false;
|
||||
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
void setLoading(bool loading) {
|
||||
_isLoading = loading;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> submitVisitPdRd(BuildContext context, String id) async {
|
||||
setLoading(true);
|
||||
try {
|
||||
Response response =
|
||||
await _apiClient.put(ApiUrls.updateTaskInventoryUrl + id);
|
||||
debugPrint('Response: $response');
|
||||
setLoading(false);
|
||||
if (response.statusCode == 200) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const DataSubmitSuccessfull()));
|
||||
}
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
debugPrint("Error: $e");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,25 @@
|
||||
import 'package:cheminova/provider/visit_pdrd_provider.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../widgets/common_app_bar.dart';
|
||||
import '../widgets/common_elevated_button.dart';
|
||||
import '../widgets/common_text_form_field.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
class VisitDealersScreen extends StatefulWidget {
|
||||
const VisitDealersScreen({super.key});
|
||||
final String? tradeName;
|
||||
final String? id;
|
||||
const VisitDealersScreen({super.key, this.tradeName, this.id});
|
||||
|
||||
@override
|
||||
State<VisitDealersScreen> createState() => VisitDealersScreenState();
|
||||
}
|
||||
|
||||
class VisitDealersScreenState extends State<VisitDealersScreen> {
|
||||
late VisitPdRdProvider _visitPdRdProvider;
|
||||
final dateController = TextEditingController(
|
||||
text: DateFormat('dd/MM/yyyy').format(DateTime.now()));
|
||||
|
||||
@ -26,13 +31,10 @@ class VisitDealersScreenState extends State<VisitDealersScreen> {
|
||||
final meetingSummaryController = TextEditingController();
|
||||
final followUpActionsController = TextEditingController();
|
||||
final nextVisitDateController = TextEditingController();
|
||||
late TextEditingController retailerController = TextEditingController();
|
||||
|
||||
String selectedPurpose = 'Sales/Liquidation';
|
||||
List<String> purposeOptions = [
|
||||
'Sales/Liquidation',
|
||||
'Dues collection',
|
||||
'Others'
|
||||
];
|
||||
String selectedPurpose = 'Sales';
|
||||
List<String> purposeOptions = ['Sales', 'Dues collection', 'Others'];
|
||||
|
||||
Future<void> _pickImage() async {
|
||||
final ImagePicker picker = ImagePicker();
|
||||
@ -40,34 +42,52 @@ class VisitDealersScreenState extends State<VisitDealersScreen> {
|
||||
// Handle the picked image
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_visitPdRdProvider = VisitPdRdProvider();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CommonBackground(
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
appBar: CommonAppBar(
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Image.asset('assets/Back_attendance.png'),
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
title: const Text('Visit Retailers',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')),
|
||||
retailerController = TextEditingController(text: widget.tradeName);
|
||||
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => _visitPdRdProvider,
|
||||
child: CommonBackground(
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
),
|
||||
drawer: const CommonDrawer(),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: SingleChildScrollView(
|
||||
appBar: CommonAppBar(
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Image.asset('assets/Back_attendance.png'),
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
title: Column(
|
||||
children: [
|
||||
const Text('Visit Retailers',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')),
|
||||
Text(widget.tradeName ?? '',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')),
|
||||
],
|
||||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
),
|
||||
drawer: const CommonDrawer(),
|
||||
body: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@ -77,7 +97,7 @@ class VisitDealersScreenState extends State<VisitDealersScreen> {
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.all(20.0).copyWith(top: 30, bottom: 30),
|
||||
// margin: const EdgeInsets.symmetric(horizontal: 30.0),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.9),
|
||||
@ -86,9 +106,10 @@ class VisitDealersScreenState extends State<VisitDealersScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
CommonTextFormField(
|
||||
readOnly: true,
|
||||
title: 'Select Retailer',
|
||||
fillColor: Colors.white,
|
||||
controller: dealerController),
|
||||
controller: retailerController),
|
||||
const SizedBox(height: 15),
|
||||
CommonTextFormField(
|
||||
title: 'Visit date',
|
||||
@ -155,15 +176,19 @@ class VisitDealersScreenState extends State<VisitDealersScreen> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: CommonElevatedButton(
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'SUBMIT',
|
||||
backgroundColor: const Color(0xff004791),
|
||||
onPressed: () {},
|
||||
Consumer<VisitPdRdProvider>(
|
||||
builder: (context, value, child) => Align(
|
||||
alignment: Alignment.center,
|
||||
child: CommonElevatedButton(
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'SUBMIT',
|
||||
backgroundColor: const Color(0xff004791),
|
||||
onPressed: () {
|
||||
value.submitVisitPdRd(context, widget.id ?? '');
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:cheminova/models/pd_rd_response_model.dart';
|
||||
import 'package:cheminova/models/product_model.dart';
|
||||
import 'package:cheminova/provider/product_provider.dart';
|
||||
import 'package:cheminova/screens/data_submit_successfull.dart';
|
||||
@ -9,20 +10,36 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class AddProductsScreen extends StatefulWidget {
|
||||
const AddProductsScreen({super.key});
|
||||
final PdRdResponseModel distributor;
|
||||
final String distributorType;
|
||||
const AddProductsScreen({
|
||||
super.key,
|
||||
required this.distributor,
|
||||
required this.distributorType,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AddProductsScreen> createState() => _AddProductsScreenState();
|
||||
}
|
||||
|
||||
class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
List<Product> selectedProducts = [];
|
||||
List<Product> filteredProducts = [];
|
||||
final searchController = TextEditingController();
|
||||
late ProductProvider provider;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
loadProducts();
|
||||
}
|
||||
|
||||
Future<void> loadProducts() async {
|
||||
provider = Provider.of<ProductProvider>(context, listen: false);
|
||||
await provider.getProducts();
|
||||
setState(() {
|
||||
provider.selectedProducts.clear();
|
||||
filteredProducts = provider.productList;
|
||||
});
|
||||
}
|
||||
|
||||
void filterProducts(String query) {
|
||||
@ -54,12 +71,15 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
title: const Text('Add Products',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')),
|
||||
title: Text(
|
||||
widget.distributor.name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
),
|
||||
@ -70,26 +90,23 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
filteredProducts = provider.productList;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
if (selectedProducts.isNotEmpty)
|
||||
if (provider.selectedProducts.isNotEmpty)
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: selectedProducts.length,
|
||||
itemCount: provider.selectedProducts.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ProductBlock(
|
||||
product: selectedProducts[index]);
|
||||
return ProductBlock(index: index);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Align(
|
||||
alignment: selectedProducts.isEmpty
|
||||
alignment: provider.selectedProducts.isEmpty
|
||||
? Alignment.center
|
||||
: Alignment.bottomCenter,
|
||||
child: Padding(
|
||||
@ -100,73 +117,86 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
isScrollControlled: true,
|
||||
constraints: BoxConstraints(
|
||||
maxHeight:
|
||||
MediaQuery.of(context).size.height * 0.9,
|
||||
),
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
decoration: const InputDecoration(
|
||||
labelText:
|
||||
'Search by name or SKU',
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.search),
|
||||
return Consumer<ProductProvider>(
|
||||
builder: (context, value, child) =>
|
||||
StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(18.0),
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
decoration: const InputDecoration(
|
||||
labelText:
|
||||
'Search by name or SKU',
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.search),
|
||||
),
|
||||
onChanged: (value) {
|
||||
filterProducts(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
onChanged: (value) {
|
||||
filterProducts(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: filteredProducts.length,
|
||||
itemBuilder: (context, index) {
|
||||
bool isAlreadySelected =
|
||||
selectedProducts.contains(
|
||||
filteredProducts[index]);
|
||||
return Card(
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
filteredProducts[index]
|
||||
.name,
|
||||
style: TextStyle(
|
||||
color: isAlreadySelected
|
||||
? Colors.grey
|
||||
: Colors.black,
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount:
|
||||
filteredProducts.length,
|
||||
itemBuilder: (context, index) {
|
||||
bool isAlreadySelected =
|
||||
provider.selectedProducts
|
||||
.contains(
|
||||
filteredProducts[
|
||||
index]);
|
||||
return Card(
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
filteredProducts[index]
|
||||
.name,
|
||||
style: TextStyle(
|
||||
color: isAlreadySelected
|
||||
? Colors.grey
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
filteredProducts[index].SKU,
|
||||
style: TextStyle(
|
||||
color: isAlreadySelected
|
||||
? Colors.grey
|
||||
: Colors.black,
|
||||
subtitle: Text(
|
||||
filteredProducts[index]
|
||||
.SKU,
|
||||
style: TextStyle(
|
||||
color: isAlreadySelected
|
||||
? Colors.grey
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
onTap: isAlreadySelected
|
||||
? null
|
||||
: () {
|
||||
setState(() {
|
||||
provider
|
||||
.selectedProducts
|
||||
.add(filteredProducts[
|
||||
index]);
|
||||
});
|
||||
Navigator.pop(
|
||||
context);
|
||||
},
|
||||
),
|
||||
onTap: isAlreadySelected
|
||||
? null
|
||||
: () {
|
||||
setState(() {
|
||||
selectedProducts.add(
|
||||
filteredProducts[
|
||||
index]);
|
||||
});
|
||||
Navigator.pop(
|
||||
context);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
).whenComplete(() {
|
||||
@ -180,7 +210,7 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
if (selectedProducts.isNotEmpty) ...[
|
||||
if (provider.selectedProducts.isNotEmpty) ...[
|
||||
const SizedBox(height: 16.0),
|
||||
CommonElevatedButton(
|
||||
borderRadius: 30,
|
||||
@ -189,13 +219,21 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
text: 'SUBMIT',
|
||||
backgroundColor: const Color(0xff004791),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const DataSubmitSuccessfull(),
|
||||
),
|
||||
);
|
||||
provider
|
||||
.submitSelectedProducts(
|
||||
"PrincipalDistributor",
|
||||
widget.distributor.id!)
|
||||
.then((value) {
|
||||
if (value) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const DataSubmitSuccessfull(),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
@ -213,9 +251,9 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
}
|
||||
|
||||
class ProductBlock extends StatefulWidget {
|
||||
final Product product;
|
||||
final int index;
|
||||
|
||||
const ProductBlock({super.key, required this.product});
|
||||
const ProductBlock({super.key, required this.index});
|
||||
|
||||
@override
|
||||
_ProductBlockState createState() => _ProductBlockState();
|
||||
@ -225,27 +263,38 @@ class _ProductBlockState extends State<ProductBlock> {
|
||||
final saleController = TextEditingController();
|
||||
final inventoryController = TextEditingController();
|
||||
String? errorMessage;
|
||||
late ProductProvider provider;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
provider = Provider.of<ProductProvider>(context, listen: false);
|
||||
}
|
||||
|
||||
void validateInput() {
|
||||
bool validateInput() {
|
||||
setState(() {
|
||||
if (saleController.text.isNotEmpty &&
|
||||
inventoryController.text.isNotEmpty) {
|
||||
int sale = int.parse(saleController.text);
|
||||
int inventory = int.parse(inventoryController.text);
|
||||
if (inventory > sale) {
|
||||
errorMessage = 'Inventory should be less than or equal to sales';
|
||||
} else {
|
||||
errorMessage = null;
|
||||
// Check if both inputs are valid integers
|
||||
try {
|
||||
int sale = int.parse(saleController.text);
|
||||
int inventory = int.parse(inventoryController.text);
|
||||
|
||||
// Validation: inventory should be less than or equal to sales
|
||||
if (inventory > sale) {
|
||||
errorMessage = 'Inventory should be less than or equal to sales';
|
||||
} else {
|
||||
errorMessage = null;
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle the case where input is not a valid integer
|
||||
errorMessage = 'Please enter valid integer values for both fields';
|
||||
}
|
||||
} else {
|
||||
errorMessage = null;
|
||||
}
|
||||
});
|
||||
return errorMessage == null;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -259,9 +308,9 @@ class _ProductBlockState extends State<ProductBlock> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Product: ${widget.product.name}',
|
||||
Text('Product: ${provider.selectedProducts[widget.index].name}',
|
||||
style: const TextStyle(fontSize: 16)),
|
||||
Text('SKU: ${widget.product.SKU}',
|
||||
Text('SKU: ${provider.selectedProducts[widget.index].SKU}',
|
||||
style: const TextStyle(fontSize: 15)),
|
||||
const SizedBox(height: 8),
|
||||
TextField(
|
||||
@ -270,7 +319,10 @@ class _ProductBlockState extends State<ProductBlock> {
|
||||
keyboardType: TextInputType.number,
|
||||
// enabled: widget.product.isPurchased,
|
||||
enabled: true,
|
||||
onChanged: (_) => validateInput(),
|
||||
onChanged: (_) => validateInput()
|
||||
? provider.selectedProducts[widget.index].sale =
|
||||
int.parse(saleController.text)
|
||||
: null,
|
||||
),
|
||||
TextField(
|
||||
controller: inventoryController,
|
||||
@ -278,7 +330,10 @@ class _ProductBlockState extends State<ProductBlock> {
|
||||
keyboardType: TextInputType.number,
|
||||
// enabled: widget.product.isPurchased,
|
||||
enabled: true,
|
||||
onChanged: (_) => validateInput(),
|
||||
onChanged: (_) => validateInput()
|
||||
? provider.selectedProducts[widget.index].inventory =
|
||||
int.parse(inventoryController.text)
|
||||
: null,
|
||||
),
|
||||
if (errorMessage != null)
|
||||
Padding(
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:cheminova/screens/select_sales_coordinator_screen.dart';
|
||||
import 'package:cheminova/screens/assign_tasks_screen.dart';
|
||||
import 'package:cheminova/screens/task_management_screen.dart';
|
||||
import 'package:cheminova/widgets/common_app_bar.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
@ -55,39 +56,40 @@ class _AssignTaskDashBoardScreenState extends State<AssignTaskDashBoardScreen> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Assign Tasks',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 200,
|
||||
width: MediaQuery.of(context).size.width / 4.2,
|
||||
child:
|
||||
_customCard(title: "Total Tasks", subtitle: "100"),
|
||||
),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
width: MediaQuery.of(context).size.width / 4.2,
|
||||
child: _customCard(
|
||||
title: "Tasks Pending", subtitle: "100"),
|
||||
),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
width: MediaQuery.of(context).size.width / 4.2,
|
||||
child: _customCard(
|
||||
title: "Reports Submitted", subtitle: "100"),
|
||||
),
|
||||
],
|
||||
),
|
||||
// const Text(
|
||||
// 'Assign Tasks',
|
||||
// style: TextStyle(
|
||||
// fontSize: 24,
|
||||
// color: Colors.white,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontFamily: 'Anek',
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 10),
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// height: 200,
|
||||
// width: MediaQuery.of(context).size.width / 4.2,
|
||||
// child:
|
||||
// _customCard(title: "Total Tasks", subtitle: "100"),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// height: 200,
|
||||
// width: MediaQuery.of(context).size.width / 4.2,
|
||||
// child: _customCard(
|
||||
// title: "Tasks Pending", subtitle: "100"),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// height: 200,
|
||||
// width: MediaQuery.of(context).size.width / 4.2,
|
||||
// child: _customCard(
|
||||
// title: "Reports Submitted", subtitle: "100"),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
const SizedBox(height: 20),
|
||||
CommonElevatedButton(
|
||||
backgroundColor: const Color(0xff004791),
|
||||
borderRadius: 30,
|
||||
@ -98,8 +100,7 @@ class _AssignTaskDashBoardScreenState extends State<AssignTaskDashBoardScreen> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const SelectSalesCoordinatorScreen(),
|
||||
builder: (context) => const AssignTasksScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -111,7 +112,12 @@ class _AssignTaskDashBoardScreenState extends State<AssignTaskDashBoardScreen> {
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'VIEW TASK STATUS',
|
||||
onPressed: () {},
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const TaskManagementScreen(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
CommonElevatedButton(
|
||||
|
@ -1,9 +1,14 @@
|
||||
import 'package:cheminova/models/pd_rd_response_model.dart';
|
||||
import 'package:cheminova/provider/task_provider.dart';
|
||||
import 'package:cheminova/screens/confirm_task_screen.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cheminova/widgets/common_app_bar.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
import 'package:cheminova/widgets/common_elevated_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:searchfield/searchfield.dart';
|
||||
|
||||
class AssignTasksScreen extends StatefulWidget {
|
||||
const AssignTasksScreen({super.key});
|
||||
@ -13,11 +18,65 @@ class AssignTasksScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
final List<bool> _isChecked = List.generate(8, (_) => false);
|
||||
bool _isSalesCoordinatorValid = true;
|
||||
bool _isTaskValid = true;
|
||||
bool _isPriorityValid = true;
|
||||
bool _isNotesValid = true;
|
||||
bool _isDistributorValid = true;
|
||||
String? selectedDistributorType;
|
||||
|
||||
String _dateSelected = DateFormat('dd/MM/yyyy').format(DateTime.now());
|
||||
void _validateAndSubmit() {
|
||||
final taskProvider = context.read<TaskProvider>();
|
||||
setState(() {
|
||||
// Validate Sales Coordinator
|
||||
_isSalesCoordinatorValid = taskProvider.selectedSalesCoordinator != null;
|
||||
|
||||
// Validate Task
|
||||
_isTaskValid = taskProvider.selectedTask != null &&
|
||||
taskProvider.selectedTask!.isNotEmpty;
|
||||
|
||||
// Validate Priority
|
||||
_isPriorityValid = taskProvider.selectedPriority != null &&
|
||||
taskProvider.selectedPriority!.isNotEmpty;
|
||||
|
||||
// Validate Notes
|
||||
if ((taskProvider.selectedTask == 'Collect KYC' ||
|
||||
taskProvider.selectedTask == 'Visit RD/PD') &&
|
||||
taskProvider.noteController.text.isEmpty) {
|
||||
_isNotesValid = false;
|
||||
} else {
|
||||
_isNotesValid = true;
|
||||
}
|
||||
|
||||
// Validate Distributor
|
||||
if ((taskProvider.selectedTask != 'Collect KYC') &&
|
||||
(taskProvider.selectedDistributor == null ||
|
||||
selectedDistributorType == null)) {
|
||||
_isDistributorValid = false;
|
||||
} else {
|
||||
_isDistributorValid = true;
|
||||
}
|
||||
});
|
||||
|
||||
// If all fields are valid, proceed to the next screen
|
||||
if (_isSalesCoordinatorValid &&
|
||||
_isTaskValid &&
|
||||
_isPriorityValid &&
|
||||
_isNotesValid &&
|
||||
_isDistributorValid) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ConfirmTaskScreen(
|
||||
selectedDistributorType: selectedDistributorType,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _selectDate(BuildContext context) async {
|
||||
final provider = context.read<TaskProvider>();
|
||||
final dateSelected = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
@ -25,14 +84,28 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
lastDate: DateTime(2025),
|
||||
);
|
||||
if (dateSelected != null) {
|
||||
setState(() {
|
||||
_dateSelected = DateFormat('dd/MM/yyyy').format(dateSelected);
|
||||
});
|
||||
provider.setDate(DateFormat('dd/MM/yyyy').format(dateSelected));
|
||||
}
|
||||
}
|
||||
|
||||
void _updateTaskProvider() {
|
||||
final provider = context.read<TaskProvider>();
|
||||
provider.clear();
|
||||
provider.getSalesCoordinators();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_updateTaskProvider();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final taskProvider = context.watch<TaskProvider>();
|
||||
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: CommonAppBar(
|
||||
@ -56,250 +129,422 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
),
|
||||
drawer: const CommonDrawer(),
|
||||
body: CommonBackground(
|
||||
child: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 30.0)
|
||||
.copyWith(bottom: 50),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Assign Tasks',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20.0)
|
||||
.copyWith(top: 15, bottom: 30),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 30.0)
|
||||
.copyWith(bottom: 50),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Sales Coordinator: Name",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Assign Tasks',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
SearchField(
|
||||
suggestionsDecoration: SuggestionDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(8.0),
|
||||
bottomRight: Radius.circular(8),
|
||||
),
|
||||
border: Border.all(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"ID: 121",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
suggestionItemDecoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
shape: BoxShape.rectangle,
|
||||
border: Border.all(
|
||||
color: Colors.transparent,
|
||||
style: BorderStyle.solid,
|
||||
width: 1.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"Tasks List:",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
searchInputDecoration: InputDecoration(
|
||||
filled: true,
|
||||
fillColor: Colors.grey.withOpacity(0.2),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.white,
|
||||
width: 2.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
child: CheckboxListTile(
|
||||
value: _isChecked[0],
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[0] = value!;
|
||||
});
|
||||
},
|
||||
title: const Text(
|
||||
"Visit Retailers",
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16.0),
|
||||
),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.white,
|
||||
width: 2.0,
|
||||
),
|
||||
),
|
||||
errorText: !_isSalesCoordinatorValid
|
||||
? 'Please select a Sales Coordinator'
|
||||
: null,
|
||||
),
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: CheckboxListTile(
|
||||
value: _isChecked[1],
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[1] = value!;
|
||||
});
|
||||
},
|
||||
title: const Text(
|
||||
"Update Sales Data",
|
||||
),
|
||||
),
|
||||
hint: 'Select Sales Coordinator',
|
||||
onSuggestionTap: (selectedItem) {
|
||||
if (selectedItem.item != null) {
|
||||
taskProvider.setSelectedSalesCoordinator(
|
||||
selectedItem.item!);
|
||||
FocusScope.of(context).unfocus();
|
||||
}
|
||||
},
|
||||
onTapOutside: (event) =>
|
||||
FocusScope.of(context).unfocus(),
|
||||
marginColor: Colors.grey.shade300,
|
||||
suggestions: taskProvider.salesCoordinators
|
||||
.map(
|
||||
(e) => SearchFieldListItem(
|
||||
e.name!,
|
||||
item: e,
|
||||
child: Text(e.name!),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: CheckboxListTile(
|
||||
value: _isChecked[2],
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[2] = value!;
|
||||
});
|
||||
},
|
||||
title: const Text(
|
||||
"Update Liqudation Data",
|
||||
),
|
||||
),
|
||||
),
|
||||
CheckboxListTile(
|
||||
value: _isChecked[3],
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[3] = value!;
|
||||
});
|
||||
},
|
||||
title: const Text(
|
||||
"Collect KYC",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"Priority:",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Row(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _isChecked[4],
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[4] = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
const Text(
|
||||
"Low",
|
||||
"Tasks List:",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Checkbox(
|
||||
value: _isChecked[5],
|
||||
SizedBox(
|
||||
height: 35,
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: 'Visit RD/PD',
|
||||
groupValue: taskProvider.selectedTask,
|
||||
onChanged: (value) {
|
||||
taskProvider.setSelectedTask(value);
|
||||
},
|
||||
title: const Text(
|
||||
"Visit RD/PD",
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: 'Update Sales Data',
|
||||
groupValue: taskProvider.selectedTask,
|
||||
onChanged: (value) {
|
||||
taskProvider.setSelectedTask(value);
|
||||
},
|
||||
title: const Text(
|
||||
"Update Sales Data Data",
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: 'Update Inventory Data',
|
||||
groupValue: taskProvider.selectedTask,
|
||||
onChanged: (value) {
|
||||
taskProvider.setSelectedTask(value);
|
||||
},
|
||||
title: const Text(
|
||||
"Update Inventory Data",
|
||||
),
|
||||
),
|
||||
),
|
||||
RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: 'Collect KYC',
|
||||
groupValue: taskProvider.selectedTask,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[5] = value!;
|
||||
});
|
||||
taskProvider.setSelectedTask(value);
|
||||
},
|
||||
title: const Text(
|
||||
"Collect KYC",
|
||||
),
|
||||
),
|
||||
const Text(
|
||||
"Medium",
|
||||
if (!_isTaskValid &&
|
||||
(taskProvider.selectedTask?.isEmpty ?? true))
|
||||
const Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Text(
|
||||
'Please select a task',
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (taskProvider.selectedTask == 'Collect KYC' ||
|
||||
taskProvider.selectedTask == 'Visit RD/PD') ...{
|
||||
Container(
|
||||
height: 150,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: TextFormField(
|
||||
controller: taskProvider.noteController,
|
||||
expands: true,
|
||||
maxLines: null,
|
||||
minLines: null,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: 14.0,
|
||||
horizontal: 16.0,
|
||||
),
|
||||
border: InputBorder.none,
|
||||
labelText: 'Note',
|
||||
hintText: 'Enter your note',
|
||||
errorText: !_isNotesValid
|
||||
? 'Please enter a note'
|
||||
: null,
|
||||
),
|
||||
Checkbox(
|
||||
value: _isChecked[6],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
)
|
||||
},
|
||||
if (taskProvider.selectedTask ==
|
||||
'Update Inventory Data' ||
|
||||
taskProvider.selectedTask == 'Visit RD/PD' ||
|
||||
taskProvider.selectedTask == 'Update Sales Data') ...{
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15.0,
|
||||
vertical: 5,
|
||||
),
|
||||
child: DropdownButtonFormField<String>(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Select Distributor Type',
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
value: selectedDistributorType,
|
||||
items: [
|
||||
'PrincipalDistributor',
|
||||
'RetailDistributor'
|
||||
].map((String type) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: type,
|
||||
child: Text(type),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedDistributorType = value;
|
||||
selectedDistributorType ==
|
||||
'PrincipalDistributor'
|
||||
? taskProvider.getPd()
|
||||
: taskProvider.getRd();
|
||||
taskProvider.setSelectedDistributor(null);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
// Dropdown for selecting distributor name based on type
|
||||
if (selectedDistributorType != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15.0, vertical: 25),
|
||||
child: DropdownButtonFormField<PdRdResponseModel>(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Select Distributor Name',
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
value: taskProvider.selectedDistributor,
|
||||
items: (selectedDistributorType ==
|
||||
'PrincipalDistributor'
|
||||
? taskProvider.pdList
|
||||
: taskProvider.rdList)
|
||||
.map((PdRdResponseModel distributor) {
|
||||
return DropdownMenuItem<PdRdResponseModel>(
|
||||
value: distributor,
|
||||
child: Text(distributor.name!),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[6] = value!;
|
||||
});
|
||||
taskProvider.setSelectedDistributor(value);
|
||||
},
|
||||
isExpanded: true,
|
||||
isDense: true,
|
||||
iconSize: 24,
|
||||
hint: Text(
|
||||
'Please select a ${selectedDistributorType ?? "Distributor Type"} first'),
|
||||
),
|
||||
),
|
||||
if (!_isDistributorValid)
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Text(
|
||||
'Please select a distributor',
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"High",
|
||||
"Priority:",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Radio<String>(
|
||||
value: "Low",
|
||||
groupValue: taskProvider.selectedPriority,
|
||||
onChanged: (value) {
|
||||
taskProvider.setSelectedPriority(value!);
|
||||
},
|
||||
),
|
||||
const Text("Low"),
|
||||
Radio<String>(
|
||||
value: "Medium",
|
||||
groupValue: taskProvider.selectedPriority,
|
||||
onChanged: (value) {
|
||||
taskProvider.setSelectedPriority(value!);
|
||||
},
|
||||
),
|
||||
const Text("Medium"),
|
||||
Radio<String>(
|
||||
value: "High",
|
||||
groupValue: taskProvider.selectedPriority,
|
||||
onChanged: (value) {
|
||||
taskProvider.setSelectedPriority(value!);
|
||||
},
|
||||
),
|
||||
const Text("High"),
|
||||
],
|
||||
),
|
||||
if (!_isPriorityValid &&
|
||||
(taskProvider.selectedPriority?.isEmpty ??
|
||||
true))
|
||||
const Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Text(
|
||||
'Please select a priority',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"Due Date:",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
taskProvider.selectedDate,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
_selectDate(context);
|
||||
},
|
||||
icon: const Icon(Icons.calendar_month),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
CommonElevatedButton(
|
||||
backgroundColor: const Color(0xff004791),
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'CONFIRM',
|
||||
onPressed: _validateAndSubmit,
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"Due Date:",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
_dateSelected,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
_selectDate(context);
|
||||
},
|
||||
icon: const Icon(Icons.calendar_month),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
CommonElevatedButton(
|
||||
backgroundColor: const Color(0xff004791),
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'CONFIRM',
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (taskProvider.isLoading)
|
||||
Container(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
239
lib/screens/confirm_task_screen.dart
Normal file
239
lib/screens/confirm_task_screen.dart
Normal file
@ -0,0 +1,239 @@
|
||||
import 'package:cheminova/provider/task_provider.dart';
|
||||
import 'package:cheminova/widgets/common_app_bar.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
import 'package:cheminova/widgets/common_elevated_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ConfirmTaskScreen extends StatefulWidget {
|
||||
final String? selectedDistributorType;
|
||||
const ConfirmTaskScreen({
|
||||
super.key,
|
||||
this.selectedDistributorType,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ConfirmTaskScreen> createState() => _ConfirmTaskScreenState();
|
||||
}
|
||||
|
||||
class _ConfirmTaskScreenState extends State<ConfirmTaskScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final taskProvider = context.watch<TaskProvider>();
|
||||
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: CommonAppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Image.asset('assets/Back_attendance.png'),
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
title: const Center(
|
||||
child: Text(
|
||||
'Confirm Task',
|
||||
style: TextStyle(color: Colors.black87, fontSize: 20),
|
||||
),
|
||||
),
|
||||
),
|
||||
drawer: const CommonDrawer(),
|
||||
body: CommonBackground(
|
||||
child: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 30.0)
|
||||
.copyWith(bottom: 50),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Confirm Task',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_customContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Sales Coordinator:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Text(
|
||||
taskProvider.selectedSalesCoordinator!.name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'ID: ${taskProvider.selectedSalesCoordinator!.uniqueId!}',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Text(
|
||||
'Tasks:',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
_customContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Task: ${taskProvider.selectedTask!}',
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'Priority: ${taskProvider.selectedPriority!}',
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'Deadline: ${taskProvider.selectedDate}',
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
if (taskProvider.selectedTask == 'Collect KYC' ||
|
||||
taskProvider.selectedTask == 'Visit RD/PD')
|
||||
_customContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Note:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Text(
|
||||
taskProvider.noteController.text,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
if (taskProvider.selectedTask != 'Collect KYC') ...{
|
||||
_customContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.selectedDistributorType!,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
Text(
|
||||
taskProvider.selectedDistributor!.name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
},
|
||||
const SizedBox(height: 20),
|
||||
CommonElevatedButton(
|
||||
isLoading: taskProvider.isLoading,
|
||||
backgroundColor: const Color(0xff004791),
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'CONFIRM',
|
||||
onPressed: () => taskProvider.assignTask(
|
||||
context: context,
|
||||
selectedDistributorType:
|
||||
widget.selectedDistributorType != null
|
||||
? widget.selectedDistributorType!
|
||||
: '',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
CommonElevatedButton(
|
||||
backgroundColor: const Color(0xff00784C),
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'EDIT',
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _customContainer({required Widget child}) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
// margin: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
@ -14,25 +14,32 @@ class DataSubmitSuccessfullState extends State<DataSubmitSuccessfull> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
Future.delayed(const Duration(seconds: 2), () {
|
||||
Navigator.pushReplacement(
|
||||
context, MaterialPageRoute(builder: (context) => const HomePage()));
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(builder: (context) => const HomePage()),
|
||||
(Route<dynamic> route) => false, // Remove all routes
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
return Scaffold(
|
||||
body: CommonBackground(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text('Data Submitted\nsuccessfully',
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')),
|
||||
const SizedBox(height: 20), // Add some space between the text and the image
|
||||
Image.asset('assets/check_circle.png', )]))));
|
||||
const Text('Data Submitted\nsuccessfully',
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')),
|
||||
const SizedBox(
|
||||
height: 20), // Add some space between the text and the image
|
||||
Image.asset(
|
||||
'assets/check_circle.png',
|
||||
)
|
||||
]))));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:cheminova/notification_service.dart';
|
||||
import 'package:cheminova/provider/user_provider.dart';
|
||||
import 'package:cheminova/screens/Visit_Dealers_screen.dart';
|
||||
import 'package:cheminova/screens/assign_task_dash_board_screen.dart';
|
||||
import 'package:cheminova/screens/calendar_screen.dart';
|
||||
import 'package:cheminova/screens/collect_kyc_screen.dart';
|
||||
@ -7,14 +8,12 @@ import 'package:cheminova/screens/mark_attendence_screen.dart';
|
||||
import 'package:cheminova/screens/notification_screen.dart';
|
||||
import 'package:cheminova/screens/products_manual_screen.dart';
|
||||
import 'package:cheminova/screens/rejected_application_screen.dart';
|
||||
import 'package:cheminova/screens/summary_screen.dart';
|
||||
import 'package:cheminova/screens/product_sales_data.dart';
|
||||
import 'package:cheminova/screens/update_inventory_screen.dart';
|
||||
import 'package:cheminova/screens/display_sales_screen.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/screens/daily_tasks_screen.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
@ -106,17 +105,7 @@ class _HomePageState extends State<HomePage> {
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
_buildCustomCard('Daily Tasks', 'Dashboard', onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const DailyTasksScreen(),
|
||||
));
|
||||
}),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
_buildCustomCard('Assign Tasks', '', onTap: () {
|
||||
_buildCustomCard('Assign Tasks', 'Dashboard', onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@ -130,9 +119,8 @@ class _HomePageState extends State<HomePage> {
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildCustomCard(
|
||||
'Display\nSales data', 'Quickly display Sales',
|
||||
onTap: () {
|
||||
child: _buildCustomCard('Display\nSales data',
|
||||
'Quickly display Sales\n', onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@ -163,14 +151,19 @@ class _HomePageState extends State<HomePage> {
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child:
|
||||
_buildCustomCard('Summary', '\n\n', onTap: () {
|
||||
Navigator.push(
|
||||
child: _buildCustomCard(
|
||||
'Visit RD/PD',
|
||||
'\n\n',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const SummaryScreen(),
|
||||
));
|
||||
}),
|
||||
builder: (context) =>
|
||||
const VisitDealersScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
|
@ -19,7 +19,7 @@ class ProductSalesDataState extends State<ProductSalesData> {
|
||||
text: DateFormat('dd/MM/yyyy').format(DateTime.now()));
|
||||
|
||||
final timeController =
|
||||
TextEditingController(text: DateFormat('hh:mm a').format(DateTime.now()));
|
||||
TextEditingController(text: DateFormat('hh:mm a').format(DateTime.now()));
|
||||
|
||||
final locationController = TextEditingController();
|
||||
final notesController = TextEditingController();
|
||||
@ -29,19 +29,19 @@ class ProductSalesDataState extends State<ProductSalesData> {
|
||||
final salesController = TextEditingController();
|
||||
final commentController = TextEditingController();
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CommonBackground(
|
||||
child: Scaffold(backgroundColor: Colors.transparent,
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
appBar: CommonAppBar(
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: ()
|
||||
{
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Image.asset('assets/Back_attendance.png'), padding: const EdgeInsets.only(right: 20),
|
||||
icon: Image.asset('assets/Back_attendance.png'),
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
title: const Text('Product Sales Data',
|
||||
@ -49,7 +49,9 @@ class ProductSalesDataState extends State<ProductSalesData> {
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')), backgroundColor: Colors.transparent, elevation: 0,
|
||||
fontFamily: 'Anek')),
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
),
|
||||
drawer: const CommonDrawer(),
|
||||
body: Padding(
|
||||
@ -63,7 +65,7 @@ class ProductSalesDataState extends State<ProductSalesData> {
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.all(20.0).copyWith(top: 30, bottom: 30),
|
||||
const EdgeInsets.all(20.0).copyWith(top: 30, bottom: 30),
|
||||
// margin: const EdgeInsets.symmetric(horizontal: 30.0),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
@ -77,42 +79,42 @@ class ProductSalesDataState extends State<ProductSalesData> {
|
||||
fillColor: Colors.white,
|
||||
controller: dealercontroller),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
CommonTextFormField(
|
||||
title: 'Select Product: Product A',
|
||||
fillColor: Colors.white,
|
||||
controller: productController),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
CommonTextFormField(
|
||||
title: 'Date Range: 10-06 to 20-06',
|
||||
readOnly: true,
|
||||
fillColor: Colors.white,
|
||||
controller: dateController),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: CommonElevatedButton(
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'VIEW DATA',
|
||||
backgroundColor: const Color(0xff004791),
|
||||
onPressed: () {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (context) => const DataSubmitSuccessfull(),));
|
||||
},
|
||||
|
||||
)
|
||||
|
||||
),
|
||||
],
|
||||
alignment: Alignment.center,
|
||||
child: CommonElevatedButton(
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'VIEW DATA',
|
||||
backgroundColor: const Color(0xff004791),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const DataSubmitSuccessfull(),
|
||||
));
|
||||
},
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
import 'package:cheminova/models/product_manual_model.dart';
|
||||
import 'package:cheminova/provider/product_manual_provider.dart';
|
||||
import 'package:cheminova/screens/view_pdf_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
import 'package:cheminova/widgets/common_app_bar.dart';
|
||||
@ -9,6 +13,13 @@ class ProductsManualScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Access the provider
|
||||
final productManualProvider =
|
||||
Provider.of<ProductManualProvider>(context, listen: false);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
productManualProvider.getProductManualList();
|
||||
});
|
||||
|
||||
return CommonBackground(
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
@ -22,12 +33,14 @@ class ProductsManualScreen extends StatelessWidget {
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
title: const Text('Products Manual',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')),
|
||||
title: const Text(
|
||||
'Products Manual',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek'),
|
||||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
),
|
||||
@ -41,25 +54,39 @@ class ProductsManualScreen extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20.0).copyWith(top: 30, bottom: 30),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.9),
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
_buildProductButton('Product 1'),
|
||||
_buildProductButton('Product 2'),
|
||||
_buildProductButton('Product 3'),
|
||||
_buildProductButton('Product 4'),
|
||||
_buildProductButton('Product 5'),
|
||||
_buildProductButton('Product 6'),
|
||||
_buildProductButton('Product 7'),
|
||||
],
|
||||
),
|
||||
Consumer<ProductManualProvider>(
|
||||
builder: (context, provider, child) {
|
||||
if (provider.isLoading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
if (provider.productManualList.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('No products available.'),
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20.0)
|
||||
.copyWith(top: 30, bottom: 30),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.9),
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: provider.productManualList
|
||||
.map(
|
||||
(product) =>
|
||||
_buildProductButton(context, product),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -69,20 +96,22 @@ class ProductsManualScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProductButton(String productName) {
|
||||
Widget _buildProductButton(BuildContext context, ProductManualModel product) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 15),
|
||||
child: CommonElevatedButton(
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: productName,
|
||||
text: product.title,
|
||||
backgroundColor: const Color(0xff004791),
|
||||
onPressed: () {
|
||||
// Handle product button press
|
||||
debugPrint('$productName pressed');
|
||||
},
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ViewPdfScreen(productManualModel: product),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
103
lib/screens/profile_screen.dart
Normal file
103
lib/screens/profile_screen.dart
Normal file
@ -0,0 +1,103 @@
|
||||
import 'package:cheminova/provider/user_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cheminova/widgets/common_app_bar.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
|
||||
class ProfileScreen extends StatelessWidget {
|
||||
const ProfileScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
CommonBackground(
|
||||
isFullWidth: true,
|
||||
child: Scaffold(
|
||||
drawer: const CommonDrawer(),
|
||||
backgroundColor: Colors.transparent,
|
||||
appBar: CommonAppBar(
|
||||
title: const Text('Profile'),
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Image.asset('assets/Back_attendance.png'),
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Consumer<UserProvider>(
|
||||
builder: (context, userProvider, child) {
|
||||
final profileData = userProvider.user;
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20.0)
|
||||
.copyWith(top: 15, bottom: 30),
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 30.0, vertical: 20.0),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.9),
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
_buildProfileItem('Name', profileData?.name ?? ''),
|
||||
_buildProfileItem('ID', profileData?.uniqueId ?? ''),
|
||||
_buildProfileItem(
|
||||
'Email ID', profileData?.email ?? ''),
|
||||
_buildProfileItem('Mobile Number',
|
||||
profileData?.mobileNumber ?? ''),
|
||||
_buildProfileItem(
|
||||
'Designation', profileData?.designation ?? ''),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProfileItem(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xff004791),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const Divider(color: Colors.grey),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import 'package:cheminova/screens/assign_tasks_screen.dart';
|
||||
import 'package:cheminova/widgets/common_app_bar.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
@ -79,10 +78,18 @@ class _SelectSalesCoordinatorScreenState
|
||||
child: ListView.builder(
|
||||
itemCount: salesCoordinators.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _customCard(
|
||||
name: salesCoordinators[index].name,
|
||||
id: salesCoordinators[index].id,
|
||||
tasks: salesCoordinators[index].tasks,
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
// taskProvider.setSelectedSalesCoordinator(
|
||||
// salesCoordinators[index],
|
||||
// );
|
||||
// Navigator.pop(context);
|
||||
},
|
||||
child: _customCard(
|
||||
name: salesCoordinators[index].name,
|
||||
id: salesCoordinators[index].id,
|
||||
tasks: salesCoordinators[index].tasks,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -98,55 +105,43 @@ class _SelectSalesCoordinatorScreenState
|
||||
|
||||
Widget _customCard(
|
||||
{required String name, required String id, required int tasks}) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return const AssignTasksScreen();
|
||||
},
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
name,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
name,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
fontSize: 16,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
"ID: $id",
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
fontSize: 16,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
"ID: $id",
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
"Tasks: $tasks",
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
fontSize: 16,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Text(
|
||||
"Tasks: $tasks",
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
272
lib/screens/task_management_screen.dart
Normal file
272
lib/screens/task_management_screen.dart
Normal file
@ -0,0 +1,272 @@
|
||||
import 'package:cheminova/models/task_model.dart';
|
||||
import 'package:cheminova/provider/task_provider.dart';
|
||||
import 'package:cheminova/widgets/common_app_bar.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
import 'package:cheminova/widgets/common_text_form_field.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class TaskManagementScreen extends StatefulWidget {
|
||||
const TaskManagementScreen({super.key});
|
||||
|
||||
@override
|
||||
State<TaskManagementScreen> createState() => _TaskManagementScreenState();
|
||||
}
|
||||
|
||||
class _TaskManagementScreenState extends State<TaskManagementScreen> {
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
List<TaskModel> _filteredTaskList = [];
|
||||
String? _selectedChip = 'New'; // State to track the selected chip
|
||||
|
||||
void _filterTaskList(String query) {
|
||||
if (query.isEmpty || query == '' || query == ' ') {
|
||||
setState(() {
|
||||
_filteredTaskList = context.read<TaskProvider>().taskModelList;
|
||||
});
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_filteredTaskList = _filteredTaskList
|
||||
.where((task) => task.taskAssignedTo.name
|
||||
.toLowerCase()
|
||||
.contains(query.toLowerCase()))
|
||||
.toList();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _updateTaskProvider() async {
|
||||
final provider = context.read<TaskProvider>();
|
||||
provider.clear();
|
||||
await provider.getNewTasks();
|
||||
_filteredTaskList.clear();
|
||||
_filteredTaskList = provider.taskModelList;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_updateTaskProvider();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final taskProvider = context.watch<TaskProvider>();
|
||||
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: CommonAppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: Image.asset('assets/Back_attendance.png'),
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
title: const Center(
|
||||
child: Text(
|
||||
'Task Management',
|
||||
style: TextStyle(color: Colors.black87, fontSize: 20),
|
||||
),
|
||||
),
|
||||
),
|
||||
drawer: const CommonDrawer(),
|
||||
body: CommonBackground(
|
||||
child: Stack(
|
||||
children: [
|
||||
SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20.0)
|
||||
.copyWith(top: 15, bottom: 30),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 30.0)
|
||||
.copyWith(bottom: 50),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(26.0),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CommonTextFormField(
|
||||
controller: _searchController,
|
||||
onChanged: (value) => _filterTaskList(value),
|
||||
title: 'Filter by Sales Coordinator:',
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_filterChip(
|
||||
title: 'New',
|
||||
icon: const Icon(Icons.new_releases),
|
||||
onSelected: () async {
|
||||
setState(() {
|
||||
_selectedChip = 'New';
|
||||
});
|
||||
await taskProvider.getNewTasks();
|
||||
_filteredTaskList.clear();
|
||||
_filteredTaskList =
|
||||
taskProvider.taskModelList;
|
||||
},
|
||||
isSelected: _selectedChip == 'New',
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
_filterChip(
|
||||
title: 'Pending',
|
||||
icon: const Icon(Icons.pending),
|
||||
onSelected: () async {
|
||||
setState(() {
|
||||
_selectedChip = 'Pending';
|
||||
});
|
||||
await taskProvider.getPendingTasks();
|
||||
_filteredTaskList.clear();
|
||||
_filteredTaskList =
|
||||
taskProvider.taskModelList;
|
||||
},
|
||||
isSelected: _selectedChip == 'Pending',
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
_filterChip(
|
||||
title: 'Completed',
|
||||
icon: const Icon(Icons.done),
|
||||
onSelected: () async {
|
||||
setState(() {
|
||||
_selectedChip = 'Completed';
|
||||
});
|
||||
await taskProvider.getCompletedTasks();
|
||||
_filteredTaskList.clear();
|
||||
_filteredTaskList =
|
||||
taskProvider.taskModelList;
|
||||
},
|
||||
isSelected: _selectedChip == 'Completed',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.55,
|
||||
child: _filteredTaskList.isEmpty
|
||||
? const Center(child: Text('No tasks found'))
|
||||
: ListView.builder(
|
||||
itemCount: _filteredTaskList.length,
|
||||
itemBuilder: (context, index) => _taskView(
|
||||
task: _filteredTaskList[
|
||||
_selectedChip == 'Completed'
|
||||
? index
|
||||
: ((_filteredTaskList.length - 1) -
|
||||
index)],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (taskProvider.isLoading)
|
||||
Container(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _customContainer({required Widget child}) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
color: const Color(0xffB4D1E5).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _taskView({required TaskModel task}) {
|
||||
final formatedDate = DateFormat('dd/MM/yyyy').format(task.taskDueDate);
|
||||
return Column(
|
||||
children: [
|
||||
_customContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Assigned to: ${task.taskAssignedTo.name}",
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"Task: ${task.task}",
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'Status: ${task.taskStatus}',
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'Deadline:$formatedDate',
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _filterChip({
|
||||
required String title,
|
||||
required Widget icon,
|
||||
required VoidCallback onSelected,
|
||||
required bool isSelected,
|
||||
}) {
|
||||
return GestureDetector(
|
||||
onTap: onSelected,
|
||||
child: Chip(
|
||||
avatar: icon,
|
||||
label: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
backgroundColor: isSelected ? Colors.blue : Colors.grey[200],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
import 'package:cheminova/screens/Add_products_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cheminova/models/pd_rd_response_model.dart';
|
||||
import 'package:cheminova/provider/pd_rd_provider.dart';
|
||||
import 'package:cheminova/screens/add_products_screen.dart';
|
||||
import 'package:cheminova/widgets/common_background.dart';
|
||||
import 'package:cheminova/widgets/common_app_bar.dart';
|
||||
import 'package:cheminova/widgets/common_drawer.dart';
|
||||
import 'package:cheminova/widgets/common_elevated_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class UpdateInventoryScreen extends StatefulWidget {
|
||||
const UpdateInventoryScreen({super.key});
|
||||
@ -13,14 +16,17 @@ class UpdateInventoryScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
final List<String> principalDistributors = ['vaibhav', 'sonu', 'monu'];
|
||||
final List<String> retailerDistributors = ['shivam', 'vivek'];
|
||||
String? selectedDistributorType;
|
||||
String? selectedDistributor;
|
||||
PdRdResponseModel? selectedDistributor;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Fetch the PdRd data when the screen is initialized
|
||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// final provider = Provider.of<PdRdProvider>(context, listen: false);
|
||||
// provider.getPdRd();
|
||||
// });
|
||||
}
|
||||
|
||||
@override
|
||||
@ -38,12 +44,14 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
padding: const EdgeInsets.only(right: 20),
|
||||
),
|
||||
],
|
||||
title: const Text('Update Inventory Data',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek')),
|
||||
title: const Text(
|
||||
'Update Inventory Data',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontFamily: 'Anek'),
|
||||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
),
|
||||
@ -57,84 +65,111 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
text: 'SUBMIT',
|
||||
backgroundColor: const Color(0xff004791),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const AddProductsScreen(),
|
||||
),
|
||||
);
|
||||
if (selectedDistributor == null ||
|
||||
selectedDistributorType == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
'Please select distributor type and distributor')),
|
||||
);
|
||||
} else {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => AddProductsScreen(
|
||||
distributor: selectedDistributor!,
|
||||
distributorType: selectedDistributorType!,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
Column(
|
||||
body: Consumer<PdRdProvider>(
|
||||
builder: (context, provider, child) {
|
||||
return Stack(
|
||||
children: [
|
||||
// Dropdown for selecting distributor type
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15.0, vertical: 25),
|
||||
child: DropdownButtonFormField<String>(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Select Distributor Type',
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(),
|
||||
Column(
|
||||
children: [
|
||||
// Dropdown for selecting distributor type
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15.0, vertical: 25),
|
||||
child: DropdownButtonFormField<String>(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Select Distributor Type',
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
value: selectedDistributorType,
|
||||
items: ['Principal Distributor', 'Retailer Distributor']
|
||||
.map((String type) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: type,
|
||||
child: Text(type),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedDistributorType = value;
|
||||
selectedDistributorType == 'Principal Distributor'
|
||||
? provider.getPd()
|
||||
: provider.getRd();
|
||||
selectedDistributor =
|
||||
null; // Reset distributor selection when type changes
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
value: selectedDistributorType,
|
||||
items: ['Principal Distributor', 'Retailer Distributor']
|
||||
.map((String type) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: type,
|
||||
child: Text(type),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedDistributorType = value;
|
||||
selectedDistributor =
|
||||
null; // Reset distributor selection when type changes
|
||||
});
|
||||
},
|
||||
),
|
||||
// Dropdown for selecting distributor name based on type
|
||||
if (selectedDistributorType != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15.0, vertical: 25),
|
||||
child: DropdownButtonFormField<PdRdResponseModel>(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Select Distributor Name',
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
value: selectedDistributor,
|
||||
items: (selectedDistributorType ==
|
||||
'Principal Distributor'
|
||||
? provider.pdList
|
||||
: provider.rdList)
|
||||
.map((PdRdResponseModel distributor) {
|
||||
return DropdownMenuItem<PdRdResponseModel>(
|
||||
value: distributor,
|
||||
child: Text(distributor.name!),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedDistributor = value;
|
||||
});
|
||||
},
|
||||
isExpanded: true,
|
||||
isDense: true,
|
||||
iconSize: 24,
|
||||
hint: Text(
|
||||
'Please select a ${selectedDistributorType ?? "Distributor Type"} first'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Dropdown for selecting distributor name based on type
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15.0, vertical: 25),
|
||||
child: DropdownButtonFormField<String>(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Select Distributor Name',
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(),
|
||||
if (provider.isLoading)
|
||||
Container(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
value: selectedDistributor,
|
||||
items: (selectedDistributorType == 'Principal Distributor'
|
||||
? principalDistributors
|
||||
: retailerDistributors)
|
||||
.map((String distributor) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: distributor,
|
||||
child: Text(distributor),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedDistributor = value;
|
||||
});
|
||||
},
|
||||
// Disable the dropdown if no distributor type is selected
|
||||
isExpanded: true,
|
||||
isDense: true,
|
||||
iconSize: 24,
|
||||
hint: Text(
|
||||
'Please select a ${selectedDistributorType ?? "Distributor Type"} first'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
24
lib/screens/view_pdf_screen.dart
Normal file
24
lib/screens/view_pdf_screen.dart
Normal file
@ -0,0 +1,24 @@
|
||||
import 'package:cheminova/models/product_manual_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
|
||||
|
||||
class ViewPdfScreen extends StatefulWidget {
|
||||
final ProductManualModel productManualModel;
|
||||
const ViewPdfScreen({super.key, required this.productManualModel});
|
||||
|
||||
@override
|
||||
State<ViewPdfScreen> createState() => _ViewPdfScreenState();
|
||||
}
|
||||
|
||||
class _ViewPdfScreenState extends State<ViewPdfScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
child: SfPdfViewer.network(
|
||||
widget.productManualModel.productManualDetail.url,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -12,4 +12,12 @@ class ApiUrls {
|
||||
static const String notificationUrl = '$baseUrl/get-notification-tm';
|
||||
static const String fcmUrl = '${baseUrl}kyc/save-fcm-tm';
|
||||
static const String getProducts = '${baseUrl}product/getAll/user/';
|
||||
static const String getRd = 'inventory/distributors-TM/RetailDistributor';
|
||||
static const String getPd = 'inventory/distributors-TM/PrincipalDistributor';
|
||||
static const String submitProducts = 'inventory/add-TM';
|
||||
static const String getSalesCoordinators = 'salescoordinator/getAll-TM';
|
||||
static const String assignTask = 'task/assign-task';
|
||||
static const String getProductsManual = 'productmanual/getall';
|
||||
static const String getAllTasks = 'task/alltasks/';
|
||||
static const String updateTaskInventoryUrl = '';
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import 'package:cheminova/provider/user_provider.dart';
|
||||
import 'package:cheminova/screens/change_password_screen.dart';
|
||||
import 'package:cheminova/screens/home_screen.dart';
|
||||
import 'package:cheminova/screens/login_screen.dart';
|
||||
import 'package:cheminova/screens/profile_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
@ -72,7 +73,14 @@ class CommonDrawer extends StatelessWidget {
|
||||
leading: const Icon(Icons.account_circle),
|
||||
title: const Text('Profile'),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return const ProfileScreen();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
|
@ -13,6 +13,7 @@ class CommonTextFormField extends StatelessWidget {
|
||||
final List<TextInputFormatter>? inputFormatters;
|
||||
final int? maxLength;
|
||||
final bool obscureText;
|
||||
final void Function(String)? onChanged;
|
||||
|
||||
const CommonTextFormField({
|
||||
super.key,
|
||||
@ -26,6 +27,7 @@ class CommonTextFormField extends StatelessWidget {
|
||||
this.keyboardType,
|
||||
this.inputFormatters,
|
||||
this.maxLength,
|
||||
this.onChanged,
|
||||
this.obscureText = false,
|
||||
});
|
||||
|
||||
@ -45,6 +47,7 @@ class CommonTextFormField extends StatelessWidget {
|
||||
readOnly: readOnly ?? false,
|
||||
maxLines: maxLines,
|
||||
maxLength: maxLength,
|
||||
onChanged: onChanged,
|
||||
onTapOutside: (event) => FocusScope.of(context).unfocus(),
|
||||
validator: validator,
|
||||
keyboardType: keyboardType,
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
@ -16,4 +17,7 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
flutter_secure_storage_linux
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
@ -5,6 +5,7 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import device_info_plus
|
||||
import file_selector_macos
|
||||
import firebase_analytics
|
||||
import firebase_core
|
||||
@ -14,8 +15,11 @@ import flutter_local_notifications
|
||||
import flutter_secure_storage_macos
|
||||
import geolocator_apple
|
||||
import path_provider_foundation
|
||||
import syncfusion_pdfviewer_macos
|
||||
import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin"))
|
||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||
@ -25,4 +29,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SyncfusionFlutterPdfViewerPlugin.register(with: registry.registrar(forPlugin: "SyncfusionFlutterPdfViewerPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
}
|
||||
|
160
pubspec.lock
160
pubspec.lock
@ -225,6 +225,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.10"
|
||||
device_info_plus:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus
|
||||
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.1.2"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
dio:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1040,6 +1056,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
searchfield:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: searchfield
|
||||
sha256: "913bb61f42d47d82c1adb67047fff3b26dcf6a199f71ecdc9af27c506dda4b48"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.9"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1117,6 +1141,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
syncfusion_flutter_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_flutter_core
|
||||
sha256: "85f96b7b06f32a60b19ab0bb8c32bf162a0474f2d94f4844384be1118e6b4954"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "26.2.11"
|
||||
syncfusion_flutter_pdf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_flutter_pdf
|
||||
sha256: "0bf5986a8ea7afc54d5712c54f1aba8530be0920872c9dbbe5e0c4369d51eef8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "26.2.11"
|
||||
syncfusion_flutter_pdfviewer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: syncfusion_flutter_pdfviewer
|
||||
sha256: "25ca744376c5dafe2e3e5c7718ccb7377a21ddbba00c0d6524801c6ed634c493"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "26.2.11"
|
||||
syncfusion_flutter_signaturepad:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_flutter_signaturepad
|
||||
sha256: "54545a6611ec8f4b975269f5fd1e7c996172d41398745363542d1307d2976884"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "26.2.11"
|
||||
syncfusion_pdfviewer_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_pdfviewer_macos
|
||||
sha256: "5731a1ea92455b8322a647387f27c2e7f52b963dff3983b8207233ecc6ef7ba7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "26.2.11"
|
||||
syncfusion_pdfviewer_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_pdfviewer_platform_interface
|
||||
sha256: f266aa4657b511201666f394b74c71ecfeaafa2717e4e75e73585a55d99d350d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "26.2.11"
|
||||
syncfusion_pdfviewer_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_pdfviewer_web
|
||||
sha256: "7a3da6586668b851b74ab1bda09d313a54250fb0f74daaadda7133ca3591b235"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "26.2.11"
|
||||
syncfusion_pdfviewer_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_pdfviewer_windows
|
||||
sha256: "670ac5e4158ba5060fbb26e2a5a04f6d7272eb9f4948d470634a0dbf33e423b2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "26.2.11"
|
||||
table_calendar:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1181,6 +1269,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
url_launcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.0"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.9"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.1"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1269,6 +1421,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.5.3"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32_registry
|
||||
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.4"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -50,6 +50,8 @@ dependencies:
|
||||
flutter_local_notifications: ^17.2.1+2
|
||||
firebase_crashlytics: ^4.0.4
|
||||
firebase_analytics: ^11.2.1
|
||||
searchfield: ^1.0.9
|
||||
syncfusion_flutter_pdfviewer: ^26.2.11
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <geolocator_windows/geolocator_windows.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
#include <syncfusion_pdfviewer_windows/syncfusion_pdfviewer_windows_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
@ -23,4 +25,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("GeolocatorWindows"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||
SyncfusionPdfviewerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("SyncfusionPdfviewerWindowsPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
flutter_secure_storage_windows
|
||||
geolocator_windows
|
||||
permission_handler_windows
|
||||
syncfusion_pdfviewer_windows
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
Loading…
Reference in New Issue
Block a user