You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
9.2 KiB

import 'dart:convert';
3 months ago
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/orders/order_requests_model.dart';
import 'accept_order_requests.dart';
3 months ago
class OrderRequestsPage extends StatefulWidget {
const OrderRequestsPage({super.key});
@override
State<OrderRequestsPage> createState() => _OrderRequestsPageState();
}
class _OrderRequestsPageState extends State<OrderRequestsPage> {
final TextEditingController searchController = TextEditingController();
List<OrderRequestsModel> orderRequestsList = [];
bool isLoading = false;
3 months ago
@override
void initState() {
super.initState();
_fetchOrders();
}
Future<void> _fetchOrders() async {
setState(() => isLoading = true);
try {
final response = await AppSettings.getOrderRequestsFromUsers();
final data = (jsonDecode(response)['data'] as List)
.map((e) => OrderRequestsModel.fromJson(e))
.toList();
setState(() {
orderRequestsList = data;
isLoading = false;
});
} catch (e) {
debugPrint("⚠️ Error fetching orders: $e");
setState(() => isLoading = false);
}
}
/// 🔹 Helper to get status based on order time
Map<String, dynamic> getOrderStatus(String orderTimeStr) {
String status = "Invalid time";
Color color = Colors.grey;
if (orderTimeStr.isEmpty) return {"status": status, "color": color};
try {
final format = DateFormat("dd-MM-yyyy HH:mm");
final orderTime = format.parse(orderTimeStr);
final now = DateTime.now();
final difference = now.difference(orderTime);
if (difference.inHours < 2) {
status = "New";
color = const Color(0XFF1D7AFC); // Blue
} else if (difference.inHours < 24) {
int remaining = 24 - difference.inHours;
status = "Expires in ${remaining}h";
if (difference.inHours < 6) {
color = const Color(0XFFE56910); // Less urgent
} else {
color = const Color(0XFFE2483D); // More urgent
}
}
else {
status = "Expired";
color = const Color(0XFF757575); // Grey
}
} catch (e) {
debugPrint("⚠️ Error parsing time: $e");
}
return {"status": status, "color": color};
}
3 months ago
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppSettings.SupplierAppBarWithHelpAction('Order Requests', context),
3 months ago
body: Padding(
padding: const EdgeInsets.all(16.0),
3 months ago
child: Column(
children: [
/// 🔹 Search Bar
_buildSearchBar(),
3 months ago
const SizedBox(height: 16),
/// 🔹 Orders List
3 months ago
Expanded(
child: isLoading
? const Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: orderRequestsList.length,
itemBuilder: (context, index) {
final order = orderRequestsList[index];
final statusMap = getOrderStatus(order.time ?? "");
final status = statusMap['status'];
final color = statusMap['color'];
3 months ago
final cardModel = OrderCardModel(
status: status,
statusColor: color,
title: order.building_name ?? "",
location: order.displayAddress ?? "",
description: "${order.capacity ?? ''} - ${order.type_of_water ?? ''}",
price: "${AppSettings.formDouble(order.quoted_amount) ?? ''}",
);
final isExpired = status.toLowerCase() == "expired";
final card = OrderCard(order: cardModel);
return isExpired
? card
: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => AcceptOrderRequests(order: order),
),
);
},
child: card,
);
},
3 months ago
),
),
],
),
),
);
}
Widget _buildSearchBar() {
return Row(
children: [
Expanded(
child: Container(
height: 42,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(22),
border: Border.all(color: const Color(0XFF939495)),
),
child: TextField(
controller: searchController,
decoration: InputDecoration(
hintText: "Search",
hintStyle: fontTextStyle(16, const Color(0XFF646566), FontWeight.w400),
prefixIcon: SizedBox(
height: 20,
width: 20,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
'images/search.png',
fit: BoxFit.contain,
),
),
),
border: InputBorder.none,
contentPadding: const EdgeInsets.symmetric(vertical: 10),
),
),
),
),
const SizedBox(width: 10),
Container(
height: 42,
width: 42,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade300),
color: Color(0XFFF5F6F6),
),
child: IconButton(
icon: Image.asset(
'images/filter.png', // your image path
height: 20,
width: 20,
fit: BoxFit.contain,
),
onPressed: () {
// Your onPressed action
},
)
),
Container(
height: 42,
width: 42,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade300),
color: Color(0XFFF5F6F6),
),
child: IconButton(
icon: Image.asset(
'images/sort.png', // your image path
height: 20,
width: 20,
fit: BoxFit.contain,
),
onPressed: () {
// Your onPressed action
},
)
),
],
);
}
3 months ago
}
/// 🔹 UI Model for rendering OrderCard
class OrderCardModel {
3 months ago
final String status;
final Color statusColor;
3 months ago
final String title;
final String location;
final String description;
final String price;
OrderCardModel({
3 months ago
required this.status,
required this.statusColor,
3 months ago
required this.title,
required this.location,
required this.description,
required this.price,
});
}
/// 🔹 Card widget
3 months ago
class OrderCard extends StatelessWidget {
final OrderCardModel order;
3 months ago
const OrderCard({super.key, required this.order});
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Color(0XFFF6F6F6),
3 months ago
borderRadius: BorderRadius.circular(12),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
3 months ago
children: [
/// 🔹 Left content
3 months ago
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// Status chip
3 months ago
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
3 months ago
decoration: BoxDecoration(
color: Color(0XFFF6F6F6),
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: order.statusColor,
width: 0.5,
),
3 months ago
),
child: Text(
order.status,
style: fontTextStyle(12, order.statusColor, FontWeight.w500)
3 months ago
),
),
SizedBox(height:MediaQuery.of(context).size.height * .008,),
3 months ago
/// Title
3 months ago
Text(
order.title,
style: fontTextStyle(16, Color(0XFF2D2E30), FontWeight.w600)
3 months ago
),
/// Location
3 months ago
Text(
order.location,
style: fontTextStyle(10, Color(0XFF939495), FontWeight.w400)
3 months ago
),
const SizedBox(height: 4),
/// Description
3 months ago
Text(
order.description,
style: fontTextStyle(14, Color(0XFF8270DB), FontWeight.w500)
3 months ago
),
],
),
),
/// 🔹 Price
3 months ago
Text(
order.price,
style: fontTextStyle(16, Color(0XFF444444), FontWeight.w600)
3 months ago
),
],
),
);
}
}