Commit 7ba7402c authored by Sai Srinivas's avatar Sai Srinivas Committed by Sai Srinivas
Browse files

Edit form and some fixes added

parent d2939607
......@@ -428,7 +428,8 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => CasualLeaveHistoryProvider()),
ChangeNotifierProvider(create: (_) => ContactProvider()),
ChangeNotifierProvider(create: (_) => QrProvider()),
ChangeNotifierProvider(create: (_) => CrmNearByGeneratorsProvider()),
ChangeNotifierProvider(create: (_) => EditCommonAccountProvider()),
],
child: Builder(
builder: (BuildContext context) {
......
......@@ -117,8 +117,18 @@ class _AccountslistState extends State<Accountslist> {
return (connection == "Online")
? Platform.isAndroid
? WillPopScope(
onWillPop: () => onBackPressed(context),
child: SafeArea(
onWillPop: () async {
onBackPressed(context);
_refreshList(context);
final provider = Provider.of<Accountslistprovider>(context, listen: false);
provider.resetValues();
provider.commonAccountListAPIFunction(context);
// Return true or false depending on whether you want to allow the pop
return true; // allow the back navigation
// return false; // prevent back navigation
},
child: SafeArea(
top: false,
bottom: true,
child: _scaffold(context),
......
This diff is collapsed.
......@@ -31,7 +31,7 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
Dropdowntheme ddtheme = Dropdowntheme();
int _currentStep = 0;
final _formKey = GlobalKey<FormState>();
List<FocusNode> focusNodes = List.generate(20, (index) => FocusNode());
final List<FocusNode> focusNodes = List.generate(30, (index) => FocusNode());
Map _source = {ConnectivityResult.mobile: true};
final MyConnectivity _connectivity = MyConnectivity.instance;
......@@ -274,7 +274,7 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
// custom continue logic:
if (_currentStep == 0) {
// validate step1 via provider
if (provider.validateStep1()) {
if (provider.validateStep1(context)) {
setState(() => _currentStep = 1);
} else {
// show error (provider sets errors and notifies)
......@@ -337,7 +337,7 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
setState(() => _currentStep = 0);
} else if (value == 1) {
// user wants to jump to step 1 - ensure step 0 valid
if (provider.validateStep1()) {
if (provider.validateStep1(context)) {
setState(() => _currentStep = 1);
} else {
provider.notifyListeners();
......@@ -345,7 +345,7 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
}
} else if (value == 2) {
// allow jump if step0 valid; step1 optional
if (provider.validateStep1()) {
if (provider.validateStep1(context)) {
setState(() => _currentStep = 2);
} else {
provider.notifyListeners();
......@@ -353,7 +353,7 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
}
} else if (value == 3) {
// final - require step0 valid
if (!provider.validateStep1()) {
if (!provider.validateStep1(context)) {
provider.notifyListeners();
setState(() => _currentStep = 0);
return;
......@@ -440,9 +440,12 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
"Company Name",
"Enter Company Name",
(p0) {
provider.updateName(p0);
provider.checkInputsAPI(context, "name", provider.nameController.text);
},
provider.updateName(p0);
provider.checkInputsAPI(context, "name", provider.nameController.text);
// Recompare with GST response if exists
provider.recheckNameWithGst();
},
TextInputType.text,
false,
null,
......@@ -708,52 +711,120 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// GST field - if provided, validate and autofill address; compare company name
textControllerWidget(
context,
provider.gstNumberController,
"GST Number",
"Enter GST Number",
(val) async {
// when user types, just update; validation on field submit
provider.gstNumberController.text = val;
provider.notifyListeners();
// GST field (unique focus node 9). Only one GST widget here.
Text("GST Number"),
const SizedBox(height: 6),
TextFormField(
controller: provider.gstNumberController,
focusNode: focusNodes[9],
textInputAction: TextInputAction.done,
keyboardType: TextInputType.text,
style: TextStyle(
height: 1.2,
color: Colors.black87,
backgroundColor: AppColors.text_field_color,
),
decoration: InputDecoration(
hintText: "Enter GST Number",
filled: true,
hintStyle: TextStyle(
height: 1.2,
backgroundColor: AppColors.text_field_color,
color: AppColors.grey_semi,
),
fillColor: AppColors.text_field_color,
contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide.none,
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide.none,
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide.none,
),
),
onChanged: (value) {
// only clear GST error when user edits
provider.updateGSTNumber(value);
final trimmed = value.trim();
if (trimmed.isEmpty) {
// user cleared GST -> clear response + errors
provider.gstResponse = null;
provider.gstNumberError = null;
provider.nameError = null; // also clear mismatch error, if any
provider.notifyListeners();
return;
}
// OPTIONAL: auto-validate once full 15-char GST typed
if (trimmed.length == 15) {
provider.checkAndApplyGst(context, trimmed);
}
},
onFieldSubmitted: (value) async {
final trimmed = value.trim();
if (trimmed.isNotEmpty) {
await provider.checkAndApplyGst(context, trimmed);
}
// move focus to Bank Account Number
FocusScope.of(context).requestFocus(focusNodes[10]);
},
TextInputType.text,
false,
null,
focusNodes[9],
focusNodes[10],
TextInputAction.next,
null,
// onEditingComplete / onFieldSubmitted, we will validate
),
// Validate GST when user leaves the field (on editing complete)
// To do that we use FocusNode
const SizedBox(height: 4),
errorWidget(context, provider.gstNumberError),
// Bank Account Number
const SizedBox(height: 4),
// errorWidget(context, provider.gstNumberError),
// Bank Account Number (use same style as other fields)
textControllerWidget(
context,
provider.bankAcNumberController,
"Bank Account Number",
"Enter Bank Account Number",
(p0) {
// update provider value and trigger bank validation if IFSC already present
provider.updateNumber(p0);
// attempt validation only when IFSC present
// If account entered but IFSC empty -> provider will set IFSC required error via checkAndApplyBank
if (provider.bankIfscCotroller.text.trim().isNotEmpty) {
_validateBankIfNeeded(provider);
// validate once IFSC is present
provider.checkAndApplyBank(context, p0.trim());
} else {
// If account present but IFSC empty, show IFSC required error
if (p0.trim().isNotEmpty) {
provider.bankIFSCError = "IFSC is required when account number is entered";
provider.notifyListeners();
} else {
provider.bankIFSCError = null;
provider.notifyListeners();
}
}
},
TextInputType.number,
false,
FilteringTextInputFormatter.digitsOnly,
focusNodes[10],
focusNodes[11],
focusNodes[10], // bank account unique
focusNodes[8], // move to IFSC next
TextInputAction.next,
),
const SizedBox(height: 4),
errorWidget(context, provider.bankAcNumberError),
// IFSC
// Bank IFSC
textControllerWidget(
context,
provider.bankIfscCotroller,
......@@ -761,28 +832,46 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
"Enter Bank IFSC",
(p0) {
provider.updateIFSC(p0);
// validate IFSC format locally; if good and account present, trigger server validation
if (_isIfscValidFormat(p0) && provider.bankAcNumberController.text.trim().isNotEmpty) {
_validateBankIfNeeded(provider);
} else {
if (p0.trim().isNotEmpty && !_isIfscValidFormat(p0)) {
provider.bankIFSCError = "Invalid IFSC format";
// local IFSC format check
final reg = RegExp(r'^[A-Za-z]{4}0[A-Za-z0-9]{6}$');
if (p0.trim().isEmpty) {
// if account exists and IFSC empty -> show required error
if (provider.bankAcNumberController.text.trim().isNotEmpty) {
provider.bankIFSCError = "IFSC is required when account number is entered";
provider.notifyListeners();
} else {
provider.bankIFSCError = null;
provider.notifyListeners();
}
return;
}
if (!reg.hasMatch(p0.trim())) {
provider.bankIFSCError = "Invalid IFSC format";
provider.notifyListeners();
return;
} else {
provider.bankIFSCError = null;
provider.notifyListeners();
}
// if acc and IFSC both present and valid -> call bank API
if (provider.bankAcNumberController.text.trim().isNotEmpty) {
provider.checkAndApplyBank(context, provider.bankAcNumberController.text.trim());
}
},
TextInputType.text,
false,
null,
focusNodes[8],
focusNodes[9],
focusNodes[8], // unique IFSC focus
focusNodes[11], // next focus after IFSC (holder / or UPI)
TextInputAction.next,
),
const SizedBox(height: 4),
errorWidget(context, provider.bankIFSCError),
// Bank Name (autofill)
const SizedBox(height: 8),
// Bank Name (autofill by API) (unique focus node 6)
textControllerWidget(
context,
provider.bankNameController,
......@@ -797,7 +886,10 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
TextInputAction.next,
),
errorWidget(context, provider.banknameError),
// Branch
const SizedBox(height: 8),
// Branch (unique focus node 7)
textControllerWidget(
context,
provider.branchNameController,
......@@ -808,11 +900,14 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
false,
null,
focusNodes[7],
focusNodes[8],
focusNodes[11],
TextInputAction.next,
),
errorWidget(context, provider.bankBranchError),
// Holder
const SizedBox(height: 8),
// Bank Holder Name (unique focus node 11) — previously incorrectly used 9
textControllerWidget(
context,
provider.bankHolderNameController,
......@@ -822,26 +917,30 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
TextInputType.text,
false,
null,
focusNodes[9],
focusNodes[10],
TextInputAction.next,
),
errorWidget(context, provider.bankHolderNameError),
// UPI
textControllerWidget(
context,
provider.bankUpiController,
"Bank UPI ID",
"Enter Bank UPI ID",
provider.updateUPI,
TextInputType.text,
false,
null,
focusNodes[11],
focusNodes[11], // <-- corrected unique index
focusNodes[12],
TextInputAction.next,
),
errorWidget(context, provider.upiError),
errorWidget(context, provider.bankHolderNameError),
const SizedBox(height: 8),
// Bank UPI (unique focus node 12)
// Bank UPI (use different focus nodes than Contact Person)
textControllerWidget(
context,
provider.bankUpiController,
"Bank UPI ID",
"Enter Bank UPI ID",
provider.updateUPI,
TextInputType.text,
false,
null,
focusNodes[17], //
focusNodes[18], // next focus
TextInputAction.next,
),
errorWidget(context, provider.upiError),
],
),
),
......@@ -973,6 +1072,23 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
return;
}
if (provider.validateStep1(context)) {
// move to first error step
final errStep = _firstErrorStep(provider);
if (errStep != null) {
setState(() {
_currentStep = errStep;
});
}else{
provider.submitClickced = true;
provider.notifyListeners();
await provider.submitCommonAccountsAPI(context, widget.from);
}
// ensure UI updated
provider.notifyListeners();
return;
}
// All good => submit
provider.submitClickced = true;
provider.notifyListeners();
......@@ -994,7 +1110,7 @@ class _AddcommonpaymentState extends State<Addcommonpayment> {
onTap: () {
setState(() {
if (_currentStep == 0) {
if (provider.validateStep1()) {
if (provider.validateStep1(context)) {
_currentStep = 1;
} else {
provider.notifyListeners();
......
This diff is collapsed.
This diff is collapsed.
......@@ -357,8 +357,21 @@ class _LeadlistbymodeState extends State<Leadlistbymode> {
),
child: Consumer<Leadlistprovider>(
builder: (context, provider, child) {
// 🔹 Initialize filter selections from widget.filter only once
if (provider.selectedLeadStatus == null &&
widget.filter?.status != null &&
widget.filter!.status!.toString().isNotEmpty) {
provider.selectedLeadStatus = widget.filter!.status;
}
if (provider.selectedOpenStatus == null &&
widget.filter?.openStatus != null &&
widget.filter!.openStatus!.toString().isNotEmpty) {
provider.selectedOpenStatus = widget.filter!.openStatus;
}
int selectedIndex = isSelected.indexWhere(
(element) => element == true,
(element) => element == true,
);
final headings = [
"Lead Status",
......@@ -373,6 +386,22 @@ class _LeadlistbymodeState extends State<Leadlistbymode> {
if (widget.mode != "executive") {
headings.add("Employee");
}
// int selectedIndex = isSelected.indexWhere(
// (element) => element == true,
// );
// final headings = [
// "Lead Status",
// "Open/Close Status",
// "Mobile Number",
// "Company Name",
// "Source",
// "Reference",
// "Team",
// "Segment",
// ];
if (widget.mode != "executive") {
headings.add("Employee");
}
return SizedBox(
height: MediaQuery.of(context).size.height * 0.7,
child: Column(
......@@ -512,17 +541,12 @@ class _LeadlistbymodeState extends State<Leadlistbymode> {
mainAxisSize: MainAxisSize.min,
children: [
if (selectedIndex == 0) ...[
...provider.leadStatusList.map((
status,
) {
...provider.leadStatusList.map((status,) {// here i want to do that i want to show selected from widget.filter!.status,
return SizedBox(
height: 35,
child: CheckboxListTile(
activeColor:
AppColors.app_blue,
controlAffinity:
ListTileControlAffinity
.leading,
activeColor: AppColors.app_blue,
controlAffinity: ListTileControlAffinity.leading,
checkboxShape: CircleBorder(
side: BorderSide(
width: 0.5,
......@@ -568,7 +592,7 @@ class _LeadlistbymodeState extends State<Leadlistbymode> {
width: 0.5,
),
),
title: Text(
title: Text(// same here widget.filter!.openStatus,
status ?? 'Unknown Status',
style: const TextStyle(
fontSize: 14,
......@@ -963,6 +987,7 @@ class _LeadlistbymodeState extends State<Leadlistbymode> {
},
);
}
void _showContactOptions(BuildContext context, String? phoneNumber) {
if (phoneNumber == null || phoneNumber.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
......
......@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:generp/Notifiers/crmProvider/addNewLeadsandProspectsProvider.dart';
import 'package:generp/screens/crm/CrmNearbyGenerators.dart';
import 'package:generp/screens/crm/addLeadsProspectsScreen.dart';
import 'package:generp/screens/crm/appointmentCalendar.dart';
import 'package:generp/screens/crm/followUpListonType.dart';
......@@ -741,6 +742,69 @@ class _CrmdashboardScreenState extends State<CrmdashboardScreen> {
],
),
),
SizedBox(height: 10,),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.only(left: 15, top: 10, right: 15),
child: Text(
"Nearby Generators",
style: TextStyle(
fontSize: 16,
color: AppColors.grey_semi,
),
),
),
),
SizedBox(height: 12,),
InkResponse(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CrmNearbyGenerators(),
),
);
},
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.nearByLeads.isNotEmpty) ...[
Align(
......
......@@ -359,16 +359,19 @@ class _AttendanceRequestDetailScreenState
"Other Details",
scaleFactor,
),
if (details.type == "Check In" || details.type == "Check In/Out")
_buildDetailTile(
"Check In Type",
details.checkInType,
scaleFactor,
),
if (details.type == "Check Out" || details.type == "Check In/Out")
_buildDetailTile(
"Check Out Type",
details.chechOutType,
scaleFactor,
),
if (details.type == "Check Out" || details.type == "Check In/Out")
_buildDetailTile(
"Check Out Time",
details.checkOutTime,
......
......@@ -72,12 +72,12 @@ class _ContactListScreenState extends State<ContactListScreen> {
// Clean phone number
final cleanPhoneNumber = _cleanPhoneNumber(phoneNumber);
// Instead of inserting contact, open system form
// Instead of inserting contact, open system form
final newContact = Contact()
..name = Name(first: name)
..phones = [Phone(cleanPhoneNumber)];
// 🟢 This opens the phone’s native “Add contact” screen (prefilled)
// This opens the phone’s native “Add contact” screen (prefilled)
await FlutterContacts.openExternalInsert(newContact);
// Hide loading
......
......@@ -25,6 +25,7 @@ export 'package:generp/Notifiers/commonProvider/accountDetailsProvider.dart';
export 'package:generp/Notifiers/commonProvider/accountsListProvider.dart';
export 'package:generp/Notifiers/commonProvider/commonPagesProvider.dart';
export 'package:generp/Notifiers/commonProvider/accountLedgerProvider.dart';
export 'package:generp/Notifiers/commonProvider/editCommonAccountProvider.dart';
export 'package:generp/Notifiers/financeProvider/DashboardProvider.dart';
export 'package:generp/Notifiers/financeProvider/RequestionListProvider.dart';
......@@ -56,6 +57,7 @@ export 'package:generp/Notifiers/crmProvider/addProspectLeadsProvider.dart';
export 'package:generp/Notifiers/crmProvider/followUpUpdateProvider.dart';
export 'package:generp/Notifiers/crmProvider/appointmentCalendarProvider.dart';
export 'package:generp/Notifiers/crmProvider/addNewLeadsandProspectsProvider.dart';
export 'package:generp/Notifiers/crmProvider/CrmNearByGeneratorsProvider.dart';
export 'package:generp/Notifiers/hrmProvider/hrmAccessiblePagesProvider.dart';
export 'package:generp/Notifiers/hrmProvider/attendanceListProvider.dart';
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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