login and signup

master
gitadmin 4 weeks ago
parent 9dc86047ed
commit 331fb02cd2

@ -150,6 +150,7 @@ class AppSettings{
static String loginUrl = host + 'supplierlogin'; static String loginUrl = host + 'supplierlogin';
static String signUpUrl = host + 'suppliers'; static String signUpUrl = host + 'suppliers';
static String forgotPasswordUrl = host + 'forgotpassword'; static String forgotPasswordUrl = host + 'forgotpassword';
static String sendSmsUrl = host + 'sendSms';
static String resetTokenUrl = host + 'reset_token'; static String resetTokenUrl = host + 'reset_token';
static String verifyPhnUrl = host + 'phone'; static String verifyPhnUrl = host + 'phone';
static String uploadPicUrl = host + 'uploads-user'; static String uploadPicUrl = host + 'uploads-user';
@ -363,7 +364,7 @@ class AppSettings{
} }
static Future<bool> getOtp(payload) async { static Future<bool> getOtp(payload) async {
var uri = Uri.parse(forgotPasswordUrl); var uri = Uri.parse(sendSmsUrl);
var response = await http.post(uri, var response = await http.post(uri,
body: json.encode(payload), headers: await buildRequestHeaders()); body: json.encode(payload), headers: await buildRequestHeaders());

@ -411,9 +411,15 @@ class _FleetEmployeesState extends State<FleetEmployees> {
_LabeledField( _LabeledField(
label: "Years of Experience *", label: "Years of Experience *",
child: TextFormField( child: TextFormField(
controller: _experienceController, // create controller controller: _experienceController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly, // Only numbers
LengthLimitingTextInputFormatter(2), // Max 2 digits
],
decoration: const InputDecoration( decoration: const InputDecoration(
border: OutlineInputBorder(), border: OutlineInputBorder(),
hintText: "Enter Years", hintText: "Enter Years",
@ -425,9 +431,15 @@ class _FleetEmployeesState extends State<FleetEmployees> {
14, const Color(0xFF2A2A2A), FontWeight.w400), 14, const Color(0xFF2A2A2A), FontWeight.w400),
validator: (value) { validator: (value) {
if (value == null || value.trim().isEmpty) { if (value == null || value.trim().isEmpty) {
return "Experience is required"; return "Experience is required";
} }
if (value.length > 2) {
return "Only 2 digits allowed";
}
return null; return null;
}, },
), ),

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:supplier_new/common/settings.dart'; import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/profile/service_locations_radius.dart'; import 'package:supplier_new/profile/service_locations_radius.dart';
@ -19,12 +20,13 @@ class _ServiceLocationState extends State<ServiceLocation> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
String _deliveryFrom = 'business'; String _deliveryFrom = 'business';
final TextEditingController _radiusController = final TextEditingController _radiusController =
TextEditingController(text: "10"); TextEditingController(text: "10");
bool _customizeEachSource = false; bool _customizeEachSource = false;
bool isLoading = false; bool isLoading = false;
int currentStep = 3; int currentStep = 3;
List<SourceLocationsModel> sourceLocationsList = []; List<SourceLocationsModel> sourceLocationsList = [];
Map<int, TextEditingController> radiusControllers = {};
Map<int, ValueNotifier<double>> radiusNotifiers = {};
// 🔹 Notifier for dynamic map radius // 🔹 Notifier for dynamic map radius
late final ValueNotifier<double> _radiusKmNotifier; late final ValueNotifier<double> _radiusKmNotifier;
@ -64,25 +66,48 @@ class _ServiceLocationState extends State<ServiceLocation> {
Future<void> _fetchSources() async { Future<void> _fetchSources() async {
setState(() => isLoading = true); setState(() => isLoading = true);
try { try {
final response = await AppSettings.getSourceLoctaions(); final response = await AppSettings.getSourceLoctaions();
final data = (jsonDecode(response)['data'] as List) final data = (jsonDecode(response)['data'] as List)
.map((e) => SourceLocationsModel.fromJson(e)) .map((e) => SourceLocationsModel.fromJson(e))
.toList(); .toList();
if (!mounted) return; if (!mounted) return;
setState(() { setState(() {
sourceLocationsList = data; sourceLocationsList = data;
isLoading = false; isLoading = false;
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
_expandedMap[i] = false; _expandedMap[i] = false;
// CREATE CONTROLLERS FOR EACH LOCATION
radiusControllers[i] = TextEditingController(text: "10");
radiusNotifiers[i] = ValueNotifier<double>(10);
// 🔁 update map when radius changes
radiusControllers[i]!.addListener(() {
final value = double.tryParse(radiusControllers[i]!.text);
radiusNotifiers[i]!.value =
(value == null || value <= 0) ? 10 : value;
});
} }
}); });
} catch (e) { } catch (e) {
debugPrint("⚠️ Error fetching source locations: $e"); debugPrint("⚠️ Error fetching source locations: $e");
setState(() => isLoading = false); setState(() => isLoading = false);
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -184,6 +209,13 @@ class _ServiceLocationState extends State<ServiceLocation> {
TextFormField( TextFormField(
controller: _radiusController, controller: _radiusController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
FilteringTextInputFormatter.deny(RegExp(r'^0')),
LengthLimitingTextInputFormatter(3), // optional (max 999 km)
],
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Enter radius in kms", hintText: "Enter radius in kms",
hintStyle: fontTextStyle( hintStyle: fontTextStyle(
@ -194,6 +226,19 @@ class _ServiceLocationState extends State<ServiceLocation> {
contentPadding: const EdgeInsets.symmetric( contentPadding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 12), horizontal: 12, vertical: 12),
), ),
validator: (value) {
if (value == null || value.isEmpty) {
return "Enter radius";
}
if (int.tryParse(value)! <= 0) {
return "Radius must be greater than 0";
}
return null;
},
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Container( Container(
@ -325,58 +370,66 @@ class _ServiceLocationState extends State<ServiceLocation> {
border: Border.all( border: Border.all(
color: const Color(0xFFE5E5E5)), color: const Color(0xFFE5E5E5)),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("Delivery Radius (in Kms) *",
Text(
"Delivery Radius (in Kms) *",
style: fontTextStyle( style: fontTextStyle(
12, 12, const Color(0xFF2F3036), FontWeight.w600),
const Color(0xFF2F3036),
FontWeight.w600)),
const SizedBox(height: 16),
TextFormField(
controller: _radiusController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: "Enter radius in kms",
hintStyle: fontTextStyle(
14,
const Color(0xFF939495),
FontWeight.w400),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(8),
),
contentPadding:
const EdgeInsets.symmetric(
horizontal: 12, vertical: 12),
), ),
),
const SizedBox(height: 16), const SizedBox(height: 16),
Container(
width: double.infinity, TextFormField(
height: 180, controller: radiusControllers[index],
decoration: BoxDecoration( keyboardType: TextInputType.number,
borderRadius: onChanged: (value) {
BorderRadius.circular(8),
border: Border.all( double radius = double.tryParse(value) ?? 0;
color: const Color(0xFFE6E6E6)),
radiusNotifiers[index]!.value = radius;
},
decoration: InputDecoration(
hintText: "Enter radius in kms",
hintStyle: fontTextStyle(
14, const Color(0xFF939495), FontWeight.w400),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
),
), ),
child: ClipRRect(
borderRadius: const SizedBox(height: 16),
BorderRadius.circular(8),
child: ServiceLocationsRadiusScreen( Container(
initialPosition: LatLng( width: double.infinity,
d.latitude ?? 17.3850, height: 180,
d.longitude ?? 78.4867, decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(color: const Color(0xFFE6E6E6)),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: ServiceLocationsRadiusScreen(
initialPosition: LatLng(
d.latitude ?? 17.3850,
d.longitude ?? 78.4867,
),
radiusKmListenable: radiusNotifiers[index]!,
), ),
radiusKmListenable:
_radiusKmNotifier,
), ),
), ),
), ],
], )
),
), ),
], ],
), ),
@ -391,15 +444,17 @@ class _ServiceLocationState extends State<ServiceLocation> {
const SizedBox(height: 16), const SizedBox(height: 16),
Container( Container(
width: double.infinity, width: double.infinity,
height: 250, height: 220, // 👈 small map fits neatly
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: const Color(0xFFE6E6E6)), border:
Border.all(color: const Color(0xFFE6E6E6)),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: ServiceLocationsRadiusScreen( child: ServiceLocationsRadiusScreen(
initialPosition: const LatLng(20.5937, 78.9629), initialPosition:
const LatLng(17.381597, 78.481791),
radiusKmListenable: _radiusKmNotifier, radiusKmListenable: _radiusKmNotifier,
), ),
), ),

@ -299,9 +299,15 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
_LabeledField( _LabeledField(
label: "Years of Experience *", label: "Years of Experience *",
child: TextFormField( child: TextFormField(
controller: _experienceController, // create controller controller: _experienceController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly, // Only numbers
LengthLimitingTextInputFormatter(2), // Max 2 digits
],
decoration: const InputDecoration( decoration: const InputDecoration(
border: OutlineInputBorder(), border: OutlineInputBorder(),
hintText: "Enter Years", hintText: "Enter Years",
@ -313,9 +319,15 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
14, const Color(0xFF2A2A2A), FontWeight.w400), 14, const Color(0xFF2A2A2A), FontWeight.w400),
validator: (value) { validator: (value) {
if (value == null || value.trim().isEmpty) { if (value == null || value.trim().isEmpty) {
return "Experience is required"; return "Experience is required";
} }
if (value.length > 2) {
return "Only 2 digits allowed";
}
return null; return null;
}, },
), ),

@ -292,21 +292,58 @@ class _ResourcesSourceScreenState extends State<ResourcesSourceScreen> {
), ),
_LabeledField( _LabeledField(
label: "Mobile Number *", label: "Phone Number *",
child: TextFormField( child: TextFormField(
controller: _mobileCtrl, controller: _mobileCtrl,
validator: (v) => _validatePhone(v, label: "Mobile Number"),
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
autovalidateMode: AutovalidateMode.onUserInteraction,
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.digitsOnly, FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10), LengthLimitingTextInputFormatter(10),
// Restrict first digit 6-9
TextInputFormatter.withFunction(
(oldValue, newValue) {
if (newValue.text.isEmpty) {
return newValue;
}
// First digit must be 6-9
if (!RegExp(r'^[6-9]').hasMatch(newValue.text)) {
return oldValue;
}
return newValue;
},
),
], ],
validator: (value) {
if (value == null || value.isEmpty) {
return "Phone Number required";
}
if (!RegExp(r'^[6-9]').hasMatch(value)) {
return "Enter digits starting 6,7,8,9";
}
if (value.length != 10) {
return "Enter valid 10 digit number";
}
return null;
},
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Mobile Number", hintText: "Mobile Number",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), hintStyle: fontTextStyle(
14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
isDense: true, isDense: true,
), ),
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
), ),
), ),

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:supplier_new/common/settings.dart'; import 'package:supplier_new/common/settings.dart';
import '../resources/tankers_model.dart'; import '../resources/tankers_model.dart';
@ -122,46 +123,61 @@ class _SetRatesScreenState extends State<SetRatesScreen>
super.dispose(); super.dispose();
} }
Widget buildTextField(String label, TextEditingController controller) { Widget buildTextField(String hint, TextEditingController controller) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: TextField( child: TextFormField(
controller: controller, controller: controller,
cursorColor: primaryColor, cursorColor: primaryColor,
readOnly: false, keyboardType: TextInputType.number,
keyboardType: TextInputType.number,
decoration: InputDecoration( // blocks -, +, . and all special chars (only digits)
counterText: '', inputFormatters: [
filled: false, FilteringTextInputFormatter.digitsOnly,
fillColor: Colors.white, LengthLimitingTextInputFormatter(5), // adjust if needed
prefixIconConstraints: BoxConstraints( ],
minWidth: 24,
minHeight: 24, decoration: InputDecoration(
), counterText: '',
border: OutlineInputBorder( filled: false,
borderRadius: BorderRadius.circular(4.0), fillColor: Colors.white,
borderSide: BorderSide( prefixIconConstraints: const BoxConstraints(
color: Color(0XFFC3C4C4), minWidth: 24,
width: 1, minHeight: 24,
)), ),
focusedBorder: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0), borderRadius: BorderRadius.circular(4.0),
borderSide: BorderSide( borderSide: const BorderSide(
color: Color(0XFF8270DB), color: Color(0XFFC3C4C4),
width: 1, width: 1,
),
), ),
enabledBorder: OutlineInputBorder( ),
borderRadius: BorderRadius.circular(4.0), focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Color(0XFFC3C4C4)), borderRadius: BorderRadius.circular(4.0),
borderSide: const BorderSide(
color: Color(0XFF8270DB),
width: 1,
), ),
hintText: label,
hintStyle: fontTextStyle(14, Color(0XFF939495), FontWeight.w400),
/* TextStyle(color: greyColor, fontWeight: FontWeight.bold //<-- SEE HERE
),*/
), ),
style: fontTextStyle(14, Color(0XFF515253), FontWeight.w500), enabledBorder: OutlineInputBorder(
)); borderRadius: BorderRadius.circular(4.0),
borderSide: const BorderSide(color: Color(0XFFC3C4C4)),
),
hintText: hint,
hintStyle: fontTextStyle(14, const Color(0XFF939495), FontWeight.w400),
),
style: fontTextStyle(14, const Color(0XFF515253), FontWeight.w500),
// optional: if you later wrap with Form and call validate()
validator: (value) {
final v = (value ?? "").trim();
if (v.isEmpty) return "Enter price";
final n = int.tryParse(v) ?? 0;
if (n <= 0) return "Enter positive value";
return null;
},
),
);
} }
Widget labelText(String label) { Widget labelText(String label) {
@ -544,3 +560,5 @@ class _SetRatesScreenState extends State<SetRatesScreen>
); );
} }
} }

@ -134,7 +134,7 @@ class _SignUpMobileNumberScreenState extends State<SignUpMobileNumberScreen> {
if(isOnline){ if(isOnline){
var payload = { var payload = {
"phone": "mobileNumbers":
mobileNumberController.text.trim() mobileNumberController.text.trim()
}; };

Loading…
Cancel
Save