assign task of KYC
This commit is contained in:
parent
7cce7db73c
commit
1436aa0131
@ -3,6 +3,7 @@ import 'dart:io';
|
||||
import 'package:cheminova/provider/collect_kyc_provider.dart';
|
||||
import 'package:cheminova/provider/pd_rd_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';
|
||||
@ -100,6 +101,7 @@ Future<void> main() async {
|
||||
ChangeNotifierProvider(create: (_) => UserProvider()),
|
||||
ChangeNotifierProvider(create: (_) => ProductProvider()),
|
||||
ChangeNotifierProvider(create: (_) => PdRdProvider()),
|
||||
ChangeNotifierProvider(create: (_) => TaskProvider()),
|
||||
],
|
||||
child: const MyApp(),
|
||||
),
|
||||
@ -121,8 +123,12 @@ class _MyAppState extends State<MyApp> {
|
||||
// scaffoldMessengerKey: SnackBarService().scaffoldMessengerKey,
|
||||
title: 'cheminova',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true),
|
||||
home: const SplashScreen());
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: const Color(0xff004791),
|
||||
),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const SplashScreen(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,123 +1,127 @@
|
||||
class PdRdResponseModel {
|
||||
String id;
|
||||
String name;
|
||||
String tradeName;
|
||||
String address;
|
||||
String state;
|
||||
String city;
|
||||
String district;
|
||||
String pincode;
|
||||
String mobileNumber;
|
||||
String principalDistributer;
|
||||
String panNumber;
|
||||
ImageModel panImg;
|
||||
String aadharNumber;
|
||||
ImageModel aadharImg;
|
||||
String gstNumber;
|
||||
ImageModel gstImg;
|
||||
ImageModel pesticideLicenseImg;
|
||||
ImageModel selfieEntranceImg;
|
||||
String status;
|
||||
String addedBy;
|
||||
String? id;
|
||||
String? uniqueId;
|
||||
String? name;
|
||||
String? tradeName;
|
||||
String? address;
|
||||
String? state;
|
||||
String? city;
|
||||
String? district;
|
||||
String? pincode;
|
||||
String? mobileNumber;
|
||||
String? principalDistributer;
|
||||
String? panNumber;
|
||||
ImageModel? panImg;
|
||||
String? aadharNumber;
|
||||
ImageModel? aadharImg;
|
||||
String? gstNumber;
|
||||
ImageModel? gstImg;
|
||||
ImageModel? pesticideLicenseImg;
|
||||
ImageModel? selfieEntranceImg;
|
||||
String? status;
|
||||
String? addedBy;
|
||||
String? userType;
|
||||
List<Note> notes;
|
||||
DateTime createdAt;
|
||||
DateTime updatedAt;
|
||||
int v;
|
||||
List<Note>? notes;
|
||||
DateTime? createdAt;
|
||||
DateTime? updatedAt;
|
||||
int? v;
|
||||
|
||||
PdRdResponseModel({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.tradeName,
|
||||
required this.address,
|
||||
required this.state,
|
||||
required this.city,
|
||||
required this.district,
|
||||
required this.pincode,
|
||||
required this.mobileNumber,
|
||||
required this.principalDistributer,
|
||||
required this.panNumber,
|
||||
required this.panImg,
|
||||
required this.aadharNumber,
|
||||
required this.aadharImg,
|
||||
required this.gstNumber,
|
||||
required this.gstImg,
|
||||
required this.pesticideLicenseImg,
|
||||
required this.selfieEntranceImg,
|
||||
required this.status,
|
||||
required this.addedBy,
|
||||
this.id,
|
||||
this.uniqueId,
|
||||
this.name,
|
||||
this.tradeName,
|
||||
this.address,
|
||||
this.state,
|
||||
this.city,
|
||||
this.district,
|
||||
this.pincode,
|
||||
this.mobileNumber,
|
||||
this.principalDistributer,
|
||||
this.panNumber,
|
||||
this.panImg,
|
||||
this.aadharNumber,
|
||||
this.aadharImg,
|
||||
this.gstNumber,
|
||||
this.gstImg,
|
||||
this.pesticideLicenseImg,
|
||||
this.selfieEntranceImg,
|
||||
this.status,
|
||||
this.addedBy,
|
||||
this.userType,
|
||||
required this.notes,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.v,
|
||||
this.notes,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.v,
|
||||
});
|
||||
|
||||
factory PdRdResponseModel.fromJson(Map<String, dynamic> json) =>
|
||||
PdRdResponseModel(
|
||||
id: json["_id"],
|
||||
name: json["name"],
|
||||
tradeName: json["trade_name"],
|
||||
address: json["address"],
|
||||
state: json["state"],
|
||||
city: json["city"],
|
||||
district: json["district"],
|
||||
pincode: json["pincode"],
|
||||
mobileNumber: json["mobile_number"],
|
||||
principalDistributer: json["principal_distributer"],
|
||||
panNumber: json["pan_number"],
|
||||
panImg: ImageModel.fromJson(json["pan_img"]),
|
||||
aadharNumber: json["aadhar_number"],
|
||||
aadharImg: ImageModel.fromJson(json["aadhar_img"]),
|
||||
gstNumber: json["gst_number"],
|
||||
gstImg: ImageModel.fromJson(json["gst_img"]),
|
||||
pesticideLicenseImg: ImageModel.fromJson(json["pesticide_license_img"]),
|
||||
selfieEntranceImg: ImageModel.fromJson(json["selfie_entrance_img"]),
|
||||
status: json["status"],
|
||||
addedBy: json["addedBy"],
|
||||
userType: json["userType"],
|
||||
notes: List<Note>.from(json["notes"].map((x) => Note.fromJson(x))),
|
||||
createdAt: DateTime.parse(json["createdAt"]),
|
||||
updatedAt: DateTime.parse(json["updatedAt"]),
|
||||
v: json["__v"],
|
||||
uniqueId: json["uniqueId"],
|
||||
// tradeName: json["trade_name"],
|
||||
// address: json["address"],
|
||||
// state: json["state"],
|
||||
// city: json["city"],
|
||||
// district: json["district"],
|
||||
// pincode: json["pincode"],
|
||||
// mobileNumber: json["mobile_number"],
|
||||
// principalDistributer: json["principal_distributer"],
|
||||
// panNumber: json["pan_number"],
|
||||
// panImg: ImageModel.fromJson(json["pan_img"]),
|
||||
// aadharNumber: json["aadhar_number"],
|
||||
// aadharImg: ImageModel.fromJson(json["aadhar_img"]),
|
||||
// gstNumber: json["gst_number"],
|
||||
// gstImg: ImageModel.fromJson(json["gst_img"]),
|
||||
// pesticideLicenseImg: ImageModel.fromJson(json["pesticide_license_img"]),
|
||||
// selfieEntranceImg: ImageModel.fromJson(json["selfie_entrance_img"]),
|
||||
// status: json["status"],
|
||||
// addedBy: json["addedBy"],
|
||||
// userType: json["userType"],
|
||||
// notes: List<Note>.from(json["notes"].map((x) => Note.fromJson(x))),
|
||||
// createdAt: DateTime.parse(json["createdAt"]),
|
||||
// updatedAt: DateTime.parse(json["updatedAt"]),
|
||||
// v: json["__v"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"_id": id,
|
||||
"name": name,
|
||||
"trade_name": tradeName,
|
||||
"address": address,
|
||||
"state": state,
|
||||
"city": city,
|
||||
"district": district,
|
||||
"pincode": pincode,
|
||||
"mobile_number": mobileNumber,
|
||||
"principal_distributer": principalDistributer,
|
||||
"pan_number": panNumber,
|
||||
"pan_img": panImg.toJson(),
|
||||
"aadhar_number": aadharNumber,
|
||||
"aadhar_img": aadharImg.toJson(),
|
||||
"gst_number": gstNumber,
|
||||
"gst_img": gstImg.toJson(),
|
||||
"pesticide_license_img": pesticideLicenseImg.toJson(),
|
||||
"selfie_entrance_img": selfieEntranceImg.toJson(),
|
||||
"status": status,
|
||||
"addedBy": addedBy,
|
||||
"userType": userType,
|
||||
"notes": List<dynamic>.from(notes.map((x) => x.toJson())),
|
||||
"createdAt": createdAt.toIso8601String(),
|
||||
"updatedAt": updatedAt.toIso8601String(),
|
||||
"__v": v,
|
||||
"uniqueId": uniqueId,
|
||||
// "trade_name": tradeName,
|
||||
// "address": address,
|
||||
// "state": state,
|
||||
// "city": city,
|
||||
// "district": district,
|
||||
// "pincode": pincode,
|
||||
// "mobile_number": mobileNumber,
|
||||
// "principal_distributer": principalDistributer,
|
||||
// "pan_number": panNumber,
|
||||
// "pan_img": panImg.toJson(),
|
||||
// "aadhar_number": aadharNumber,
|
||||
// "aadhar_img": aadharImg.toJson(),
|
||||
// "gst_number": gstNumber,
|
||||
// "gst_img": gstImg.toJson(),
|
||||
// "pesticide_license_img": pesticideLicenseImg.toJson(),
|
||||
// "selfie_entrance_img": selfieEntranceImg.toJson(),
|
||||
// "status": status,
|
||||
// "addedBy": addedBy,
|
||||
// "userType": userType,
|
||||
// "notes": List<dynamic>.from(notes.map((x) => x.toJson())),
|
||||
// "createdAt": createdAt.toIso8601String(),
|
||||
// "updatedAt": updatedAt.toIso8601String(),
|
||||
// "__v": v,
|
||||
};
|
||||
}
|
||||
|
||||
class ImageModel {
|
||||
String publicId;
|
||||
String url;
|
||||
String? publicId;
|
||||
String? url;
|
||||
|
||||
ImageModel({
|
||||
required this.publicId,
|
||||
required this.url,
|
||||
this.publicId,
|
||||
this.url,
|
||||
});
|
||||
|
||||
factory ImageModel.fromJson(Map<String, dynamic> json) => ImageModel(
|
||||
@ -132,14 +136,14 @@ class ImageModel {
|
||||
}
|
||||
|
||||
class Note {
|
||||
String message;
|
||||
DateTime replyDate;
|
||||
String id;
|
||||
String? message;
|
||||
DateTime? replyDate;
|
||||
String? id;
|
||||
|
||||
Note({
|
||||
required this.message,
|
||||
required this.replyDate,
|
||||
required this.id,
|
||||
this.message,
|
||||
this.replyDate,
|
||||
this.id,
|
||||
});
|
||||
|
||||
factory Note.fromJson(Map<String, dynamic> json) => Note(
|
||||
@ -150,7 +154,7 @@ class Note {
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"message": message,
|
||||
"replyDate": replyDate.toIso8601String(),
|
||||
// "replyDate": replyDate.toIso8601String(),
|
||||
"_id": id,
|
||||
};
|
||||
}
|
||||
|
@ -8,8 +8,10 @@ class PdRdProvider extends ChangeNotifier {
|
||||
bool _isLoading = false;
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
List<PdRdResponseModel> _pdRdList = [];
|
||||
List<PdRdResponseModel> get pdRdList => _pdRdList;
|
||||
List<PdRdResponseModel> _pdList = [];
|
||||
List<PdRdResponseModel> get pdList => _pdList;
|
||||
List<PdRdResponseModel> _rdList = [];
|
||||
List<PdRdResponseModel> get rdList => _rdList;
|
||||
|
||||
final _apiClient = ApiClient();
|
||||
|
||||
@ -18,16 +20,42 @@ class PdRdProvider extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getPdRd() async {
|
||||
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.getPdRdUrl);
|
||||
Response response = await _apiClient.get(ApiUrls.getPd);
|
||||
if (response.statusCode == 200) {
|
||||
// Assuming the response data is a list of PdRdResponseModel objects
|
||||
List<PdRdResponseModel> data = (response.data as List)
|
||||
.map((json) => PdRdResponseModel.fromJson(json))
|
||||
.toList();
|
||||
_pdRdList = data;
|
||||
_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}");
|
||||
}
|
||||
|
111
lib/provider/task_provider.dart
Normal file
111
lib/provider/task_provider.dart
Normal file
@ -0,0 +1,111 @@
|
||||
import 'package:cheminova/models/pd_rd_response_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 = [];
|
||||
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;
|
||||
|
||||
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();
|
||||
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(BuildContext context) async {
|
||||
setLoading(true);
|
||||
try {
|
||||
Response response = await _apiClient.post(
|
||||
ApiUrls.assignTask,
|
||||
data: {
|
||||
'taskAssignedTo': _selectedSalesCoordinator!.id,
|
||||
'task': _selectedTask,
|
||||
'taskPriority': _selectedPriority,
|
||||
'taskDueDate': _selectedDate,
|
||||
'note': _noteController.text,
|
||||
},
|
||||
);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -72,7 +72,7 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
widget.distributor.name,
|
||||
widget.distributor.name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.black,
|
||||
@ -222,7 +222,7 @@ class _AddProductsScreenState extends State<AddProductsScreen> {
|
||||
provider
|
||||
.submitSelectedProducts(
|
||||
"PrincipalDistributor",
|
||||
widget.distributor.id)
|
||||
widget.distributor.id!)
|
||||
.then((value) {
|
||||
if (value) {
|
||||
Navigator.push(
|
||||
@ -275,27 +275,25 @@ class _ProductBlockState extends State<ProductBlock> {
|
||||
setState(() {
|
||||
if (saleController.text.isNotEmpty &&
|
||||
inventoryController.text.isNotEmpty) {
|
||||
// Check if the input can be parsed as an integer
|
||||
if (int.tryParse(saleController.text) == null ||
|
||||
int.tryParse(inventoryController.text) == null) {
|
||||
errorMessage = 'Please enter valid integer value';
|
||||
} else {
|
||||
// Parse the input as integers
|
||||
// Check if both inputs are valid integers
|
||||
try {
|
||||
int sale = int.parse(saleController.text);
|
||||
int inventory = int.parse(inventoryController.text);
|
||||
|
||||
// Validate if inventory is less than or equal to sales
|
||||
// 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 = 'Please fill in both fields';
|
||||
errorMessage = null;
|
||||
}
|
||||
});
|
||||
|
||||
return errorMessage == null;
|
||||
}
|
||||
|
||||
|
@ -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,13 @@
|
||||
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 +17,45 @@ 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;
|
||||
|
||||
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.noteController.text.isEmpty) {
|
||||
_isNotesValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
// If all fields are valid, proceed to the next screen
|
||||
if (_isSalesCoordinatorValid && _isTaskValid && _isPriorityValid) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const ConfirmTaskScreen(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _selectDate(BuildContext context) async {
|
||||
final provider = context.read<TaskProvider>();
|
||||
final dateSelected = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
@ -25,14 +63,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,13 +108,15 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
),
|
||||
drawer: const CommonDrawer(),
|
||||
body: CommonBackground(
|
||||
child: SafeArea(
|
||||
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),
|
||||
padding: const EdgeInsets.all(20.0)
|
||||
.copyWith(top: 15, bottom: 30),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 30.0)
|
||||
.copyWith(bottom: 50),
|
||||
decoration: BoxDecoration(
|
||||
@ -84,37 +138,69 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
),
|
||||
),
|
||||
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),
|
||||
SearchField(
|
||||
suggestionsDecoration: SuggestionDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(8.0),
|
||||
bottomRight: Radius.circular(8),
|
||||
),
|
||||
child: const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Sales Coordinator: Name",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
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),
|
||||
),
|
||||
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),
|
||||
),
|
||||
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,
|
||||
),
|
||||
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),
|
||||
@ -137,12 +223,12 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
child: CheckboxListTile(
|
||||
value: _isChecked[0],
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: 'Visit Retailers',
|
||||
groupValue: taskProvider.selectedTask,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[0] = value!;
|
||||
});
|
||||
taskProvider.setSelectedTask(value);
|
||||
},
|
||||
title: const Text(
|
||||
"Visit Retailers",
|
||||
@ -151,12 +237,12 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
),
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: CheckboxListTile(
|
||||
value: _isChecked[1],
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: 'Update Sales Data',
|
||||
groupValue: taskProvider.selectedTask,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[1] = value!;
|
||||
});
|
||||
taskProvider.setSelectedTask(value);
|
||||
},
|
||||
title: const Text(
|
||||
"Update Sales Data",
|
||||
@ -165,32 +251,75 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
),
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: CheckboxListTile(
|
||||
value: _isChecked[2],
|
||||
child: RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: 'Update Liqudation Data',
|
||||
groupValue: taskProvider.selectedTask,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[2] = value!;
|
||||
});
|
||||
taskProvider.setSelectedTask(value);
|
||||
},
|
||||
title: const Text(
|
||||
"Update Liqudation Data",
|
||||
),
|
||||
),
|
||||
),
|
||||
CheckboxListTile(
|
||||
value: _isChecked[3],
|
||||
RadioListTile<String>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: 'Collect KYC',
|
||||
groupValue: taskProvider.selectedTask,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[3] = value!;
|
||||
});
|
||||
taskProvider.setSelectedTask(value);
|
||||
},
|
||||
title: const Text(
|
||||
"Collect KYC",
|
||||
),
|
||||
),
|
||||
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') ...{
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
)
|
||||
},
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
@ -213,41 +342,43 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _isChecked[4],
|
||||
Radio<String>(
|
||||
value: "Low",
|
||||
groupValue: taskProvider.selectedPriority,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[4] = value!;
|
||||
});
|
||||
taskProvider.setSelectedPriority(value!);
|
||||
},
|
||||
),
|
||||
const Text(
|
||||
"Low",
|
||||
),
|
||||
Checkbox(
|
||||
value: _isChecked[5],
|
||||
const Text("Low"),
|
||||
Radio<String>(
|
||||
value: "Medium",
|
||||
groupValue: taskProvider.selectedPriority,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[5] = value!;
|
||||
});
|
||||
taskProvider.setSelectedPriority(value!);
|
||||
},
|
||||
),
|
||||
const Text(
|
||||
"Medium",
|
||||
),
|
||||
Checkbox(
|
||||
value: _isChecked[6],
|
||||
const Text("Medium"),
|
||||
Radio<String>(
|
||||
value: "High",
|
||||
groupValue: taskProvider.selectedPriority,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_isChecked[6] = value!;
|
||||
});
|
||||
taskProvider.setSelectedPriority(value!);
|
||||
},
|
||||
),
|
||||
const Text(
|
||||
"High",
|
||||
),
|
||||
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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -274,7 +405,7 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
_dateSelected,
|
||||
taskProvider.selectedDate,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
@ -293,7 +424,7 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'CONFIRM',
|
||||
onPressed: () {},
|
||||
onPressed: _validateAndSubmit,
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -301,6 +432,15 @@ class _AssignTasksScreenState extends State<AssignTasksScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (taskProvider.isLoading)
|
||||
Container(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
204
lib/screens/confirm_task_screen.dart
Normal file
204
lib/screens/confirm_task_screen.dart
Normal file
@ -0,0 +1,204 @@
|
||||
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 {
|
||||
const ConfirmTaskScreen({super.key});
|
||||
|
||||
@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')
|
||||
_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),
|
||||
CommonElevatedButton(
|
||||
isLoading: taskProvider.isLoading,
|
||||
backgroundColor: const Color(0xff004791),
|
||||
borderRadius: 30,
|
||||
width: double.infinity,
|
||||
height: kToolbarHeight - 10,
|
||||
text: 'CONFIRM',
|
||||
onPressed: () => taskProvider.assignTask(context),
|
||||
),
|
||||
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,10 +14,13 @@ 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(
|
||||
@ -32,7 +35,11 @@ class DataSubmitSuccessfullState extends State<DataSubmitSuccessfull> {
|
||||
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 SizedBox(
|
||||
height: 20), // Add some space between the text and the image
|
||||
Image.asset(
|
||||
'assets/check_circle.png',
|
||||
)
|
||||
]))));
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
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,18 +105,7 @@ 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();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
margin: const EdgeInsets.all(8),
|
||||
@ -147,7 +143,6 @@ class _SelectSalesCoordinatorScreenState
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
254
lib/screens/task_management_screen.dart
Normal file
254
lib/screens/task_management_screen.dart
Normal file
@ -0,0 +1,254 @@
|
||||
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';
|
||||
|
||||
class TaskManagementScreen extends StatefulWidget {
|
||||
const TaskManagementScreen({super.key});
|
||||
|
||||
@override
|
||||
State<TaskManagementScreen> createState() => _TaskManagementScreenState();
|
||||
}
|
||||
|
||||
class _TaskManagementScreenState extends State<TaskManagementScreen> {
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
final List<String> _taskList = [
|
||||
'Task 1',
|
||||
'Task 2',
|
||||
'Task 3',
|
||||
'Task 4',
|
||||
'Task 5',
|
||||
'Task 6',
|
||||
'Task 7',
|
||||
'Task 8',
|
||||
'Task 9',
|
||||
'Task 10',
|
||||
];
|
||||
|
||||
final List<String> _filters = [
|
||||
'All',
|
||||
'Pending',
|
||||
'Completed',
|
||||
];
|
||||
|
||||
List<String> _filteredTaskList = [];
|
||||
|
||||
void _filterTaskList(String query) {
|
||||
setState(() {
|
||||
_filteredTaskList = _taskList
|
||||
.where((task) => task.toLowerCase().contains(query.toLowerCase()))
|
||||
.toList();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_filteredTaskList = _taskList;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
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: 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: 'All',
|
||||
icon: const Icon(Icons.all_inclusive),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
_filterChip(
|
||||
title: 'Pending',
|
||||
icon: const Icon(Icons.pending),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
_filterChip(
|
||||
title: 'Completed',
|
||||
icon: const Icon(Icons.done),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Text(
|
||||
'Tasks:',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.55,
|
||||
child: ListView.builder(
|
||||
itemCount: _filteredTaskList.length,
|
||||
itemBuilder: (context, index) => _taskView(
|
||||
title: _filteredTaskList[index],
|
||||
),
|
||||
),
|
||||
),
|
||||
// CommonElevatedButton(
|
||||
// backgroundColor: const Color(0xff004791),
|
||||
// borderRadius: 30,
|
||||
// width: double.infinity,
|
||||
// height: kToolbarHeight - 10,
|
||||
// text: 'EDIT',
|
||||
// onPressed: () => Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) => const AssignTasksScreen(),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 20),
|
||||
// CommonElevatedButton(
|
||||
// backgroundColor: const Color(0xff00784C),
|
||||
// borderRadius: 30,
|
||||
// width: double.infinity,
|
||||
// height: kToolbarHeight - 10,
|
||||
// text: 'REASSIGN',
|
||||
// onPressed: () => Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) =>
|
||||
// const SelectSalesCoordinatorScreen(),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 20),
|
||||
// CommonElevatedButton(
|
||||
// backgroundColor: const Color(0xff00784C),
|
||||
// borderRadius: 30,
|
||||
// width: double.infinity,
|
||||
// height: kToolbarHeight - 10,
|
||||
// text: 'MARK AS COMPLETED',
|
||||
// onPressed: () {},
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _taskView({required String title}) {
|
||||
return Column(
|
||||
children: [
|
||||
_customContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Sales Coordinator: 1',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
'Status: Pending',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
'Deadline: 12/12/2024',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _filterChip({required String title, required Widget icon}) {
|
||||
return Chip(
|
||||
avatar: icon,
|
||||
label: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Anek',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -23,10 +23,10 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
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();
|
||||
});
|
||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// final provider = Provider.of<PdRdProvider>(context, listen: false);
|
||||
// provider.getPdRd();
|
||||
// });
|
||||
}
|
||||
|
||||
@override
|
||||
@ -65,9 +65,12 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
text: 'SUBMIT',
|
||||
backgroundColor: const Color(0xff004791),
|
||||
onPressed: () {
|
||||
if(selectedDistributor == null || selectedDistributorType == null){
|
||||
if (selectedDistributor == null ||
|
||||
selectedDistributorType == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Please select distributor type and distributor')),
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
'Please select distributor type and distributor')),
|
||||
);
|
||||
} else {
|
||||
Navigator.push(
|
||||
@ -85,22 +88,6 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
),
|
||||
body: Consumer<PdRdProvider>(
|
||||
builder: (context, provider, child) {
|
||||
if (provider.isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (provider.pdRdList.isEmpty) {
|
||||
return const Center(child: Text('No distributors available.'));
|
||||
}
|
||||
|
||||
List<PdRdResponseModel> principalDistributors = provider.pdRdList
|
||||
.where((item) => item.userType == 'SalesCoOrdinator')
|
||||
.toList();
|
||||
|
||||
List<PdRdResponseModel> retailerDistributors = provider.pdRdList
|
||||
.where((item) => item.userType != 'SalesCoOrdinator')
|
||||
.toList();
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
@ -127,6 +114,9 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedDistributorType = value;
|
||||
selectedDistributorType == 'Principal Distributor'
|
||||
? provider.getPd()
|
||||
: provider.getRd();
|
||||
selectedDistributor =
|
||||
null; // Reset distributor selection when type changes
|
||||
});
|
||||
@ -148,12 +138,12 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
value: selectedDistributor,
|
||||
items: (selectedDistributorType ==
|
||||
'Principal Distributor'
|
||||
? principalDistributors
|
||||
: retailerDistributors)
|
||||
? provider.pdList
|
||||
: provider.rdList)
|
||||
.map((PdRdResponseModel distributor) {
|
||||
return DropdownMenuItem<PdRdResponseModel>(
|
||||
value: distributor,
|
||||
child: Text(distributor.name),
|
||||
child: Text(distributor.name!),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
@ -170,6 +160,13 @@ class _UpdateInventoryScreenState extends State<UpdateInventoryScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (provider.isLoading)
|
||||
Container(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
@ -12,7 +12,9 @@ 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 getPdRdUrl =
|
||||
'inventory/distributors-TM/RetailDistributor';
|
||||
static const String getPd = 'inventory/distributors-TM/RetailDistributor';
|
||||
static const String getRd = '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';
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -1040,6 +1040,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:
|
||||
|
@ -50,6 +50,7 @@ dependencies:
|
||||
flutter_local_notifications: ^17.2.1+2
|
||||
firebase_crashlytics: ^4.0.4
|
||||
firebase_analytics: ^11.2.1
|
||||
searchfield: ^1.0.9
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user