Commit b38d986d authored by Sai Srinivas's avatar Sai Srinivas
Browse files

23-07-2025 By Sai Srinivas

CRM Lead Details, Generate Quotation & Followup and Prospect List.
parent c0252747
......@@ -328,6 +328,7 @@ class LeadProducts {
String? productId;
String? qty;
String? price;
String? prodTotalPrice;
String? date;
String? isDel;
String? isExists;
......@@ -341,6 +342,7 @@ class LeadProducts {
this.productId,
this.qty,
this.price,
this.prodTotalPrice,
this.date,
this.isDel,
this.isExists,
......@@ -354,6 +356,7 @@ class LeadProducts {
productId = json['product_id'];
qty = json['qty'];
price = json['price'];
prodTotalPrice = json['prod_total_price'];
date = json['date'];
isDel = json['is_del'];
isExists = json['is_exists'];
......@@ -369,6 +372,7 @@ class LeadProducts {
data['product_id'] = this.productId;
data['qty'] = this.qty;
data['price'] = this.price;
data['prod_total_price'] = this.prodTotalPrice;
data['date'] = this.date;
data['is_del'] = this.isDel;
data['is_exists'] = this.isExists;
......
class crmAddFollowUpResponse {
String? redirectTo;
String? error;
String? message;
int? sessionExists;
crmAddFollowUpResponse(
{this.redirectTo, this.error, this.message, this.sessionExists});
crmAddFollowUpResponse.fromJson(Map<String, dynamic> json) {
redirectTo = json['redirect_to'];
error = json['error'];
message = json['message'];
sessionExists = json['session_exists'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['redirect_to'] = this.redirectTo;
data['error'] = this.error;
data['message'] = this.message;
data['session_exists'] = this.sessionExists;
return data;
}
}
class crmDashboardResponse {
Hotleads? hotleads;
Hotleads? pendingTasks;
Hotleads? coldleads;
Hotleads? warmleads;
Hotleads? totalleads;
Hotleads? openleads;
Hotleads? visits;
Hotleads? calls;
Hotleads? quote;
Hotleads? orderlost;
Hotleads? norequirement;
Hotleads? openEnquiries;
List<NearbyLeads>? nearbyLeads;
String? error;
String? message;
int? sessionExists;
crmDashboardResponse(
{this.hotleads,
this.pendingTasks,
this.coldleads,
this.warmleads,
this.totalleads,
this.openleads,
this.visits,
this.calls,
this.quote,
this.orderlost,
this.norequirement,
this.openEnquiries,
this.nearbyLeads,
this.error,
this.message});
this.message,
this.sessionExists});
crmDashboardResponse.fromJson(Map<String, dynamic> json) {
hotleads = json['hotleads'] != null
? new Hotleads.fromJson(json['hotleads'])
: null;
pendingTasks = json['pending_tasks'] != null
? new Hotleads.fromJson(json['pending_tasks'])
: null;
coldleads = json['coldleads'] != null
? new Hotleads.fromJson(json['coldleads'])
: null;
......@@ -33,6 +50,13 @@ class crmDashboardResponse {
totalleads = json['totalleads'] != null
? new Hotleads.fromJson(json['totalleads'])
: null;
openleads = json['openleads'] != null
? new Hotleads.fromJson(json['openleads'])
: null;
visits =
json['visits'] != null ? new Hotleads.fromJson(json['visits']) : null;
calls = json['calls'] != null ? new Hotleads.fromJson(json['calls']) : null;
quote = json['quote'] != null ? new Hotleads.fromJson(json['quote']) : null;
orderlost = json['orderlost'] != null
? new Hotleads.fromJson(json['orderlost'])
: null;
......@@ -42,8 +66,15 @@ class crmDashboardResponse {
openEnquiries = json['open_enquiries'] != null
? new Hotleads.fromJson(json['open_enquiries'])
: null;
if (json['nearby_leads'] != null) {
nearbyLeads = <NearbyLeads>[];
json['nearby_leads'].forEach((v) {
nearbyLeads!.add(new NearbyLeads.fromJson(v));
});
}
error = json['error'];
message = json['message'];
sessionExists = json['session_exists'];
}
Map<String, dynamic> toJson() {
......@@ -51,6 +82,9 @@ class crmDashboardResponse {
if (this.hotleads != null) {
data['hotleads'] = this.hotleads!.toJson();
}
if (this.pendingTasks != null) {
data['pending_tasks'] = this.pendingTasks!.toJson();
}
if (this.coldleads != null) {
data['coldleads'] = this.coldleads!.toJson();
}
......@@ -60,6 +94,18 @@ class crmDashboardResponse {
if (this.totalleads != null) {
data['totalleads'] = this.totalleads!.toJson();
}
if (this.openleads != null) {
data['openleads'] = this.openleads!.toJson();
}
if (this.visits != null) {
data['visits'] = this.visits!.toJson();
}
if (this.calls != null) {
data['calls'] = this.calls!.toJson();
}
if (this.quote != null) {
data['quote'] = this.quote!.toJson();
}
if (this.orderlost != null) {
data['orderlost'] = this.orderlost!.toJson();
}
......@@ -69,8 +115,12 @@ class crmDashboardResponse {
if (this.openEnquiries != null) {
data['open_enquiries'] = this.openEnquiries!.toJson();
}
if (this.nearbyLeads != null) {
data['nearby_leads'] = this.nearbyLeads!.map((v) => v.toJson()).toList();
}
data['error'] = this.error;
data['message'] = this.message;
data['session_exists'] = this.sessionExists;
return data;
}
}
......@@ -124,3 +174,116 @@ class Filter {
return data;
}
}
class NearbyLeads {
String? id;
String? ownerId;
String? accId;
String? accManagerId;
String? status;
String? openStatus;
String? date;
String? closeDate;
String? closereason;
String? competitor;
String? orderGainId;
String? loc;
String? isExists;
String? createdDatetime;
String? updatedDatetime;
String? followupFunction;
String? name;
String? product;
String? contName;
String? address;
String? mob1;
String? mob2;
String? tel;
String? email;
String? distance;
NearbyLeads(
{this.id,
this.ownerId,
this.accId,
this.accManagerId,
this.status,
this.openStatus,
this.date,
this.closeDate,
this.closereason,
this.competitor,
this.orderGainId,
this.loc,
this.isExists,
this.createdDatetime,
this.updatedDatetime,
this.followupFunction,
this.name,
this.product,
this.contName,
this.address,
this.mob1,
this.mob2,
this.tel,
this.email,
this.distance});
NearbyLeads.fromJson(Map<String, dynamic> json) {
id = json['id'];
ownerId = json['owner_id'];
accId = json['acc_id'];
accManagerId = json['acc_manager_id'];
status = json['status'];
openStatus = json['open_status'];
date = json['date'];
closeDate = json['close_date'];
closereason = json['closereason'];
competitor = json['competitor'];
orderGainId = json['order_gain_id'];
loc = json['loc'];
isExists = json['is_exists'];
createdDatetime = json['created_datetime'];
updatedDatetime = json['updated_datetime'];
followupFunction = json['followup_function'];
name = json['name'];
product = json['product'];
contName = json['cont_name'];
address = json['address'];
mob1 = json['mob1'];
mob2 = json['mob2'];
tel = json['tel'];
email = json['email'];
distance = json['distance'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['owner_id'] = this.ownerId;
data['acc_id'] = this.accId;
data['acc_manager_id'] = this.accManagerId;
data['status'] = this.status;
data['open_status'] = this.openStatus;
data['date'] = this.date;
data['close_date'] = this.closeDate;
data['closereason'] = this.closereason;
data['competitor'] = this.competitor;
data['order_gain_id'] = this.orderGainId;
data['loc'] = this.loc;
data['is_exists'] = this.isExists;
data['created_datetime'] = this.createdDatetime;
data['updated_datetime'] = this.updatedDatetime;
data['followup_function'] = this.followupFunction;
data['name'] = this.name;
data['product'] = this.product;
data['cont_name'] = this.contName;
data['address'] = this.address;
data['mob1'] = this.mob1;
data['mob2'] = this.mob2;
data['tel'] = this.tel;
data['email'] = this.email;
data['distance'] = this.distance;
return data;
}
}
......@@ -3,9 +3,10 @@ class crmLeadDetailsGenerateQuotationViewResponse {
List<LeadProducts>? leadProducts;
String? error;
String? message;
int? sessionExists;
crmLeadDetailsGenerateQuotationViewResponse(
{this.quoteDetails, this.leadProducts, this.error, this.message});
{this.quoteDetails, this.leadProducts, this.error, this.message,this.sessionExists});
crmLeadDetailsGenerateQuotationViewResponse.fromJson(
Map<String, dynamic> json) {
......@@ -20,6 +21,7 @@ class crmLeadDetailsGenerateQuotationViewResponse {
}
error = json['error'];
message = json['message'];
sessionExists = json['session_exists'];
}
Map<String, dynamic> toJson() {
......@@ -33,6 +35,7 @@ class crmLeadDetailsGenerateQuotationViewResponse {
}
data['error'] = this.error;
data['message'] = this.message;
data['session_exists'] = this.sessionExists;
return data;
}
}
......@@ -84,6 +87,7 @@ class LeadProducts {
String? productId;
String? qty;
String? price;
String? prodTotalPrice;
String? date;
String? isDel;
String? isExists;
......@@ -97,6 +101,7 @@ class LeadProducts {
this.productId,
this.qty,
this.price,
this.prodTotalPrice,
this.date,
this.isDel,
this.isExists,
......@@ -110,6 +115,7 @@ class LeadProducts {
productId = json['product_id'];
qty = json['qty'];
price = json['price'];
prodTotalPrice = json['prod_total_price'];
date = json['date'];
isDel = json['is_del'];
isExists = json['is_exists'];
......@@ -125,6 +131,7 @@ class LeadProducts {
data['product_id'] = this.productId;
data['qty'] = this.qty;
data['price'] = this.price;
data['prod_total_price'] = this.prodTotalPrice;
data['date'] = this.date;
data['is_del'] = this.isDel;
data['is_exists'] = this.isExists;
......
......@@ -3,6 +3,9 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:generp/Models/crmModels/crmDashboardResponse.dart';
import 'package:generp/Utils/app_colors.dart';
import 'package:geolocator/geolocator.dart';
import 'package:geolocator/geolocator.dart' as geo_location;
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
......@@ -13,37 +16,20 @@ import '../../services/api_calling.dart';
import '../HomeScreenNotifier.dart';
class Crmdashboardprovider extends ChangeNotifier {
TextEditingController nextAppointmentDateController = TextEditingController();
String _googleApikey = "AIzaSyBGzvgMMKwPBAANTwaoRsAnrCpiWCj8wVs";
TextEditingController searchController = TextEditingController();
List<PagesAccessible> _accessPages = [];
List<PagesAccessible> get accessPages => _accessPages;
List<PendingTasks> _pendingTasks = [];
List<PendingTasks> _pendingTasksList = [];
List<PendingTasks> get pendingTasksLists => _pendingTasks;
List<PendingTasks> get pendingTasksLists => _pendingTasksList;
List<Accounts> _accountsList = [];
List<Leads> _leadsList = [];
List<Enquires> _enquiresList = [];
TimeOfDay _selectedTime = TimeOfDay.now();
String _formattedTime = "";
String? _selectedFollowupType;
String? _selectedLeadStatus;
String? _nextAppointmentStatus;
String? _selectNextAppointmentType;
DateTime? _date;
String? _formattedDate;
String? _dateError;
TimeOfDay get selectedTime => _selectedTime;
String get formattedTime => _formattedTime;
String? get selectedFollowupType => _selectedFollowupType;
String? get selectedLeadStatus => _selectedLeadStatus;
String? get nextAppointmentStatus => _nextAppointmentStatus;
String? get selectNextAppointmentType => _selectNextAppointmentType;
LatLng? currentLocationLatLng;
String latlongs = "";
List<Accounts> get accountsList => _accountsList;
......@@ -51,24 +37,54 @@ class Crmdashboardprovider extends ChangeNotifier {
List<Enquires> get enquiresList => _enquiresList;
List<NearbyLeads> _nearByLeads = [];
List<NearbyLeads> get nearByLeads => _nearByLeads;
Hotleads _hotleads = Hotleads();
Hotleads get hotleads => _hotleads;
Hotleads _pendingTasks = Hotleads();
Hotleads get pendingTasks => _pendingTasks;
Hotleads _coldleads = Hotleads();
Hotleads get coldleads => _coldleads;
Hotleads _warmleads = Hotleads();
Hotleads get warmleads => _warmleads;
Hotleads _totalleads = Hotleads();
Hotleads get totalleads => _totalleads;
Hotleads _openleads = Hotleads();
Hotleads get openleads => _openleads;
Hotleads _visits = Hotleads();
Hotleads get visits => _visits;
Hotleads _calls = Hotleads();
Hotleads get calls => _calls;
Hotleads _quote = Hotleads();
Hotleads get quote => _quote;
Hotleads _orderlost = Hotleads();
Hotleads get orderlost => _orderlost;
Hotleads _norequirement = Hotleads();
Hotleads get norequirement => _norequirement;
Hotleads _openEnquiries = Hotleads();
Hotleads get openEnquiries => _openEnquiries;
......@@ -77,25 +93,7 @@ class Crmdashboardprovider extends ChangeNotifier {
List<Hotleads> get allLeads => _allLeads;
set selectedFollowupType(String? value){
_selectedFollowupType = value;
notifyListeners();
}
set selectedLeadStatus(String? value){
_selectedLeadStatus = value;
notifyListeners();
}
set nextAppointmentStatus(String? value){
_nextAppointmentStatus = value;
notifyListeners();
}
set selectNextAppointmentType(String? value){
_selectNextAppointmentType = value;
notifyListeners();
}
Future<void> accessPagesAPIFunction(context) async {
try {
......@@ -116,47 +114,82 @@ class Crmdashboardprovider extends ChangeNotifier {
} catch (e, s) {}
}
Future<void> crmDashboardAPIFunction(
context,
mode,
from,
to,
teamemployee,
) async {
Future<void> getCurrentLocation(context) async {
try {
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: geo_location.LocationAccuracy.high,
);
currentLocationLatLng = LatLng(position.latitude, position.longitude);
print("Current Loc: ${currentLocationLatLng}");
latlongs = '${position.latitude},${position.longitude}';
print("latlongs : ${latlongs}");
notifyListeners();
crmDashboardAPIFunction(context);
} catch (e) {
print("Error getting current location: $e");
}
}
Future<void> crmDashboardAPIFunction(context) async {
try {
var HomeProv = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.crmDashboardAPI(
HomeProv.empId,
HomeProv.session,
mode,
from,
to,
teamemployee,
latlongs,
);
if (data != null) {
if (data.error == "0") {
_hotleads = data.hotleads!;
_pendingTasks = data.pendingTasks!;
_coldleads = data.coldleads!;
_warmleads = data.warmleads!;
_totalleads = data.totalleads!;
_openleads = data.openleads!;
_visits = data.visits!;
_calls = data.calls!;
_quote = data.quote!;
_orderlost = data.orderlost!;
_norequirement = data.norequirement!;
_openEnquiries = data.openEnquiries!;
_allLeads = [
_openleads,
_quote,
_pendingTasks,
_visits,
_calls,
_hotleads,
_coldleads,
_warmleads,
_totalleads,
_orderlost,
_norequirement,
_openEnquiries,
];
_nearByLeads = data.nearbyLeads!;
notifyListeners();
}
}
} catch (e, s) {}
}
String getStaticMapUrl(double lat, double lng) {
const apiKey = 'YOUR_GOOGLE_MAPS_API_KEY';
const zoom = 15;
const size = '400x400';
return 'https://maps.googleapis.com/maps/api/staticmap?center=$lat,$lng&zoom=$zoom&size=$size&key=$_googleApikey';
}
String getSimpleOSMImage(double lat, double lng) {
final zoom = 15;
//https://maps.googleapis.com/maps/api/staticmap?center=15.4919328,80.0492584&zoom=15&size=400x400
return 'https://static-maps.yandex.ru/1.x/?ll=$lng,$lat&z=$zoom&size=400,400&l=map&pt=$lng,$lat,pm2rdm';
}
({double lat, double lng}) parseLocation(String loc) {
final parts = loc.split(',');
return (
lat: double.parse(parts[0].trim()),
lng: double.parse(parts[1].trim()),
);
}
Future<void> crmPendingTasksAPIFunction(context) async {
try {
var HomeProv = Provider.of<HomescreenNotifier>(context, listen: false);
......@@ -166,7 +199,7 @@ class Crmdashboardprovider extends ChangeNotifier {
);
if (data != null) {
if (data.error == "0") {
_pendingTasks = data.pendingTasks!;
_pendingTasksList = data.pendingTasks!;
notifyListeners();
}
}
......@@ -192,117 +225,4 @@ class Crmdashboardprovider extends ChangeNotifier {
} catch (e, s) {}
}
set formattedDate(String? value) {
_formattedDate = value;
nextAppointmentDateController.text = _formattedDate!;
_dateError = null;
notifyListeners();
}
set dateError(value){
_dateError = value;
notifyListeners();
}
void setDate(DateTime newDate) {
_date = newDate;
_formattedDate = DateFormat('yyyy-MM-dd').format(newDate);
nextAppointmentDateController.text = _formattedDate!;
_dateError = null;
notifyListeners();
}
Future<void> selectTime(BuildContext context) async {
final TimeOfDay? picked = await showTimePicker(
context: context,
initialTime: _selectedTime,
);
if (picked != null && picked != _selectedTime) _selectedTime = picked;
_formattedTime =
_selectedTime.hour.toString() + ":" + _selectedTime.minute.toString();
notifyListeners();
}
String formatTime(int hour, int minute) {
String period = (hour >= 12) ? 'pm' : 'am';
if (hour == 0) {
hour = 12;
} else if (hour > 12) {
hour -= 12;
}
String formattedHour = (hour < 10) ? '0$hour' : '$hour';
String formattedMinute = (minute < 10) ? '0$minute' : '$minute';
print("formattedTime: $formattedHour:$formattedMinute $period");
return '$formattedHour:$formattedMinute $period';
}
void showDatePickerDialog(BuildContext context) {
showCupertinoModalPopup<void>(
context: context,
builder:
(BuildContext context) => Container(
height: 216,
padding: const EdgeInsets.only(top: 6.0),
margin: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
color: CupertinoColors.systemBackground.resolveFrom(context),
child: SafeArea(
top: false,
child: Column(
children: [
Expanded(
flex: 1,
child: SizedBox(
height: 40,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CupertinoButton(
child: Text(
'Cancel',
style: TextStyle(fontFamily: "JakartaMedium",color: AppColors.app_blue),
),
onPressed: () {
Navigator.pop(context);
},
),
CupertinoButton(
child: Text(
'Done',
style: TextStyle(fontFamily: "JakartaMedium",color: AppColors.app_blue),
),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
),
Expanded(
flex: 3,
child: CupertinoDatePicker(
dateOrder: DatePickerDateOrder.dmy,
initialDateTime: _date ?? DateTime.now(),
mode: CupertinoDatePickerMode.date,
use24hFormat: true,
showDayOfWeek: true,
onDateTimeChanged: (DateTime newDate) {
setDate(newDate);
},
),
),
],
),
),
),
);
}
}
......@@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_download_manager/flutter_download_manager.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:generp/Models/crmModels/crmLeadDetailsGenerateQuotationViewResponse.dart';
import 'package:generp/screens/LoginScreen.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
......@@ -23,6 +24,10 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
final GlobalKey webViewKey = GlobalKey();
var dl = DownloadManager();
TextEditingController addEditProductPriceController = TextEditingController();
TextEditingController addEditQuantityController = TextEditingController();
TextEditingController addEditTotalAmountController = TextEditingController();
TextEditingController mailIdController = TextEditingController();
TextEditingController mobileController = TextEditingController();
TextEditingController subjectsController = TextEditingController();
......@@ -30,7 +35,14 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
TextEditingController SpecialNoteController = TextEditingController();
TextEditingController forController = TextEditingController();
TextEditingController paymentTermsController = TextEditingController();
List<Map<String, dynamic>> _productRows = []; // For backend
List<Map<String, dynamic>> get productRows => _productRows;
set productRows(value) {
_productRows = value;
notifyListeners();
}
String? mailIdError = "";
String? mobileError = "";
......@@ -45,6 +57,9 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
bool _isLoading = true;
String? _quotationFilePath;
LeadProducts? _selectedLeadProducts;
String? _selectedAddEditLeadProductId;
String? _selectedAddEditLeadProductName;
List<TextEditingController> editProductPriceControllers = [];
List<TextEditingController> editQuantityControllers = [];
List<TextEditingController> editTotalAmountControllers = [];
......@@ -58,21 +73,88 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
QuoteDetails get quoteDetails => _quoteDetails;
List<LeadProducts> get leadProductsList => _leadProductsList;
set leadProductsList(List<LeadProducts> value) {
_leadProductsList = value;
notifyListeners();
}
LeadProducts? get selectedLeadProducts => _selectedLeadProducts;
bool get isLoading => _isLoading;
List<String?> get selectedProductIds => _selectedProductIds;
String? get selectedAddEditLeadProductId => _selectedAddEditLeadProductId;
String? get selectedAddEditLeadProductName => _selectedAddEditLeadProductName;
List<String?> get selectedValues => _selectedValues;
bool get submitLoading => _submitLoading;
set selectedLeadProducts(LeadProducts? value) {
_selectedLeadProducts = value;
_selectedAddEditLeadProductId = value?.productId!;
_selectedAddEditLeadProductName = value?.productName;
notifyListeners();
}
set selectedAddEditLeadProductId(String? value) {
_selectedAddEditLeadProductId = value;
notifyListeners();
}
set selectedAddEditLeadProductName(String? value) {
_selectedAddEditLeadProductName = value;
notifyListeners();
}
set submitLoading(bool value) {
_submitLoading = value;
notifyListeners();
}
void addEditUpdateTotalAmount(value) {
final price = double.tryParse(addEditProductPriceController.text) ?? 0;
final qty = int.tryParse(addEditQuantityController.text) ?? 0;
addEditTotalAmountController.text = (price * qty).toString();
notifyListeners();
}
void editProduct(int index, LeadProducts updatedProduct) {
if (index >= 0 && index < leadProductsList.length) {
leadProductsList[index] = updatedProduct;
_productRows[index] = {
"product_id": updatedProduct.productId!,
"price": updatedProduct.price,
"qty": updatedProduct.qty,
"net_price": updatedProduct.prodTotalPrice,
};
notifyListeners();
}
}
void addEditInitializeForm(BuildContext context) {
addEditProductPriceController.clear();
addEditQuantityController.clear();
addEditTotalAmountController.clear();
selectedLeadProducts = null;
selectedAddEditLeadProductId = null;
selectedAddEditLeadProductName = null;
notifyListeners();
}
void preFillFormForEdit(LeadProducts product) {
selectedLeadProducts = product;
selectedAddEditLeadProductId = product.id;
selectedAddEditLeadProductName = product.productName;
addEditProductPriceController.text = product.price?.toString() ?? '';
addEditQuantityController.text = product.qty?.toString() ?? '';
addEditTotalAmountController.text =
product.prodTotalPrice?.toString() ?? '';
notifyListeners();
}
void initializeForm(BuildContext context) {
// Clear existing controllers
......@@ -155,7 +237,7 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
"product_id": _selectedProductIds[i]!,
"price": editProductPriceControllers[i].text,
"qty": editQuantityControllers[i].text,
"net_price":editTotalAmountControllers[i].text
"net_price": editTotalAmountControllers[i].text,
};
insertData.add(rowData);
}
......@@ -175,9 +257,11 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
leadID,
);
if (data != null) {
if (data.sessionExists == 1) {
if (data.error == "0") {
_isLoading = false;
_leadProductsList = data.leadProducts ?? [];
_quoteDetails =
data.quoteDetails ??
QuoteDetails(
......@@ -189,18 +273,38 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
paymentTerms: "",
subject: "",
);
mailIdController.text = data.quoteDetails!.email??"-";
mobileController.text = data.quoteDetails!.mobile??"-";
subjectsController.text = data.quoteDetails!.subject??"-";
mailIdController.text = data.quoteDetails!.email ?? "-";
mobileController.text = data.quoteDetails!.mobile ?? "-";
subjectsController.text = data.quoteDetails!.subject ?? "-";
// taxesController.text = data.quoteDetails!1;
// SpecialNoteController.text = data.quoteDetails;
forController.text = data.quoteDetails!.forText??"-";
paymentTermsController.text = data.quoteDetails!.paymentTerms??"-";
forController.text = data.quoteDetails!.forText ?? "-";
paymentTermsController.text =
data.quoteDetails!.paymentTerms ?? "-";
for (var product in data.leadProducts!) {
_productRows.add({
"product_id": product.productId!,
"price": product.price,
"qty": product.qty,
"net_price": product.prodTotalPrice,
});
}
print("_productRows : ${_productRows}");
notifyListeners();
} else {
_isLoading = false;
notifyListeners();
}
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginScreen(),
settings: RouteSettings(name: 'LoginScreen'),
),
);
}
} else {
_isLoading = false;
notifyListeners();
......@@ -235,16 +339,22 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
if (data != null) {
if (data.error == "0") {
_quotationFilePath = data.quoteFilepath!;
if(quotation_type=="genquotedown"){
if (quotation_type == "genquotedown") {
String suggestedFilename = getUniqueFilename('quotation', 'pdf');
String contentDisposition = 'attachment; filename="$suggestedFilename"';
String contentDisposition =
'attachment; filename="$suggestedFilename"';
// openWhatsApp(data.quoteFilepath!);
_handleDownload(context,data.quoteFilepath!,contentDisposition,'application/octet-stream','');
}
else if(quotation_type=="genquotewhatsappbymynum"){
_handleDownload(
context,
data.quoteFilepath!,
contentDisposition,
'application/octet-stream',
'',
);
} else if (quotation_type == "genquotewhatsappbymynum") {
openWhatsApp(data.quoteFilepath!);
}
Navigator.pop(context,true);
Navigator.pop(context, true);
toast(context, data.message);
resetForm();
notifyListeners();
......@@ -260,6 +370,7 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
final formattedDate = DateFormat('yyyyMMdd_HHmmss').format(now);
return '${baseName}_$formattedDate.$ext';
}
void openWhatsApp(String path) async {
final Uri url = Uri.parse(path); // Example: 919876543210
if (await canLaunchUrl(url)) {
......@@ -268,6 +379,7 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
throw 'Could not launch $url';
}
}
Future<void> _handleDownload(
context,
String url,
......@@ -277,7 +389,7 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
) async {
// Request notification permission for Android 13+
if (Platform.isIOS) {
_handleIOSDownload(context,url, suggestedFilename);
_handleIOSDownload(context, url, suggestedFilename);
} else if (Platform.isAndroid) {
if (await Permission.notification.request().isGranted) {
try {
......@@ -293,10 +405,12 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
'mimeType': mimeType,
'suggestedFilename': suggestedFilename,
});
await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
await launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication,
);
} else if (Platform.isIOS) {
_handleIOSDownload(context,url, suggestedFilename);
_handleIOSDownload(context, url, suggestedFilename);
}
} catch (e) {
print("Download Error $e");
......@@ -307,7 +421,11 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
}
}
Future<void> _handleIOSDownload(context,String url, String suggestedFilename) async {
Future<void> _handleIOSDownload(
context,
String url,
String suggestedFilename,
) async {
try {
// Show initial download notification
await _showDownloadNotification(0, suggestedFilename, isComplete: false);
......@@ -407,39 +525,66 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
);
}
onChangemailId(value){
onChangemailId(value) {
mailIdError = "";
notifyListeners();
}
onChangemobile(value){
onChangemobile(value) {
mobileError = "";
notifyListeners();
}
onChangesubjects(value){
onChangesubjects(value) {
subjectsError = "";
notifyListeners();
}
onChangetaxes(value){
onChangetaxes(value) {
taxesError = "";
notifyListeners();
}
onChangeSpecialNote(value){
onChangeSpecialNote(value) {
SpecialNoteError = "";
notifyListeners();
}
onChangefor(value){
onChangefor(value) {
forError = "";
notifyListeners();
}
onChangepaymentTerms(value){
onChangepaymentTerms(value) {
paymentTermsError = "";
notifyListeners();
}
void resetForm() {
checkDropdownReset();
_productRows.clear();
addEditProductPriceController.clear();
addEditQuantityController.clear();
addEditTotalAmountController.clear();
editProductPriceControllers.clear();
editQuantityControllers.clear();
editTotalAmountControllers.clear();
_selectedLeadProducts = null;
_selectedAddEditLeadProductId = null;
_selectedAddEditLeadProductName = null;
notifyListeners();
}
void checkDropdownReset() {
if (!_leadProductsList.contains(_selectedLeadProducts) &&
_selectedLeadProducts != null) {
_selectedAddEditLeadProductId = null;
_selectedAddEditLeadProductName = null;
}
notifyListeners();
}
resetForm(){
resetForm2() {
mailIdController.clear();
mobileController.clear();
subjectsController.clear();
......@@ -460,6 +605,5 @@ class Crmgeneratequotationprovider extends ChangeNotifier {
SpecialNoteError = "";
forError = "";
paymentTermsError = "";
}
}
......@@ -196,14 +196,12 @@ class crmNearbyOpenLeadsProvider extends ChangeNotifier {
List<Marker> markers = [];
// print("Hello Nutsby!");
ByteData data = await rootBundle.load("assets/images/dg_set.png");
ByteData data = await rootBundle.load("assets/images/leads_ic.png");
Uint8List bytes = data.buffer.asUint8List();
await Future.forEach(leadsList, (leads) async {
ui.Codec codec = await ui.instantiateImageCodec(
bytes,
targetWidth: 75,
targetHeight: 95,
);
ui.FrameInfo fi = await codec.getNextFrame();
Uint8List resizedBytes =
......@@ -214,9 +212,11 @@ class crmNearbyOpenLeadsProvider extends ChangeNotifier {
markers.add(
Marker(
markerId: MarkerId(leads.id.toString()),
position: _parseLatLng(leads.loc),
icon: BitmapDescriptor.fromBytes(resizedBytes),
infoWindow: InfoWindow(
onTap:() {
// onMarkerTap(context, leads.id);
Navigator.push(
......
......@@ -126,11 +126,17 @@ import 'package:generp/Notifiers/HomeScreenNotifier.dart';
import 'package:generp/services/api_calling.dart';
import 'package:provider/provider.dart';
import '../../Models/crmModels/crmLeadDetailsEditProductsViewResponse.dart';
import 'crmLeadDetailsProvider.dart';
class Editproductlistprovider extends ChangeNotifier {
TextEditingController addEditProductPriceController = TextEditingController();
TextEditingController addEditQuantityController = TextEditingController();
TextEditingController addEditTotalAmountController = TextEditingController();
List<Products> _productsList = [];
List<LeadProducts> _leadProductsList = [];
Products? _selectedProducts;
String? _selectedAddEditProductId;
String? _selectedAddEditProductName;
List<TextEditingController> editProductPriceControllers = [];
List<TextEditingController> editQuantityControllers = [];
List<TextEditingController> editTotalAmountControllers = [];
......@@ -139,14 +145,35 @@ class Editproductlistprovider extends ChangeNotifier {
bool _submitLoading = false;
List<Products> get productsList => _productsList;
List<LeadProducts> get leadProductsList => _leadProductsList;
Products? get selectedProducts => _selectedProducts;
String? get selectedAddEditProductId => _selectedAddEditProductId;
String? get selectedAddEditProductName => _selectedAddEditProductName;
List<String?> get selectedProductIds => _selectedProductIds;
List<String?> get selectedValues => _selectedValues;
bool get submitLoading => _submitLoading;
set selectedProducts(Products? value) {
_selectedProducts = value;
_selectedAddEditProductId = value!.id!;
_selectedAddEditProductName = value.name;
notifyListeners();
}
set selectedAddEditProductId(String? value) {
_selectedAddEditProductId = value;
notifyListeners();
}
set selectedAddEditProductName(String? value) {
_selectedAddEditProductName = value;
notifyListeners();
}
......@@ -165,10 +192,20 @@ class Editproductlistprovider extends ChangeNotifier {
// Initialize controllers for each lead product
for (var product in _leadProductsList) {
editProductPriceControllers.add(TextEditingController(text: product.price?.toString() ?? ''));
editQuantityControllers.add(TextEditingController(text: product.qty?.toString() ?? ''));
editTotalAmountControllers.add(TextEditingController(
text: (double.parse(product.price?.toString() ?? '0') * int.parse(product.qty?.toString() ?? '0')).toString()));
editProductPriceControllers.add(
TextEditingController(text: product.price?.toString() ?? ''),
);
editQuantityControllers.add(
TextEditingController(text: product.qty?.toString() ?? ''),
);
editTotalAmountControllers.add(
TextEditingController(
text:
(double.parse(product.price?.toString() ?? '0') *
int.parse(product.qty?.toString() ?? '0'))
.toString(),
),
);
_selectedProductIds.add(product.productId);
_selectedValues.add(product.productName);
}
......@@ -215,6 +252,13 @@ class Editproductlistprovider extends ChangeNotifier {
notifyListeners();
}
void addEditUpdateTotalAmount() {
final price = double.tryParse(addEditProductPriceController.text) ?? 0;
final qty = int.tryParse(addEditQuantityController.text) ?? 0;
addEditTotalAmountController.text = (price * qty).toString();
notifyListeners();
}
List<Map<String, String>> getFormData() {
final List<Map<String, String>> insertData = [];
for (int i = 0; i < editProductPriceControllers.length; i++) {
......@@ -230,10 +274,17 @@ class Editproductlistprovider extends ChangeNotifier {
return insertData;
}
Future<void> crmLeadDetailsEditProductsViewAPIFunction(BuildContext context, String leadID) async {
Future<void> crmLeadDetailsEditProductsViewAPIFunction(
BuildContext context,
String leadID,
) async {
try {
final prov = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.crmLeadDetailsEditProductsViewAPI(prov.empId, prov.session, leadID);
final data = await ApiCalling.crmLeadDetailsEditProductsViewAPI(
prov.empId,
prov.session,
leadID,
);
if (data != null && data.error == "0") {
_leadProductsList = data.leadProducts ?? [];
_productsList = data.products ?? [];
......@@ -244,13 +295,22 @@ class Editproductlistprovider extends ChangeNotifier {
}
}
Future<void> crmLeadDetailsEditProductsSubmitAPIFunction(BuildContext context,products, String leadID) async {
Future<void> crmLeadDetailsEditProductsSubmitAPIFunction(
BuildContext context,
products,
String leadID,
) async {
try {
final prov = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.crmLeadDetailsEditProductsSubmitAPI(prov.empId, prov.session,products, leadID);
final data = await ApiCalling.crmLeadDetailsEditProductsSubmitAPI(
prov.empId,
prov.session,
products,
leadID,
);
if (data != null && data.error == "0") {
resetForm();
Navigator.pop(context,true);
Navigator.pop(context, true);
notifyListeners();
}
} catch (e, s) {
......@@ -258,22 +318,78 @@ class Editproductlistprovider extends ChangeNotifier {
}
}
void submitForm(BuildContext context,leadID) async {
Future<void> crmLeadDetailsAddEditProductsSubmitAPIFunction(
BuildContext context,
mode,
String leadID,
type,
leadProductId,
productId,
) async {
try {
_submitLoading = true;
notifyListeners();
final prov = Provider.of<HomescreenNotifier>(context, listen: false);
final prov2 = Provider.of<crmLeadDetailsProvider>(context, listen: false);
final data = await ApiCalling.crmLeadDetailsAddEditProductsAPI(
prov.empId,
prov.session,
leadID,
type,
leadProductId,
productId,
addEditQuantityController.text,
addEditTotalAmountController.text,
);
if (data != null && data.error == "0") {
_submitLoading = false;
resetForm();
Navigator.pop(context, true);
prov2.crmLeadDetailsAPIFunction(context, leadID, mode);
notifyListeners();
}else{
_submitLoading = false;
notifyListeners();
}
} catch (e, s) {
_submitLoading = false;
notifyListeners();
print("Error: $e, Stack: $s");
}
}
void submitForm(BuildContext context, leadID) async {
submitLoading = true;
final insertedData = getFormData();
print("Form Data: $insertedData");
crmLeadDetailsEditProductsSubmitAPIFunction(context,insertedData,leadID);
crmLeadDetailsEditProductsSubmitAPIFunction(context, insertedData, leadID);
submitLoading = false;
}
void resetForm() {
checkDropdownReset();
addEditProductPriceController.clear();
addEditQuantityController.clear();
addEditTotalAmountController.clear();
editProductPriceControllers.clear();
editQuantityControllers.clear();
editTotalAmountControllers.clear();
_selectedProductIds.clear();
_selectedProducts = null;
_selectedAddEditProductId = null;
_selectedAddEditProductName = null;
_selectedValues.clear();
_leadProductsList.clear();
notifyListeners();
}
void checkDropdownReset(){
if(!_productsList.contains(_selectedProducts)&&_selectedProducts!=null){
_selectedAddEditProductId = null;
_selectedAddEditProductName = null;
}
notifyListeners();
}
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:generp/Notifiers/HomeScreenNotifier.dart';
import 'package:generp/Utils/app_colors.dart';
import 'package:geolocator/geolocator.dart';
import 'package:geolocator/geolocator.dart' as geo_location;
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import '../../services/api_calling.dart';
import 'crmLeadDetailsProvider.dart';
class followUpUpdateProvider extends ChangeNotifier {
bool _submitLoading = false;
TextEditingController nextAppointmentDateController = TextEditingController();
TextEditingController followUpFeedbackController = TextEditingController();
TextEditingController noteController = TextEditingController();
TextEditingController reasonController = TextEditingController();
TimeOfDay _selectedTime = TimeOfDay.now();
String _formattedTime = "";
String? _selectedFollowupType;
String? _selectedLeadStatus;
String? _nextAppointmentStatus;
String? _selectNextAppointmentType;
String? _selectOrderStatus;
String? _selectedCompetitor;
LatLng? currentLocationLatLng;
String? latlongs;
DateTime? _date;
String? _formattedDate;
String? _dateError;
bool get submitLoading => _submitLoading;
TimeOfDay get selectedTime => _selectedTime;
String get formattedTime => _formattedTime;
String? get selectedFollowupType => _selectedFollowupType;
String? get selectedLeadStatus => _selectedLeadStatus;
String? get nextAppointmentStatus => _nextAppointmentStatus;
String? get selectNextAppointmentType => _selectNextAppointmentType;
String? get selectOrderStatus => _selectOrderStatus;
String? get selectedCompetitor => _selectedCompetitor;
set submitLoading(bool value){
_submitLoading = value;
notifyListeners();
}
set selectedFollowupType(String? value) {
_selectedFollowupType = value;
notifyListeners();
}
set selectedLeadStatus(String? value) {
_selectedLeadStatus = value;
notifyListeners();
}
set nextAppointmentStatus(String? value) {
_nextAppointmentStatus = value;
notifyListeners();
}
set selectNextAppointmentType(String? value) {
_selectNextAppointmentType = value;
notifyListeners();
}
set selectOrderStatus(String? value) {
_selectOrderStatus = value;
notifyListeners();
}
set selectedCompetitor(String? value) {
_selectedCompetitor = value;
notifyListeners();
}
bool _checked = false;
var _smsSent = "0";
bool get checked => _checked;
get smsSent => _smsSent;
set smsSent(value) {
_smsSent = value;
notifyListeners();
}
set checked(value) {
_checked = value;
notifyListeners();
}
set formattedDate(String? value) {
_formattedDate = value;
nextAppointmentDateController.text = _formattedDate!;
_dateError = null;
notifyListeners();
}
set dateError(value) {
_dateError = value;
notifyListeners();
}
Future<void> getCurrentLocation(context) async {
try {
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: geo_location.LocationAccuracy.high,
);
currentLocationLatLng = LatLng(position.latitude, position.longitude);
print("Current Loc: ${currentLocationLatLng}");
latlongs = '${position.latitude},${position.longitude}';
print("latlongs : ${latlongs}");
notifyListeners();
} catch (e) {
print("Error getting current location: $e");
}
}
Future<void> crmAddFollowUpAPIFunction(
BuildContext context,
nextAppointmentStatus,
orderStatus,
leadID,
followupType,
competitor,
leadStatus,
appointmentType,
sms,
[mode]
) async {
try {
_submitLoading = true;
notifyListeners();
final prov = Provider.of<HomescreenNotifier>(context, listen: false);
final prov2 = Provider.of<crmLeadDetailsProvider>(context, listen: false);
final data = await ApiCalling.crmLeadDetailsAddFollowUpAPI(
prov.session,
prov.empId,
nextAppointmentStatus,
orderStatus,
leadID,
followUpFeedbackController.text,
followupType,
_selectedTime.hour.toString() + ":" + _selectedTime.minute.toString(),
latlongs,
competitor,
reasonController.text,
leadStatus,
nextAppointmentDateController.text,
appointmentType,
sms,
noteController.text,
);
if (data != null && data.error == "0") {
_submitLoading = false;
resetForm();
Navigator.pop(context);
if(mode.isNotEmpty){
prov2.crmLeadDetailsAPIFunction(context, leadID, mode);
}
notifyListeners();
} else {
_submitLoading = false;
notifyListeners();
}
} catch (e, s) {
_submitLoading = false;
notifyListeners();
print("Error: $e, Stack: $s");
}
}
void setDate(DateTime newDate) {
_date = newDate;
_formattedDate = DateFormat('yyyy-MM-dd').format(newDate);
nextAppointmentDateController.text = _formattedDate!;
_dateError = null;
notifyListeners();
}
Future<void> selectTime(BuildContext context) async {
final TimeOfDay? picked = await showTimePicker(
context: context,
initialTime: _selectedTime,
);
if (picked != null && picked != _selectedTime) _selectedTime = picked;
_formattedTime =
_selectedTime.hour.toString() + ":" + _selectedTime.minute.toString();
notifyListeners();
}
String formatTime(int hour, int minute) {
String period = (hour >= 12) ? 'pm' : 'am';
if (hour == 0) {
hour = 12;
} else if (hour > 12) {
hour -= 12;
}
String formattedHour = (hour < 10) ? '0$hour' : '$hour';
String formattedMinute = (minute < 10) ? '0$minute' : '$minute';
print("formattedTime: $formattedHour:$formattedMinute $period");
return '$formattedHour:$formattedMinute $period';
}
void showDatePickerDialog(BuildContext context) {
showCupertinoModalPopup<void>(
context: context,
builder:
(BuildContext context) => Container(
height: 216,
padding: const EdgeInsets.only(top: 6.0),
margin: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
color: CupertinoColors.systemBackground.resolveFrom(context),
child: SafeArea(
top: false,
child: Column(
children: [
Expanded(
flex: 1,
child: SizedBox(
height: 40,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CupertinoButton(
child: Text(
'Cancel',
style: TextStyle(
fontFamily: "JakartaMedium",
color: AppColors.app_blue,
),
),
onPressed: () {
Navigator.pop(context);
},
),
CupertinoButton(
child: Text(
'Done',
style: TextStyle(
fontFamily: "JakartaMedium",
color: AppColors.app_blue,
),
),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
),
Expanded(
flex: 3,
child: CupertinoDatePicker(
dateOrder: DatePickerDateOrder.dmy,
initialDateTime: _date ?? DateTime.now(),
mode: CupertinoDatePickerMode.date,
use24hFormat: true,
showDayOfWeek: true,
onDateTimeChanged: (DateTime newDate) {
setDate(newDate);
},
),
),
],
),
),
),
);
}
onFollowUpChanged(value) {}
onNoteChanged(value) {}
onReasonChanged(value) {}
void resetForm(){
nextAppointmentDateController.clear();
followUpFeedbackController.clear();
noteController.clear();
reasonController.clear();
_selectedFollowupType = null;
_selectedLeadStatus = null;
_nextAppointmentStatus = null;
_selectNextAppointmentType = null;
_selectOrderStatus = null;
_selectedCompetitor = null;
notifyListeners();
}
}
......@@ -414,7 +414,7 @@ class Requestionlistprovider extends ChangeNotifier {
_accounts = data.accounts ?? [];
if (mode != "self") {
_accounts = [
Accounts(id: "", name: "Select"),
Accounts(id: "", name: "Select Account"),
...data.accounts ?? [],
];
}
......
......@@ -220,6 +220,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => Addprospectleadsprovider()),
ChangeNotifierProvider(create: (_) => Editorderprovider()),
ChangeNotifierProvider(create: (_) => Dispatchorderprovider()),
ChangeNotifierProvider(create: (_) => followUpUpdateProvider()),
],
child: Builder(
builder: (BuildContext context) {
......
......@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:generp/Notifiers/crmProvider/crmLeadDetailsProvider.dart';
import 'package:generp/Notifiers/crmProvider/editProductListProvider.dart';
import 'package:generp/Utils/commonServices.dart';
import 'package:generp/Utils/dropdownTheme.dart';
import 'package:generp/screens/crm/AppointmentDetails.dart';
......@@ -18,6 +19,7 @@ import 'package:generp/screens/crm/followUpUpdateScreen.dart';
import 'package:generp/screens/crm/productDetails.dart';
import 'package:provider/provider.dart';
import '../../Models/crmModels/crmLeadDetailsEditProductsViewResponse.dart';
import '../../Utils/app_colors.dart';
import '../../Utils/commonWidgets.dart';
import '../finance/FileViewer.dart';
......@@ -97,8 +99,8 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
}
Widget _scaffold(BuildContext context) {
return Consumer<crmLeadDetailsProvider>(
builder: (context, provider, child) {
return Consumer2<crmLeadDetailsProvider, Editproductlistprovider>(
builder: (context, provider, editProvider, child) {
var leadDetails = provider.leadDetails;
var headings1 = ["Account Manager Name", "Account Created By"];
......@@ -124,7 +126,7 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
var headings4 = ["Lead Status", "Last Followup Date", "Lead Age"];
var subHeadings4 = [
provider.leadDetails!.status ?? "-",
provider.followupDetails.first!.fdate ?? "-",
provider.leadDetails!.date ?? "-",
"${provider.leadDetails!.lage ?? "-"} days",
];
// var totalHeadings = [];
......@@ -638,6 +640,7 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
child: Column(
children: [
///product details
if(provider.leadProducts.isNotEmpty)...[
Container(
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
child: Row(
......@@ -654,6 +657,12 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
),
),
Expanded(
child: InkResponse(
onTap: () async {
editProvider.resetForm();
await editProvider.crmLeadDetailsEditProductsViewAPIFunction(context, provider.leadDetails.id!);
_showAddEditProductsSheet(context,widget.mode, "add", "");
},
child: Text(
textAlign: TextAlign.right,
"+ Add Product",
......@@ -664,12 +673,13 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
),
),
),
),
],
),
),
SizedBox(
width: double.infinity,
height: 125,
height: 130,
child: ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
......@@ -679,18 +689,28 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
itemBuilder: (context, lp) {
return InkResponse(
onTap: () async {
var res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) => EditProductsList(
leadID: provider.leadDetails.id ?? "",
),
),
// var res = await Navigator.push(
// context,
// MaterialPageRoute(
// builder:
// (context) => EditProductsList(
// leadID: provider.leadDetails.id ?? "",
// ),
// ),
// );
await editProvider.crmLeadDetailsEditProductsViewAPIFunction(context, provider.leadDetails.id!);
editProvider.addEditProductPriceController.text = provider.leadProducts[lp].price!;
editProvider.addEditQuantityController.text = provider.leadProducts[lp].qty!;
editProvider.addEditTotalAmountController.text = provider.leadProducts[lp].prodTotalPrice!;
editProvider.selectedProducts = editProvider.productsList.firstWhere(
(product) => product.id == provider.leadProducts[lp].productId
);
editProvider.selectedAddEditProductId = provider.leadProducts[lp].productId!;
editProvider.selectedAddEditProductName = provider.leadProducts[lp].productName!;
_showAddEditProductsSheet(context,widget.mode, "edit", provider.leadProducts[lp].id);
},
child: Container(
height: 125,
height: 130,
width: MediaQuery.of(context).size.width * 0.95,
decoration: BoxDecoration(
color: Colors.white,
......@@ -698,7 +718,12 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
),
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
vertical: 8,
),
margin: EdgeInsets.symmetric(
horizontal: 5,
// vertical: 10,
),
child: Row(
......@@ -730,6 +755,8 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
.leadProducts[lp]
.productName ??
"-",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontFamily: "JakartaMedium",
fontSize: 14,
......@@ -759,7 +786,7 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
color: AppColors.grey_semi,
),
),
SizedBox(height: 10),
SizedBox(height: 5),
DottedLine(
dashGapLength: 4,
dashGapColor: Colors.white,
......@@ -767,9 +794,9 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
dashLength: 2,
lineThickness: 0.5,
),
SizedBox(height: 10),
SizedBox(height: 5),
Text(
"₹${provider.leadProducts[lp].price ?? " - "}",
"₹${provider.leadProducts[lp].prodTotalPrice ?? " - "}",
style: TextStyle(
fontFamily: "JakartaMedium",
fontSize: 14,
......@@ -787,8 +814,10 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
},
),
),
],
///contact details
if(provider.contactDetails.isNotEmpty)...[
Container(
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
child: Row(
......@@ -831,12 +860,18 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
itemBuilder: (context, lp) {
return InkResponse(
onTap: () async {
provider.editNameController.text = provider.contactDetails[lp].name??"";
provider.editDesignationController.text = provider.contactDetails[lp].designation??"";
provider.editMobileNumberController.text = provider.contactDetails[lp].mob1??"";
provider.editAlternativeMobileController.text = provider.contactDetails[lp].mob2??"";
provider.editTelephoneController.text = provider.contactDetails[lp].tel??"";
provider.editEmailController.text = provider.contactDetails[lp].email??"";
provider.editNameController.text =
provider.contactDetails[lp].name ?? "";
provider.editDesignationController.text =
provider.contactDetails[lp].designation ?? "";
provider.editMobileNumberController.text =
provider.contactDetails[lp].mob1 ?? "";
provider.editAlternativeMobileController.text =
provider.contactDetails[lp].mob2 ?? "";
provider.editTelephoneController.text =
provider.contactDetails[lp].tel ?? "";
provider.editEmailController.text =
provider.contactDetails[lp].email ?? "";
_showEditContactSheet(context, lp);
},
child: Container(
......@@ -915,8 +950,10 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
);
},
),
],
///Followup details
if (provider.followupDetails.isNotEmpty) ...[
Container(
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
child: Row(
......@@ -938,7 +975,10 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
var res = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Followupupdatescreen(),
builder: (context) => Followupupdatescreen(
leadID: provider.leadDetails.id,
mode: widget.mode,
),
settings: RouteSettings(
name: 'Followupupdatescreen',
),
......@@ -966,7 +1006,10 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
padding: EdgeInsets.symmetric(
vertical: 10,
horizontal: 10,
),
itemCount: provider.followupDetails.length,
itemBuilder: (context, lp) {
return Container(
......@@ -1023,7 +1066,8 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
"JakartaMedium",
fontSize: 14,
color:
AppColors.semi_black,
AppColors
.semi_black,
),
),
Text(
......@@ -1047,7 +1091,9 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(8),
BorderRadius.circular(
8,
),
color: Color(0xFFF3FFD5),
),
padding: EdgeInsets.symmetric(
......@@ -1056,13 +1102,16 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
),
child: Center(
child: Text(
textAlign: TextAlign.right,
textAlign:
TextAlign.right,
"${provider.followupDetails[lp].fstatus ?? "-"}",
style: TextStyle(
fontFamily:
"JakartaMedium",
fontSize: 14,
color: Color(0xFF586000),
color: Color(
0xFF586000,
),
),
),
),
......@@ -1112,7 +1161,8 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
return Container(
padding: EdgeInsets.symmetric(vertical: 3),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
......@@ -1185,7 +1235,9 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
Expanded(
child: Text(
textAlign: TextAlign.right,
provider.followupDetails[lp].ffeedback ==
provider
.followupDetails[lp]
.ffeedback ==
""
? "-"
: provider
......@@ -1208,8 +1260,10 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
},
),
),
],
///Appointment details
if(provider.appointmentDetails.isNotEmpty)...[
Container(
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
child: Row(
......@@ -1467,8 +1521,10 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
},
),
),
],
///Quotation details
if(provider.quotationsDetails.isNotEmpty)...[
Container(
padding: EdgeInsets.only(left: 10, right: 10, top: 10),
child: Row(
......@@ -1698,7 +1754,7 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
},
),
),
],
SizedBox(height: 75),
],
),
......@@ -1742,7 +1798,7 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
Align(
alignment: Alignment.topLeft,
child: Text(
"Add Contact",
"Add Appointment",
style: TextStyle(
color: AppColors.app_blue,
fontSize: 16,
......@@ -1885,12 +1941,6 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
child: Container(
alignment: Alignment.center,
height: 45,
margin: EdgeInsets.only(
left: 5.0,
right: 5.0,
top: 5.0,
bottom: 5.0,
),
decoration: BoxDecoration(
color: AppColors.app_blue, //1487C9
borderRadius: BorderRadius.circular(14.0),
......@@ -2382,4 +2432,253 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
},
);
}
Future<void> _showAddEditProductsSheet(
BuildContext context,
mode,
type,
leadProductId,
) {
return showModalBottomSheet(
useSafeArea: true,
isDismissible: true,
isScrollControlled: true,
showDragHandle: true,
backgroundColor: Colors.white,
enableDrag: true,
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return SafeArea(
child: Consumer2<crmLeadDetailsProvider, Editproductlistprovider>(
builder: (context, provider, editProvider, child) {
final price =
double.tryParse(
editProvider.addEditProductPriceController.text,
) ??
0;
final qty =
int.tryParse(
editProvider.addEditQuantityController.text,
) ??
0;
editProvider.addEditTotalAmountController.text =
(price * qty).toString();
return Container(
margin: EdgeInsets.only(
bottom: 15,
left: 15,
right: 15,
top: 10,
),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
type == "add" ? "Add Product" : "Edit Product",
style: TextStyle(
fontSize: 14,
color: AppColors.app_blue,
fontFamily: "JakartaMedium",
),
),
SizedBox(height: 10,),
TextWidget(context, "Product"),
DropdownButtonHideUnderline(
child: Row(
children: [
Expanded(
child: DropdownButton2<Products>(
isExpanded: true,
hint: const Text(
'Select Product',
style: TextStyle(fontSize: 14),
overflow: TextOverflow.ellipsis,
),
items:
editProvider.productsList
.map(
(
ord,
) => DropdownMenuItem<Products>(
value: ord,
child: Text(
"(Product Name: ${ord.name})",
style: const TextStyle(
fontSize: 14,
),
overflow:
TextOverflow.ellipsis,
),
),
)
.toList(),
// value: editProvider.selectedAddEditProductId != null
// ? editProvider.productsList.firstWhere(
// (ord) => ord.id == editProvider.selectedProductIds,
// orElse: () => editProvider.productsList[0],
// )
// : null,
value: editProvider.selectedProducts,
onChanged: (Products? value) {
if (value != null) {
editProvider.selectedProducts = value;
editProvider.selectedAddEditProductId =
value.id;
editProvider
.selectedAddEditProductName =
value.name;
// editProvider.updateSelectedProductIds(j, value);
// editProvider.selectedProductIds[j] =
// value.id?.toString() ?? '';
// editProvider.updateTotalAmount(j);
}
},
buttonStyleData: ddtheme.buttonStyleData,
iconStyleData: ddtheme.iconStyleData,
menuItemStyleData:
ddtheme.menuItemStyleData,
dropdownStyleData:
ddtheme.dropdownStyleData,
),
),
],
),
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
flex: 2,
child: textControllerWidget(
context,
editProvider.addEditProductPriceController,
"Product Price",
"Enter Product Price",
(value) =>
editProvider.addEditUpdateTotalAmount,
TextInputType.number,
false,
null,
),
),
],
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
flex: 2,
child: textControllerWidget(
context,
editProvider.addEditQuantityController,
"Quantity",
"Enter Quantity",
(value) =>
editProvider.addEditUpdateTotalAmount,
TextInputType.number,
false,
FilteringTextInputFormatter.digitsOnly,
),
),
],
),
errorWidget(
context,
"Note: Submit Quantity as Zero (0) to delete Product",
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
flex: 2,
child: textControllerWidget(
context,
editProvider.addEditTotalAmountController,
"Amount",
"Total Amount",
(_) {},
TextInputType.number,
true,
FilteringTextInputFormatter.digitsOnly,
),
),
],
),
// IconButton(
// icon: const Icon(Icons.delete),
// onPressed: editProvider.editProductPriceControllers.length > 1
// ? () => editProvider.editRemoveRow(j)
// : null,
// ),
InkResponse(
onTap:
editProvider.submitLoading
? null
: () {
editProvider
.crmLeadDetailsAddEditProductsSubmitAPIFunction(
context,
mode,
provider.leadDetails.id!,
type,
leadProductId,
editProvider
.selectedAddEditProductId,
);
},
child: Container(
height: 45,
alignment: Alignment.center,
margin: const EdgeInsets.symmetric(
horizontal: 0,
vertical: 15,
),
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
decoration: BoxDecoration(
color: AppColors.app_blue,
borderRadius: BorderRadius.circular(15),
),
child:
editProvider.submitLoading
? CircularProgressIndicator.adaptive(
valueColor:
AlwaysStoppedAnimation<Color>(
AppColors.white,
),
)
: const Text(
"Submit",
style: TextStyle(
fontSize: 15,
fontFamily: "JakartaMedium",
color: Colors.white,
),
),
),
),
],
),
),
);
},
),
);
},
);
},
).whenComplete(() {
Provider.of<crmLeadDetailsProvider>(context).crmLeadDetailsAPIFunction(context, widget.leadId, widget.mode);
Provider.of<Editproductlistprovider>(context).resetForm();
},);
}
}
......@@ -18,7 +18,9 @@ import '../../Notifiers/crmProvider/crmNearbyOpenLeadsProvider.dart';
import '../../Utils/dropdownTheme.dart';
class NearbyOpenLeads extends StatefulWidget {
const NearbyOpenLeads({super.key});
final latitude;
final longitude;
const NearbyOpenLeads({super.key, this.latitude, this.longitude});
@override
State<NearbyOpenLeads> createState() => _NearbyOpenLeadsState();
......@@ -121,6 +123,7 @@ class _NearbyOpenLeadsState extends State<NearbyOpenLeads> {
zoomGesturesEnabled: true,
zoomControlsEnabled: true,
gestureRecognizers: {
Factory<OneSequenceGestureRecognizer>(
() => EagerGestureRecognizer(),
),
......@@ -132,7 +135,9 @@ class _NearbyOpenLeadsState extends State<NearbyOpenLeads> {
), // Prioritize pinch-to-zoom
},
initialCameraPosition: CameraPosition(
target: provider.startLocation,
target: widget.latitude!=null||widget.longitude!=null?
LatLng(widget.latitude,widget.longitude):
provider.startLocation,
zoom: 14.0,
),
markers: provider.markers.toSet(),
......
......@@ -198,7 +198,7 @@ class _ProspectListByModeState extends State<ProspectListByMode> {
),
),
Text(
crmLists[index].accman??"-",
crmLists[index].mob1??"-",
maxLines: 1,
style: TextStyle(
fontFamily: "JakartaMedium",
......
......@@ -5,7 +5,6 @@ import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:generp/Models/crmModels/crmPendingTasksResponse.dart';
import 'package:generp/screens/crm/pendingTasksDetails.dart';
import 'package:generp/screens/crm/pendingTasksList.dart';
import 'package:generp/screens/crm/universalSearchScreen.dart';
......@@ -38,8 +37,9 @@ class _CrmdashboardScreenState extends State<CrmdashboardScreen> {
});
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
var prov = Provider.of<Crmdashboardprovider>(context, listen: false);
prov.getCurrentLocation(context);
prov.accessPagesAPIFunction(context);
prov.crmDashboardAPIFunction(context, "executive", "", "", "");
// prov.crmDashboardAPIFunction(context);
prov.crmPendingTasksAPIFunction(context);
});
}
......@@ -208,7 +208,7 @@ class _CrmdashboardScreenState extends State<CrmdashboardScreen> {
'Pending Tasks',
'Today Visits',
'Today Calls',
'Hot Leads'
'Hot Leads',
'Cold Leads',
'Warm Leads',
// 'Total Leads',
......@@ -322,6 +322,8 @@ class _CrmdashboardScreenState extends State<CrmdashboardScreen> {
},
),
),
]else...[
SizedBox(height: 10,),
],
// ListView.builder(
......@@ -435,6 +437,7 @@ class _CrmdashboardScreenState extends State<CrmdashboardScreen> {
// );
// },
// ),
Container(
height: MediaQuery.of(context).size.height * 0.2,
margin: EdgeInsets.symmetric(horizontal: 10),
......@@ -638,6 +641,207 @@ class _CrmdashboardScreenState extends State<CrmdashboardScreen> {
),
),
if (provider.nearByLeads.isNotEmpty) ...[
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.only(left: 15, top: 10, right: 15),
child: Row(
children: [
Text(
"NearBy Leads",
style: TextStyle(
fontSize: 16,
color: AppColors.grey_semi,
),
),
Spacer(),
InkResponse(
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NearbyOpenLeads(),
settings: RouteSettings(
name: "NearbyOpenLeads",
),
),
);
},
child: SizedBox(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"View All",
style: TextStyle(
fontFamily: "JakartaMedium",
fontSize: 14,
color: AppColors.app_blue,
),
),
SizedBox(width: 5),
SvgPicture.asset(
"assets/svg/next_button.svg",
),
],
),
),
),
],
),
),
),
SizedBox(
width: double.infinity,
height: 150,
child: ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(
vertical: 10,
horizontal: 10,
),
itemCount: provider.nearByLeads.length,
itemBuilder: (context, index) {
final lead = provider.nearByLeads[index];
final location = provider.parseLocation(lead.loc!);
final latitude = location.lat;
final longitude = location.lng;
return InkResponse(
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NearbyOpenLeads(
latitude:latitude,
longitude:longitude
),
settings: RouteSettings(
name: "NearbyOpenLeads",
),
),
);
},
child: Container(
alignment: Alignment.center,
height: 150,
width: MediaQuery.of(context).size.width * 0.8,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14),
),
margin: EdgeInsets.symmetric(
horizontal: 5,
vertical: 5,
),
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 15,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment:CrossAxisAlignment.start,
children: [
Text(
provider.nearByLeads[index].name ?? "-",
maxLines: 1,
style: TextStyle(
fontSize: 14,
color: AppColors.semi_black,
fontFamily: "JakartaMedium"
),
),
Text(
provider.nearByLeads[index].product ??
"-",
maxLines: 2,
style: TextStyle(
fontSize: 14,
color: AppColors.grey_semi,
fontFamily: "JakartaMedium"
),
),
],
),
),
SizedBox(width: 10,),
Expanded(
child: ClipRRect(
borderRadius:BorderRadius.circular(16),
child: Image.network(
provider.getSimpleOSMImage(latitude, longitude),
width: 400,
height: 400,
fit: BoxFit.cover,
),
),
),
],
),
),
);
},
),
),
]else...[
SizedBox(height: 10,),
InkResponse(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NearbyOpenLeads(),
),
);
},
child: Container(
height: 60,
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: Row(
children: [
Expanded(
flex: 1,
child: Container(
height: 35,
width: 35,
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Color(0xFFEDF8FF),
shape: BoxShape.circle,
),
child: SvgPicture.asset(
"assets/svg/find_generator.svg",
),
),
),
Expanded(
flex: 4,
child: Text(
"Find Nearby Generators",
style: TextStyle(
fontSize: 14,
color: AppColors.app_blue,
),
),
),
],
),
),
),
],
if (provider.pendingTasksLists.length > 0) ...[
Align(
alignment: Alignment.centerLeft,
......@@ -720,7 +924,9 @@ class _CrmdashboardScreenState extends State<CrmdashboardScreen> {
builder:
(context) =>
Pendingtasksdetails(detailIndex: index),
settings: RouteSettings(name: 'Pendingtasksdetails')
settings: RouteSettings(
name: 'Pendingtasksdetails',
),
),
);
},
......
......@@ -4,7 +4,7 @@ import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:generp/Notifiers/crmProvider/crmDashboardProvider.dart';
import 'package:generp/Notifiers/crmProvider/followUpUpdateProvider.dart';
import 'package:generp/Utils/app_colors.dart';
import 'package:generp/Utils/commonServices.dart';
import 'package:generp/Utils/commonWidgets.dart';
......@@ -12,7 +12,9 @@ import 'package:generp/Utils/dropdownTheme.dart';
import 'package:provider/provider.dart';
class Followupupdatescreen extends StatefulWidget {
const Followupupdatescreen({super.key});
final leadID;
final mode;
const Followupupdatescreen({super.key,required this.leadID, this.mode});
@override
State<Followupupdatescreen> createState() => _FollowupupdatescreenState();
......@@ -22,12 +24,7 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
Dropdowntheme ddtheme = Dropdowntheme();
Map _source = {ConnectivityResult.mobile: true};
final MyConnectivity _connectivity = MyConnectivity.instance;
TextEditingController followUpFeedbackController = TextEditingController();
TextEditingController noteController = TextEditingController();
onFollowUpChanged(value) {}
onNoteChanged(value) {}
@override
void initState() {
......@@ -36,7 +33,10 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
_connectivity.myStream.listen((event) {
setState(() => _source = event);
});
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {});
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final provider = Provider.of<followUpUpdateProvider>(context);
provider.getCurrentLocation(context);
});
}
@override
......@@ -74,7 +74,7 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
}
Widget _scaffold(BuildContext context) {
return Consumer<Crmdashboardprovider>(
return Consumer<followUpUpdateProvider>(
builder: (context, provider, child) {
return Scaffold(
resizeToAvoidBottomInset: true,
......@@ -185,9 +185,10 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
],
),
items:
<String>['Active', 'Inactive', 'Suspense']
<String>['Phone', 'Visit']
.map(
(value) => DropdownMenuItem<String>(
(value) =>
DropdownMenuItem<String>(
value: value,
child: Text(
value ?? '',
......@@ -216,10 +217,10 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
),
textControllerWidget(
context,
followUpFeedbackController,
provider.followUpFeedbackController,
"Feedback",
"Write Feedback",
onFollowUpChanged,
provider.onFollowUpChanged,
TextInputType.text,
false,
null,
......@@ -244,15 +245,10 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
],
),
items:
<String>[
'Cold',
'Hot',
'Warm',
'Open',
'Closed',
]
<String>['Cold', 'Hot', 'Warm']
.map(
(value) => DropdownMenuItem<String>(
(value) =>
DropdownMenuItem<String>(
value: value,
child: Text(
value ?? '',
......@@ -303,14 +299,12 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
),
items:
<String>[
'Cold',
'Hot',
'Warm',
'Open',
'Closed',
'Next Appointment',
'Update Order Status',
]
.map(
(value) => DropdownMenuItem<String>(
(value) =>
DropdownMenuItem<String>(
value: value,
child: Text(
value ?? '',
......@@ -341,12 +335,17 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
),
),
SizedBox(height: 15),
if (provider.nextAppointmentStatus ==
"Update Order Status") ...[
Container(
padding: EdgeInsets.only(left: 10),
alignment: Alignment.topLeft,
child: Text(
"Next Appointment",
style: TextStyle(color: AppColors.grey_thick, fontSize: 16),
"Update Order Status",
style: TextStyle(
color: AppColors.grey_thick,
fontSize: 16,
),
),
),
Container(
......@@ -356,6 +355,177 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
TextWidget(context, "Select Status"),
DropdownButtonHideUnderline(
child: Row(
children: [
Expanded(
child: DropdownButton2<String>(
isExpanded: true,
hint: const Row(
children: [
Expanded(
child: Text(
'Select Status',
style: TextStyle(fontSize: 14),
overflow: TextOverflow.ellipsis,
),
),
],
),
items:
<String>[
'Order Gain',
'Order Lost',
'No Requirement',
]
.map(
(value) =>
DropdownMenuItem<String>(
value: value,
child: Text(
value ?? '',
style: const TextStyle(
fontSize: 14,
),
overflow: TextOverflow.ellipsis,
),
),
)
.toList(),
value: provider.selectOrderStatus,
onChanged: (String? newValue) {
setState(() {
provider.selectOrderStatus = newValue!;
});
},
buttonStyleData: ddtheme.buttonStyleData,
iconStyleData: ddtheme.iconStyleData,
menuItemStyleData: ddtheme.menuItemStyleData,
dropdownStyleData: ddtheme.dropdownStyleData,
),
),
],
),
),
if (provider.selectOrderStatus == "Order Gain")
...[]
else
...[
if (provider.selectOrderStatus == "Order Lost") ...[
TextWidget(context, "Select Competitor"),
DropdownButtonHideUnderline(
child: Row(
children: [
Expanded(
child: DropdownButton2<String>(
isExpanded: true,
hint: const Row(
children: [
Expanded(
child: Text(
'Select Competitor',
style: TextStyle(fontSize: 14),
overflow: TextOverflow.ellipsis,
),
),
],
),
items:
<String>[
"Mahindra",
"Kirloskar",
"Cummins",
"Ashok Leyland",
"Escorts",
"Eicher",
"Eicher Volovo",
"Ecogen",
"Crompton Greaves",
"Caterpillar",
]
.map(
(value) =>
DropdownMenuItem<String>(
value: value,
child: Text(
value ?? '',
style: const TextStyle(
fontSize: 14,
),
overflow:
TextOverflow
.ellipsis,
),
),
)
.toList(),
value: provider.selectedCompetitor,
onChanged: (String? newValue) {
setState(() {
provider.selectedCompetitor =
newValue!;
});
},
buttonStyleData: ddtheme
.buttonStyleData,
iconStyleData: ddtheme.iconStyleData,
menuItemStyleData:
ddtheme.menuItemStyleData,
dropdownStyleData:
ddtheme.dropdownStyleData,
),
),
],
),
),
] else
if (provider.selectOrderStatus ==
"No Requirement")
...[],
textControllerWidget(
context,
provider.reasonController,
"Reason",
"Reason (Description)",
provider.onReasonChanged,
TextInputType.text,
false,
null,
),
],
],
),
),
] else
...[
Container(
padding: EdgeInsets.only(left: 10),
alignment: Alignment.topLeft,
child: Text(
"Next Appointment",
style: TextStyle(
color: AppColors.grey_thick,
fontSize: 16,
),
),
),
GestureDetector(
onTap: () {
provider.showDatePickerDialog(context);
},
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
padding: EdgeInsets.symmetric(
horizontal: 10, vertical: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
......@@ -369,9 +539,15 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
borderRadius: BorderRadius.circular(14),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10, 0),
padding: const EdgeInsets.fromLTRB(
10.0,
0.0,
10,
0,
),
child: TextFormField(
controller: provider.nextAppointmentDateController,
controller:
provider.nextAppointmentDateController,
keyboardType: TextInputType.text,
enabled: false,
maxLines: 1,
......@@ -411,9 +587,10 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
],
),
items:
<String>['Active', 'Inactive', 'Suspense']
<String>['Phone', 'Visit']
.map(
(value) => DropdownMenuItem<String>(
(value) =>
DropdownMenuItem<String>(
value: value,
child: Text(
value ?? '',
......@@ -434,19 +611,48 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
},
buttonStyleData: ddtheme.buttonStyleData,
iconStyleData: ddtheme.iconStyleData,
menuItemStyleData: ddtheme.menuItemStyleData,
dropdownStyleData: ddtheme.dropdownStyleData,
menuItemStyleData: ddtheme
.menuItemStyleData,
dropdownStyleData: ddtheme
.dropdownStyleData,
),
),
],
),
),
if (provider.selectNextAppointmentType ==
"Visit") ...[
CheckboxListTile(
checkboxShape: CircleBorder(),
controlAffinity: ListTileControlAffinity.leading,
value: provider.checked,
contentPadding: EdgeInsets.symmetric(
horizontal: 0),
title: Text(
"Send SMS reminder to Customer",
style: TextStyle(
fontSize: 14,
fontFamily: "JakartaRegular",
),
),
onChanged: (value) {
provider.checked = !provider.checked;
if (value == true) {
provider.smsSent = "1";
} else {
provider.smsSent = "0";
}
print(provider.smsSent +
provider.checked.toString());
},
),
],
textControllerWidget(
context,
noteController,
provider.noteController,
"Note",
"Write Note",
onNoteChanged,
provider.onNoteChanged,
TextInputType.text,
false,
null,
......@@ -454,7 +660,8 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
],
),
),
),
],
SizedBox(height: 150),
],
),
......@@ -462,7 +669,20 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
floatingActionButton: InkResponse(
onTap: () {},
onTap:provider.submitLoading?null: () {
provider.submitLoading = true;
provider.crmAddFollowUpAPIFunction(
context,
provider.nextAppointmentStatus,
provider.selectOrderStatus,
widget.leadID,
provider.selectedFollowupType,
provider.selectedCompetitor,
provider.selectedLeadStatus,
provider.selectNextAppointmentType,
provider.smsSent,
widget.mode);
},
child: Container(
height: 45,
alignment: Alignment.center,
......@@ -472,7 +692,9 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
color: AppColors.app_blue,
borderRadius: BorderRadius.circular(15),
),
child: Text(
child:provider.submitLoading?CircularProgressIndicator.adaptive(
valueColor: AlwaysStoppedAnimation(AppColors.white),
): Text(
"Submit",
style: TextStyle(
fontSize: 15,
......
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../../Models/crmModels/crmLeadDetailsGenerateQuotationViewResponse.dart';
import '../../Notifiers/crmProvider/crmGenerateQuotationProvider.dart';
import '../../Notifiers/crmProvider/crmLeadDetailsProvider.dart';
import '../../Utils/app_colors.dart';
import '../../Utils/commonServices.dart';
import '../../Utils/commonWidgets.dart';
import '../../Utils/dropdownTheme.dart';
class Generatequotationaddeditproduct extends StatefulWidget {
final leadId;
final type;
final product;
final index;
const Generatequotationaddeditproduct({
super.key,
required this.leadId,
this.type,
this.product,
this.index,
});
@override
State<Generatequotationaddeditproduct> createState() =>
_GeneratequotationaddeditproductState();
}
class _GeneratequotationaddeditproductState
extends State<Generatequotationaddeditproduct> {
Map _source = {ConnectivityResult.mobile: true};
final MyConnectivity _connectivity = MyConnectivity.instance;
Dropdowntheme ddtheme = Dropdowntheme();
@override
void initState() {
// TODO: implement initState
super.initState();
_connectivity.initialise();
_connectivity.myStream.listen((source) {
setState(() => _source = source);
});
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final provider = Provider.of<Crmgeneratequotationprovider>(
context,
listen: false,
);
provider.crmLeadDetailsGenerateQuoteViewAPIFunction(
context,
widget.leadId,
);
// provider.resetForm();
if (widget.type == "add") {
// Initialize controllers and dropdowns after API call
provider.addEditInitializeForm(context);
} else {
provider.preFillFormForEdit(widget.product);
}
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_connectivity.disposeStream();
}
@override
Widget build(BuildContext context) {
switch (_source.keys.toList()[0]) {
case ConnectivityResult.mobile:
connection = 'Online';
break;
case ConnectivityResult.wifi:
connection = 'Online';
break;
case ConnectivityResult.none:
default:
connection = 'Offline';
}
return (connection == "Online")
? Platform.isAndroid
? WillPopScope(
onWillPop: () => onBackPressed(context),
child: SafeArea(
top: false,
bottom: true,
child: _scaffold(context),
),
)
: _scaffold(context)
: NoNetwork(context);
}
Widget _scaffold(BuildContext context) {
return Consumer<Crmgeneratequotationprovider>(
builder: (context, provider, child) {
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: appbarNew(context, "Generate Quotation", 0xFFFFFFFF),
backgroundColor: AppColors.scaffold_bg_color,
body: SingleChildScrollView(
child: Column(
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
margin: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextWidget(context, "Product"),
DropdownButtonHideUnderline(
child: Row(
children: [
Expanded(
child: DropdownButton2<LeadProducts>(
isExpanded: true,
hint: const Text(
'Select Product',
style: TextStyle(fontSize: 14),
overflow: TextOverflow.ellipsis,
),
items:
provider.leadProductsList
.map(
(
ord,
) => DropdownMenuItem<LeadProducts>(
value: ord,
child: Text(
"(Product Name: ${ord.productName})",
style: const TextStyle(
fontSize: 14,
),
overflow: TextOverflow.ellipsis,
),
),
)
.toList(),
// provider.selectedOrderIds[index] != null?
// provider
// .orderList
// .firstWhere(
// (product) =>
// product
// .orderId ==
// provider
// .selectedOrderIds[index],
// )
value:
provider.selectedLeadProducts != null
? provider.leadProductsList.firstWhere(
(element) =>
element.id ==
provider
.selectedAddEditLeadProductId,
)
: null,
onChanged: (LeadProducts? value) {
if (value != null) {
provider.selectedLeadProducts = value;
provider.selectedAddEditLeadProductId =
value!.productId!;
provider.selectedAddEditLeadProductName =
value.productName;
}
},
buttonStyleData: ddtheme.buttonStyleData,
iconStyleData: ddtheme.iconStyleData,
menuItemStyleData: ddtheme.menuItemStyleData,
dropdownStyleData: ddtheme.dropdownStyleData,
),
),
],
),
),
const SizedBox(height: 10),
textControllerWidget(
context,
provider.addEditProductPriceController,
"Product Price",
"Enter Product Price",
provider.addEditUpdateTotalAmount,
TextInputType.number,
false,
FilteringTextInputFormatter.digitsOnly,
),
const SizedBox(height: 10),
textControllerWidget(
context,
provider.addEditQuantityController,
"Quantity",
"Enter Quantity",
provider.addEditUpdateTotalAmount,
TextInputType.number,
false,
FilteringTextInputFormatter.digitsOnly,
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
flex: 2,
child: textControllerWidget(
context,
provider.addEditTotalAmountController,
"Amount",
"Total Amount",
(_) {},
TextInputType.number,
true,
FilteringTextInputFormatter.digitsOnly,
),
),
],
),
// IconButton(
// icon: const Icon(Icons.delete),
// onPressed: provider.editProductPriceControllers.length > 1
// ? () => provider.editRemoveRow(j)
// : null,
// ),
],
),
),
],
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
floatingActionButton: InkWell(
onTap: () {
if (provider.selectedLeadProducts != null) {
var newProduct;
if (widget.type == "add") {
newProduct = LeadProducts(
id: provider.selectedAddEditLeadProductId,
productName: provider.selectedAddEditLeadProductName,
price: provider.addEditProductPriceController.text,
qty: provider.addEditQuantityController.text,
prodTotalPrice: provider.addEditTotalAmountController.text,
);
provider.leadProductsList.add(newProduct);
provider.productRows.add({
"product_id": provider.selectedAddEditLeadProductId!,
"price": provider.addEditProductPriceController.text,
"qty": provider.addEditQuantityController.text,
"net_price": provider.addEditTotalAmountController.text,
});
Navigator.pop(context, newProduct);
} else {
final updatedProduct = LeadProducts(
id: provider.selectedAddEditLeadProductId,
productName: provider.selectedAddEditLeadProductName,
price: provider.addEditProductPriceController.text,
qty: provider.addEditQuantityController.text,
prodTotalPrice: provider.addEditTotalAmountController.text,
);
provider.editProduct(widget.index!, updatedProduct);
Navigator.pop(context, updatedProduct);
}
// if (widget.index != null) {
// // Editing existing product
// provider.editProduct(widget.index!, newProduct);
// } else {
// // Adding new product
// provider.addProduct(newProduct);
// }
}
},
child: Container(
alignment: Alignment.center,
height: 45,
decoration: BoxDecoration(
color: AppColors.app_blue, //1487C9
borderRadius: BorderRadius.circular(14.0),
),
margin: EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
"Submit",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
),
),
);
},
);
}
}
import 'dart:io';
import 'package:dotted_line/dotted_line.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:generp/Utils/dropdownTheme.dart';
import 'package:generp/screens/crm/generateQuotationAddEditProduct.dart';
import 'package:provider/provider.dart';
import '../../Models/crmModels/crmLeadDetailsGenerateQuotationViewResponse.dart';
......@@ -39,7 +41,7 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
);
// Initialize controllers and dropdowns after API call
provider.initializeForm(context);
provider.addEditInitializeForm(context);
});
}
......@@ -49,27 +51,40 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
builder: (context, provider, child) {
return WillPopScope(
onWillPop: () async {
// provider.resetForm();
provider.resetForm();
return true;
},
child: SafeArea(
top: false,
bottom: Platform.isIOS?false:true,
bottom: Platform.isIOS ? false : true,
child: Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: AppColors.scaffold_bg_color,
appBar: appbar2(
appBar: appbar2New(
context,
"Generate Quotation",
provider.resetForm,
const SizedBox(width: 0),
0xFFFFFFFF,
),
body: Container(
decoration: BoxDecoration(color: AppColors.white),
padding: const EdgeInsets.symmetric(horizontal: 10),
child: SingleChildScrollView(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
margin: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
children: [
textControllerWidget(
context,
......@@ -106,10 +121,49 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
null,
),
errorWidget(context, provider.subjectsError),
],
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
margin: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
children: [
InkResponse(
onTap: () {
provider.editAddNewRow();
onTap: () async {
var res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(context) =>
Generatequotationaddeditproduct(
leadId: widget.leadId,
type: "add",
),
settings: RouteSettings(
name: 'Generatequotationaddeditproduct',
),
),
);
if (res != null) {
print("result ${res}");
// provider
// .crmLeadDetailsGenerateQuoteViewAPIFunction(
// context,
// widget.leadId,
// );
}
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 10),
......@@ -134,163 +188,377 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
),
),
),
if (provider.leadProductsList.isNotEmpty ||
provider.editProductPriceControllers.isNotEmpty) ...[
ListView.builder(
itemCount: provider.editProductPriceControllers.length,
physics: const NeverScrollableScrollPhysics(),
if (provider.leadProductsList.isNotEmpty) ...[
SizedBox(
width: double.infinity,
height: 125,
child: ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, j) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
margin: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: 0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextWidget(context, "Product"),
DropdownButtonHideUnderline(
child: Row(
children: [
Expanded(
child: DropdownButton2<LeadProducts>(
isExpanded: true,
hint: const Text(
'Select Product',
style: TextStyle(fontSize: 14),
overflow: TextOverflow.ellipsis,
),
items:
provider.leadProductsList
.map(
(ord) => DropdownMenuItem<
LeadProducts
>(
value: ord,
child: Text(
"(Product Name: ${ord.productName})",
style: const TextStyle(
fontSize: 14,
itemCount: provider.leadProductsList.length,
itemBuilder: (context, lp) {
return InkResponse(
onTap: () async {
var res = await Navigator.push(
context,
MaterialPageRoute(
builder:
(
context,
) => Generatequotationaddeditproduct(
leadId: widget.leadId,
type: "edit",
product:
provider
.leadProductsList[lp]!,
index: lp,
),
overflow:
TextOverflow
.ellipsis,
settings: RouteSettings(
name:
'Generatequotationaddeditproduct',
),
),
)
.toList(),
value:
provider.selectedProductIds[j] !=
null
? provider.leadProductsList
.firstWhere(
(ord) =>
ord.id ==
provider
.selectedProductIds[j],
orElse:
() =>
provider
.leadProductsList[0],
)
: null,
onChanged: (LeadProducts? value) {
if (value != null) {
provider.updateSelectedProductIds(
j,
value,
);
provider.selectedProductIds[j] =
value.id?.toString() ?? '';
provider.updateTotalAmount(j);
if (res != null) {
print("result ${res}");
}
},
buttonStyleData:
ddtheme.buttonStyleData,
iconStyleData: ddtheme.iconStyleData,
menuItemStyleData:
ddtheme.menuItemStyleData,
dropdownStyleData:
ddtheme.dropdownStyleData,
child: Container(
height: 115,
width:
MediaQuery.of(context).size.width *
0.8,
decoration: BoxDecoration(
color: Color(0xFFE6F6FF),
borderRadius: BorderRadius.circular(14),
),
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
),
],
margin: EdgeInsets.symmetric(
horizontal: 5,
// vertical: 10,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: SvgPicture.asset(
"assets/svg/crm/product_details_ic.svg",
),
),
const SizedBox(height: 10),
SizedBox(width: 10),
Expanded(
flex: 6,
child: SizedBox(
child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Row(
children: [
Expanded(
flex: 2,
child: textControllerWidget(
context,
provider.editProductPriceControllers[j],
"Product Price",
"Enter Product Price",
(value) =>
provider.updateTotalAmount(j),
TextInputType.number,
false,
FilteringTextInputFormatter.digitsOnly,
flex: 4,
child: Text(
provider
.leadProductsList[lp]
.productName ??
"-",
maxLines: 1,
overflow:
TextOverflow
.ellipsis,
style: TextStyle(
fontFamily:
"JakartaMedium",
fontSize: 14,
color:
AppColors
.semi_black,
),
),
],
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
flex: 2,
child: textControllerWidget(
context,
provider.editQuantityControllers[j],
"Quantity",
"Enter Quantity",
(value) =>
provider.updateTotalAmount(j),
TextInputType.number,
false,
FilteringTextInputFormatter.digitsOnly,
child: Text(
textAlign:
TextAlign.right,
"₹${provider.leadProductsList[lp].price ?? "-"}",
style: TextStyle(
fontFamily:
"JakartaMedium",
fontSize: 14,
color:
AppColors
.semi_black,
),
),
),
],
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
flex: 2,
child: textControllerWidget(
context,
provider.editTotalAmountControllers[j],
"Amount",
"Total Amount",
(_) {},
TextInputType.number,
true,
FilteringTextInputFormatter.digitsOnly,
Text(
"x ${provider.leadProductsList[lp].qty ?? "-"}",
style: TextStyle(
fontFamily:
"JakartaMedium",
fontSize: 14,
color:
AppColors.grey_semi,
),
),
SizedBox(height: 5),
DottedLine(
dashGapLength: 4,
dashGapColor: Colors.white,
dashColor:
AppColors.grey_semi,
dashLength: 2,
lineThickness: 0.5,
),
SizedBox(height: 5),
Text(
"₹${provider.leadProductsList[lp].prodTotalPrice ?? " - "}",
style: TextStyle(
fontFamily:
"JakartaMedium",
fontSize: 14,
color:
AppColors.semi_black,
),
),
],
),
// IconButton(
// icon: const Icon(Icons.delete),
// onPressed: provider.editProductPriceControllers.length > 1
// ? () => provider.editRemoveRow(j)
// : null,
// ),
),
),
],
),
),
);
},
),
),
],
// if (provider.leadProductsList.isNotEmpty ||
// provider
// .editProductPriceControllers
// .isNotEmpty) ...[
// ListView.builder(
// itemCount:
// provider.editProductPriceControllers.length,
// physics: const NeverScrollableScrollPhysics(),
// shrinkWrap: true,
// itemBuilder: (context, j) {
// return Container(
// padding: const EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 10,
// ),
// margin: const EdgeInsets.symmetric(
// vertical: 10,
// ),
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(20),
// ),
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// TextWidget(context, "Product"),
// DropdownButtonHideUnderline(
// child: Row(
// children: [
// Expanded(
// child: DropdownButton2<
// LeadProducts
// >(
// isExpanded: true,
// hint: const Text(
// 'Select Product',
// style: TextStyle(
// fontSize: 14,
// ),
// overflow:
// TextOverflow.ellipsis,
// ),
// items:
// provider.leadProductsList
// .map(
// (
// ord,
// ) => DropdownMenuItem<
// LeadProducts
// >(
// value: ord,
// child: Text(
// "(Product Name: ${ord.productName})",
// style:
// const TextStyle(
// fontSize:
// 14,
// ),
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// )
// .toList(),
// value:
// provider.selectedProductIds[j] !=
// null
// ? provider
// .leadProductsList
// .firstWhere(
// (ord) =>
// ord.id ==
// provider
// .selectedProductIds[j],
// orElse:
// () =>
// provider
// .leadProductsList[0],
// )
// : null,
// onChanged: (
// LeadProducts? value,
// ) {
// if (value != null) {
// provider
// .updateSelectedProductIds(
// j,
// value,
// );
// provider.selectedProductIds[j] =
// value.id?.toString() ??
// '';
// provider.updateTotalAmount(
// j,
// );
// }
// },
// buttonStyleData:
// ddtheme.buttonStyleData,
// iconStyleData:
// ddtheme.iconStyleData,
// menuItemStyleData:
// ddtheme.menuItemStyleData,
// dropdownStyleData:
// ddtheme.dropdownStyleData,
// ),
// ),
// ],
// ),
// ),
// const SizedBox(height: 10),
// Row(
// children: [
// Expanded(
// flex: 2,
// child: textControllerWidget(
// context,
// provider
// .editProductPriceControllers[j],
// "Product Price",
// "Enter Product Price",
// (value) =>
// provider.updateTotalAmount(j),
// TextInputType.number,
// false,
// FilteringTextInputFormatter
// .digitsOnly,
// ),
// ),
// ],
// ),
// const SizedBox(height: 10),
// Row(
// children: [
// Expanded(
// flex: 2,
// child: textControllerWidget(
// context,
// provider
// .editQuantityControllers[j],
// "Quantity",
// "Enter Quantity",
// (value) =>
// provider.updateTotalAmount(j),
// TextInputType.number,
// false,
// FilteringTextInputFormatter
// .digitsOnly,
// ),
// ),
// ],
// ),
// const SizedBox(height: 10),
// Row(
// children: [
// Expanded(
// flex: 2,
// child: textControllerWidget(
// context,
// provider
// .editTotalAmountControllers[j],
// "Amount",
// "Total Amount",
// (_) {},
// TextInputType.number,
// true,
// FilteringTextInputFormatter
// .digitsOnly,
// ),
// ),
// ],
// ),
// // IconButton(
// // icon: const Icon(Icons.delete),
// // onPressed: provider.editProductPriceControllers.length > 1
// // ? () => provider.editRemoveRow(j)
// // : null,
// // ),
// ],
// ),
// );
// },
// ),
// ],
],
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
margin: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Column(
children: [
textControllerWidget(
context,
provider.taxesController,
......@@ -341,6 +609,8 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
],
),
),
],
),
),
floatingActionButtonLocation:
......@@ -369,7 +639,8 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
? null
: () {
//genquotedown
final insertedData = provider.getFormData();
final insertedData = provider.productRows;
print(insertedData);
provider
.crmLeadDetailsGenerateQuoteSubmitAPIFunction(
context,
......@@ -400,7 +671,9 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
AppColors.app_blue,
),
)
: SvgPicture.asset("assets/svg/download_quote.svg"),
: SvgPicture.asset(
"assets/svg/download_quote.svg",
),
),
),
),
......@@ -443,7 +716,9 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
AppColors.app_blue,
),
)
: SvgPicture.asset("assets/svg/mail_quote.svg")
: SvgPicture.asset(
"assets/svg/mail_quote.svg",
),
),
),
),
......@@ -486,7 +761,9 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
AppColors.app_blue,
),
)
: SvgPicture.asset("assets/svg/whatsapp_quote.svg")
: SvgPicture.asset(
"assets/svg/whatsapp_quote.svg",
),
),
),
),
......@@ -529,7 +806,9 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
AppColors.app_blue,
),
)
:SvgPicture.asset("assets/svg/whatsapp_quote_self.svg")
: SvgPicture.asset(
"assets/svg/whatsapp_quote_self.svg",
),
),
),
),
......
......@@ -37,7 +37,7 @@ class _PendingtasksdetailsState extends State<Pendingtasksdetails> {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
var prov = Provider.of<Crmdashboardprovider>(context, listen: false);
prov.accessPagesAPIFunction(context);
prov.crmDashboardAPIFunction(context, "executive", "", "", "");
prov.crmDashboardAPIFunction(context);
prov.crmPendingTasksAPIFunction(context);
});
}
......@@ -255,7 +255,9 @@ class _PendingtasksdetailsState extends State<Pendingtasksdetails> {
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => Followupupdatescreen()),
MaterialPageRoute(builder: (context) => Followupupdatescreen(
leadID: task.leadid,
)),
);
},
child: Container(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment