resources functionality

master
Sneha 2 months ago
parent b0fcf7d149
commit 3d564d843e

@ -771,7 +771,14 @@ class _HomeScreenState extends State<HomeScreen> {
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
TextButton(
onPressed: () {},
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FleetStep1Page(),
),
);
},
child: const Text(
"Edit Profile",
style: TextStyle(color: Colors.blue, fontSize: 14),

@ -140,6 +140,11 @@ class AppSettings{
static String uploadPicUrl = host + 'uploads-user';
static String getOrderRequestsFromUsersUrl = host + 'getuserRequestbookingsforsupplier';
static String acceptOrderRequestsUrl = host + 'request-booking-with-charges';
static String getAcceptedOrdersFromUsersUrl = host + 'supplier/booking/advance-paid';
static String getTankersUrl = host + 'getTankers';
static String addTankerUrl = host + 'addTankers';
static String getDriversUrl = host + 'getalldeliveryboys';
static String addDriversUrl = host + 'addDeliveryboys';
static String formDouble(dynamic s) {
@ -413,6 +418,140 @@ class AppSettings{
}
}
static Future<String> getAcceptedOrdersFromUsers() async {
var uri = Uri.parse(getAcceptedOrdersFromUsersUrl+'/'+supplierId);
//uri = uri.replace(query: 'customerId=$customerId');
var response = await http.get(uri, headers: await buildRequestHeaders());
if (response.statusCode == 200) {
return response.body;
} else if (response.statusCode == 401) {
bool status = await AppSettings.resetToken();
if (status) {
response = await http.get(uri, headers: await buildRequestHeaders());
if (response.statusCode == 200) {
return response.body;
} else {
return '';
}
} else {
return '';
}
} else {
return '';
}
}
static Future<String> getTankers() async {
var uri = Uri.parse(getTankersUrl);
uri = uri.replace(query: 'supplierId=$supplierId');
var response = await http.get(uri, headers: await buildRequestHeaders());
if (response.statusCode == 200) {
return response.body;
} else if (response.statusCode == 401) {
bool status = await AppSettings.resetToken();
if (status) {
response = await http.get(uri, headers: await buildRequestHeaders());
if (response.statusCode == 200) {
return response.body;
} else {
return '';
}
} else {
return '';
}
} else {
return '';
}
}
static Future<bool> addTankers(payload) async {
var response = await http.post(Uri.parse(addTankerUrl + '/' + supplierId),
body: json.encode(payload), headers: await buildRequestHeaders());
if (response.statusCode == 200) {
try {
var _response = json.decode(response.body);
print(_response);
return true;
} catch (e) {
// display error toast
return false;
}
} else if (response.statusCode == 401) {
bool status = await AppSettings.resetToken();
if (status) {
response = await http.post(Uri.parse(addTankerUrl + '/' + supplierId),
body: json.encode(payload), headers: await buildRequestHeaders());
if (response.statusCode == 200) {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
static Future<String> getDrivers() async {
var uri = Uri.parse(getDriversUrl+'/'+supplierId);
//uri = uri.replace(query: 'supplierId=$supplierId');
var response = await http.get(uri, headers: await buildRequestHeaders());
if (response.statusCode == 200) {
return response.body;
} else if (response.statusCode == 401) {
bool status = await AppSettings.resetToken();
if (status) {
response = await http.get(uri, headers: await buildRequestHeaders());
if (response.statusCode == 200) {
return response.body;
} else {
return '';
}
} else {
return '';
}
} else {
return '';
}
}
static Future<bool> addDrivers(payload) async {
var response = await http.post(Uri.parse(addDriversUrl + '/' + supplierId),
body: json.encode(payload), headers: await buildRequestHeaders());
if (response.statusCode == 200) {
try {
var _response = json.decode(response.body);
print(_response);
return true;
} catch (e) {
// display error toast
return false;
}
} else if (response.statusCode == 401) {
bool status = await AppSettings.resetToken();
if (status) {
response = await http.post(Uri.parse(addTankerUrl + '/' + supplierId),
body: json.encode(payload), headers: await buildRequestHeaders());
if (response.statusCode == 200) {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
/*Apis ends here*/

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/orders/order_requests.dart';
@ -17,70 +19,60 @@ class AllOrders extends StatefulWidget {
class _AllOrdersState extends State<AllOrders> {
final TextEditingController searchController = TextEditingController();
bool isLoading=false;
final List<OrdersModel> orders =[];
List<OrdersModel> ordersList = [];
@override
void initState() {
// TODO: implement initState
super.initState();
_fetchOrders();
}
Future<void> _fetchOrders() async {
setState(() => isLoading = true);
try {
final response = await AppSettings.getAcceptedOrdersFromUsers();
final data = (jsonDecode(response)['data'] as List)
.map((e) => OrdersModel.fromJson(e))
.toList();
if (!mounted) return;
setState(() {
ordersList = data;
isLoading = false;
});
} catch (e) {
debugPrint("⚠️ Error fetching orders: $e");
setState(() => isLoading = false);
}
}
@override
Widget build(BuildContext context) {
final List<OrdersModel> orders = [
OrdersModel(
date: DateTime(2025, 8, 24),
imageAsset: "images/building.png",// sample image
status: "completed",
title: "Rajpushpa Atria",
location: "Kokapet",
quantity: "15,000L - Bore Water",
time: "01:00 AM, Today",
extraInfo: "Delivered by Suresh",
),
OrdersModel(
date: DateTime(2025, 8, 24),
imageAsset: "images/building.png",// sample image
status: "in-progress",
title: "Rajpushpa Atria",
location: "Kokapet",
quantity: "15,000L - Bore Water",
time: "01:00 AM, 21/07/2025",
extraInfo: "Track Delivery",
),
OrdersModel(
date: DateTime(2025, 8, 23),
imageAsset: "images/building.png",// sample image
status: "cancelled",
title: "Lakeview Towers",
location: "Madhapur",
quantity: "8,000L - Tanker Water",
time: "09:30 PM, Yesterday",
extraInfo: "Cancelled by user",
),
OrdersModel(
date: DateTime(2025, 8, 25),
imageAsset: "images/building.png",// sample image
status: "assigned",
title: "Lakeview Towers",
location: "Madhapur",
quantity: "8,000L - Tanker Water",
time: "09:30 PM, Yesterday",
extraInfo: "Assigned to Madhav",
),
OrdersModel(
date: DateTime(2025, 8, 26),
imageAsset: "images/building.png",// sample image
status: "pending",
title: "Lakeview Towers",
location: "Madhapur",
quantity: "8,000L - Tanker Water",
time: "09:30 PM, Yesterday",
extraInfo: "",
),
];
// Group orders by date
final Map<String, List<OrdersModel>> groupedOrders = {};
for (var order in orders) {
final formattedDate = DateFormat("dd MMM yyyy").format(order.date);
String formatOrderDate(String? dateStr) {
if (dateStr == null || dateStr.trim().isEmpty) {
return ""; // or return a fallback like "N/A"
}
try {
final inputFormat = DateFormat("dd-MMM-yyyy"); // matches 10-Sep-2025
final outputFormat = DateFormat("dd MMM yyyy"); // output 10 Sep 2025
final parsedDate = inputFormat.parse(dateStr);
return outputFormat.format(parsedDate);
} catch (e) {
print("Date parse error: $e");
return dateStr; // fallback to original string
}
}
for (var order in ordersList) {
final formattedDate = formatOrderDate(order.date); // "10 Sep 2025"
groupedOrders.putIfAbsent(formattedDate, () => []).add(order);
}
return Scaffold(
@ -299,6 +291,8 @@ class OrderCard extends StatelessWidget {
return Color(0XFFF9DBC6);
case "pending":
return Color(0XFFFDF3D3);
case "advance_paid":
return Color(0XFFFDF3D3);
default:
return Colors.grey;
}
@ -316,6 +310,8 @@ class OrderCard extends StatelessWidget {
return Color(0XFFE56910);
case "pending":
return Color(0XFFD0AE3C);
case "advance_paid":
return Color(0XFFD0AE3C);
default:
return Colors.grey;
}
@ -349,15 +345,15 @@ class OrderCard extends StatelessWidget {
topLeft: Radius.circular(12),
bottomLeft: Radius.circular(0),
),
child: order.imageAsset != null
child: order.imageAsset != ''
? Image.asset(
order.imageAsset!,
order.imageAsset,
height: 145,
width: 145,
fit: BoxFit.cover,
)
: Image.network(
order.imageUrl!,
order.imageAsset,
height: 100,
width: 100,
fit: BoxFit.cover,
@ -389,33 +385,55 @@ class OrderCard extends StatelessWidget {
const SizedBox(height: 6),
Text(
order.title,
order.building_name,
style:fontTextStyle(16,Color(0XFF2D2E30),FontWeight.w600)
),
Text(
order.location,
order.displayAddress,
style: fontTextStyle(12,Color(0XFF646566),FontWeight.w400)
),
const SizedBox(height: 4),
Text(
order.quantity,
order.capacity+' - '+order.type_of_water,
style: fontTextStyle(14,Color(0XFF444444),FontWeight.w500)
),
Text(
order.time,
style:fontTextStyle(12,Color(0XFF939495),FontWeight.w400)
order.time+' , '+order.date,
style:fontTextStyle(8,Color(0XFF646566),FontWeight.w400)
),
const SizedBox(height: 4),
const SizedBox(height: 12),
Visibility(
visible: order.status.toLowerCase().toString()=='advance_paid',
child: GestureDetector(
onTap: (){
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(22),
border: Border.all(color: const Color(0XFF939495)),
),
child: Padding(
padding: EdgeInsets.fromLTRB(8,4,8,4),
child: Text(
"Assign",
style: fontTextStyle(
14, const Color(0XFF515253), FontWeight.w400),
),
)
),
),),
Text(
/*Text(
order.extraInfo,
style:fontTextStyle(12, order.status == "in-progress"
? Color(0XFF1D7AFC)
: Color(0XFF646566),FontWeight.w400)
),
),*/
],
),
),

@ -52,7 +52,7 @@ class _OrderRequestsPageState extends State<OrderRequestsPage> {
// Statuses that ignore time
if (dbLower == "reject") return {"status": "Rejected", "color": const Color(0XFFE2483D)};
if (dbLower == "accept") return {"status": "Accepted", "color": const Color(0XFF0A9E04)};
if (dbLower == "delivered") return {"status": "Delivered", "color": const Color(0XFF2E7D32)};
if (dbLower == "advance_paid") return {"status": "Accepted", "color": const Color(0XFF0A9E04)};
if (dbLower == "cancelled" || dbLower == "cancelled_by_user" || dbLower == "cancelled_by_supplier") {
return {"status": "Cancelled", "color": const Color(0XFF757575)};
}
@ -128,7 +128,7 @@ class _OrderRequestsPageState extends State<OrderRequestsPage> {
price: "${AppSettings.formDouble(order.quoted_amount) ?? ''}",
);
final noNavigateStatuses = ["expired", "rejected", "accepted", "delivered", "cancelled"];
final noNavigateStatuses = ["expired", "rejected", "accepted", "advance_paid", "cancelled"];
final disableNavigation = noNavigateStatuses.contains(status.toLowerCase());
final card = OrderCard(order: cardModel);

@ -1,23 +1,70 @@
class OrdersModel {
final DateTime date;
final String? imageUrl; // Network image
final String? imageAsset;
final String status;
final String title;
final String location;
final String quantity;
final String time;
final String extraInfo;
OrdersModel({
required this.date,
this.imageUrl,
this.imageAsset,
required this.status,
required this.title,
required this.location,
required this.quantity,
required this.time,
required this.extraInfo,
});
import 'package:supplier_new/common/settings.dart';
import 'package:geolocator/geolocator.dart';
class OrdersModel {
String building_name = '';
String address = '';
String type_of_water = '';
String capacity = '';
String quantity = '';
String time = '';
String averageTime = '';
String quoted_amount = '';
String displayAddress='';
double lat=0;
double lng=0;
double distanceInMeters=0;
double distanceInKm=0.0;
String dbId = '';
String status='';
String date='';
String imageAsset='images/building.png';
OrdersModel();
factory OrdersModel.fromJson(Map<String, dynamic> json){
OrdersModel rtvm = new OrdersModel();
rtvm.building_name = json['buildingName'] ?? '';
rtvm.dbId = json['_id']?? '';
rtvm.address = json['address'] ?? '';
rtvm.type_of_water = json['typeofwater '] ?? '';
rtvm.capacity = json['capacity'] ?? '';
rtvm.quantity = json['quantity']?? '';
rtvm.time = json['time'] ?? '';
rtvm.date = json['dateOfOrder'] ?? '';
rtvm.status = json['orderStatus'] ?? '';
rtvm.quoted_amount = json['price'].toString() ?? '';
rtvm.lng=json['longitude'] ?? 0.0;
rtvm.lat=json['latitude'] ?? 0.0;
// Split and trim
List<String> parts = rtvm.address.split(',').map((e) => e.trim()).toList();
// Usually, the locality is the part before the main city (Hyderabad)displayAddress = "";
if (parts.length >= 2) {
rtvm.displayAddress = parts[parts.length -4]; // "Banjara Hills"
}
// Distance in meters
rtvm.distanceInMeters = double.parse(
Geolocator.distanceBetween(
rtvm.lat,
rtvm.lng,
AppSettings.supplierLatitude,
AppSettings.supplierLongitude,
).toStringAsFixed(2),
);
// Distance in km
rtvm.distanceInKm = double.parse(
(rtvm.distanceInMeters / 1000).toStringAsFixed(2),
);
return rtvm;
}
Map<String, dynamic> toJson() => {
"boreName":this.building_name,
};
}

@ -0,0 +1,22 @@
class DriversModel {
String supplier_name='';
String driver_name='';
String status='';
String address='';
String deliveries='13';
String commision='';
List<String> availability= ['filled', 'available'];
DriversModel();
factory DriversModel.fromJson(Map<String, dynamic> json){
DriversModel rtvm = new DriversModel();
rtvm.supplier_name = json['supplier_name'] ?? '';
rtvm.driver_name = json['name'] ?? '';
rtvm.status = json['status'] ?? '';
rtvm.address = json['address'] ?? '';
return rtvm;
}
}

@ -5,10 +5,6 @@ import 'package:supplier_new/resources/source_location.dart';
import 'Fleet_1.dart';
// If you want to navigate on Continue, import your next page here.
// import 'fleet_1.dart';
void main() => runApp(const MaterialApp(home: FleetEmployees()));
class FleetEmployees extends StatefulWidget {
const FleetEmployees({super.key});
@ -81,22 +77,48 @@ class _FleetEmployeesState extends State<FleetEmployees> {
setState(() {});
}
void _addDriver() {
void _addDriver() async{
final ok = _formKey.currentState?.validate() ?? false;
setState(() {}); // ensure error texts render
if (!ok ||
selectedLicense == null ||
selectedExperience == null ||
selectedLicense!.isEmpty ||
selectedExperience!.isEmpty) {
if (selectedLicense == null || selectedExperience == null) {
if (selectedExperience == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Please select License & Experience")),
);
}
return;
}
_drivers.add(_buildPayload());
var payload = new Map<String, dynamic>();
payload["tankerName"] = _nameCtrl.text.toString();
payload["Name"] = _nameCtrl.text.toString();
payload["license_number"] =selectedLicense.toString();
payload["address"] = AppSettings.userAddress;
payload["supplier_name"] = AppSettings.userName;
payload["phone"] = _mobileCtrl.text.toString();
payload["alternativeContactNumber"] ='';
payload["years_of_experience"] =selectedExperience.toString();
payload["status"] = 'string';
bool tankStatus = await AppSettings.addDrivers(payload);
try {
if (tankStatus) {
AppSettings.longSuccessToast("Tanker Created Successfully");
_nameCtrl.text = '';
Navigator.pop(context,true);
}
else {
AppSettings.longFailedToast("Tanker Creation failed");
}
} catch (exception) {
print(exception);
}
_clearForm();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Driver added (${_drivers.length})")),

@ -2,11 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:supplier_new/common/settings.dart';
import 'employees.dart';
import 'fleet_1.dart';
void main() => runApp(const MaterialApp(home: FleetStep1Page()));
class FleetStep1Page extends StatefulWidget {
const FleetStep1Page({super.key});
@ -33,6 +28,12 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
];
String? selectedType;
final List<String> typeOfWater = [
"Bore Water",
"Drinking Water",
];
String? selectedTypeOfWater;
final List<String> featureOptions = [
"GPS",
"Stainless Steel",
@ -99,18 +100,38 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
setState(() {});
}
void _addTanker() {
void _addTanker() async{
final ok = _formKey.currentState?.validate() ?? false;
setState(() {}); // in case you show chip validation below labels
if (!ok || selectedFeatures.isEmpty) {
if (selectedFeatures.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Select at least one Tanker Feature")),
);
var payload = new Map<String, dynamic>();
payload["tankerName"] = _nameCtrl.text.toString();
payload["capacity"] = _capacityCtrl.text.toString();
payload["typeofwater"] =selectedTypeOfWater.toString();
payload["supplier_address"] = AppSettings.userAddress;
payload["supplier_name"] = AppSettings.userName;
payload["phoneNumber"] = AppSettings.phoneNumber;
payload["tanker_type"] =selectedType;
payload["license_plate"] =_plateCtrl.text.trim();
payload["manufacturing_year"] = _mfgYearCtrl.text.trim();
payload["insurance_exp_date"] = _insExpiryCtrl.text.trim();
bool tankStatus = await AppSettings.addTankers(payload);
try {
if (tankStatus) {
AppSettings.longSuccessToast("Tanker Created Successfully");
_nameCtrl.text = '';
_capacityCtrl.text = '';
Navigator.pop(context,true);
}
else {
AppSettings.longFailedToast("Tanker Creation failed");
}
return;
} catch (exception) {
print(exception);
}
_tankers.add(_buildPayload());
_clearForm();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Tanker added (${_tankers.length})")),
@ -267,21 +288,21 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
),
_LabeledField(
label: "Tanker Features *",
label: "Type of water *",
child: DropdownButtonFormField<String>(
value: selectedType,
items: tankerTypes
value: selectedTypeOfWater,
items: typeOfWater
.map((t) => DropdownMenuItem(value: t, child: Text(t)))
.toList(),
onChanged: (v) => setState(() => selectedType = v),
onChanged: (v) => setState(() => selectedTypeOfWater = v),
validator: (v) =>
v == null || v.isEmpty ? "Tanker Type is required" : null,
v == null || v.isEmpty ? "Type of water is required" : null,
isExpanded: true,
alignment: Alignment.centerLeft,
// <-- Hint: left-aligned, vertically centered by padding
hint: Text(
"Select Features",
"Select type of water",
style: fontTextStyle(
14, const Color(0xFF939495), FontWeight.w400),
),
@ -374,29 +395,72 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
const SizedBox(height: 12),
// Continue (primary)
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB), // purple bg
foregroundColor: Colors.white, // ripple/icon/text color
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24)),
/* SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB), // purple bg
foregroundColor: Colors.white, // ripple/icon/text color
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24)),
),
onPressed: () async{
if (_nameCtrl.text != '' &&
_capacityCtrl.text != '' &&
_plateCtrl.text != '') {
var payload = new Map<String, dynamic>();
payload["tankerName"] = _nameCtrl.text.toString();
payload["capacity"] = _capacityCtrl.text.toString();
payload["typeofwater"] =selectedTypeOfWater.toString();
payload["supplier_address"] = AppSettings.userAddress;
payload["supplier_name"] = AppSettings.userName;
bool tankStatus = await AppSettings.addTankers(payload);
try {
if (tankStatus) {
AppSettings.longSuccessToast(
"Tanker Created Successfully");
_nameCtrl.text = '';
//tankerPhoneNumberController.text = '';
_capacityCtrl.text = '';
//tankerAlternativePhoneNumberController.text='';
Navigator.pop(context);
*//* await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TankersView()),
);*//*
}
else {
AppSettings.longFailedToast("Tanker Creation failed");
}
} catch (exception) {
print(exception);
}
} else {
AppSettings.longFailedToast("Please enter valid details");
}
_nameCtrl.clear();
_capacityCtrl.text = "10,000";
_plateCtrl.text = "AB 05 H 4948";
_mfgYearCtrl.clear();
_insExpiryCtrl.clear();
selectedType = null;
selectedFeatures.clear();
},
child: Text(
"Continue",
style: fontTextStyle(
14, Colors.white, FontWeight.w400), // white text
),
),
onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(builder: (_) => const FleetStep2Page()),
// );
},
child: Text(
"Continue",
style: fontTextStyle(
14, Colors.white, FontWeight.w400), // white text
),
),
)
)*/
],
)
],

@ -1,5 +1,8 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/drivers_model.dart';
import 'package:supplier_new/resources/resources_sources.dart';
import 'fleet.dart';
import 'resources_drivers.dart';
@ -20,6 +23,35 @@ class ResourcesDriverScreen extends StatefulWidget {
class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
int selectedTab = 1; // default "Drivers"
String search = '';
bool isLoading = false;
List<DriversModel> driversList = [];
@override
void initState() {
// TODO: implement initState
super.initState();
_fetchDrivers();
}
Future<void> _fetchDrivers() async {
setState(() => isLoading = true);
try {
final response = await AppSettings.getDrivers();
final data = (jsonDecode(response)['data'] as List)
.map((e) => DriversModel.fromJson(e))
.toList();
if (!mounted) return;
setState(() {
driversList = data;
isLoading = false;
});
} catch (e) {
debugPrint("⚠️ Error fetching orders: $e");
setState(() => isLoading = false);
}
}
final List<Map<String, dynamic>> drivers = [
{
@ -80,7 +112,7 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text('09',
Text('${driversList.length.toString()}',
style: fontTextStyle(
24, const Color(0xFF0D3771), FontWeight.w500)),
const SizedBox(height: 6),
@ -167,16 +199,16 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
// Driver list
Expanded(
child: ListView.separated(
itemCount: drivers.length,
itemCount: driversList.length,
separatorBuilder: (_, __) => const SizedBox(height: 12),
itemBuilder: (context, idx) {
final d = drivers[idx];
final d = driversList[idx];
return DriverCard(
name: d['name'],
status: d['status'],
location: d['location'],
deliveries: d['deliveries'],
commission: d['commission'],
name: d.driver_name,
status: d.status,
location: d.address,
deliveries: int.parse(d.deliveries),
commission: d.commision,
);
},
),
@ -191,10 +223,18 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
// Floating Action Button
floatingActionButton: FloatingActionButton(
onPressed: () {
// TODO: Navigate to the next step/screen
// Navigator.push(context, MaterialPageRoute(builder: (_) => FleetEmployees()));
onPressed: () async{
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FleetEmployees(),
),
);
// If result indicates API reload
if (result == true) {
_fetchDrivers();
}
},
backgroundColor: Colors.black,
shape: const CircleBorder(),

@ -1,5 +1,9 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/tankers_model.dart';
import 'fleet.dart';
import 'resources_drivers.dart';
import 'resources_sources.dart';
@ -19,8 +23,50 @@ class ResourcesFleetScreen extends StatefulWidget {
}
class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
final _formKey = GlobalKey<FormState>();
// Controllers
final _nameCtrl = TextEditingController();
final _capacityCtrl = TextEditingController(); // hint-like
final _plateCtrl = TextEditingController();
final _mfgYearCtrl = TextEditingController();
final _insExpiryCtrl = TextEditingController();
String? _required(String? v, {String field = "This field"}) {
if (v == null || v.trim().isEmpty) return "$field is required";
return null;
}
int selectedTab = 0;
String search = '';
bool isLoading = false;
List<TankersModel> tankersList = [];
@override
void initState() {
// TODO: implement initState
super.initState();
_fetchTankers();
}
Future<void> _fetchTankers() async {
setState(() => isLoading = true);
try {
final response = await AppSettings.getTankers();
final data = (jsonDecode(response)['data'] as List)
.map((e) => TankersModel.fromJson(e))
.toList();
if (!mounted) return;
setState(() {
tankersList = data;
isLoading = false;
});
} catch (e) {
debugPrint("⚠️ Error fetching orders: $e");
setState(() => isLoading = false);
}
}
final List<Map<String, dynamic>> items = [
{
@ -60,14 +106,179 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
},
];
void openTankerSimpleSheet(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (context) {
return Padding(
padding: EdgeInsets.only(
left: 20,
right: 20,
top: 16,
bottom: MediaQuery.of(context).viewInsets.bottom + 20,
),
child: Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
children: [
// Tanker Name
Text("Tanker Name *",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600)),
const SizedBox(height: 6),
TextFormField(
controller: _nameCtrl,
validator: (v) => _required(v, field: "Tanker Name"),
decoration: const InputDecoration(
hintText: "Enter Tanker Name",
border: OutlineInputBorder(),
isDense: true,
),
textInputAction: TextInputAction.next,
),
const SizedBox(height: 14),
// Capacity
Text("Tanker Capacity (in L) *",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600)),
const SizedBox(height: 6),
TextFormField(
controller: _capacityCtrl,
validator: (v) => _required(v, field: "Tanker Capacity"),
decoration: InputDecoration(
hintText: "10,000 L",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9,]')),
],
textInputAction: TextInputAction.next,
),
const SizedBox(height: 14),
// License Plate
Text("License Plate *",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600)),
const SizedBox(height: 6),
TextFormField(
controller: _plateCtrl,
validator: (v) => _required(v, field: "License Plate"),
decoration: InputDecoration(
hintText: "AB 05 H 4948",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
textCapitalization: TextCapitalization.characters,
textInputAction: TextInputAction.next,
),
const SizedBox(height: 14),
// Manufacturing Year (optional)
Text("Manufacturing Year (opt)",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600)),
const SizedBox(height: 6),
TextFormField(
controller: _mfgYearCtrl,
decoration: InputDecoration(
hintText: "YYYY",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(4),
],
textInputAction: TextInputAction.next,
),
const SizedBox(height: 14),
// Insurance Expiry Date (optional)
Text("Insurance Expiry Date (opt)",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600)),
const SizedBox(height: 6),
TextFormField(
controller: _insExpiryCtrl,
readOnly: true,
decoration: InputDecoration(
hintText: "DD-MM-YYYY",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
suffixIcon: const Icon(Icons.calendar_today_outlined, size: 18),
),
onTap: () async {
final now = DateTime.now();
final picked = await showDatePicker(
context: context,
initialDate: now,
firstDate: DateTime(now.year - 30),
lastDate: DateTime(now.year + 30),
);
if (picked != null) {
final dd = picked.day.toString().padLeft(2, '0');
final mm = picked.month.toString().padLeft(2, '0');
final yyyy = picked.year.toString();
_insExpiryCtrl.text = "$dd-$mm-$yyyy";
}
},
),
const SizedBox(height: 20),
// Save button
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
),
onPressed: () async {
if (_formKey.currentState?.validate() != true) return;
// TODO: Replace with your save logic / API call
// Example:
// final ok = await saveTanker();
// if (ok) Navigator.pop(context, true);
Navigator.pop(context, true); // close sheet on success
},
child: Text(
"Save",
style: fontTextStyle(14, Colors.white, FontWeight.w600),
),
),
),
],
),
),
);
},
);
}
@override
Widget build(BuildContext context) {
final filtered = items.where((it) {
final filtered = tankersList.where((it) {
final q = search.trim().toLowerCase();
if (q.isEmpty) return true;
return it['title'].toLowerCase().contains(q) ||
it['subtitle'].toLowerCase().contains(q) ||
it['owner'].toLowerCase().contains(q);
return it.tanker_name.toLowerCase().contains(q);
}).toList();
return Scaffold(
@ -120,7 +331,7 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [Text('14', style: fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500,
children: [Text(tankersList.length.toString(), style: fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500,
),
),
@ -241,11 +452,12 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
itemBuilder: (context, idx) {
final it = filtered[idx];
return TankCard(
title: it['title'],
subtitle: it['subtitle'],
code: it['code'],
owner: it['owner'],
status: List<String>.from(it['status']),
title: it.tanker_name,
subtitle: it.type_of_water,
capacity: it.capacity,
code: it.license_plate,
owner: it.supplier_name,
status: List<String>.from(it.availability),
);
},
),
@ -258,9 +470,19 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// TODO: Navigate to the next step/screen
// Navigator.push(context, MaterialPageRoute(builder: (_) => const FleetStep1Page()));
onPressed: () async{
// openTankerSimpleSheet(context);
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FleetStep1Page(),
),
);
// If result indicates API reload
if (result == true) {
_fetchTankers();
}
},
backgroundColor: const Color(0xFF000000),
@ -310,6 +532,7 @@ class SmallMetricBox extends StatelessWidget {
class TankCard extends StatelessWidget {
final String title;
final String subtitle;
final String capacity;
final String code;
final String owner;
final List<String> status;
@ -318,6 +541,7 @@ class TankCard extends StatelessWidget {
super.key,
required this.title,
required this.subtitle,
required this.capacity,
required this.code,
required this.owner,
required this.status,
@ -392,13 +616,13 @@ class TankCard extends StatelessWidget {
}).toList(),
),
const SizedBox(height: 8),
Text(title,
Text (title,
style: fontTextStyle(
14, const Color(0xFF343637), FontWeight.w600)),
const SizedBox(height: 6),
Text(subtitle,
Text(subtitle+' - '+capacity+' L',
style: fontTextStyle(
10, const Color(0xFF515253), FontWeight.w600)),
10, const Color(0xFF343637), FontWeight.w600)),
const SizedBox(height: 10),
Row(
children: [

@ -7,11 +7,6 @@ import '../common/settings.dart';
import 'employees.dart';
import 'fleet.dart';
void main() => runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: ResourcesMainScreen(),
));
class ResourcesMainScreen extends StatefulWidget {
const ResourcesMainScreen({super.key});
@ -165,11 +160,11 @@ class _ResourcesMainScreenState extends State<ResourcesMainScreen>
],
),
),
floatingActionButton: AnimatedBuilder(
/*floatingActionButton: AnimatedBuilder(
animation: _tabController.animation!,
builder: (context, _) =>
_buildFAB(_tabController.index) ?? const SizedBox.shrink(),
),
),*/
);
}
}

@ -234,9 +234,15 @@ class _ResourcesSourceScreenState extends State<ResourcesSourceScreen> {
floatingActionButton: FloatingActionButton(
onPressed: () {
// TODO: Navigate to the next step/screen
// Navigator.push(context, MaterialPageRoute(builder: (_) => const SourceLocation()));
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const HeroMode(
enabled: false,
child: SourceLocation(),
),
),
);
},
backgroundColor: const Color(0xFF000000),
shape: const CircleBorder(),

@ -0,0 +1,29 @@
class TankersModel {
String tanker_name = '';
String address = '';
String type_of_water = '';
String capacity = '';
String dbId = '';
String status='';
String license_plate='';
String supplier_name='';
List<String> availability= ['filled', 'available'];
TankersModel();
factory TankersModel.fromJson(Map<String, dynamic> json){
TankersModel rtvm = new TankersModel();
rtvm.tanker_name = json['tankerName']?? '';
rtvm.dbId = json['_id']?? '';
rtvm.address = json['supplier_address']?? '';
rtvm.type_of_water = json['typeofwater'] ?? '';
rtvm.capacity = json['capacity'] ?? '';
rtvm.license_plate = json['license_plate'] ?? '';
rtvm.supplier_name = json['supplier_name'] ?? '';
return rtvm;
}
Map<String, dynamic> toJson() => {
"boreName":this.tanker_name,
};
}
Loading…
Cancel
Save