Files
Fondex-Driver/lib/controllers/parcel_search_controller.dart
2025-12-08 23:25:00 +05:00

194 lines
7.4 KiB
Dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:driver/constant/constant.dart';
import 'package:driver/constant/send_notification.dart';
import 'package:driver/models/parcel_category.dart';
import 'package:driver/models/parcel_order_model.dart';
import 'package:driver/models/user_model.dart';
import 'package:driver/utils/fire_store_utils.dart';
import 'package:driver/widget/geoflutterfire/src/geoflutterfire.dart';
import 'package:driver/widget/geoflutterfire/src/models/point.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' as latlong;
import 'package:intl/intl.dart';
class ParcelSearchController extends GetxController {
// Implement parcel search logic here
RxBool isLoading = true.obs;
final Rx<TextEditingController> sourceTextEditController = TextEditingController().obs;
final Rx<TextEditingController> destinationTextEditController = TextEditingController().obs;
final Rx<TextEditingController> dateTimeTextEditController = TextEditingController().obs;
// Journey
final Rx<LatLng?> departureLatLong = Rx<LatLng?>(null);
final Rx<LatLng?> destinationLatLong = Rx<LatLng?>(null);
final Rx<latlong.LatLng?> departureLatLongOsm = Rx<latlong.LatLng?>(null);
final Rx<latlong.LatLng?> destinationLatLongOsm = Rx<latlong.LatLng?>(null);
Rx<DateTime> pickUpDateTime = DateTime.now().obs;
RxList<ParcelOrderModel> parcelList = <ParcelOrderModel>[].obs;
Rx<UserModel> driverModel = UserModel().obs;
Rx<UserModel> ownerModel = UserModel().obs;
@override
void onInit() {
isLoading.value = false;
driverModel.value = Constant.userModel!;
// TODO: implement onInit
if (driverModel.value.ownerId != null && driverModel.value.ownerId!.isNotEmpty) {
getOwnerDetails(driverModel.value.ownerId!);
}
loadParcelCategories();
super.onInit();
}
String formatDate(Timestamp timestamp) {
final dateTime = timestamp.toDate();
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
}
Future<void> getOwnerDetails(String ownerId) async {
ownerModel.value = await FireStoreUtils.getUserProfile(ownerId) ?? UserModel();
update();
}
void searchParcel() {
searchParcelsOnce(
srcLat: Constant.selectedMapType == 'osm' ? departureLatLongOsm.value!.latitude : departureLatLong.value!.latitude,
srcLng: Constant.selectedMapType == 'osm' ? departureLatLongOsm.value!.longitude : departureLatLong.value!.longitude,
destLat: Constant.selectedMapType == 'osm' ? destinationLatLongOsm.value?.latitude : destinationLatLong.value?.latitude,
destLng: Constant.selectedMapType == 'osm' ? destinationLatLongOsm.value?.longitude : destinationLatLong.value?.longitude,
date: pickUpDateTime.value, // required
).then(
(event) {
parcelList.value = event;
update();
},
);
}
Future<void> acceptParcelBooking(ParcelOrderModel parcelBookingData) async {
parcelBookingData.status = Constant.driverAccepted;
parcelBookingData.driver = Constant.userModel;
parcelBookingData.driverId = Constant.userModel!.id;
parcelBookingData.receiverPickupDateTime = Timestamp.fromDate(DateTime.now());
await FireStoreUtils.setParcelOrder(parcelBookingData);
Map<String, dynamic> payLoad = <String, dynamic>{"type": "parcel_order", "orderId": parcelBookingData.id};
await SendNotification.sendFcmMessage(Constant.parcelAccepted, parcelBookingData.author!.fcmToken.toString(), payLoad);
Get.back(result: true);
}
String calculateParcelTotalAmountBooking(ParcelOrderModel parcelBookingData) {
String subTotal = parcelBookingData.subTotal.toString();
String discount = parcelBookingData.discount ?? "0.0";
String taxAmount = "0.0";
for (var element in parcelBookingData.taxSetting!) {
taxAmount = (double.parse(taxAmount) + Constant.calculateTax(amount: (double.parse(subTotal) - double.parse(discount)).toString(), taxModel: element))
.toStringAsFixed(int.tryParse(Constant.currencyModel!.decimalDigits.toString()) ?? 2);
}
return ((double.parse(subTotal) - (double.parse(discount))) + double.parse(taxAmount)).toStringAsFixed(int.tryParse(Constant.currencyModel!.decimalDigits.toString()) ?? 2);
}
Future<List<ParcelOrderModel>> searchParcelsOnce({
required double srcLat,
required double srcLng,
double? destLat,
double? destLng,
required DateTime date,
}) async {
final ref = FireStoreUtils.fireStore.collection("parcel_orders").where("sectionId",isEqualTo: driverModel.value.sectionId).where('status', isEqualTo: "Order Placed");
GeoFirePoint center = Geoflutterfire().point(latitude: srcLat, longitude: srcLng);
// Take first snapshot from the stream
final docs = await Geoflutterfire()
.collection(collectionRef: ref)
.within(
center: center,
radius: double.parse(Constant.parcelRadius),
field: "sourcePoint",
strictMode: true,
)
.first;
final filtered = docs.where((doc) {
final data = doc.data() as Map<String, dynamic>;
if (data['senderPickupDateTime'] == null) return false;
final driverZoneId = driverModel.value.zoneId;
// ✅ Check both sender and receiver zone
final senderZoneId = data['senderZoneId'];
final receiverZoneId = data['receiverZoneId'];
if (senderZoneId == null && receiverZoneId == null) return false;
// Match if driver zone equals either sender or receiver zone
final zoneMatch = (senderZoneId == driverZoneId) || (receiverZoneId == driverZoneId);
if (!zoneMatch) return false;
// ✅ Date check
final Timestamp ts = data['senderPickupDateTime'];
final orderDate = ts.toDate().toLocal();
final inputDate = date.toLocal();
bool sameDay = orderDate.year == inputDate.year && orderDate.month == inputDate.month && orderDate.day == inputDate.day;
if (!sameDay) return false;
// ✅ Destination check
if (destLat != null && destLng != null && data['receiverLatLong'] != null) {
final rec = data['receiverLatLong'];
double recLat = rec['latitude'];
double recLng = rec['longitude'];
double distance = Geoflutterfire().point(latitude: destLat, longitude: destLng).kmDistance(lat: recLat, lng: recLng);
if (distance > double.parse(Constant.parcelRadius)) return false;
}
return true;
}).toList();
return filtered.map((e) => ParcelOrderModel.fromJson(e.data()!)).toList();
}
Future<void> pickDateTime() async {
DateTime? date = await showDatePicker(
context: Get.context!,
initialDate: pickUpDateTime.value,
firstDate: DateTime.now(),
lastDate: DateTime(2100),
);
if (date == null) return;
pickUpDateTime.value = date;
dateTimeTextEditController.value.text = DateFormat('dd-MMM-yyyy').format(date);
update();
}
RxList<ParcelCategory> parcelCategory = <ParcelCategory>[].obs;
void loadParcelCategories() async {
final categories = await FireStoreUtils.getParcelServiceCategory();
parcelCategory.value = categories;
}
ParcelCategory? getSelectedCategory(ParcelOrderModel parcelOrder) {
try {
return parcelCategory.firstWhere(
(cat) => cat.title?.toLowerCase().trim() == parcelOrder.parcelType?.toLowerCase().trim(),
orElse: () => ParcelCategory(),
);
} catch (e) {
return null;
}
}
}