INFRA: Set Up Project.
This commit is contained in:
21
lib/constant/assets.dart
Normal file
21
lib/constant/assets.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
class AppAssets {
|
||||
static const assetFromImagesPath = 'assets/images/';
|
||||
static const assetFromIconsPath = 'assets/icons/';
|
||||
|
||||
//images
|
||||
static const onBoardingBG = '${assetFromImagesPath}onboarding_bg.png';
|
||||
static const imgOnBoarding = '${assetFromImagesPath}img_onboarding.png';
|
||||
|
||||
|
||||
//icons
|
||||
static const icAppLogo = '${assetFromIconsPath}app_logo.png';
|
||||
static const icArrowLeft = '${assetFromIconsPath}ic_arrow_left.png';
|
||||
static const icMessage = '${assetFromIconsPath}ic_message.png';
|
||||
static const icIndia = '${assetFromIconsPath}ic_india.png';
|
||||
static const icArrowsClockwise = '${assetFromIconsPath}ic_arrows_clockwise.png';
|
||||
static const icLocation = '${assetFromIconsPath}ic_location.png';
|
||||
static const icPickup = '${assetFromIconsPath}ic_pickup.png';
|
||||
static const icPlus = '${assetFromIconsPath}plus.svg';
|
||||
|
||||
|
||||
}
|
||||
61
lib/constant/collection_name.dart
Normal file
61
lib/constant/collection_name.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
class CollectionName {
|
||||
static const String users = "users";
|
||||
static const String zone = "zone";
|
||||
static const String onBoarding = "on_boarding";
|
||||
static const String referral = "referral";
|
||||
static const String sections = "sections";
|
||||
static const String bookedTable = "booked_table";
|
||||
static const String chatDriver = "chat_driver";
|
||||
static const String chatStore = "chat_store";
|
||||
static const String coupons = "coupons";
|
||||
static const String currencies = "currencies";
|
||||
static const String documents = "documents";
|
||||
static const String documentsVerify = "documents_verify";
|
||||
static const String driverPayouts = "driver_payouts";
|
||||
static const String dynamicNotification = "dynamic_notification";
|
||||
static const String emailTemplates = "email_templates";
|
||||
static const String favoriteItem = "favorite_item";
|
||||
static const String favoriteVendor = "favorite_vendor";
|
||||
static const String giftCards = "gift_cards";
|
||||
static const String giftPurchases = "gift_purchases";
|
||||
static const String bannerItems = "banner_items";
|
||||
static const String notifications = "notifications";
|
||||
static const String payouts = "payouts";
|
||||
static const String vendorOrders = "vendor_orders";
|
||||
static const String reviewAttributes = "review_attributes";
|
||||
static const String settings = "settings";
|
||||
static const String story = "story";
|
||||
static const String tax = "tax";
|
||||
static const String vendorAttributes = "vendor_attributes";
|
||||
static const String vendorCategories = "vendor_categories";
|
||||
static const String vendorProducts = "vendor_products";
|
||||
static const String vendors = "vendors";
|
||||
static const String wallet = "wallet";
|
||||
static const String withdrawMethod = "withdraw_method";
|
||||
static const String advertisements = "advertisements";
|
||||
static const String cashback = "cashback";
|
||||
static const String cashbackRedeem = "cashback_redeem";
|
||||
static const String currency = 'currencies';
|
||||
static const String brands = 'brands';
|
||||
static const String parcelCategory = 'parcel_categories';
|
||||
static const String parcelWeight = 'parcel_weight';
|
||||
static const String parcelOrders = "parcel_orders";
|
||||
static const String vehicleType = 'vehicle_type';
|
||||
static const String rides = 'rides';
|
||||
static const String popularDestinations = 'popular_destinations';
|
||||
static const String providerCategories = 'provider_categories';
|
||||
static const String providersServices = 'providers_services';
|
||||
static const String favoriteService = 'favorite_service';
|
||||
static const String itemsReview = 'items_review';
|
||||
static const String providersCoupons = 'providers_coupons';
|
||||
static const String providerOrders = 'provider_orders';
|
||||
static const String providersWorkers = 'providers_workers';
|
||||
static const String promos = 'promos';
|
||||
static const String parcelCoupons = 'parcel_coupons';
|
||||
static const String rentalVehicleType = 'rental_vehicle_type';
|
||||
static const String rentalPackages = 'rental_packages';
|
||||
static const String rentalCoupons = 'rental_coupons';
|
||||
static const String rentalOrders = 'rental_orders';
|
||||
static const String sos = 'SOS';
|
||||
static const String complaints = 'complaints';
|
||||
}
|
||||
779
lib/constant/constant.dart
Normal file
779
lib/constant/constant.dart
Normal file
@@ -0,0 +1,779 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/controllers/theme_controller.dart';
|
||||
import 'package:customer/models/currency_model.dart';
|
||||
import 'package:customer/models/order_model.dart';
|
||||
import 'package:customer/models/tax_model.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:customer/models/zone_model.dart';
|
||||
import 'package:customer/themes/app_them_data.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:firebase_storage/firebase_storage.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:geolocator/geolocator.dart' as geolocator;
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:mailer/mailer.dart';
|
||||
import 'package:mailer/smtp_server.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../models/cart_product_model.dart';
|
||||
import '../models/coupon_model.dart';
|
||||
import '../models/email_template_model.dart';
|
||||
import '../models/language_model.dart';
|
||||
import '../models/mail_setting.dart';
|
||||
import '../models/section_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
import '../widget/permission_dialog.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
RxList<CartProductModel> cartItem = <CartProductModel>[].obs;
|
||||
|
||||
class Constant {
|
||||
static const userPlaceHolder = "assets/images/user_placeholder.png";
|
||||
|
||||
static String senderId = '';
|
||||
static String jsonNotificationFileURL = '';
|
||||
static String appVersion = '';
|
||||
static List<TaxModel> taxList = [];
|
||||
static String? country = "";
|
||||
static String? selectedMapType = "";
|
||||
static String? websiteUrl = '';
|
||||
static MailSettings? mailSettings;
|
||||
static bool isSubscriptionModelApplied = false;
|
||||
static CurrencyModel? currencyData;
|
||||
static SectionModel? sectionConstantModel;
|
||||
static geolocator.Position? currentLocation;
|
||||
|
||||
static String cabServiceType = "cab-service";
|
||||
static String parcelServiceType = "parcel-service";
|
||||
|
||||
static bool isZoneAvailable = false;
|
||||
static ZoneModel? selectedZone;
|
||||
static List<ZoneModel> zoneList = [];
|
||||
|
||||
static List sectionColor = [
|
||||
[Color(0xFFFEF8E7), Color(0xFFF7CD59)],
|
||||
[Color(0xFFEEEBF9), Color(0xFF8F7CD8)],
|
||||
[Color(0xFFFFF8E5), Color(0xFFF7CD59)],
|
||||
[Color(0xFFF5E5FF), Color(0xFFCC80FF)],
|
||||
[Color(0xFFFAEBEB), Color(0xFFDB7474)],
|
||||
[Color(0xFFE5F9FF), Color(0xFF72DEFF)],
|
||||
[Color(0xFFEFF5F1), Color(0xFFADCEB7)],
|
||||
[Color(0xFFEAFBF1), Color(0xFF85E5AE)],
|
||||
[Color(0xFFE7F8FE), Color(0xFF529DB6)],
|
||||
[Color(0xFFEEEBF9), Color(0xFF8F7CD8)],
|
||||
];
|
||||
|
||||
static List colorList = [
|
||||
Color(0xFFFFBC99),
|
||||
const Color(0xFFCABDFF),
|
||||
const Color(0xFFB1E5FC),
|
||||
const Color(0xFFB5EBCD),
|
||||
const Color(0xFFFFD88D),
|
||||
const Color(0xFFCBEBA4),
|
||||
const Color(0xFFFB9B9B),
|
||||
const Color(0xFFF8B0ED),
|
||||
const Color(0xFFAFC6FF),
|
||||
];
|
||||
|
||||
static String userRoleDriver = 'driver';
|
||||
static String userRoleCustomer = 'customer';
|
||||
static String userRoleVendor = 'vendor';
|
||||
|
||||
static ShippingAddress selectedLocation = ShippingAddress();
|
||||
static UserModel? userModel;
|
||||
static const globalUrl = "https://Replace_your_domain/";
|
||||
|
||||
static String mapAPIKey = "";
|
||||
static String placeHolderImage = "";
|
||||
static String defaultCountryCode = "";
|
||||
static String defaultCountry = "";
|
||||
|
||||
static bool isCashbackActive = false;
|
||||
static bool isEnableOTPTripStart = false;
|
||||
static bool isEnableOTPTripStartForRental = false;
|
||||
static bool isMaintenanceModeForCustomer = false;
|
||||
|
||||
static String distanceType = "km";
|
||||
|
||||
static String googlePlayLink = "";
|
||||
static String appStoreLink = "";
|
||||
static String termsAndConditions = "";
|
||||
static String privacyPolicy = "";
|
||||
static String supportURL = "";
|
||||
static String minimumAmountToDeposit = "0.0";
|
||||
static String minimumAmountToWithdrawal = "0.0";
|
||||
static bool? walletSetting = true;
|
||||
static bool? storyEnable = true;
|
||||
static bool? specialDiscountOffer = true;
|
||||
|
||||
static const String orderPlaced = "Order Placed";
|
||||
static const String orderAccepted = "Order Accepted";
|
||||
static const String orderRejected = "Order Rejected";
|
||||
static const String orderCancelled = "Order Cancelled";
|
||||
static const String driverPending = "Driver Pending";
|
||||
static const String driverRejected = "Driver Rejected";
|
||||
static const String driverAccepted = 'Driver Accepted';
|
||||
static const String orderShipped = "Order Shipped";
|
||||
static const String orderInTransit = "In Transit";
|
||||
static const String orderCompleted = "Order Completed";
|
||||
|
||||
static const String orderAssigned = "Order Assigned";
|
||||
static const String orderOngoing = "Order Ongoing";
|
||||
static const String bookingPlaced = "booking_placed";
|
||||
|
||||
static CurrencyModel? currencyModel;
|
||||
static List<VendorModel>? restaurantList = [];
|
||||
|
||||
static String walletTopup = "wallet_topup";
|
||||
static String newVendorSignup = "new_vendor_signup";
|
||||
static String payoutRequestStatus = "payout_request_status";
|
||||
static String payoutRequest = "payout_request";
|
||||
|
||||
static String newOrderPlaced = "order_placed";
|
||||
static String scheduleOrder = "schedule_order";
|
||||
static String dineInPlaced = "dinein_placed";
|
||||
static String dineInCanceled = "dinein_canceled";
|
||||
static String dineinAccepted = "dinein_accepted";
|
||||
static String restaurantRejected = "restaurant_rejected";
|
||||
static String driverCompleted = "driver_completed";
|
||||
static String restaurantAccepted = "restaurant_accepted";
|
||||
static String takeawayCompleted = "takeaway_completed";
|
||||
static String newParcelBook = "new_parcel_book";
|
||||
static String newOnDemandBook = "new_ondemand_book";
|
||||
|
||||
// static String selectedMapType = 'osm';
|
||||
static String? mapType = "google";
|
||||
|
||||
static String? we = "google";
|
||||
|
||||
static bool isEnableAdsFeature = true;
|
||||
static bool isSelfDeliveryFeature = false;
|
||||
|
||||
static double getDoubleVal(dynamic input) {
|
||||
if (input == null) return 0.1;
|
||||
if (input is int) return input.toDouble();
|
||||
if (input is double) return input;
|
||||
return 0.1;
|
||||
}
|
||||
|
||||
static bool checkZoneCheck(double latitude, double longLatitude) {
|
||||
bool isZoneAvailable = false;
|
||||
for (var element in Constant.zoneList) {
|
||||
if (Constant.isPointInPolygon(LatLng(latitude, longLatitude), element.area!)) {
|
||||
isZoneAvailable = true;
|
||||
break;
|
||||
} else {
|
||||
isZoneAvailable = false;
|
||||
}
|
||||
}
|
||||
return isZoneAvailable;
|
||||
}
|
||||
|
||||
static String? getZoneId(double latitude, double longLatitude) {
|
||||
String? zoneId;
|
||||
for (var element in Constant.zoneList) {
|
||||
if (Constant.isPointInPolygon(LatLng(latitude, longLatitude), element.area!)) {
|
||||
zoneId = element.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return zoneId;
|
||||
}
|
||||
|
||||
static String getReferralCode() {
|
||||
var rng = Random();
|
||||
return (rng.nextInt(900000) + 100000).toString(); // 6 digit
|
||||
}
|
||||
|
||||
static Future<void> checkPermission({required BuildContext context, required Function() onTap}) async {
|
||||
LocationPermission permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
}
|
||||
if (permission == LocationPermission.denied) {
|
||||
ShowToastDialog.showToast("You have to allow location permission to use your location");
|
||||
} else if (permission == LocationPermission.deniedForever) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return const PermissionDialog();
|
||||
},
|
||||
);
|
||||
} else {
|
||||
onTap();
|
||||
}
|
||||
}
|
||||
|
||||
static bool get isRtl {
|
||||
final locale = Get.locale ?? Get.deviceLocale ?? const Locale('en');
|
||||
return Bidi.isRtlLanguage(locale.languageCode);
|
||||
}
|
||||
|
||||
static bool isExpire(VendorModel venderModel) {
|
||||
bool isPlanExpire = false;
|
||||
if (venderModel.subscriptionPlan?.id != null) {
|
||||
if (venderModel.subscriptionExpiryDate == null) {
|
||||
if (venderModel.subscriptionPlan?.expiryDay == '-1') {
|
||||
isPlanExpire = false;
|
||||
} else {
|
||||
isPlanExpire = true;
|
||||
}
|
||||
} else {
|
||||
DateTime expiryDate = venderModel.subscriptionExpiryDate!.toDate();
|
||||
isPlanExpire = expiryDate.isBefore(DateTime.now());
|
||||
}
|
||||
} else {
|
||||
isPlanExpire = true;
|
||||
}
|
||||
return isPlanExpire;
|
||||
}
|
||||
|
||||
static bool isExpireDate({required bool expiryDay, Timestamp? subscriptionExpiryDate}) {
|
||||
bool isPlanExpire = false;
|
||||
if (expiryDay == true) {
|
||||
isPlanExpire = false;
|
||||
} else {
|
||||
if (subscriptionExpiryDate != null) {
|
||||
DateTime expiryDate = subscriptionExpiryDate.toDate();
|
||||
isPlanExpire = expiryDate.isBefore(DateTime.now());
|
||||
} else {
|
||||
isPlanExpire = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isPlanExpire;
|
||||
}
|
||||
|
||||
static Future<void> showProgress(String message, bool isDismissible) async {
|
||||
ShowToastDialog.showLoader("$message ");
|
||||
}
|
||||
|
||||
static void hideProgress() {
|
||||
ShowToastDialog.closeLoader();
|
||||
}
|
||||
|
||||
static String amountShow({required String? amount}) {
|
||||
if (currencyModel!.symbolatright == true) {
|
||||
return "${double.parse(amount.toString()).toStringAsFixed(currencyModel?.decimal ?? 0)} ${currencyModel!.symbol.toString()}";
|
||||
} else {
|
||||
return "${currencyModel!.symbol.toString()} ${amount == null || amount.isEmpty ? "0.0" : double.parse(amount.toString()).toStringAsFixed(currencyModel?.decimal ?? 0)}";
|
||||
}
|
||||
}
|
||||
|
||||
static Color statusColor({required String? status}) {
|
||||
if (status == orderPlaced) {
|
||||
return AppThemeData.ecommerce300;
|
||||
} else if (status == orderAccepted || status == orderCompleted) {
|
||||
return AppThemeData.success400;
|
||||
} else if (status == orderRejected) {
|
||||
return AppThemeData.danger300;
|
||||
} else {
|
||||
return AppThemeData.warning300;
|
||||
}
|
||||
}
|
||||
|
||||
static Color statusText({required String? status}) {
|
||||
if (status == orderPlaced) {
|
||||
return AppThemeData.grey50;
|
||||
} else if (status == orderAccepted || status == orderCompleted) {
|
||||
return AppThemeData.grey50;
|
||||
} else if (status == orderRejected) {
|
||||
return AppThemeData.grey50;
|
||||
} else {
|
||||
return AppThemeData.grey900;
|
||||
}
|
||||
}
|
||||
|
||||
static String productCommissionPrice(VendorModel vendorModel, String price) {
|
||||
String commission = "0";
|
||||
if (sectionConstantModel!.adminCommision!.isEnabled == true) {
|
||||
if (vendorModel.adminCommission == null) {
|
||||
if (sectionConstantModel!.adminCommision!.commissionType!.toLowerCase() == "Percent".toLowerCase() ||
|
||||
sectionConstantModel!.adminCommision!.commissionType?.toLowerCase() == "Percentage".toLowerCase()) {
|
||||
commission = (double.parse(price) + (double.parse(price) * double.parse(sectionConstantModel!.adminCommision!.amount.toString()) / 100)).toString();
|
||||
} else {
|
||||
commission = (double.parse(price) + double.parse(sectionConstantModel!.adminCommision!.amount.toString())).toString();
|
||||
}
|
||||
} else {
|
||||
if (vendorModel.adminCommission!.commissionType!.toLowerCase() == "Percent".toLowerCase() || vendorModel.adminCommission!.commissionType?.toLowerCase() == "Percentage".toLowerCase()) {
|
||||
commission = (double.parse(price) + (double.parse(price) * double.parse(vendorModel.adminCommission!.amount.toString()) / 100)).toString();
|
||||
} else {
|
||||
commission = (double.parse(price) + double.parse(vendorModel.adminCommission!.amount.toString())).toString();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
commission = price;
|
||||
}
|
||||
|
||||
return commission;
|
||||
}
|
||||
|
||||
static double calculateTax({String? amount, TaxModel? taxModel}) {
|
||||
double taxAmount = 0.0;
|
||||
if (taxModel != null && taxModel.enable == true) {
|
||||
if (taxModel.type == "fix") {
|
||||
taxAmount = double.parse(taxModel.tax.toString());
|
||||
} else {
|
||||
taxAmount = (double.parse(amount.toString()) * double.parse(taxModel.tax!.toString())) / 100;
|
||||
}
|
||||
}
|
||||
return taxAmount;
|
||||
}
|
||||
|
||||
static double calculateDiscount({String? amount, CouponModel? offerModel}) {
|
||||
double taxAmount = 0.0;
|
||||
if (offerModel != null) {
|
||||
if (offerModel.discountType == "Percentage" || offerModel.discountType == "percentage") {
|
||||
taxAmount = (double.parse(amount.toString()) * double.parse(offerModel.discount.toString())) / 100;
|
||||
} else {
|
||||
taxAmount = double.parse(offerModel.discount.toString());
|
||||
}
|
||||
}
|
||||
return taxAmount;
|
||||
}
|
||||
|
||||
static String calculateReview({required String? reviewCount, required String? reviewSum}) {
|
||||
if (0 == double.parse(reviewSum.toString()) && 0 == double.parse(reviewSum.toString())) {
|
||||
return "0";
|
||||
}
|
||||
return (double.parse(reviewSum.toString()) / double.parse(reviewCount.toString())).toStringAsFixed(1);
|
||||
}
|
||||
|
||||
static String getUuid() {
|
||||
return const Uuid().v4();
|
||||
}
|
||||
|
||||
static Widget loader() {
|
||||
return Center(child: CircularProgressIndicator(color: AppThemeData.primary300));
|
||||
}
|
||||
|
||||
static Widget showEmptyView({required String message}) {
|
||||
final themeController = Get.find<ThemeController>();
|
||||
final isDark = themeController.isDark.value;
|
||||
return Center(child: Text(message, style: TextStyle(fontFamily: AppThemeData.fontFamily, fontSize: 18, color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900)));
|
||||
}
|
||||
|
||||
static String maskingString(String documentId, int maskingDigit) {
|
||||
String maskedDigits = documentId;
|
||||
for (int i = 0; i < documentId.length - maskingDigit; i++) {
|
||||
maskedDigits = maskedDigits.replaceFirst(documentId[i], "*");
|
||||
}
|
||||
return maskedDigits;
|
||||
}
|
||||
|
||||
String? validateRequired(String? value, String type) {
|
||||
if (value!.isEmpty) {
|
||||
return '$type required';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String? validateEmail(String? value) {
|
||||
String pattern = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
|
||||
RegExp regExp = RegExp(pattern);
|
||||
if (value == null || value.isEmpty) {
|
||||
return "Email is Required";
|
||||
} else if (!regExp.hasMatch(value)) {
|
||||
return "Invalid Email";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String getDistance({required String lat1, required String lng1, required String lat2, required String lng2}) {
|
||||
double distance;
|
||||
double distanceInMeters = Geolocator.distanceBetween(double.parse(lat1), double.parse(lng1), double.parse(lat2), double.parse(lng2));
|
||||
if (distanceType == "miles") {
|
||||
distance = distanceInMeters / 1609;
|
||||
} else {
|
||||
distance = distanceInMeters / 1000;
|
||||
}
|
||||
return distance.toStringAsFixed(2);
|
||||
}
|
||||
|
||||
bool hasValidUrl(String? value) {
|
||||
String pattern = r'(http|https)://[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?';
|
||||
RegExp regExp = RegExp(pattern);
|
||||
if (value == null || value.isEmpty) {
|
||||
return false;
|
||||
} else if (!regExp.hasMatch(value)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static Future<String> uploadUserImageToFireStorage(File image, String filePath, String fileName) async {
|
||||
Reference upload = FirebaseStorage.instance.ref().child('$filePath/$fileName');
|
||||
UploadTask uploadTask = upload.putFile(image);
|
||||
var downloadUrl = await (await uploadTask.whenComplete(() {})).ref.getDownloadURL();
|
||||
return downloadUrl.toString();
|
||||
}
|
||||
|
||||
static Future<void> makePhoneCall(String phoneNumber) async {
|
||||
final Uri launchUri = Uri(scheme: 'tel', path: phoneNumber);
|
||||
await launchUrl(launchUri);
|
||||
}
|
||||
|
||||
Future<void> launchURL(Uri url) async {
|
||||
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
|
||||
throw Exception('Could not launch $url');
|
||||
}
|
||||
}
|
||||
|
||||
Future<Uint8List> getBytesFromAsset(String path, int width) async {
|
||||
ByteData data = await rootBundle.load(path);
|
||||
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
|
||||
ui.FrameInfo fi = await codec.getNextFrame();
|
||||
return (await fi.image.toByteData(format: ui.ImageByteFormat.png))!.buffer.asUint8List();
|
||||
}
|
||||
|
||||
static Future<TimeOfDay?> selectTime(context) async {
|
||||
FocusScope.of(context).requestFocus(FocusNode()); //remove focus
|
||||
TimeOfDay? newTime = await showTimePicker(context: context, initialTime: TimeOfDay.now());
|
||||
if (newTime != null) {
|
||||
return newTime;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<DateTime?> selectDate(context) async {
|
||||
DateTime? pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
builder: (context, child) {
|
||||
return Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
colorScheme: ColorScheme.light(
|
||||
primary: AppThemeData.primary300, // header background color
|
||||
onPrimary: AppThemeData.grey900, // header text color
|
||||
onSurface: AppThemeData.grey900, // body text color
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppThemeData.grey900, // button text color
|
||||
),
|
||||
),
|
||||
),
|
||||
child: child!,
|
||||
);
|
||||
},
|
||||
initialDate: DateTime.now(),
|
||||
//get today's date
|
||||
firstDate: DateTime(2000),
|
||||
//DateTime.now() - not to allow to choose before today.
|
||||
lastDate: DateTime(2101),
|
||||
);
|
||||
return pickedDate;
|
||||
}
|
||||
|
||||
static int calculateDifference(DateTime date) {
|
||||
DateTime now = DateTime.now();
|
||||
return DateTime(date.year, date.month, date.day).difference(DateTime(now.year, now.month, now.day)).inDays;
|
||||
}
|
||||
|
||||
static String timestampToDate(Timestamp timestamp) {
|
||||
DateTime dateTime = timestamp.toDate();
|
||||
return DateFormat('MMM dd,yyyy').format(dateTime);
|
||||
}
|
||||
|
||||
static String timestampToDateTime(Timestamp timestamp) {
|
||||
DateTime dateTime = timestamp.toDate();
|
||||
return DateFormat('MMM dd,yyyy hh:mm aa').format(dateTime);
|
||||
}
|
||||
|
||||
static String timestampToDateTime2(Timestamp timestamp) {
|
||||
DateTime dateTime = timestamp.toDate();
|
||||
return DateFormat('EEE MMM d yyyy').format(dateTime);
|
||||
}
|
||||
|
||||
static String timestampToTime(Timestamp timestamp) {
|
||||
DateTime dateTime = timestamp.toDate();
|
||||
return DateFormat('hh:mm aa').format(dateTime);
|
||||
}
|
||||
|
||||
static String timestampToDateChat(Timestamp timestamp) {
|
||||
DateTime dateTime = timestamp.toDate();
|
||||
return DateFormat('dd/MM/yyyy').format(dateTime);
|
||||
}
|
||||
|
||||
static DateTime stringToDate(String openDineTime) {
|
||||
return DateFormat('HH:mm').parse(DateFormat('HH:mm').format(DateFormat("hh:mm a").parse((Intl.getCurrentLocale() == "en_US") ? openDineTime : openDineTime.toLowerCase())));
|
||||
}
|
||||
|
||||
static LanguageModel getLanguage() {
|
||||
final String user = Preferences.getString(Preferences.languageCodeKey);
|
||||
Map<String, dynamic> userMap = jsonDecode(user);
|
||||
return LanguageModel.fromJson(userMap);
|
||||
}
|
||||
|
||||
static String orderId({String orderId = ''}) {
|
||||
return "#$orderId";
|
||||
//return "#${(orderId).substring(orderId.length - 10)}";
|
||||
}
|
||||
|
||||
static bool isPointInPolygon(LatLng point, List<GeoPoint> polygon) {
|
||||
int crossings = 0;
|
||||
for (int i = 0; i < polygon.length; i++) {
|
||||
int next = (i + 1) % polygon.length;
|
||||
if (polygon[i].latitude <= point.latitude && polygon[next].latitude > point.latitude || polygon[i].latitude > point.latitude && polygon[next].latitude <= point.latitude) {
|
||||
double edgeLong = polygon[next].longitude - polygon[i].longitude;
|
||||
double edgeLat = polygon[next].latitude - polygon[i].latitude;
|
||||
double interpol = (point.latitude - polygon[i].latitude) / edgeLat;
|
||||
if (point.longitude < polygon[i].longitude + interpol * edgeLong) {
|
||||
crossings++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (crossings % 2 != 0);
|
||||
}
|
||||
|
||||
static final smtpServer = SmtpServer(
|
||||
mailSettings!.host.toString(),
|
||||
username: mailSettings!.userName.toString(),
|
||||
password: mailSettings!.password.toString(),
|
||||
port: 465,
|
||||
ignoreBadCertificate: false,
|
||||
ssl: true,
|
||||
allowInsecure: true,
|
||||
);
|
||||
|
||||
static Future<void> sendMail({String? subject, String? body, bool? isAdmin = false, List<dynamic>? recipients}) async {
|
||||
// Create our message.
|
||||
if (mailSettings != null) {
|
||||
if (isAdmin == true) {
|
||||
recipients!.add(mailSettings!.userName.toString());
|
||||
}
|
||||
final message =
|
||||
Message()
|
||||
..from = Address(mailSettings!.userName.toString(), mailSettings!.fromName.toString())
|
||||
..recipients = recipients!
|
||||
..subject = subject
|
||||
..text = body
|
||||
..html = body;
|
||||
|
||||
try {
|
||||
final sendReport = await send(message, smtpServer);
|
||||
print('Message sent: $sendReport');
|
||||
} on MailerException catch (e) {
|
||||
print(e);
|
||||
print('Message not sent.');
|
||||
for (var p in e.problems) {
|
||||
print('Problem: ${p.code}: ${p.msg}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// var connection = PersistentConnection(smtpServer);
|
||||
//
|
||||
// // Send the first message
|
||||
// await connection.send(message);
|
||||
}
|
||||
|
||||
static Uri createCoordinatesUrl(double latitude, double longitude, [String? label]) {
|
||||
Uri uri;
|
||||
if (kIsWeb) {
|
||||
uri = Uri.https('www.google.com', '/maps/search/', {'api': '1', 'query': '$latitude,$longitude'});
|
||||
} else if (Platform.isAndroid) {
|
||||
var query = '$latitude,$longitude';
|
||||
if (label != null) query += '($label)';
|
||||
uri = Uri(scheme: 'geo', host: '0,0', queryParameters: {'q': query});
|
||||
} else if (Platform.isIOS) {
|
||||
var params = {'ll': '$latitude,$longitude'};
|
||||
if (label != null) params['q'] = label;
|
||||
uri = Uri.https('maps.apple.com', '/', params);
|
||||
} else {
|
||||
uri = Uri.https('www.google.com', '/maps/search/', {'api': '1', 'query': '$latitude,$longitude'});
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
static Future<void> sendOrderEmail({required OrderModel orderModel}) async {
|
||||
EmailTemplateModel? emailTemplateModel = await FireStoreUtils.getEmailTemplates(newOrderPlaced);
|
||||
if (emailTemplateModel != null) {
|
||||
String firstHTML = """
|
||||
<table style="width: 100%; border-collapse: collapse; border: 1px solid rgb(0, 0, 0);">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Product Name<br></th>
|
||||
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Quantity<br></th>
|
||||
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Price<br></th>
|
||||
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Extra Item Price<br></th>
|
||||
<th style="text-align: left; border: 1px solid rgb(0, 0, 0);">Total<br></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
""";
|
||||
|
||||
String newString = emailTemplateModel.message.toString();
|
||||
newString = newString.replaceAll("{username}", "${Constant.userModel!.firstName} ${Constant.userModel!.lastName}");
|
||||
newString = newString.replaceAll("{orderid}", orderModel.id.toString());
|
||||
newString = newString.replaceAll("{date}", DateFormat('yyyy-MM-dd').format(orderModel.createdAt!.toDate()));
|
||||
newString = newString.replaceAll("{address}", orderModel.address!.getFullAddress());
|
||||
newString = newString.replaceAll("{paymentmethod}", orderModel.paymentMethod.toString());
|
||||
|
||||
double deliveryCharge = 0.0;
|
||||
double total = 0.0;
|
||||
double specialDiscount = 0.0;
|
||||
double discount = 0.0;
|
||||
double taxAmount = 0.0;
|
||||
double tipValue = 0.0;
|
||||
String specialLabel = '(${orderModel.specialDiscount!['special_discount_label']}${orderModel.specialDiscount!['specialType'] == "amount" ? currencyModel!.symbol : "%"})';
|
||||
List<String> htmlList = [];
|
||||
|
||||
if (orderModel.deliveryCharge != null) {
|
||||
deliveryCharge = double.parse(orderModel.deliveryCharge.toString());
|
||||
}
|
||||
if (orderModel.tipAmount != null) {
|
||||
tipValue = double.parse(orderModel.tipAmount.toString());
|
||||
}
|
||||
for (var element in orderModel.products!) {
|
||||
if (element.extrasPrice != null && element.extrasPrice!.isNotEmpty && double.parse(element.extrasPrice!) != 0.0) {
|
||||
total += double.parse(element.quantity.toString()) * double.parse(element.extrasPrice!);
|
||||
}
|
||||
total += double.parse(element.quantity.toString()) * double.parse(element.price.toString());
|
||||
|
||||
List<dynamic>? addon = element.extras;
|
||||
String extrasDisVal = '';
|
||||
for (int i = 0; i < addon!.length; i++) {
|
||||
extrasDisVal += '${addon[i].toString().replaceAll("\"", "")} ${(i == addon.length - 1) ? "" : ","}';
|
||||
}
|
||||
String product = """
|
||||
<tr>
|
||||
<td style="width: 20%; border-top: 1px solid rgb(0, 0, 0);">${element.name}</td>
|
||||
<td style="width: 20%; border: 1px solid rgb(0, 0, 0);" rowspan="2">${element.quantity}</td>
|
||||
<td style="width: 20%; border: 1px solid rgb(0, 0, 0);" rowspan="2">${amountShow(amount: element.price.toString())}</td>
|
||||
<td style="width: 20%; border: 1px solid rgb(0, 0, 0);" rowspan="2">${amountShow(amount: element.extrasPrice.toString())}</td>
|
||||
<td style="width: 20%; border: 1px solid rgb(0, 0, 0);" rowspan="2">${amountShow(amount: ((double.parse(element.quantity.toString()) * double.parse(element.extrasPrice!) + (double.parse(element.quantity.toString()) * double.parse(element.price.toString())))).toString())}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 20%;">${extrasDisVal.isEmpty ? "" : "Extra Item : $extrasDisVal"}</td>
|
||||
</tr>
|
||||
""";
|
||||
htmlList.add(product);
|
||||
}
|
||||
|
||||
if (orderModel.specialDiscount!.isNotEmpty) {
|
||||
specialDiscount = double.parse(orderModel.specialDiscount!['special_discount'].toString());
|
||||
}
|
||||
|
||||
if (orderModel.couponId != null && orderModel.couponId!.isNotEmpty) {
|
||||
discount = double.parse(orderModel.discount.toString());
|
||||
}
|
||||
|
||||
List<String> taxHtmlList = [];
|
||||
for (var element in taxList) {
|
||||
taxAmount = taxAmount + calculateTax(amount: (total - discount - specialDiscount).toString(), taxModel: element);
|
||||
String taxHtml =
|
||||
"""<span style="font-size: 1rem;">${element.title}: ${amountShow(amount: calculateTax(amount: (total - discount - specialDiscount).toString(), taxModel: element).toString())}${taxList.indexOf(element) == taxList.length - 1 ? "</span>" : "<br></span>"}""";
|
||||
taxHtmlList.add(taxHtml);
|
||||
}
|
||||
|
||||
var totalamount =
|
||||
orderModel.deliveryCharge == null || orderModel.deliveryCharge!.isEmpty
|
||||
? total + taxAmount - discount - specialDiscount
|
||||
: total + taxAmount + double.parse(orderModel.deliveryCharge!) + double.parse(orderModel.tipAmount!) - discount - specialDiscount;
|
||||
|
||||
newString = newString.replaceAll("{subtotal}", amountShow(amount: total.toString()));
|
||||
newString = newString.replaceAll("{coupon}", orderModel.couponId.toString());
|
||||
newString = newString.replaceAll("{discountamount}", amountShow(amount: orderModel.discount.toString()));
|
||||
newString = newString.replaceAll("{specialcoupon}", specialLabel);
|
||||
newString = newString.replaceAll("{specialdiscountamount}", amountShow(amount: specialDiscount.toString()));
|
||||
newString = newString.replaceAll("{shippingcharge}", amountShow(amount: deliveryCharge.toString()));
|
||||
newString = newString.replaceAll("{tipamount}", amountShow(amount: tipValue.toString()));
|
||||
newString = newString.replaceAll("{totalAmount}", amountShow(amount: totalamount.toString()));
|
||||
|
||||
String tableHTML = htmlList.join();
|
||||
String lastHTML = "</tbody></table>";
|
||||
newString = newString.replaceAll("{productdetails}", firstHTML + tableHTML + lastHTML);
|
||||
newString = newString.replaceAll("{taxdetails}", taxHtmlList.join());
|
||||
newString = newString.replaceAll("{newwalletbalance}.", amountShow(amount: Constant.userModel!.walletAmount.toString()));
|
||||
|
||||
String subjectNewString = emailTemplateModel.subject.toString();
|
||||
subjectNewString = subjectNewString.replaceAll("{orderid}", orderModel.id.toString());
|
||||
await sendMail(subject: subjectNewString, isAdmin: emailTemplateModel.isSendToAdmin, body: newString, recipients: [Constant.userModel!.email]);
|
||||
}
|
||||
}
|
||||
|
||||
double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
const R = 6371; // Earth's radius in km
|
||||
final dLat = _degToRad(lat2 - lat1);
|
||||
final dLon = _degToRad(lon2 - lon1);
|
||||
final a = sin(dLat / 2) * sin(dLat / 2) + cos(_degToRad(lat1)) * cos(_degToRad(lat2)) * sin(dLon / 2) * sin(dLon / 2);
|
||||
final c = 2 * atan2(sqrt(a), sqrt(1 - a));
|
||||
return R * c;
|
||||
}
|
||||
|
||||
double _degToRad(double deg) => deg * (pi / 180);
|
||||
|
||||
String getTimeInTheMinutes({required double distance}) {
|
||||
double averageSpeed = 40.0;
|
||||
double estimatedTime = (distance / averageSpeed) * 60;
|
||||
return "${estimatedTime.toStringAsFixed(2)} minutes";
|
||||
}
|
||||
|
||||
/// Calculate tax amount for a single tax model
|
||||
static double getTaxValue({required String amount, required TaxModel taxModel}) {
|
||||
double taxVal = 0.0;
|
||||
if (taxModel.enable == true) {
|
||||
if (taxModel.type == "fix") {
|
||||
taxVal = double.tryParse(taxModel.tax.toString()) ?? 0.0;
|
||||
} else {
|
||||
taxVal = (double.tryParse(amount) ?? 0.0) * (double.tryParse(taxModel.tax.toString()) ?? 0.0) / 100;
|
||||
}
|
||||
}
|
||||
return taxVal;
|
||||
}
|
||||
|
||||
Future<Uint8List> getBytesFromUrl(String url, {int width = 100}) async {
|
||||
try {
|
||||
final http.Response response = await http.get(Uri.parse(url));
|
||||
if (response.statusCode != 200) throw Exception("Failed to load image");
|
||||
|
||||
final Uint8List bytes = response.bodyBytes;
|
||||
final ui.Codec codec = await ui.instantiateImageCodec(bytes, targetWidth: width);
|
||||
final ui.FrameInfo frameInfo = await codec.getNextFrame();
|
||||
|
||||
final ByteData? byteData = await frameInfo.image.toByteData(format: ui.ImageByteFormat.png);
|
||||
return byteData!.buffer.asUint8List();
|
||||
} catch (e) {
|
||||
print("⚠️ getBytesFromUrl error: $e — using default cab icon");
|
||||
final ByteData data = await rootBundle.load('assets/images/ic_cab.png');
|
||||
return data.buffer.asUint8List();
|
||||
}
|
||||
}
|
||||
|
||||
// Future<Uint8List> getBytesFromUrl(String url, {int width = 100}) async {
|
||||
// final http.Response response = await http.get(Uri.parse(url));
|
||||
// if (response.statusCode != 200) {
|
||||
// throw Exception("Failed to load image from $url");
|
||||
// }
|
||||
//
|
||||
// final Uint8List bytes = response.bodyBytes;
|
||||
//
|
||||
// // Decode & resize
|
||||
// final ui.Codec codec = await ui.instantiateImageCodec(bytes, targetWidth: width);
|
||||
// final ui.FrameInfo frameInfo = await codec.getNextFrame();
|
||||
//
|
||||
// final ByteData? byteData = await frameInfo.image.toByteData(format: ui.ImageByteFormat.png);
|
||||
// return byteData!.buffer.asUint8List();
|
||||
// }
|
||||
}
|
||||
|
||||
extension StringExtension on String {
|
||||
String capitalizeString() {
|
||||
return "${this[0].toUpperCase()}${substring(1).toLowerCase()}";
|
||||
}
|
||||
}
|
||||
932
lib/controllers/0n_demand_payment_controller.dart
Normal file
932
lib/controllers/0n_demand_payment_controller.dart
Normal file
@@ -0,0 +1,932 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import '../../models/onprovider_order_model.dart';
|
||||
import '../models/wallet_transaction_model.dart';
|
||||
import '../payment/xenditModel.dart';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as maths;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_paypal/flutter_paypal.dart';
|
||||
import 'package:flutter_stripe/flutter_stripe.dart';
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../models/payment_model/cod_setting_model.dart';
|
||||
import '../models/payment_model/flutter_wave_model.dart';
|
||||
import '../models/payment_model/mercado_pago_model.dart';
|
||||
import '../models/payment_model/mid_trans.dart';
|
||||
import '../models/payment_model/orange_money.dart';
|
||||
import '../models/payment_model/pay_fast_model.dart';
|
||||
import '../models/payment_model/pay_stack_model.dart';
|
||||
import '../models/payment_model/paypal_model.dart';
|
||||
import '../models/payment_model/paytm_model.dart';
|
||||
import '../models/payment_model/razorpay_model.dart';
|
||||
import '../models/payment_model/stripe_model.dart';
|
||||
import '../models/payment_model/wallet_setting_model.dart';
|
||||
import '../models/payment_model/xendit.dart';
|
||||
import '../payment/MercadoPagoScreen.dart';
|
||||
import '../payment/PayFastScreen.dart';
|
||||
import '../payment/getPaytmTxtToken.dart';
|
||||
import '../payment/midtrans_screen.dart';
|
||||
import '../payment/orangePayScreen.dart';
|
||||
import '../payment/paystack/pay_stack_screen.dart';
|
||||
import '../payment/paystack/pay_stack_url_model.dart';
|
||||
import '../payment/paystack/paystack_url_genrater.dart';
|
||||
import '../payment/stripe_failed_model.dart';
|
||||
import '../payment/xenditScreen.dart';
|
||||
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import '../screen_ui/on_demand_service/on_demand_dashboard_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../service/send_notification.dart';
|
||||
import '../themes/app_them_data.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
import '../utils/preferences.dart';
|
||||
import 'on_demand_dashboard_controller.dart';
|
||||
|
||||
class OnDemandPaymentController extends GetxController {
|
||||
Rx<OnProviderOrderModel?> onDemandOrderModel = Rx<OnProviderOrderModel?>(null);
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
late bool isExtra;
|
||||
|
||||
RxBool isLoading = false.obs;
|
||||
|
||||
RxString selectedPaymentMethod = ''.obs;
|
||||
RxBool isOrderPlaced = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
isLoading.value = true;
|
||||
final args = Get.arguments as Map<String, dynamic>;
|
||||
onDemandOrderModel = args['onDemandOrderModel'];
|
||||
totalAmount = (args['totalAmount'] as double).obs;
|
||||
print("payment totalAmount ::::::::: $totalAmount");
|
||||
isExtra = args['isExtra'];
|
||||
|
||||
getPaymentSettings();
|
||||
}
|
||||
|
||||
Future<void> placeOrder() async {
|
||||
if (!isExtra) {
|
||||
// Normal Order
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
|
||||
onDemandOrderModel.value?.payment_method = selectedPaymentMethod.value;
|
||||
onDemandOrderModel.value?.paymentStatus = onDemandOrderModel.value?.provider.priceUnit == "Fixed" && selectedPaymentMethod.value == "cod" ? false : true;
|
||||
onDemandOrderModel.value?.extraPaymentStatus = true;
|
||||
|
||||
await FireStoreUtils.onDemandOrderPlace(onDemandOrderModel.value!, totalAmount.value);
|
||||
|
||||
if (onDemandOrderModel.value?.status == Constant.orderPlaced) {
|
||||
await FireStoreUtils.sendOrderOnDemandServiceEmail(orderModel: onDemandOrderModel.value!);
|
||||
|
||||
final providerUser = await FireStoreUtils.getUserProfile(onDemandOrderModel.value!.provider.author!);
|
||||
|
||||
if (providerUser != null) {
|
||||
final payLoad = {"type": 'provider_order', "orderId": onDemandOrderModel.value?.id};
|
||||
await SendNotification.sendFcmMessage(Constant.bookingPlaced, providerUser.fcmToken ?? '', payLoad);
|
||||
}
|
||||
|
||||
ShowToastDialog.showToast("OnDemand Service successfully booked".tr);
|
||||
}
|
||||
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: double.parse(totalAmount.value.toString()),
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: false,
|
||||
orderId: onDemandOrderModel.value!.id,
|
||||
note: "Booking Amount debited".tr,
|
||||
paymentStatus: "success".tr,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
if (value == true) {
|
||||
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid()).then((value) {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.offAll(const OnDemandDashboardScreen());
|
||||
OnDemandDashboardController controller = Get.put(OnDemandDashboardController());
|
||||
controller.selectedIndex.value = 2;
|
||||
} else {
|
||||
// Extra Charges Flow
|
||||
onDemandOrderModel.value?.createdAt = Timestamp.now();
|
||||
onDemandOrderModel.value?.extraPaymentStatus = true;
|
||||
|
||||
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: double.parse(totalAmount.value.toString()),
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: false,
|
||||
orderId: onDemandOrderModel.value!.id,
|
||||
note: "Booking Extra charge debited",
|
||||
paymentStatus: "success".tr,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
if (value == true) {
|
||||
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid()).then((value) {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle wallet payment if needed
|
||||
if (selectedPaymentMethod.value != 'cod') {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
serviceType: 'ondemand-service',
|
||||
amount: totalAmount.value,
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "provider",
|
||||
userId: onDemandOrderModel.value?.provider.author!,
|
||||
isTopup: true,
|
||||
orderId: onDemandOrderModel.value?.id,
|
||||
note: 'Extra Charge Amount Credited',
|
||||
paymentStatus: "success".tr,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
if (value == true) {
|
||||
await FireStoreUtils.updateUserWallet(amount: "-$totalAmount", userId: FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await FireStoreUtils.updateOnDemandOrder(onDemandOrderModel.value!);
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.offAll(const OnDemandDashboardScreen());
|
||||
OnDemandDashboardController controller = Get.put(OnDemandDashboardController());
|
||||
controller.selectedIndex.value = 2;
|
||||
}
|
||||
}
|
||||
|
||||
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
|
||||
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
|
||||
Rx<PayFastModel> payFastModel = PayFastModel().obs;
|
||||
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
|
||||
Rx<PayPalModel> payPalModel = PayPalModel().obs;
|
||||
Rx<StripeModel> stripeModel = StripeModel().obs;
|
||||
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
|
||||
Rx<PayStackModel> payStackModel = PayStackModel().obs;
|
||||
Rx<PaytmModel> paytmModel = PaytmModel().obs;
|
||||
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
|
||||
|
||||
Rx<MidTrans> midTransModel = MidTrans().obs;
|
||||
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
|
||||
Rx<Xendit> xenditModel = Xendit().obs;
|
||||
|
||||
Future<void> getPaymentSettings() async {
|
||||
isLoading.value = true;
|
||||
await FireStoreUtils.getPaymentSettingsData().then((value) {
|
||||
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
|
||||
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
|
||||
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
|
||||
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
|
||||
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
|
||||
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
|
||||
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
|
||||
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
|
||||
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
|
||||
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
|
||||
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
|
||||
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
|
||||
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
|
||||
|
||||
if (walletSettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.wallet.name;
|
||||
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.cod.name;
|
||||
} else if (stripeModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.stripe.name;
|
||||
} else if (payPalModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.paypal.name;
|
||||
} else if (payStackModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payStack.name;
|
||||
} else if (mercadoPagoModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
|
||||
} else if (flutterWaveModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
|
||||
} else if (payFastModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payFast.name;
|
||||
} else if (razorPayModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
|
||||
} else if (midTransModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
|
||||
} else if (orangeMoneyModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
|
||||
} else if (xenditModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.xendit.name;
|
||||
}
|
||||
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
|
||||
Stripe.merchantIdentifier = 'eMart Customer';
|
||||
Stripe.instance.applySettings();
|
||||
setRef();
|
||||
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
|
||||
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
|
||||
isLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// Strip
|
||||
Future<void> stripeMakePayment({required String amount}) async {
|
||||
log(double.parse(amount).toStringAsFixed(0));
|
||||
try {
|
||||
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
|
||||
log("stripe Responce====>$paymentIntentData");
|
||||
if (paymentIntentData!.containsKey("error")) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
} else {
|
||||
await Stripe.instance.initPaymentSheet(
|
||||
paymentSheetParameters: SetupPaymentSheetParameters(
|
||||
paymentIntentClientSecret: paymentIntentData['client_secret'],
|
||||
allowsDelayedPaymentMethods: false,
|
||||
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
|
||||
customFlow: true,
|
||||
style: ThemeMode.system,
|
||||
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
|
||||
merchantDisplayName: 'GoRide',
|
||||
),
|
||||
);
|
||||
displayStripePaymentSheet(amount: amount);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log("$e \n$s");
|
||||
ShowToastDialog.showToast("exception:$e \n$s");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> displayStripePaymentSheet({required String amount}) async {
|
||||
try {
|
||||
await Stripe.instance.presentPaymentSheet().then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
placeOrder();
|
||||
});
|
||||
} on StripeException catch (e) {
|
||||
var lo1 = jsonEncode(e);
|
||||
var lo2 = jsonDecode(lo1);
|
||||
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
|
||||
ShowToastDialog.showToast(lom.error.message);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future createStripeIntent({required String amount}) async {
|
||||
try {
|
||||
Map<String, dynamic> body = {
|
||||
'amount': ((double.parse(amount) * 100).round()).toString(),
|
||||
'currency': "USD",
|
||||
'payment_method_types[]': 'card',
|
||||
"description": "Strip Payment",
|
||||
"shipping[name]": Constant.userModel?.fullName(),
|
||||
"shipping[address][line1]": "510 Townsend St",
|
||||
"shipping[address][postal_code]": "98140",
|
||||
"shipping[address][city]": "San Francisco",
|
||||
"shipping[address][state]": "CA",
|
||||
"shipping[address][country]": "US",
|
||||
};
|
||||
var stripeSecret = stripeModel.value.stripeSecret;
|
||||
var response = await http.post(
|
||||
Uri.parse('https://api.stripe.com/v1/payment_intents'),
|
||||
body: body,
|
||||
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
);
|
||||
|
||||
return jsonDecode(response.body);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//mercadoo
|
||||
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
|
||||
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"items": [
|
||||
{
|
||||
"title": "Test",
|
||||
"description": "Test Payment",
|
||||
"quantity": 1,
|
||||
"currency_id": "BRL", // or your preferred currency
|
||||
"unit_price": double.parse(amount),
|
||||
},
|
||||
],
|
||||
"payer": {"email": Constant.userModel?.email},
|
||||
"back_urls": {"failure": "${Constant.globalUrl}payment/failure", "pending": "${Constant.globalUrl}payment/pending", "success": "${Constant.globalUrl}payment/success"},
|
||||
"auto_return": "approved",
|
||||
// Automatically return after payment is approved
|
||||
});
|
||||
|
||||
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Error creating preference: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Paypal
|
||||
void paypalPaymentSheet(String amount, context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(BuildContext context) => UsePaypal(
|
||||
sandboxMode: payPalModel.value.isLive == true ? false : true,
|
||||
clientId: payPalModel.value.paypalClient ?? '',
|
||||
secretKey: payPalModel.value.paypalSecret ?? '',
|
||||
returnURL: "com.parkme://paypalpay",
|
||||
cancelURL: "com.parkme://paypalpay",
|
||||
transactions: [
|
||||
{
|
||||
"amount": {
|
||||
"total": amount,
|
||||
"currency": "USD",
|
||||
"details": {"subtotal": amount},
|
||||
},
|
||||
},
|
||||
],
|
||||
note: "Contact us for any questions on your order.",
|
||||
onSuccess: (Map params) async {
|
||||
placeOrder();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
},
|
||||
onError: (error) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
onCancel: (params) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///PayStack Payment Method
|
||||
Future<void> payStackPayment(String totalAmount) async {
|
||||
await PayStackURLGen.payStackURLGen(
|
||||
amount: (double.parse(totalAmount) * 100).toString(),
|
||||
currency: "ZAR",
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
userModel: Constant.userModel!,
|
||||
).then((value) async {
|
||||
if (value != null) {
|
||||
PayStackUrlModel payStackModel0 = value;
|
||||
Get.to(
|
||||
PayStackScreen(
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
callBackUrl: payStackModel.value.callbackURL.toString(),
|
||||
initialURl: payStackModel0.data.authorizationUrl,
|
||||
amount: totalAmount,
|
||||
reference: payStackModel0.data.reference,
|
||||
),
|
||||
)!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//flutter wave Payment Method
|
||||
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
|
||||
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
|
||||
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"tx_ref": _ref,
|
||||
"amount": amount,
|
||||
"currency": "NGN",
|
||||
"redirect_url": "${Constant.globalUrl}payment/success",
|
||||
"payment_options": "ussd, card, barter, payattitude",
|
||||
"customer": {"email": Constant.userModel?.email.toString(), "phonenumber": Constant.userModel?.phoneNumber, "name": Constant.userModel?.fullName()},
|
||||
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
|
||||
});
|
||||
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Payment initialization failed: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? _ref;
|
||||
|
||||
void setRef() {
|
||||
maths.Random numRef = maths.Random();
|
||||
int year = DateTime.now().year;
|
||||
int refNumber = numRef.nextInt(20000);
|
||||
if (Platform.isAndroid) {
|
||||
_ref = "AndroidRef$year$refNumber";
|
||||
} else if (Platform.isIOS) {
|
||||
_ref = "IOSRef$year$refNumber";
|
||||
}
|
||||
}
|
||||
|
||||
// payFast
|
||||
void payFastPayment({required BuildContext context, required String amount}) {
|
||||
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: Constant.userModel!).then((String? value) async {
|
||||
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
|
||||
if (isDone) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///Paytm payment function
|
||||
Future<void> getPaytmCheckSum(context, {required double amount}) async {
|
||||
final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(getChecksum),
|
||||
headers: {},
|
||||
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString()},
|
||||
);
|
||||
|
||||
final data = jsonDecode(response.body);
|
||||
await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
|
||||
initiatePayment(amount: amount, orderId: orderId).then((value) {
|
||||
String callback = "";
|
||||
if (paytmModel.value.isSandboxEnabled == true) {
|
||||
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
} else {
|
||||
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
}
|
||||
|
||||
GetPaymentTxtTokenModel result = value;
|
||||
startTransaction(context, txnTokenBy: result.body.txnToken ?? '', orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> startTransaction(context, {required String txnTokenBy, required orderId, required double amount, required callBackURL, required isStaging}) async {
|
||||
// try {
|
||||
// var response = AllInOneSdk.startTransaction(
|
||||
// paytmModel.value.paytmMID.toString(),
|
||||
// orderId,
|
||||
// amount.toString(),
|
||||
// txnTokenBy,
|
||||
// callBackURL,
|
||||
// isStaging,
|
||||
// true,
|
||||
// true,
|
||||
// );
|
||||
//
|
||||
// response.then((value) {
|
||||
// if (value!["RESPMSG"] == "Txn Success") {
|
||||
// print("txt done!!");
|
||||
// ShowToastDialog.showToast("Payment Successful!!");
|
||||
// placeOrder();
|
||||
// }
|
||||
// }).catchError((onError) {
|
||||
// if (onError is PlatformException) {
|
||||
// Get.back();
|
||||
//
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// } else {
|
||||
// log("======>>2");
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// }
|
||||
// });
|
||||
// } catch (err) {
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(err.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
|
||||
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
|
||||
final response = await http.post(
|
||||
Uri.parse(getChecksum),
|
||||
headers: {},
|
||||
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(), "checksum_value": checkSum},
|
||||
);
|
||||
final data = jsonDecode(response.body);
|
||||
return data['status'];
|
||||
}
|
||||
|
||||
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
|
||||
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
|
||||
String callback = "";
|
||||
if (paytmModel.value.isSandboxEnabled == true) {
|
||||
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
} else {
|
||||
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
}
|
||||
final response = await http.post(
|
||||
Uri.parse(initiateURL),
|
||||
headers: {},
|
||||
body: {
|
||||
"mid": paytmModel.value.paytmMID,
|
||||
"order_id": orderId,
|
||||
"key_secret": paytmModel.value.pAYTMMERCHANTKEY,
|
||||
"amount": amount.toString(),
|
||||
"currency": "INR",
|
||||
"callback_url": callback,
|
||||
"custId": FireStoreUtils.getCurrentUid(),
|
||||
"issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
|
||||
},
|
||||
);
|
||||
log(response.body);
|
||||
final data = jsonDecode(response.body);
|
||||
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
}
|
||||
return GetPaymentTxtTokenModel.fromJson(data);
|
||||
}
|
||||
|
||||
///RazorPay payment function
|
||||
final Razorpay razorPay = Razorpay();
|
||||
|
||||
void openCheckout({required amount, required orderId}) async {
|
||||
var options = {
|
||||
'key': razorPayModel.value.razorpayKey,
|
||||
'amount': amount * 100,
|
||||
'name': 'GoRide',
|
||||
'order_id': orderId,
|
||||
"currency": "INR",
|
||||
'description': 'wallet Topup',
|
||||
'retry': {'enabled': true, 'max_count': 1},
|
||||
'send_sms_hash': true,
|
||||
'prefill': {'contact': Constant.userModel?.phoneNumber, 'email': Constant.userModel?.email},
|
||||
'external': {
|
||||
'wallets': ['paytm'],
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
razorPay.open(options);
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void handlePaymentSuccess(PaymentSuccessResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
}
|
||||
|
||||
void handleExternalWaller(ExternalWalletResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Processing!! via".tr);
|
||||
}
|
||||
|
||||
void handlePaymentError(PaymentFailureResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed!!".tr);
|
||||
}
|
||||
|
||||
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
|
||||
final currentDate = DateTime.now();
|
||||
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
|
||||
}
|
||||
|
||||
//Midtrans payment
|
||||
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
|
||||
await createPaymentLink(amount: amount).then((url) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (url != '') {
|
||||
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> createPaymentLink({required var amount}) async {
|
||||
var ordersId = const Uuid().v1();
|
||||
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!)},
|
||||
body: jsonEncode({
|
||||
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
|
||||
'usage_limit': 2,
|
||||
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
String generateBasicAuthHeader(String apiKey) {
|
||||
String credentials = '$apiKey:';
|
||||
String base64Encoded = base64Encode(utf8.encode(credentials));
|
||||
return 'Basic $base64Encoded';
|
||||
}
|
||||
|
||||
///Orangepay payment
|
||||
|
||||
// static variables to store transaction session
|
||||
static String accessToken = '';
|
||||
static String payToken = '';
|
||||
static String orderId = '';
|
||||
static String amount = '';
|
||||
|
||||
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
|
||||
reset();
|
||||
|
||||
var id = const Uuid().v4();
|
||||
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
|
||||
if (paymentURL.toString().isNotEmpty) {
|
||||
Get.to(() => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
|
||||
String apiUrl = 'https://api.orange.com/oauth/v3/token';
|
||||
Map<String, String> requestBody = {'grant_type': 'client_credentials'};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{'Authorization': "Basic ${orangeMoneyModel.value.auth ?? ''}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
|
||||
accessToken = responseData['access_token'] ?? '';
|
||||
if (accessToken.isEmpty) {
|
||||
ShowToastDialog.showToast("Failed to get access token".tr);
|
||||
return '';
|
||||
}
|
||||
|
||||
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
|
||||
orderId = orderIdData;
|
||||
amount = amountData;
|
||||
|
||||
// ✅ Null-safe handling
|
||||
bool isSandbox = orangeMoneyModel.value.isSandbox ?? false;
|
||||
|
||||
String apiUrl = isSandbox ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
|
||||
|
||||
Map<String, String> requestBody = {
|
||||
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
|
||||
"currency": isSandbox ? "OUV" : currency,
|
||||
"order_id": orderId,
|
||||
"amount": amount,
|
||||
"reference": 'Y-Note Test',
|
||||
"lang": "en",
|
||||
"return_url": orangeMoneyModel.value.returnUrl ?? "",
|
||||
"cancel_url": orangeMoneyModel.value.cancelUrl ?? "",
|
||||
"notif_url": orangeMoneyModel.value.notifUrl ?? "",
|
||||
};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
body: json.encode(requestBody),
|
||||
);
|
||||
|
||||
if (response.statusCode == 201) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
if (responseData['message'] == 'OK') {
|
||||
payToken = responseData['pay_token'] ?? '';
|
||||
return responseData['payment_url'] ?? '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
accessToken = '';
|
||||
payToken = '';
|
||||
orderId = '';
|
||||
amount = '';
|
||||
}
|
||||
|
||||
// static String accessToken = '';
|
||||
// static String payToken = '';
|
||||
// static String orderId = '';
|
||||
// static String amount = '';
|
||||
//
|
||||
// Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
|
||||
// reset();
|
||||
// var id = const Uuid().v4();
|
||||
// var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
|
||||
// ShowToastDialog.closeLoader();
|
||||
// if (paymentURL.toString() != '') {
|
||||
// Get.to(
|
||||
// () => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken),
|
||||
// )!.then((value) {
|
||||
// if (value == true) {
|
||||
// ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
// placeOrder();
|
||||
// ();
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
|
||||
// String apiUrl = 'https://api.orange.com/oauth/v3/token';
|
||||
// Map<String, String> requestBody = {'grant_type': 'client_credentials'};
|
||||
//
|
||||
// var response = await http.post(
|
||||
// Uri.parse(apiUrl),
|
||||
// headers: <String, String>{'Authorization': "Basic ${orangeMoneyModel.value.auth!}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
|
||||
// body: requestBody,
|
||||
// );
|
||||
//
|
||||
// // Handle the response
|
||||
//
|
||||
// if (response.statusCode == 200) {
|
||||
// Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
//
|
||||
// accessToken = responseData['access_token'];
|
||||
// // ignore: use_build_context_synchronously
|
||||
// return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
|
||||
// } else {
|
||||
// ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
// return '';
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
|
||||
// orderId = orderIdData;
|
||||
// amount = amountData;
|
||||
// String apiUrl =
|
||||
// orangeMoneyModel.value.isSandbox! == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
|
||||
// Map<String, String> requestBody = {
|
||||
// "merchant_key": orangeMoneyModel.value.merchantKey ?? '',
|
||||
// "currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
|
||||
// "order_id": orderId,
|
||||
// "amount": amount,
|
||||
// "reference": 'Y-Note Test',
|
||||
// "lang": "en",
|
||||
// "return_url": orangeMoneyModel.value.returnUrl ?? "",
|
||||
// "cancel_url": orangeMoneyModel.value.cancelUrl ?? "",
|
||||
// "notif_url": orangeMoneyModel.value.notifUrl ?? "",
|
||||
// // "return_url": orangeMoneyModel.value.returnUrl!.toString(),
|
||||
// // "cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
|
||||
// // "notif_url": orangeMoneyModel.value.notifUrl!.toString(),
|
||||
// };
|
||||
//
|
||||
// var response = await http.post(
|
||||
// Uri.parse(apiUrl),
|
||||
// headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
// body: json.encode(requestBody),
|
||||
// );
|
||||
//
|
||||
// // Handle the response
|
||||
// if (response.statusCode == 201) {
|
||||
// Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
// if (responseData['message'] == 'OK') {
|
||||
// payToken = responseData['pay_token'];
|
||||
// return responseData['payment_url'];
|
||||
// } else {
|
||||
// return '';
|
||||
// }
|
||||
// } else {
|
||||
// ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
// return '';
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// static void reset() {
|
||||
// accessToken = '';
|
||||
// payToken = '';
|
||||
// orderId = '';
|
||||
// amount = '';
|
||||
// }
|
||||
|
||||
///XenditPayment
|
||||
Future<void> xenditPayment(context, amount) async {
|
||||
await createXenditInvoice(amount: amount).then((model) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (model.id != null) {
|
||||
Get.to(() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<XenditModel> createXenditInvoice({required var amount}) async {
|
||||
const url = 'https://api.xendit.co/v2/invoices';
|
||||
var headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
|
||||
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
|
||||
};
|
||||
|
||||
final body = jsonEncode({
|
||||
'external_id': const Uuid().v1(),
|
||||
'amount': amount,
|
||||
'payer_email': 'customer@domain.com',
|
||||
'description': 'Test - VA Successful invoice payment',
|
||||
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(Uri.parse(url), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
|
||||
return model;
|
||||
} else {
|
||||
return XenditModel();
|
||||
}
|
||||
} catch (e) {
|
||||
return XenditModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
1605
lib/controllers/Intercity_home_controller.dart
Normal file
1605
lib/controllers/Intercity_home_controller.dart
Normal file
File diff suppressed because it is too large
Load Diff
43
lib/controllers/address_list_controller.dart
Normal file
43
lib/controllers/address_list_controller.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../constant/constant.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class AddressListController extends GetxController {
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
|
||||
RxList<ShippingAddress> shippingAddressList = <ShippingAddress>[].obs;
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getUser();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getUser() async {
|
||||
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
|
||||
if (value != null) {
|
||||
userModel.value = value;
|
||||
if (userModel.value.shippingAddress != null) {
|
||||
shippingAddressList.value = userModel.value.shippingAddress!;
|
||||
}
|
||||
}
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> deleteAddress(int index) async {
|
||||
if (shippingAddressList.isNotEmpty && index < shippingAddressList.length) {
|
||||
shippingAddressList.removeAt(index);
|
||||
userModel.value.shippingAddress = shippingAddressList;
|
||||
if (shippingAddressList.isNotEmpty) {
|
||||
Constant.selectedLocation = shippingAddressList.first;
|
||||
}
|
||||
await FireStoreUtils.updateUser(userModel.value);
|
||||
shippingAddressList.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
48
lib/controllers/advertisement_list_controller.dart
Normal file
48
lib/controllers/advertisement_list_controller.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/advertisement_model.dart';
|
||||
import 'package:customer/models/favourite_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AdvertisementListController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getAdvertisementList();
|
||||
getFavouriteRestaurant();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
RxList<AdvertisementModel> advertisementList = <AdvertisementModel>[].obs;
|
||||
|
||||
Future<void> getAdvertisementList() async {
|
||||
advertisementList.clear();
|
||||
List<VendorModel> allNearestRestaurant = <VendorModel>[];
|
||||
FireStoreUtils.getAllNearestRestaurant().listen((event) async {
|
||||
allNearestRestaurant.addAll(event);
|
||||
await FireStoreUtils.getAllAdvertisement().then((value) {
|
||||
List<AdvertisementModel> adsList = value;
|
||||
advertisementList.addAll(
|
||||
adsList.where(
|
||||
(ads) => allNearestRestaurant.any(
|
||||
(restaurant) => restaurant.id == ads.vendorId,
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
isLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
|
||||
|
||||
Future<void> getFavouriteRestaurant() async {
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getFavouriteRestaurant().then((value) {
|
||||
favouriteList.value = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
58
lib/controllers/all_brand_product_controller.dart
Normal file
58
lib/controllers/all_brand_product_controller.dart
Normal file
@@ -0,0 +1,58 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/brands_model.dart';
|
||||
import 'package:customer/models/product_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AllBrandProductController extends GetxController {
|
||||
RxList<ProductModel> productList = <ProductModel>[].obs;
|
||||
Rx<BrandsModel> brandModel = BrandsModel().obs;
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArguments();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getArguments() async {
|
||||
final arguments = Get.arguments;
|
||||
if (arguments != null) {
|
||||
brandModel.value = arguments['brandModel'];
|
||||
await getProductByCategoryId();
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getProductByCategoryId() async {
|
||||
List<ProductModel> productDataList = await FireStoreUtils.getProductListByBrandId(brandModel.value.id.toString());
|
||||
|
||||
List<VendorModel> vendorList = await FireStoreUtils.getAllStoresFuture();
|
||||
List<ProductModel> allProduct = <ProductModel>[];
|
||||
for (var vendor in vendorList) {
|
||||
await FireStoreUtils.getAllProducts(vendor.id.toString()).then((value) {
|
||||
if (Constant.isSubscriptionModelApplied == true || vendor.adminCommission?.isEnabled == true) {
|
||||
if (vendor.subscriptionPlan != null && Constant.isExpire(vendor) == false) {
|
||||
if (vendor.subscriptionPlan?.itemLimit == '-1') {
|
||||
allProduct.addAll(value);
|
||||
} else {
|
||||
int selectedProduct =
|
||||
value.length < int.parse(vendor.subscriptionPlan?.itemLimit ?? '0') ? (value.isEmpty ? 0 : (value.length)) : int.parse(vendor.subscriptionPlan?.itemLimit ?? '0');
|
||||
allProduct.addAll(value.sublist(0, selectedProduct));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allProduct.addAll(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (var element in productDataList) {
|
||||
final bool productIsInList = allProduct.any((product) => product.id == element.id);
|
||||
if (productIsInList) {
|
||||
productList.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
lib/controllers/all_category_product_controller.dart
Normal file
30
lib/controllers/all_category_product_controller.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:customer/models/product_model.dart';
|
||||
import 'package:customer/models/vendor_category_model.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AllCategoryProductController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
Rx<VendorCategoryModel> categoryModel = VendorCategoryModel().obs;
|
||||
RxList<ProductModel> productList = <ProductModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArguments();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getArguments() async {
|
||||
final arguments = Get.arguments;
|
||||
if (arguments != null) {
|
||||
categoryModel.value = arguments['categoryModel'];
|
||||
await getProductByCategoryId();
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getProductByCategoryId() async {
|
||||
productList.value = await FireStoreUtils.getProductListByCategoryId(categoryModel.value.id.toString());
|
||||
}
|
||||
}
|
||||
340
lib/controllers/book_parcel_controller.dart
Normal file
340
lib/controllers/book_parcel_controller.dart
Normal file
@@ -0,0 +1,340 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:customer/widget/geoflutterfire/src/geoflutterfire.dart';
|
||||
import 'package:dropdown_textfield/dropdown_textfield.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geocoding/geocoding.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart' as latlong;
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../models/parcel_category.dart';
|
||||
import '../models/parcel_order_model.dart';
|
||||
import '../models/parcel_weight_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../screen_ui/parcel_service/parcel_order_confirmation.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class BookParcelController extends GetxController {
|
||||
// Sender details
|
||||
final Rx<TextEditingController> senderLocationController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> senderNameController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> senderMobileController = TextEditingController().obs;
|
||||
final Rx<SingleValueDropDownController> senderWeightController = SingleValueDropDownController().obs;
|
||||
final Rx<TextEditingController> senderNoteController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> senderCountryCodeController = TextEditingController(text: Constant.defaultCountryCode).obs;
|
||||
|
||||
// Receiver details
|
||||
final Rx<TextEditingController> receiverLocationController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> receiverNameController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> receiverMobileController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> receiverNoteController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> receiverCountryCodeController = TextEditingController(text: Constant.defaultCountryCode).obs;
|
||||
|
||||
// Delivery type
|
||||
final RxString selectedDeliveryType = 'now'.obs;
|
||||
|
||||
// Scheduled delivery fields
|
||||
final Rx<TextEditingController> scheduledDateController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> scheduledTimeController = TextEditingController().obs;
|
||||
final RxString scheduledDate = ''.obs;
|
||||
final RxString scheduledTime = ''.obs;
|
||||
|
||||
// Parcel weight list
|
||||
final RxList<ParcelWeightModel> parcelWeight = <ParcelWeightModel>[].obs;
|
||||
|
||||
final RxList<XFile> images = <XFile>[].obs;
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
|
||||
Rx<UserLocation?> senderLocation = Rx<UserLocation?>(null);
|
||||
Rx<UserLocation?> receiverLocation = Rx<UserLocation?>(null);
|
||||
|
||||
ParcelWeightModel? selectedWeight;
|
||||
ParcelCategory? selectedCategory;
|
||||
|
||||
// UI observables
|
||||
RxBool isScheduled = false.obs;
|
||||
RxDouble distance = 0.0.obs;
|
||||
RxDouble duration = 0.0.obs;
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
setArguments();
|
||||
getParcelWeight();
|
||||
setCurrentLocationForSenderAndReceiver();
|
||||
}
|
||||
|
||||
void setArguments() {
|
||||
if (Get.arguments != null && Get.arguments['parcelCategory'] != null) {
|
||||
selectedCategory = Get.arguments['parcelCategory'];
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getParcelWeight() async {
|
||||
parcelWeight.value = await FireStoreUtils.getParcelWeight();
|
||||
}
|
||||
|
||||
Future<void> pickScheduledDate(BuildContext context) async {
|
||||
final DateTime? picked = await showDatePicker(context: context, initialDate: DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime.now().add(const Duration(days: 365)));
|
||||
if (picked != null) {
|
||||
final formattedDate = "${picked.day}/${picked.month}/${picked.year}";
|
||||
scheduledDate.value = formattedDate;
|
||||
scheduledDateController.value.text = formattedDate;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> pickScheduledTime(BuildContext context) async {
|
||||
final TimeOfDay? picked = await showTimePicker(context: context, initialTime: TimeOfDay.now());
|
||||
if (picked != null) {
|
||||
final formattedTime = picked.format(context);
|
||||
scheduledTime.value = formattedTime;
|
||||
scheduledTimeController.value.text = formattedTime;
|
||||
}
|
||||
}
|
||||
|
||||
void onCameraClick(BuildContext context) {
|
||||
final action = CupertinoActionSheet(
|
||||
message: Text('Add your parcel image.'.tr, style: const TextStyle(fontSize: 15.0)),
|
||||
actions: <Widget>[
|
||||
CupertinoActionSheetAction(
|
||||
child: Text('Choose image from gallery'.tr),
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
final imageList = await _picker.pickMultiImage();
|
||||
if (imageList.isNotEmpty) {
|
||||
images.addAll(imageList);
|
||||
}
|
||||
},
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: Text('Take a picture'.tr),
|
||||
onPressed: () async {
|
||||
Navigator.pop(context);
|
||||
final XFile? photo = await _picker.pickImage(source: ImageSource.camera);
|
||||
if (photo != null) {
|
||||
images.add(photo);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
cancelButton: CupertinoActionSheetAction(child: Text('Cancel'.tr), onPressed: () => Navigator.pop(context)),
|
||||
);
|
||||
showCupertinoModalPopup(context: context, builder: (context) => action);
|
||||
}
|
||||
|
||||
Future<void> setCurrentLocationForSenderAndReceiver() async {
|
||||
try {
|
||||
await Geolocator.requestPermission();
|
||||
final position = await Geolocator.getCurrentPosition();
|
||||
final placemarks = await placemarkFromCoordinates(position.latitude, position.longitude);
|
||||
final place = placemarks.first;
|
||||
final address = "${place.name}, ${place.subLocality}, ${place.locality}, ${place.administrativeArea}, ${place.postalCode}, ${place.country}";
|
||||
|
||||
final userLocation = UserLocation(latitude: position.latitude, longitude: position.longitude);
|
||||
senderLocation.value = userLocation;
|
||||
senderLocationController.value.text = address;
|
||||
} catch (e) {
|
||||
debugPrint("Failed to fetch current location: $e");
|
||||
}
|
||||
}
|
||||
|
||||
bool validateFields() {
|
||||
if (senderNameController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter sender name".tr);
|
||||
return false;
|
||||
} else if (senderMobileController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter sender mobile".tr);
|
||||
return false;
|
||||
} else if (senderLocationController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter sender address".tr);
|
||||
return false;
|
||||
} else if (receiverNameController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter receiver name".tr);
|
||||
return false;
|
||||
} else if (receiverMobileController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter receiver mobile".tr);
|
||||
return false;
|
||||
} else if (receiverLocationController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter receiver address".tr);
|
||||
return false;
|
||||
} else if (isScheduled.value) {
|
||||
if (scheduledDate.value.isEmpty) {
|
||||
ShowToastDialog.showToast("Please select scheduled date".tr);
|
||||
return false;
|
||||
} else if (scheduledTime.value.isEmpty) {
|
||||
ShowToastDialog.showToast("Please select scheduled time".tr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedWeight == null) {
|
||||
ShowToastDialog.showToast("Please select parcel weight".tr);
|
||||
return false;
|
||||
} else if (senderLocation.value == null || receiverLocation.value == null) {
|
||||
ShowToastDialog.showToast("Please select both sender and receiver locations".tr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> bookNow() async {
|
||||
if (!validateFields()) return;
|
||||
|
||||
try {
|
||||
distance.value = 0.0;
|
||||
|
||||
if (Constant.selectedMapType == 'osm') {
|
||||
print("Fetching route using OSM");
|
||||
print("Sender Location: ${senderLocation.value?.latitude}, ${senderLocation.value?.longitude}");
|
||||
print("Receiver Location: ${receiverLocation.value?.latitude}, ${receiverLocation.value?.longitude}");
|
||||
await fetchRouteWithWaypoints([
|
||||
latlong.LatLng(senderLocation.value?.latitude ?? 0.0, senderLocation.value?.longitude ?? 0.0),
|
||||
latlong.LatLng(receiverLocation.value?.latitude ?? 0.0, receiverLocation.value?.longitude ?? 0.0),
|
||||
]);
|
||||
} else {
|
||||
await fetchGoogleRouteWithWaypoints();
|
||||
}
|
||||
|
||||
if (distance.value < 0.5) {
|
||||
ShowToastDialog.showToast("Sender's location to receiver's location should be more than 1 km.".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
subTotal.value = (distance.value * double.parse(selectedWeight!.deliveryCharge.toString()));
|
||||
goToCart();
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("Something went wrong while booking.".tr);
|
||||
debugPrint("bookNow error: $e");
|
||||
}
|
||||
}
|
||||
|
||||
void goToCart() {
|
||||
DateTime senderPickup = isScheduled.value ? parseScheduledDateTime(scheduledDate.value, scheduledTime.value) : DateTime.now();
|
||||
|
||||
print("Sender Pickup: $distance");
|
||||
ParcelOrderModel order = ParcelOrderModel(
|
||||
id: Constant.getUuid(),
|
||||
subTotal: subTotal.value.toString(),
|
||||
parcelType: selectedCategory?.title ?? '',
|
||||
parcelCategoryID: selectedCategory?.id ?? '',
|
||||
note: senderNoteController.value.text,
|
||||
receiverNote: receiverNoteController.value.text,
|
||||
distance: distance.value.toStringAsFixed(4),
|
||||
parcelWeight: selectedWeight?.title ?? '',
|
||||
parcelWeightCharge: selectedWeight?.deliveryCharge,
|
||||
sendToDriver: isScheduled.value == true ? false : true,
|
||||
senderPickupDateTime: Timestamp.fromDate(senderPickup),
|
||||
receiverPickupDateTime: Timestamp.fromDate(DateTime.now()),
|
||||
taxSetting: Constant.taxList,
|
||||
isSchedule: isScheduled.value,
|
||||
sourcePoint: G(
|
||||
geopoint: GeoPoint(senderLocation.value!.latitude ?? 0.0, senderLocation.value!.longitude ?? 0.0),
|
||||
geohash: Geoflutterfire().point(latitude: senderLocation.value!.latitude ?? 0.0, longitude: senderLocation.value!.longitude ?? 0.0).hash,
|
||||
),
|
||||
destinationPoint: G(
|
||||
geopoint: GeoPoint(receiverLocation.value!.latitude ?? 0.0, receiverLocation.value!.longitude ?? 0.0),
|
||||
geohash: Geoflutterfire().point(latitude: receiverLocation.value!.latitude ?? 0.0, longitude: receiverLocation.value!.longitude ?? 0.0).hash,
|
||||
),
|
||||
sender: LocationInformation(
|
||||
address: senderLocationController.value.text,
|
||||
name: senderNameController.value.text,
|
||||
phone: "(${senderCountryCodeController.value.text}) ${senderMobileController.value.text}",
|
||||
),
|
||||
receiver: LocationInformation(
|
||||
address: receiverLocationController.value.text,
|
||||
name: receiverNameController.value.text,
|
||||
phone: "(${receiverCountryCodeController.value.text}) ${receiverMobileController.value.text}",
|
||||
),
|
||||
receiverLatLong: receiverLocation.value,
|
||||
senderLatLong: senderLocation.value,
|
||||
sectionId: Constant.sectionConstantModel?.id ?? '',
|
||||
);
|
||||
|
||||
debugPrint("Order Distance: ${distance.value}");
|
||||
debugPrint("Subtotal: ${subTotal.value}");
|
||||
debugPrint("Order JSON: ${order.toJson()}");
|
||||
|
||||
Get.to(() => ParcelOrderConfirmationScreen(), arguments: {'parcelOrder': order, 'images': images});
|
||||
}
|
||||
|
||||
DateTime parseScheduledDateTime(String dateStr, String timeStr) {
|
||||
try {
|
||||
final dateParts = dateStr.split('/');
|
||||
final day = int.parse(dateParts[0]);
|
||||
final month = int.parse(dateParts[1]);
|
||||
final year = int.parse(dateParts[2]);
|
||||
|
||||
final time = TimeOfDay(hour: int.parse(timeStr.split(':')[0]), minute: int.parse(timeStr.split(':')[1].split(' ')[0]));
|
||||
final isPM = timeStr.toLowerCase().contains('pm');
|
||||
final hour24 = isPM && time.hour < 12 ? time.hour + 12 : time.hour;
|
||||
|
||||
return DateTime(year, month, day, hour24, time.minute);
|
||||
} catch (e) {
|
||||
debugPrint("Failed to parse scheduled date/time: $e");
|
||||
return DateTime.now();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchGoogleRouteWithWaypoints() async {
|
||||
final origin = '${senderLocation.value!.latitude},${senderLocation.value!.longitude}';
|
||||
final destination = '${receiverLocation.value!.latitude},${receiverLocation.value!.longitude}';
|
||||
final url = Uri.parse('https://maps.googleapis.com/maps/api/directions/json?origin=$origin&destination=$destination&mode=driving&key=${Constant.mapAPIKey}');
|
||||
|
||||
try {
|
||||
final response = await http.get(url);
|
||||
final data = json.decode(response.body);
|
||||
if (data['status'] == 'OK') {
|
||||
final route = data['routes'][0];
|
||||
final legs = route['legs'] as List;
|
||||
num totalDistance = 0;
|
||||
num totalDuration = 0;
|
||||
for (var leg in legs) {
|
||||
totalDistance += leg['distance']['value'];
|
||||
totalDuration += leg['duration']['value'];
|
||||
}
|
||||
if (Constant.distanceType.toLowerCase() == "KM".toLowerCase()) {
|
||||
distance.value = totalDistance / 1000.0;
|
||||
} else {
|
||||
distance.value = totalDistance / 1609.34;
|
||||
}
|
||||
duration.value = (totalDuration / 60).round().toDouble();
|
||||
} else {
|
||||
debugPrint('Google Directions API Error: ${data['status']}');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Google route fetch error: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchRouteWithWaypoints(List<latlong.LatLng> points) async {
|
||||
final coordinates = points.map((p) => '${p.longitude},${p.latitude}').join(';');
|
||||
final url = Uri.parse('https://router.project-osrm.org/route/v1/driving/$coordinates?overview=full&geometries=geojson');
|
||||
|
||||
try {
|
||||
final response = await http.get(url);
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
final dist = decoded['routes'][0]['distance'];
|
||||
final dur = decoded['routes'][0]['duration'];
|
||||
|
||||
if (Constant.distanceType.toLowerCase() == "KM".toLowerCase()) {
|
||||
distance.value = dist / 1000.00;
|
||||
} else {
|
||||
distance.value = dist / 1609.34;
|
||||
}
|
||||
duration.value = (dur / 60).round().toDouble();
|
||||
} else {
|
||||
debugPrint("Failed to get route: ${response.body}");
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Route fetch error: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
1596
lib/controllers/cab_booking_controller.dart
Normal file
1596
lib/controllers/cab_booking_controller.dart
Normal file
File diff suppressed because it is too large
Load Diff
30
lib/controllers/cab_coupon_code_controller.dart
Normal file
30
lib/controllers/cab_coupon_code_controller.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class CabCouponCodeController extends GetxController {
|
||||
// Add your methods and properties here
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
|
||||
void getData(){
|
||||
getCouponCode();
|
||||
}
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<CouponModel> cabCouponList = <CouponModel>[].obs;
|
||||
|
||||
Future<void> getCouponCode() async {
|
||||
await FireStoreUtils.getCabCoupon().then((value) {
|
||||
cabCouponList.value = value;
|
||||
// Handle the retrieved coupon code
|
||||
});
|
||||
print("cabCouponList ${cabCouponList.length}");
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
33
lib/controllers/cab_dashboard_controller.dart
Normal file
33
lib/controllers/cab_dashboard_controller.dart
Normal file
@@ -0,0 +1,33 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/screen_ui/cab_service_screens/cab_home_screen.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../screen_ui/cab_service_screens/my_cab_booking_screen.dart';
|
||||
|
||||
class CabDashboardController extends GetxController {
|
||||
RxInt selectedIndex = 0.obs;
|
||||
|
||||
RxList pageList = [].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getTaxList();
|
||||
if (Constant.walletSetting == false) {
|
||||
pageList.value = [CabHomeScreen(), const MyCabBookingScreen(), const ProfileScreen()];
|
||||
} else {
|
||||
pageList.value = [CabHomeScreen(), const MyCabBookingScreen(), const WalletScreen(), const ProfileScreen()];
|
||||
}
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getTaxList() async {
|
||||
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
|
||||
if (value != null) {
|
||||
Constant.taxList = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
22
lib/controllers/cab_home_controller.dart
Normal file
22
lib/controllers/cab_home_controller.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:customer/models/banner_model.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class CabHomeController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<BannerModel> bannerTopHome = <BannerModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
await FireStoreUtils.getHomeTopBanner().then((value) {
|
||||
bannerTopHome.value = value;
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
138
lib/controllers/cab_order_details_controller.dart
Normal file
138
lib/controllers/cab_order_details_controller.dart
Normal file
@@ -0,0 +1,138 @@
|
||||
import 'dart:convert';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/rating_model.dart';
|
||||
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart' as gmap;
|
||||
import 'package:latlong2/latlong.dart' as osm;
|
||||
import '../models/cab_order_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/app_them_data.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class CabOrderDetailsController extends GetxController {
|
||||
Rx<CabOrderModel> cabOrder = CabOrderModel().obs;
|
||||
|
||||
RxBool isLoading = false.obs;
|
||||
|
||||
// Google Maps Data
|
||||
RxSet<gmap.Marker> googleMarkers = <gmap.Marker>{}.obs;
|
||||
RxSet<gmap.Polyline> googlePolylines = <gmap.Polyline>{}.obs;
|
||||
|
||||
// OSM Data
|
||||
RxList<osm.LatLng> osmPolyline = <osm.LatLng>[].obs;
|
||||
|
||||
final String googleApiKey = Constant.mapAPIKey;
|
||||
|
||||
final Rx<UserModel> driverUser = UserModel().obs;
|
||||
Rx<RatingModel> ratingModel = RatingModel().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
final args = Get.arguments;
|
||||
if (args != null) {
|
||||
cabOrder.value = args['cabOrderModel'] as CabOrderModel;
|
||||
calculateTotalAmount();
|
||||
_setMarkers();
|
||||
_getGoogleRoute();
|
||||
_getOsmRoute();
|
||||
}
|
||||
fetchDriverDetails();
|
||||
}
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble discount = 0.0.obs;
|
||||
RxDouble taxAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
|
||||
String formatDate(Timestamp timestamp) {
|
||||
final dateTime = timestamp.toDate();
|
||||
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
|
||||
}
|
||||
|
||||
Future<void> fetchDriverDetails() async {
|
||||
if (cabOrder.value.driverId != null) {
|
||||
await FireStoreUtils.getUserProfile(cabOrder.value.driverId ?? '').then((value) {
|
||||
if (value != null) {
|
||||
driverUser.value = value;
|
||||
}
|
||||
});
|
||||
|
||||
print(driverUser.value.toJson());
|
||||
await FireStoreUtils.getReviewsbyID(cabOrder.value.id.toString()).then((value) {
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void calculateTotalAmount() {
|
||||
taxAmount = 0.0.obs;
|
||||
discount = 0.0.obs;
|
||||
subTotal.value = double.parse(cabOrder.value.subTotal.toString());
|
||||
discount.value = double.parse(cabOrder.value.discount ?? '0.0');
|
||||
|
||||
if (cabOrder.value.taxSetting != null) {
|
||||
for (var element in cabOrder.value.taxSetting!) {
|
||||
taxAmount.value = (taxAmount.value + Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element));
|
||||
}
|
||||
}
|
||||
|
||||
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
|
||||
update();
|
||||
}
|
||||
|
||||
void _setMarkers() {
|
||||
final sourceLat = cabOrder.value.sourceLocation!.latitude;
|
||||
final sourceLng = cabOrder.value.sourceLocation!.longitude;
|
||||
final destLat = cabOrder.value.destinationLocation!.latitude;
|
||||
final destLng = cabOrder.value.destinationLocation!.longitude;
|
||||
|
||||
googleMarkers.value = {
|
||||
gmap.Marker(markerId: const gmap.MarkerId('source'), position: gmap.LatLng(sourceLat!, sourceLng!), icon: gmap.BitmapDescriptor.defaultMarkerWithHue(gmap.BitmapDescriptor.hueGreen)),
|
||||
gmap.Marker(markerId: const gmap.MarkerId('destination'), position: gmap.LatLng(destLat!, destLng!), icon: gmap.BitmapDescriptor.defaultMarkerWithHue(gmap.BitmapDescriptor.hueRed)),
|
||||
};
|
||||
}
|
||||
|
||||
///Google Directions API
|
||||
Future<void> _getGoogleRoute() async {
|
||||
final src = cabOrder.value.sourceLocation;
|
||||
final dest = cabOrder.value.destinationLocation;
|
||||
|
||||
final url = "https://maps.googleapis.com/maps/api/directions/json?origin=${src!.latitude},${src.longitude}&destination=${dest!.latitude},${dest.longitude}&key=$googleApiKey";
|
||||
|
||||
final response = await http.get(Uri.parse(url));
|
||||
final data = jsonDecode(response.body);
|
||||
|
||||
if (data["routes"].isNotEmpty) {
|
||||
final points = data["routes"][0]["overview_polyline"]["points"];
|
||||
final polylinePoints = PolylinePoints.decodePolyline(points);
|
||||
|
||||
final polylineCoords = polylinePoints.map((p) => gmap.LatLng(p.latitude, p.longitude)).toList();
|
||||
|
||||
googlePolylines.value = {gmap.Polyline(polylineId: const gmap.PolylineId("google_route"), color: AppThemeData.onDemandDark100, width: 5, points: polylineCoords)};
|
||||
}
|
||||
}
|
||||
|
||||
/// OSM Route (OSRM API)
|
||||
Future<void> _getOsmRoute() async {
|
||||
final src = cabOrder.value.sourceLocation;
|
||||
final dest = cabOrder.value.destinationLocation;
|
||||
|
||||
final url = "http://router.project-osrm.org/route/v1/driving/${src!.longitude},${src.latitude};${dest!.longitude},${dest.latitude}?overview=full&geometries=geojson";
|
||||
|
||||
final response = await http.get(Uri.parse(url));
|
||||
final data = jsonDecode(response.body);
|
||||
|
||||
if (data["routes"].isNotEmpty) {
|
||||
final coords = data["routes"][0]["geometry"]["coordinates"] as List<dynamic>;
|
||||
|
||||
osmPolyline.value = coords.map((c) => osm.LatLng(c[1].toDouble(), c[0].toDouble())).toList();
|
||||
}
|
||||
}
|
||||
}
|
||||
34
lib/controllers/cab_rental_dashboard_controllers.dart
Normal file
34
lib/controllers/cab_rental_dashboard_controllers.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import 'package:customer/screen_ui/rental_service/rental_home_screen.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../screen_ui/rental_service/my_rental_booking_screen.dart';
|
||||
|
||||
class CabRentalDashboardControllers extends GetxController {
|
||||
RxInt selectedIndex = 0.obs;
|
||||
|
||||
RxList pageList = [].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getTaxList();
|
||||
if (Constant.walletSetting == false) {
|
||||
pageList.value = [RentalHomeScreen(), MyRentalBookingScreen(), const ProfileScreen()];
|
||||
} else {
|
||||
pageList.value = [RentalHomeScreen(), MyRentalBookingScreen(), const WalletScreen(), const ProfileScreen()];
|
||||
}
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getTaxList() async {
|
||||
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
|
||||
if (value != null) {
|
||||
Constant.taxList = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
133
lib/controllers/cab_review_controller.dart
Normal file
133
lib/controllers/cab_review_controller.dart
Normal file
@@ -0,0 +1,133 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/cab_order_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../constant/collection_name.dart';
|
||||
import '../models/rating_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class CabReviewController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
final Rx<CabOrderModel?> order = Rx<CabOrderModel?>(null);
|
||||
|
||||
final Rx<RatingModel?> ratingModel = Rx<RatingModel?>(null);
|
||||
final RxDouble ratings = 0.0.obs;
|
||||
final Rx<TextEditingController> comment = TextEditingController().obs;
|
||||
|
||||
final Rx<UserModel?> driverUser = Rx<UserModel?>(null);
|
||||
|
||||
final RxInt futureCount = 0.obs;
|
||||
final RxInt futureSum = 0.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
final args = Get.arguments;
|
||||
if (args != null && args['order'] != null) {
|
||||
order.value = args['order'] as CabOrderModel;
|
||||
getReview();
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch old review + driver stats
|
||||
Future<void> getReview() async {
|
||||
await FireStoreUtils.getReviewsbyID(order.value?.id ?? "").then((value) {
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
ratings.value = value.rating ?? 0;
|
||||
comment.value.text = value.comment ?? "";
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getUserProfile(order.value?.driverId ?? '').then((value) {
|
||||
if (value != null) {
|
||||
driverUser.value = value;
|
||||
|
||||
final int userReviewsCount = int.tryParse(driverUser.value!.reviewsCount?.toString() ?? "0") ?? 0;
|
||||
final int userReviewsSum = int.tryParse(driverUser.value!.reviewsSum?.toString() ?? "0") ?? 0;
|
||||
|
||||
if (ratingModel.value != null) {
|
||||
final int oldRating = ratingModel.value?.rating?.toInt() ?? 0;
|
||||
futureCount.value = userReviewsCount - 1;
|
||||
futureSum.value = userReviewsSum - oldRating;
|
||||
} else {
|
||||
futureCount.value = userReviewsCount;
|
||||
futureSum.value = userReviewsSum;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
/// Save / update review
|
||||
Future<void> submitReview() async {
|
||||
if (comment.value.text.trim().isEmpty || ratings.value == 0) {
|
||||
ShowToastDialog.showToast("Please provide rating and comment".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowToastDialog.showLoader("Submit in...".tr);
|
||||
|
||||
final user = await FireStoreUtils.getUserProfile(order.value?.driverId ?? '');
|
||||
|
||||
if (user != null) {
|
||||
user.reviewsCount = (futureCount.value + 1).toString();
|
||||
user.reviewsSum = (futureSum.value + ratings.value.toInt()).toString();
|
||||
}
|
||||
if (ratingModel.value != null) {
|
||||
/// Update existing review
|
||||
final updatedRating = RatingModel(
|
||||
id: ratingModel.value!.id,
|
||||
comment: comment.value.text,
|
||||
photos: ratingModel.value?.photos ?? [],
|
||||
rating: ratings.value,
|
||||
orderId: ratingModel.value!.orderId,
|
||||
driverId: ratingModel.value!.driverId,
|
||||
customerId: ratingModel.value!.customerId,
|
||||
vendorId: ratingModel.value?.vendorId,
|
||||
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
|
||||
profile: Constant.userModel?.profilePictureURL,
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
await FireStoreUtils.updateReviewById(updatedRating);
|
||||
if (user != null) {
|
||||
await FireStoreUtils.updateUser(user);
|
||||
}
|
||||
} else {
|
||||
/// New review
|
||||
final docRef = FireStoreUtils.fireStore.collection(CollectionName.itemsReview).doc();
|
||||
final newRating = RatingModel(
|
||||
id: docRef.id,
|
||||
comment: comment.value.text,
|
||||
photos: [],
|
||||
rating: ratings.value,
|
||||
orderId: order.value?.id,
|
||||
driverId: order.value?.driverId.toString(),
|
||||
customerId: Constant.userModel?.id,
|
||||
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
|
||||
profile: Constant.userModel?.profilePictureURL,
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
await FireStoreUtils.updateReviewById(newRating);
|
||||
if (user != null) {
|
||||
await FireStoreUtils.updateUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.back(result: true);
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
comment.value.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
1113
lib/controllers/cart_controller.dart
Normal file
1113
lib/controllers/cart_controller.dart
Normal file
File diff suppressed because it is too large
Load Diff
24
lib/controllers/cashback_controller.dart
Normal file
24
lib/controllers/cashback_controller.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import '../models/cashback_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class CashbackController extends GetxController {
|
||||
RxList<CashbackModel> cashbackList = <CashbackModel>[].obs;
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getCashback();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getCashback() async {
|
||||
await FireStoreUtils.getCashbackList().then((value) {
|
||||
if (value.isNotEmpty) {
|
||||
cashbackList.value = value;
|
||||
}
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
62
lib/controllers/category_restaurant_controller.dart
Normal file
62
lib/controllers/category_restaurant_controller.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import '../models/vendor_category_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class CategoryRestaurantController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxBool dineIn = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Rx<VendorCategoryModel> vendorCategoryModel = VendorCategoryModel().obs;
|
||||
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
vendorCategoryModel.value = argumentData['vendorCategoryModel'];
|
||||
dineIn.value = argumentData['dineIn'];
|
||||
await getZone();
|
||||
await getRestaurant();
|
||||
}
|
||||
Future.delayed(Duration(seconds: 1), () {
|
||||
isLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future getRestaurant() async {
|
||||
FireStoreUtils.getAllNearestRestaurantByCategoryId(categoryId: vendorCategoryModel.value.id.toString(), isDining: dineIn.value).listen((
|
||||
event,
|
||||
) async {
|
||||
allNearestRestaurant.clear();
|
||||
allNearestRestaurant.addAll(event);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> getZone() async {
|
||||
await FireStoreUtils.getZone().then((value) {
|
||||
if (value != null) {
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
if (Constant.isPointInPolygon(
|
||||
LatLng(Constant.selectedLocation.location!.latitude ?? 0.0, Constant.selectedLocation.location!.longitude ?? 0.0),
|
||||
value[i].area!,
|
||||
)) {
|
||||
Constant.selectedZone = value[i];
|
||||
Constant.isZoneAvailable = true;
|
||||
break;
|
||||
} else {
|
||||
Constant.isZoneAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
44
lib/controllers/change_language_controller.dart
Normal file
44
lib/controllers/change_language_controller.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/language_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../constant/collection_name.dart';
|
||||
|
||||
class ChangeLanguageController extends GetxController {
|
||||
Rx<LanguageModel> selectedLanguage = LanguageModel().obs;
|
||||
RxList<LanguageModel> languageList = <LanguageModel>[].obs;
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getLanguage();
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getLanguage() async {
|
||||
await FireStoreUtils.fireStore.collection(CollectionName.settings).doc("languages").get().then((event) {
|
||||
if (event.exists) {
|
||||
List languageListTemp = event.data()!["list"];
|
||||
for (var element in languageListTemp) {
|
||||
LanguageModel languageModel = LanguageModel.fromJson(element);
|
||||
languageList.add(languageModel);
|
||||
}
|
||||
|
||||
if (Preferences.getString(Preferences.languageCodeKey).toString().isNotEmpty) {
|
||||
LanguageModel pref = Constant.getLanguage();
|
||||
for (var element in languageList) {
|
||||
if (element.slug == pref.slug) {
|
||||
selectedLanguage.value = element;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
142
lib/controllers/chat_controller.dart
Normal file
142
lib/controllers/chat_controller.dart
Normal file
@@ -0,0 +1,142 @@
|
||||
import 'dart:async';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import '../models/conversation_model.dart';
|
||||
import '../models/inbox_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../service/send_notification.dart';
|
||||
|
||||
class ChatController extends GetxController {
|
||||
Rx<TextEditingController> messageController = TextEditingController().obs;
|
||||
|
||||
final ScrollController scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
if (scrollController.hasClients) {
|
||||
Timer(const Duration(milliseconds: 500), () => scrollController.jumpTo(scrollController.position.maxScrollExtent));
|
||||
}
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
RxString orderId = "".obs;
|
||||
RxString customerId = "".obs;
|
||||
RxString customerName = "".obs;
|
||||
RxString customerProfileImage = "".obs;
|
||||
RxString restaurantId = "".obs;
|
||||
RxString restaurantName = "".obs;
|
||||
RxString restaurantProfileImage = "".obs;
|
||||
RxString token = "".obs;
|
||||
RxString chatType = "".obs;
|
||||
|
||||
void getArgument() {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
orderId.value = argumentData['orderId'];
|
||||
customerId.value = argumentData['customerId'];
|
||||
customerName.value = argumentData['customerName'];
|
||||
customerProfileImage.value = argumentData['customerProfileImage'] ?? "";
|
||||
restaurantId.value = argumentData['restaurantId'];
|
||||
restaurantName.value = argumentData['restaurantName'];
|
||||
restaurantProfileImage.value = argumentData['restaurantProfileImage'] ?? "";
|
||||
token.value = argumentData['token'] ?? "";
|
||||
chatType.value = argumentData['chatType'];
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> sendMessage(String message, Url? url, String videoThumbnail, String messageType) async {
|
||||
InboxModel inboxModel = InboxModel(
|
||||
lastSenderId: customerId.value,
|
||||
customerId: customerId.value,
|
||||
customerName: customerName.value,
|
||||
restaurantId: restaurantId.value,
|
||||
restaurantName: restaurantName.value,
|
||||
createdAt: Timestamp.now(),
|
||||
orderId: orderId.value,
|
||||
customerProfileImage: customerProfileImage.value,
|
||||
restaurantProfileImage: restaurantProfileImage.value,
|
||||
lastMessage: messageController.value.text,
|
||||
chatType: chatType.value,
|
||||
);
|
||||
|
||||
print("chatType: ${chatType.value}");
|
||||
if (chatType.value == "Driver") {
|
||||
await FireStoreUtils.addDriverInbox(inboxModel);
|
||||
} else if (chatType.value == "worker" || chatType.value == "Worker") {
|
||||
await FireStoreUtils.addWorkerInbox(inboxModel);
|
||||
} else if (chatType.value == "provider" || chatType.value == "Provider") {
|
||||
await FireStoreUtils.addProviderInbox(inboxModel);
|
||||
} else {
|
||||
await FireStoreUtils.addRestaurantInbox(inboxModel);
|
||||
}
|
||||
|
||||
ConversationModel conversationModel = ConversationModel(
|
||||
id: const Uuid().v4(),
|
||||
message: message,
|
||||
senderId: customerId.value,
|
||||
receiverId: restaurantId.value,
|
||||
createdAt: Timestamp.now(),
|
||||
url: url,
|
||||
orderId: orderId.value,
|
||||
messageType: messageType,
|
||||
videoThumbnail: videoThumbnail,
|
||||
);
|
||||
|
||||
if (url != null) {
|
||||
if (url.mime.contains('image')) {
|
||||
conversationModel.message = "sent a message".tr;
|
||||
} else if (url.mime.contains('video')) {
|
||||
conversationModel.message = "Sent a video".tr;
|
||||
} else if (url.mime.contains('audio')) {
|
||||
conversationModel.message = "Sent a audio".tr;
|
||||
}
|
||||
}
|
||||
|
||||
if (chatType.value == "Driver") {
|
||||
await FireStoreUtils.addDriverChat(conversationModel);
|
||||
} else if (chatType.value == "worker" || chatType.value == "Worker") {
|
||||
await FireStoreUtils.addWorkerChat(conversationModel);
|
||||
} else if (chatType.value == "provider" || chatType.value == "Provider") {
|
||||
await FireStoreUtils.addProviderChat(conversationModel);
|
||||
} else {
|
||||
await FireStoreUtils.addRestaurantChat(conversationModel);
|
||||
}
|
||||
|
||||
//await SendNotification.sendChatFcmMessage(customerName.value, conversationModel.message.toString(), token.value, {});
|
||||
await SendNotification.sendChatFcmMessage(customerName.value, conversationModel.message.toString(), token.value, {
|
||||
"type": "chat",
|
||||
"chatType": chatType.value,
|
||||
"orderId": orderId.value,
|
||||
"customerId": customerId.value,
|
||||
"customerName": customerName.value,
|
||||
"customerProfileImage": customerProfileImage.value,
|
||||
"restaurantId": restaurantId.value,
|
||||
"restaurantName": restaurantName.value,
|
||||
"restaurantProfileImage": restaurantProfileImage.value,
|
||||
"token": token.value,
|
||||
});
|
||||
}
|
||||
|
||||
final ImagePicker imagePicker = ImagePicker();
|
||||
|
||||
// Future pickFile({required ImageSource source}) async {
|
||||
// try {
|
||||
// XFile? image = await imagePicker.pickImage(source: source);
|
||||
// if (image == null) return;
|
||||
// Url url = await FireStoreUtils.uploadChatImageToFireStorage(File(image.path), Get.context!);
|
||||
// sendMessage('', url, '', 'image');
|
||||
// Get.back();
|
||||
// } on PlatformException catch (e) {
|
||||
// ShowToastDialog.showToast("${"failed_to_pick".tr} : \n $e");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
95
lib/controllers/complain_controller.dart
Normal file
95
lib/controllers/complain_controller.dart
Normal file
@@ -0,0 +1,95 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../models/cab_order_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class ComplainController extends GetxController {
|
||||
Rx<CabOrderModel> order = CabOrderModel().obs;
|
||||
|
||||
final Rx<TextEditingController> title = TextEditingController().obs;
|
||||
final Rx<TextEditingController> comment = TextEditingController().obs;
|
||||
|
||||
final RxBool isLoading = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
final args = Get.arguments;
|
||||
if (args != null && args is Map && args['order'] is CabOrderModel) {
|
||||
order.value = args['order'] as CabOrderModel;
|
||||
getComplain();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Order data not found".tr);
|
||||
Get.back();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getComplain() async {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
final data = await FireStoreUtils.getRideComplainData(order.value.id ?? '');
|
||||
if (data != null) {
|
||||
title.value.text = data['title'] ?? '';
|
||||
comment.value.text = data['description'] ?? '';
|
||||
}
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("Failed to load complaint".tr);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> submitComplain() async {
|
||||
// Validation
|
||||
if (title.value.text.trim().isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter complaint title".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (comment.value.text.trim().isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter complaint description".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
ShowToastDialog.showLoader("Please wait...");
|
||||
|
||||
try {
|
||||
// Check if complaint already exists
|
||||
bool exists = await FireStoreUtils.isRideComplainAdded(order.value.id ?? '');
|
||||
|
||||
if (!exists) {
|
||||
await FireStoreUtils.setRideComplain(
|
||||
orderId: order.value.id ?? '',
|
||||
title: title.value.text.trim(),
|
||||
description: comment.value.text.trim(),
|
||||
customerID: order.value.authorID ?? '',
|
||||
customerName: "${order.value.author?.firstName ?? ''} ${order.value.author?.lastName ?? ''}".trim(),
|
||||
driverID: order.value.driverId ?? '',
|
||||
driverName: "${order.value.driver?.firstName ?? ''} ${order.value.driver?.lastName ?? ''}".trim(),
|
||||
);
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Your complaint has been submitted to admin".tr);
|
||||
Get.back();
|
||||
} else {
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Your complaint is already submitted".tr);
|
||||
}
|
||||
} catch (e) {
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Something went wrong, please try again".tr);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
title.value.dispose();
|
||||
comment.value.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
46
lib/controllers/dash_board_controller.dart
Normal file
46
lib/controllers/dash_board_controller.dart
Normal file
@@ -0,0 +1,46 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import '../screen_ui/multi_vendor_service/favourite_screens/favourite_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/home_screen/home_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/home_screen/home_screen_two.dart';
|
||||
import '../screen_ui/multi_vendor_service/order_list_screen/order_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DashBoardController extends GetxController {
|
||||
RxInt selectedIndex = 0.obs;
|
||||
|
||||
RxList pageList = [].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getTaxList();
|
||||
if (Constant.sectionConstantModel!.theme == "theme_2") {
|
||||
if (Constant.walletSetting == false) {
|
||||
pageList.value = [const HomeScreen(), const FavouriteScreen(), const OrderScreen(), const ProfileScreen()];
|
||||
} else {
|
||||
pageList.value = [const HomeScreen(), const FavouriteScreen(), const WalletScreen(), const OrderScreen(), const ProfileScreen()];
|
||||
}
|
||||
} else {
|
||||
if (Constant.walletSetting == false) {
|
||||
pageList.value = [const HomeScreenTwo(), const FavouriteScreen(), const OrderScreen(), const ProfileScreen()];
|
||||
} else {
|
||||
pageList.value = [const HomeScreenTwo(), const FavouriteScreen(), const WalletScreen(), const OrderScreen(), const ProfileScreen()];
|
||||
}
|
||||
}
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getTaxList() async {
|
||||
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
|
||||
if (value != null) {
|
||||
Constant.taxList = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DateTime? currentBackPressTime;
|
||||
RxBool canPopNow = false.obs;
|
||||
}
|
||||
37
lib/controllers/dash_board_ecommarce_controller.dart
Normal file
37
lib/controllers/dash_board_ecommarce_controller.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/screen_ui/ecommarce/home_e_commerce_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/favourite_screens/favourite_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/order_list_screen/order_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DashBoardEcommerceController extends GetxController {
|
||||
RxInt selectedIndex = 0.obs;
|
||||
|
||||
RxList pageList = [].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getTaxList();
|
||||
if (Constant.walletSetting == false) {
|
||||
pageList.value = [const HomeECommerceScreen(), const FavouriteScreen(), const OrderScreen(), const ProfileScreen()];
|
||||
} else {
|
||||
pageList.value = [const HomeECommerceScreen(), const FavouriteScreen(), const WalletScreen(), const OrderScreen(), const ProfileScreen()];
|
||||
}
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getTaxList() async {
|
||||
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
|
||||
if (value != null) {
|
||||
Constant.taxList = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DateTime? currentBackPressTime;
|
||||
RxBool canPopNow = false.obs;
|
||||
}
|
||||
34
lib/controllers/dine_in_booking_controller.dart
Normal file
34
lib/controllers/dine_in_booking_controller.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import '../models/dine_in_booking_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DineInBookingController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
RxBool isFeature = true.obs;
|
||||
|
||||
RxList<DineInBookingModel> featureList = <DineInBookingModel>[].obs;
|
||||
RxList<DineInBookingModel> historyList = <DineInBookingModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getDineInBooking();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getDineInBooking() async {
|
||||
await FireStoreUtils.getDineInBooking(true).then(
|
||||
(value) {
|
||||
featureList.value = value;
|
||||
},
|
||||
);
|
||||
await FireStoreUtils.getDineInBooking(false).then(
|
||||
(value) {
|
||||
historyList.value = value;
|
||||
},
|
||||
);
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
24
lib/controllers/dine_in_booking_details_controller.dart
Normal file
24
lib/controllers/dine_in_booking_details_controller.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:customer/models/dine_in_booking_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DineInBookingDetailsController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Rx<DineInBookingModel> bookingModel = DineInBookingModel().obs;
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
bookingModel.value = argumentData['bookingModel'];
|
||||
}
|
||||
isLoading.value = false;
|
||||
update();
|
||||
}
|
||||
}
|
||||
100
lib/controllers/dine_in_controller.dart
Normal file
100
lib/controllers/dine_in_controller.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/favourite_model.dart';
|
||||
import 'package:customer/models/vendor_category_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import '../models/banner_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DineInController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxBool isPopular = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getCategory();
|
||||
getData();
|
||||
// TODO: implement onInit
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
RxList<VendorCategoryModel> vendorCategoryModel = <VendorCategoryModel>[].obs;
|
||||
|
||||
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
|
||||
RxList<VendorModel> newArrivalRestaurantList = <VendorModel>[].obs;
|
||||
RxList<VendorModel> popularRestaurantList = <VendorModel>[].obs;
|
||||
|
||||
RxList<BannerModel> bannerBottomModel = <BannerModel>[].obs;
|
||||
Rx<PageController> pageBottomController = PageController(viewportFraction: 0.877).obs;
|
||||
RxInt currentBottomPage = 0.obs;
|
||||
|
||||
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
|
||||
|
||||
Future<void> getData() async {
|
||||
isLoading.value = true;
|
||||
await getZone();
|
||||
|
||||
FireStoreUtils.getAllNearestRestaurant(isDining: true).listen((event) async {
|
||||
newArrivalRestaurantList.clear();
|
||||
allNearestRestaurant.clear();
|
||||
popularRestaurantList.clear();
|
||||
|
||||
allNearestRestaurant.addAll(event);
|
||||
newArrivalRestaurantList.addAll(event);
|
||||
popularRestaurantList.addAll(event);
|
||||
|
||||
popularRestaurantList.sort(
|
||||
(a, b) => Constant.calculateReview(reviewCount: b.reviewsCount.toString(), reviewSum: b.reviewsSum.toString())
|
||||
.compareTo(Constant.calculateReview(reviewCount: a.reviewsCount.toString(), reviewSum: a.reviewsSum.toString())),
|
||||
);
|
||||
|
||||
newArrivalRestaurantList.sort(
|
||||
(a, b) => (b.createdAt ?? Timestamp.now()).toDate().compareTo((a.createdAt ?? Timestamp.now()).toDate()),
|
||||
);
|
||||
});
|
||||
|
||||
update();
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getCategory() async {
|
||||
await FireStoreUtils.getHomeVendorCategory().then(
|
||||
(value) {
|
||||
vendorCategoryModel.value = value;
|
||||
},
|
||||
);
|
||||
|
||||
await FireStoreUtils.getHomeBottomBanner().then(
|
||||
(value) {
|
||||
bannerBottomModel.value = value;
|
||||
},
|
||||
);
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getFavouriteRestaurant().then(
|
||||
(value) {
|
||||
favouriteList.value = value;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getZone() async {
|
||||
await FireStoreUtils.getZone().then((value) {
|
||||
if (value != null) {
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
if (Constant.isPointInPolygon(LatLng(Constant.selectedLocation.location!.latitude ?? 0.0, Constant.selectedLocation.location!.longitude ?? 0.0), value[i].area!)) {
|
||||
Constant.selectedZone = value[i];
|
||||
Constant.isZoneAvailable = true;
|
||||
break;
|
||||
} else {
|
||||
Constant.isZoneAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
287
lib/controllers/dine_in_restaurant_details_controller.dart
Normal file
287
lib/controllers/dine_in_restaurant_details_controller.dart
Normal file
@@ -0,0 +1,287 @@
|
||||
import 'dart:async';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/dine_in_booking_model.dart';
|
||||
import 'package:customer/models/favourite_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../screen_ui/multi_vendor_service/dine_in_booking/dine_in_booking_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../service/send_notification.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class DineInRestaurantDetailsController extends GetxController {
|
||||
Rx<TextEditingController> searchEditingController = TextEditingController().obs;
|
||||
|
||||
Rx<TextEditingController> additionRequestController = TextEditingController().obs;
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
RxBool firstVisit = false.obs;
|
||||
Rx<PageController> pageController = PageController().obs;
|
||||
RxInt currentPage = 0.obs;
|
||||
RxInt noOfQuantity = 1.obs;
|
||||
|
||||
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
|
||||
RxList tags = [].obs;
|
||||
|
||||
// List occasionList = ["Birthday", "Anniversary"];
|
||||
RxList<String> occasionList = ["Birthday", "Anniversary"].obs;
|
||||
|
||||
/// Localized title for each occasion
|
||||
String getLocalizedOccasion(String key) {
|
||||
switch (key) {
|
||||
case "Birthday":
|
||||
return "Birthday".tr;
|
||||
case "Anniversary":
|
||||
return "Anniversary".tr;
|
||||
default:
|
||||
return key;
|
||||
}
|
||||
}
|
||||
RxString selectedOccasion = "".obs;
|
||||
|
||||
RxList<DateModel> dateList = <DateModel>[].obs;
|
||||
RxList<TimeModel> timeSlotList = <TimeModel>[].obs;
|
||||
|
||||
Rx<Timestamp> selectedDate = Timestamp.now().obs;
|
||||
RxString selectedTimeSlot = '6:00 PM'.obs;
|
||||
|
||||
RxString selectedTimeDiscount = '0'.obs;
|
||||
RxString selectedTimeDiscountType = ''.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
getRecord();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> orderBook() async {
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
|
||||
DateTime dt = selectedDate.value.toDate();
|
||||
String hour = DateFormat("kk:mm").format(DateFormat('hh:mm a').parse((Intl.getCurrentLocale() == "en_US") ? selectedTimeSlot.value : selectedTimeSlot.value.toLowerCase()));
|
||||
dt = DateTime(dt.year, dt.month, dt.day, int.parse(hour.split(":")[0]), int.parse(hour.split(":")[1]), dt.second, dt.millisecond, dt.microsecond);
|
||||
selectedDate.value = Timestamp.fromDate(dt);
|
||||
DineInBookingModel dineInBookingModel = DineInBookingModel(
|
||||
id: Constant.getUuid(),
|
||||
author: Constant.userModel,
|
||||
authorID: FireStoreUtils.getCurrentUid(),
|
||||
createdAt: Timestamp.now(),
|
||||
date: selectedDate.value,
|
||||
status: Constant.orderPlaced,
|
||||
vendor: vendorModel.value,
|
||||
specialRequest: additionRequestController.value.text.isEmpty ? "" : additionRequestController.value.text,
|
||||
vendorID: vendorModel.value.id,
|
||||
guestEmail: Constant.userModel!.email,
|
||||
guestFirstName: Constant.userModel!.firstName,
|
||||
guestLastName: Constant.userModel!.lastName,
|
||||
guestPhone: Constant.userModel!.phoneNumber,
|
||||
occasion: selectedOccasion.value,
|
||||
discount: selectedTimeDiscount.value,
|
||||
discountType: selectedTimeDiscountType.value,
|
||||
totalGuest: noOfQuantity.value.toString(),
|
||||
firstVisit: firstVisit.value);
|
||||
await FireStoreUtils.setBookedOrder(dineInBookingModel);
|
||||
await SendNotification.sendFcmMessage(Constant.dineInPlaced, vendorModel.value.fcmToken.toString(), {});
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.back();
|
||||
Get.to(const DineInBookingScreen());
|
||||
ShowToastDialog.showToast('Dine-In Request submitted successfully.'.tr);
|
||||
}
|
||||
|
||||
void getRecord() {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
final now = DateTime.now().add(Duration(days: i));
|
||||
var day = DateFormat('EEEE').format(now);
|
||||
if (vendorModel.value.specialDiscount?.isNotEmpty == true && vendorModel.value.specialDiscountEnable == true) {
|
||||
for (var element in vendorModel.value.specialDiscount!) {
|
||||
if (day == element.day.toString()) {
|
||||
if (element.timeslot!.isNotEmpty) {
|
||||
SpecialDiscountTimeslot employeeWithMaxSalary =
|
||||
element.timeslot!.reduce((item1, item2) => double.parse(item1.discount.toString()) > double.parse(item2.discount.toString()) ? item1 : item2);
|
||||
if (employeeWithMaxSalary.discountType == "dinein") {
|
||||
DateModel model = DateModel(date: Timestamp.fromDate(now), discountPer: employeeWithMaxSalary.discount.toString());
|
||||
dateList.add(model);
|
||||
} else {
|
||||
DateModel model = DateModel(date: Timestamp.fromDate(now), discountPer: "0");
|
||||
dateList.add(model);
|
||||
}
|
||||
} else {
|
||||
DateModel model = DateModel(date: Timestamp.fromDate(now), discountPer: "0");
|
||||
dateList.add(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DateModel model = DateModel(date: Timestamp.fromDate(now), discountPer: "0");
|
||||
dateList.add(model);
|
||||
}
|
||||
}
|
||||
selectedDate.value = dateList.first.date;
|
||||
|
||||
timeSet(selectedDate.value);
|
||||
if (timeSlotList.isNotEmpty) {
|
||||
selectedTimeSlot.value = DateFormat('hh:mm a').format(timeSlotList[0].time!);
|
||||
}
|
||||
}
|
||||
|
||||
void timeSet(Timestamp selectedDate) {
|
||||
timeSlotList.clear();
|
||||
|
||||
for (DateTime time = Constant.stringToDate(vendorModel.value.openDineTime.toString());
|
||||
time.isBefore(Constant.stringToDate(vendorModel.value.closeDineTime.toString()));
|
||||
time = time.add(const Duration(minutes: 30))) {
|
||||
final now = DateTime.parse(selectedDate.toDate().toString());
|
||||
var day = DateFormat('EEEE').format(now);
|
||||
var date = DateFormat('dd-MM-yyyy').format(now);
|
||||
|
||||
if (vendorModel.value.specialDiscount?.isNotEmpty == true && vendorModel.value.specialDiscountEnable == true) {
|
||||
for (var element in vendorModel.value.specialDiscount!) {
|
||||
if (day == element.day.toString()) {
|
||||
if (element.timeslot!.isNotEmpty) {
|
||||
for (var element in element.timeslot!) {
|
||||
if (element.discountType == "dinein") {
|
||||
var start = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.from}");
|
||||
var end = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.to}");
|
||||
var selected = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${DateFormat.Hm().format(time)}");
|
||||
|
||||
if (isCurrentDateInRangeDineIn(start, end, selected)) {
|
||||
var contains = timeSlotList.where((element) => element.time == time);
|
||||
if (contains.isNotEmpty) {
|
||||
var index = timeSlotList.indexWhere((element) => element.time == time);
|
||||
if (timeSlotList[index].discountPer == "0") {
|
||||
timeSlotList.removeAt(index);
|
||||
TimeModel model = TimeModel(time: time, discountPer: element.discount, discountType: element.type);
|
||||
timeSlotList.insert(index == 0 ? 0 : index, model);
|
||||
}
|
||||
} else {
|
||||
TimeModel model = TimeModel(time: time, discountPer: element.discount, discountType: element.type);
|
||||
timeSlotList.add(model);
|
||||
}
|
||||
} else {
|
||||
var contains = timeSlotList.where((element) => element.time == time);
|
||||
if (contains.isEmpty) {
|
||||
TimeModel model = TimeModel(time: time, discountPer: "0", discountType: "amount");
|
||||
timeSlotList.add(model);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TimeModel model = TimeModel(time: time, discountPer: "0", discountType: "amount");
|
||||
timeSlotList.add(model);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TimeModel model = TimeModel(time: time, discountPer: "0", discountType: "amount");
|
||||
timeSlotList.add(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TimeModel model = TimeModel(time: time, discountPer: "0", discountType: "amount");
|
||||
timeSlotList.add(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void animateSlider() {
|
||||
if (vendorModel.value.photos != null && vendorModel.value.photos!.isNotEmpty) {
|
||||
Timer.periodic(const Duration(seconds: 2), (Timer timer) {
|
||||
if (currentPage < vendorModel.value.photos!.length) {
|
||||
currentPage++;
|
||||
} else {
|
||||
currentPage.value = 0;
|
||||
}
|
||||
|
||||
if (pageController.value.hasClients) {
|
||||
pageController.value.animateToPage(
|
||||
currentPage.value,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeIn,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Rx<VendorModel> vendorModel = VendorModel().obs;
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
vendorModel.value = argumentData['vendorModel'];
|
||||
}
|
||||
animateSlider();
|
||||
statusCheck();
|
||||
isLoading.value = false;
|
||||
await getFavouriteList();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> getFavouriteList() async {
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getFavouriteRestaurant().then(
|
||||
(value) {
|
||||
favouriteList.value = value;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await FireStoreUtils.getVendorCuisines(vendorModel.value.id.toString()).then(
|
||||
(value) {
|
||||
tags.value = value;
|
||||
},
|
||||
);
|
||||
update();
|
||||
}
|
||||
|
||||
RxBool isOpen = false.obs;
|
||||
|
||||
void statusCheck() {
|
||||
final now = DateTime.now();
|
||||
var day = DateFormat('EEEE', 'en_US').format(now);
|
||||
var date = DateFormat('dd-MM-yyyy').format(now);
|
||||
for (var element in vendorModel.value.workingHours!) {
|
||||
if (day == element.day.toString()) {
|
||||
if (element.timeslot!.isNotEmpty) {
|
||||
for (var element in element.timeslot!) {
|
||||
var start = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.from}");
|
||||
var end = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.to}");
|
||||
if (isCurrentDateInRange(start, end)) {
|
||||
isOpen.value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isCurrentDateInRangeDineIn(DateTime startDate, DateTime endDate, DateTime selected) {
|
||||
return selected.isAtSameMomentAs(startDate) || selected.isAtSameMomentAs(endDate) || selected.isAfter(startDate) && selected.isBefore(endDate);
|
||||
}
|
||||
|
||||
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
|
||||
final currentDate = DateTime.now();
|
||||
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
|
||||
}
|
||||
}
|
||||
|
||||
class DateModel {
|
||||
late Timestamp date;
|
||||
late String discountPer;
|
||||
|
||||
DateModel({required this.date, required this.discountPer});
|
||||
}
|
||||
|
||||
class TimeModel {
|
||||
DateTime? time;
|
||||
String? discountPer;
|
||||
String? discountType;
|
||||
|
||||
TimeModel({required this.time, required this.discountPer, required this.discountType});
|
||||
}
|
||||
28
lib/controllers/discount_restaurant_list_controller.dart
Normal file
28
lib/controllers/discount_restaurant_list_controller.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DiscountRestaurantListController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<VendorModel> vendorList = <VendorModel>[].obs;
|
||||
RxList<CouponModel> couponList = <CouponModel>[].obs;
|
||||
|
||||
RxString title = "Restaurants".obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
vendorList.value = argumentData['vendorList'];
|
||||
couponList.value = argumentData['couponList'];
|
||||
title.value = argumentData['title'] ?? "Restaurants";
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
77
lib/controllers/edit_profile_controller.dart
Normal file
77
lib/controllers/edit_profile_controller.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
import 'dart:io';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class EditProfileController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
|
||||
Rx<TextEditingController> firstNameController = TextEditingController().obs;
|
||||
Rx<TextEditingController> lastNameController = TextEditingController().obs;
|
||||
Rx<TextEditingController> emailController = TextEditingController().obs;
|
||||
Rx<TextEditingController> phoneNumberController = TextEditingController().obs;
|
||||
Rx<TextEditingController> countryCodeController = TextEditingController(text: "+91").obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
|
||||
if (value != null) {
|
||||
userModel.value = value;
|
||||
firstNameController.value.text = userModel.value.firstName.toString();
|
||||
lastNameController.value.text = userModel.value.lastName.toString();
|
||||
emailController.value.text = userModel.value.email.toString();
|
||||
phoneNumberController.value.text = userModel.value.phoneNumber.toString();
|
||||
countryCodeController.value.text = userModel.value.countryCode.toString();
|
||||
profileImage.value = userModel.value.profilePictureURL ?? "";
|
||||
}
|
||||
});
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> saveData() async {
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
if (Constant().hasValidUrl(profileImage.value) == false && profileImage.value.isNotEmpty) {
|
||||
profileImage.value = await Constant.uploadUserImageToFireStorage(
|
||||
File(profileImage.value),
|
||||
"profileImage/${FireStoreUtils.getCurrentUid()}",
|
||||
File(profileImage.value).path.split('/').last,
|
||||
);
|
||||
}
|
||||
|
||||
userModel.value.firstName = firstNameController.value.text;
|
||||
userModel.value.lastName = lastNameController.value.text;
|
||||
userModel.value.profilePictureURL = profileImage.value;
|
||||
|
||||
await FireStoreUtils.updateUser(userModel.value).then((value) {
|
||||
ShowToastDialog.closeLoader();
|
||||
//Get.back(result: true);
|
||||
});
|
||||
}
|
||||
|
||||
final ImagePicker _imagePicker = ImagePicker();
|
||||
RxString profileImage = "".obs;
|
||||
|
||||
Future pickFile({required ImageSource source}) async {
|
||||
try {
|
||||
XFile? image = await _imagePicker.pickImage(source: source);
|
||||
if (image == null) return;
|
||||
Get.back();
|
||||
profileImage.value = image.path;
|
||||
} on PlatformException catch (e) {
|
||||
ShowToastDialog.showToast("${"failed_to_pick".tr} : \n $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
83
lib/controllers/enter_manually_location_controller.dart
Normal file
83
lib/controllers/enter_manually_location_controller.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../models/user_model.dart';
|
||||
|
||||
class EnterManuallyLocationController extends GetxController {
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
|
||||
RxList<ShippingAddress> shippingAddressList = <ShippingAddress>[].obs;
|
||||
|
||||
List saveAsList = ['Home', 'Work', 'Hotel', 'other'].obs;
|
||||
RxString selectedSaveAs = "Home".obs;
|
||||
|
||||
Rx<TextEditingController> houseBuildingTextEditingController = TextEditingController().obs;
|
||||
Rx<TextEditingController> localityEditingController = TextEditingController().obs;
|
||||
Rx<TextEditingController> landmarkEditingController = TextEditingController().obs;
|
||||
Rx<UserLocation> location = UserLocation().obs;
|
||||
Rx<ShippingAddress> shippingModel = ShippingAddress().obs;
|
||||
RxBool isLoading = false.obs;
|
||||
RxBool isDefault = false.obs;
|
||||
|
||||
RxString mode = "Add".obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
//check mode
|
||||
mode.value = argumentData['mode'] ?? "Add";
|
||||
|
||||
//check address
|
||||
if (argumentData['address'] != null && argumentData['address'] is ShippingAddress) {
|
||||
shippingModel.value = argumentData['address'];
|
||||
setData(shippingModel.value);
|
||||
}
|
||||
}
|
||||
|
||||
await getUser();
|
||||
isLoading.value = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void setData(ShippingAddress shippingAddress) {
|
||||
shippingModel.value = shippingAddress;
|
||||
houseBuildingTextEditingController.value.text = shippingAddress.address.toString();
|
||||
localityEditingController.value.text = shippingAddress.locality.toString();
|
||||
landmarkEditingController.value.text = shippingAddress.landmark.toString();
|
||||
selectedSaveAs.value = shippingAddress.addressAs.toString();
|
||||
location.value = shippingAddress.location!;
|
||||
}
|
||||
|
||||
Future<void> getUser() async {
|
||||
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
|
||||
if (value != null) {
|
||||
userModel.value = value;
|
||||
if (userModel.value.shippingAddress != null) {
|
||||
shippingAddressList.value = userModel.value.shippingAddress!;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String getLocalizedSaveAs(String key) {
|
||||
switch (key) {
|
||||
case 'Home':
|
||||
return 'Home'.tr;
|
||||
case 'Work':
|
||||
return 'Work'.tr;
|
||||
case 'Hotel':
|
||||
return 'Hotel'.tr;
|
||||
case 'Other':
|
||||
return 'Other'.tr;
|
||||
default:
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
93
lib/controllers/favourite_controller.dart
Normal file
93
lib/controllers/favourite_controller.dart
Normal file
@@ -0,0 +1,93 @@
|
||||
import 'package:customer/constant/collection_name.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/favourite_item_model.dart';
|
||||
import 'package:customer/models/favourite_model.dart';
|
||||
import 'package:customer/models/product_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class FavouriteController extends GetxController {
|
||||
RxBool favouriteRestaurant = true.obs;
|
||||
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
|
||||
RxList<VendorModel> favouriteVendorList = <VendorModel>[].obs;
|
||||
|
||||
RxList<FavouriteItemModel> favouriteItemList = <FavouriteItemModel>[].obs;
|
||||
RxList<ProductModel> favouriteFoodList = <ProductModel>[].obs;
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getFavouriteRestaurant().then((value) {
|
||||
favouriteList.value = value;
|
||||
});
|
||||
|
||||
await FireStoreUtils.getFavouriteItem().then((value) {
|
||||
favouriteItemList.value = value;
|
||||
});
|
||||
|
||||
for (var element in favouriteList) {
|
||||
await FireStoreUtils.getVendorById(element.restaurantId.toString()).then((value) async {
|
||||
if (value != null) {
|
||||
if ((Constant.isSubscriptionModelApplied == true || value.adminCommission?.isEnabled == true) && value.subscriptionPlan != null) {
|
||||
if (value.subscriptionTotalOrders == "-1") {
|
||||
favouriteVendorList.add(value);
|
||||
} else {
|
||||
print("Restaurant :: ${value.title.toString()}");
|
||||
if ((value.subscriptionExpiryDate != null && value.subscriptionExpiryDate!.toDate().isBefore(DateTime.now()) == false) ||
|
||||
value.subscriptionPlan?.expiryDay == '-1') {
|
||||
if (value.subscriptionTotalOrders != '0') {
|
||||
favouriteVendorList.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
favouriteVendorList.add(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (var element in favouriteItemList) {
|
||||
await FireStoreUtils.getProductById(element.productId.toString()).then((value) async {
|
||||
if (value != null) {
|
||||
await FireStoreUtils.fireStore.collection(CollectionName.vendors).doc(value.vendorID.toString()).get().then((value1) async {
|
||||
if (value1.exists) {
|
||||
VendorModel vendorModel = VendorModel.fromJson(value1.data()!);
|
||||
if(value.publish == true){
|
||||
if (Constant.isSubscriptionModelApplied == true || vendorModel.adminCommission?.isEnabled == true) {
|
||||
if (vendorModel.subscriptionPlan != null) {
|
||||
if (vendorModel.subscriptionTotalOrders == "-1") {
|
||||
favouriteFoodList.add(value);
|
||||
} else {
|
||||
if ((vendorModel.subscriptionExpiryDate != null && vendorModel.subscriptionExpiryDate!.toDate().isBefore(DateTime.now()) == false) ||
|
||||
vendorModel.subscriptionPlan?.expiryDay == "-1") {
|
||||
if (vendorModel.subscriptionTotalOrders != '0') {
|
||||
favouriteFoodList.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
favouriteFoodList.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
73
lib/controllers/favourite_ondemmand_controller.dart
Normal file
73
lib/controllers/favourite_ondemmand_controller.dart
Normal file
@@ -0,0 +1,73 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/category_model.dart';
|
||||
import 'package:customer/models/favorite_ondemand_service_model.dart';
|
||||
import 'package:customer/models/provider_serivce_model.dart';
|
||||
import 'package:customer/screen_ui/auth_screens/login_screen.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class FavouriteOndemmandController extends GetxController {
|
||||
// Add your controller logic here
|
||||
|
||||
Rx<bool> isLoading = false.obs;
|
||||
RxList<FavouriteOndemandServiceModel> lstFav = <FavouriteOndemandServiceModel>[].obs;
|
||||
RxList<CategoryModel> categories = <CategoryModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
isLoading.value = true;
|
||||
await FireStoreUtils.getOnDemandCategory().then((catValue) {
|
||||
categories.value = catValue;
|
||||
});
|
||||
await FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid()).then((favList) {
|
||||
lstFav.value = favList;
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
void toggleFavourite(ProviderServiceModel provider) {
|
||||
if (Constant.userModel == null) {
|
||||
Get.to(LoginScreen());
|
||||
} else {
|
||||
var contain = lstFav.where((element) => element.service_id == provider.id);
|
||||
if (contain.isNotEmpty) {
|
||||
FavouriteOndemandServiceModel favouriteModel = FavouriteOndemandServiceModel(
|
||||
section_id: provider.sectionId,
|
||||
service_id: provider.id,
|
||||
user_id: FireStoreUtils.getCurrentUid(),
|
||||
serviceAuthorId: provider.author,
|
||||
);
|
||||
FireStoreUtils.removeFavouriteOndemandService(favouriteModel);
|
||||
lstFav.removeWhere((item) => item.service_id == provider.id);
|
||||
} else {
|
||||
FavouriteOndemandServiceModel favouriteModel = FavouriteOndemandServiceModel(
|
||||
section_id: provider.sectionId,
|
||||
service_id: provider.id,
|
||||
user_id: FireStoreUtils.getCurrentUid(),
|
||||
serviceAuthorId: provider.author,
|
||||
);
|
||||
FireStoreUtils.setFavouriteOndemandSection(favouriteModel);
|
||||
lstFav.add(favouriteModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get category by id safely from cached categories
|
||||
Future<CategoryModel?> getCategory(String? categoryId) async {
|
||||
if (categoryId == null || categoryId.isEmpty) return null;
|
||||
|
||||
// Try to find category from cached list
|
||||
CategoryModel? cat = categories.firstWhereOrNull((element) => element.id == categoryId);
|
||||
|
||||
// If not found, fetch from Firestore
|
||||
cat ??= await FireStoreUtils.getCategoryById(categoryId);
|
||||
|
||||
return cat;
|
||||
}
|
||||
}
|
||||
191
lib/controllers/food_home_controller.dart
Normal file
191
lib/controllers/food_home_controller.dart
Normal file
@@ -0,0 +1,191 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/controllers/dash_board_controller.dart';
|
||||
import 'package:customer/models/advertisement_model.dart';
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/models/favourite_model.dart';
|
||||
import 'package:customer/models/vendor_category_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import '../models/banner_model.dart';
|
||||
import '../models/story_model.dart';
|
||||
import '../service/cart_provider.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class FoodHomeController extends GetxController {
|
||||
DashBoardController dashBoardController = Get.find<DashBoardController>();
|
||||
final CartProvider cartProvider = CartProvider();
|
||||
|
||||
Future<void> getCartData() async {
|
||||
cartProvider.cartStream.listen((event) async {
|
||||
cartItem.clear();
|
||||
cartItem.addAll(event);
|
||||
});
|
||||
update();
|
||||
}
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
RxBool isListView = true.obs;
|
||||
RxBool isPopular = true.obs;
|
||||
RxString selectedOrderTypeValue = "Delivery".tr.obs;
|
||||
|
||||
Rx<PageController> pageController = PageController(viewportFraction: 0.877).obs;
|
||||
Rx<PageController> pageBottomController = PageController(viewportFraction: 0.877).obs;
|
||||
RxInt currentPage = 0.obs;
|
||||
RxInt currentBottomPage = 0.obs;
|
||||
|
||||
late TabController tabController;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
await getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
RxList<VendorCategoryModel> vendorCategoryModel = <VendorCategoryModel>[].obs;
|
||||
|
||||
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
|
||||
RxList<VendorModel> newArrivalRestaurantList = <VendorModel>[].obs;
|
||||
RxList<AdvertisementModel> advertisementList = <AdvertisementModel>[].obs;
|
||||
RxList<VendorModel> popularRestaurantList = <VendorModel>[].obs;
|
||||
RxList<VendorModel> couponRestaurantList = <VendorModel>[].obs;
|
||||
RxList<CouponModel> couponList = <CouponModel>[].obs;
|
||||
|
||||
RxList<StoryModel> storyList = <StoryModel>[].obs;
|
||||
RxList<BannerModel> bannerModel = <BannerModel>[].obs;
|
||||
RxList<BannerModel> bannerBottomModel = <BannerModel>[].obs;
|
||||
|
||||
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
|
||||
|
||||
Future<void> getData() async {
|
||||
isLoading.value = true;
|
||||
getCartData();
|
||||
selectedOrderTypeValue.value = Preferences.getString(Preferences.foodDeliveryType, defaultValue: "Delivery");
|
||||
await getZone();
|
||||
FireStoreUtils.getAllNearestRestaurant().listen((event) async {
|
||||
popularRestaurantList.clear();
|
||||
newArrivalRestaurantList.clear();
|
||||
allNearestRestaurant.clear();
|
||||
advertisementList.clear();
|
||||
|
||||
allNearestRestaurant.addAll(event);
|
||||
newArrivalRestaurantList.addAll(event);
|
||||
popularRestaurantList.addAll(event);
|
||||
Constant.restaurantList = allNearestRestaurant;
|
||||
popularRestaurantList.sort(
|
||||
(a, b) => Constant.calculateReview(
|
||||
reviewCount: b.reviewsCount.toString(),
|
||||
reviewSum: b.reviewsSum.toString(),
|
||||
).compareTo(Constant.calculateReview(reviewCount: a.reviewsCount.toString(), reviewSum: a.reviewsSum.toString())),
|
||||
);
|
||||
|
||||
newArrivalRestaurantList.sort((a, b) => (b.createdAt ?? Timestamp.now()).toDate().compareTo((a.createdAt ?? Timestamp.now()).toDate()));
|
||||
await getVendorCategory();
|
||||
await FireStoreUtils.getHomeCoupon().then((value) {
|
||||
couponRestaurantList.clear();
|
||||
couponList.clear();
|
||||
for (var element1 in value) {
|
||||
for (var element in allNearestRestaurant) {
|
||||
if (element1.vendorID == element.id && element1.expiresAt!.toDate().isAfter(DateTime.now())) {
|
||||
couponList.add(element1);
|
||||
couponRestaurantList.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getStory().then((stories) {
|
||||
storyList.clear();
|
||||
|
||||
print("Total stories fetched: ${stories.length}");
|
||||
// Create a fast lookup Set of all nearest vendor IDs
|
||||
final nearestIds = allNearestRestaurant.map((e) => e.id).toSet();
|
||||
|
||||
print("nearestIds: $nearestIds");
|
||||
// Filter stories whose vendorID exists in nearestIds
|
||||
storyList.addAll(
|
||||
stories.where((story) => nearestIds.contains(story.vendorID))
|
||||
);
|
||||
print("Filtered storyList length: ${storyList.length}");
|
||||
});
|
||||
|
||||
if (Constant.isEnableAdsFeature == true) {
|
||||
await FireStoreUtils.getAllAdvertisement().then((value) {
|
||||
advertisementList.clear();
|
||||
for (var element1 in value) {
|
||||
for (var element in allNearestRestaurant) {
|
||||
if (element1.vendorId == element.id) {
|
||||
advertisementList.add(element1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
setLoading();
|
||||
}
|
||||
|
||||
Future<void> setLoading() async {
|
||||
await Future.delayed(Duration(seconds: 1), () async {
|
||||
if (allNearestRestaurant.isEmpty) {
|
||||
await Future.delayed(Duration(seconds: 2), () {
|
||||
isLoading.value = false;
|
||||
});
|
||||
} else {
|
||||
isLoading.value = false;
|
||||
}
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> getVendorCategory() async {
|
||||
await FireStoreUtils.getHomeVendorCategory().then((value) {
|
||||
vendorCategoryModel.value = value;
|
||||
if (Constant.restaurantList != null) {
|
||||
List<String> usedCategoryIds = Constant.restaurantList!.expand((vendor) => vendor.categoryID ?? []).whereType<String>().toSet().toList();
|
||||
vendorCategoryModel.value = vendorCategoryModel.where((category) => usedCategoryIds.contains(category.id)).toList();
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getHomeTopBanner().then((value) {
|
||||
bannerModel.value = value;
|
||||
});
|
||||
|
||||
await FireStoreUtils.getHomeBottomBanner().then((value) {
|
||||
bannerBottomModel.value = value;
|
||||
});
|
||||
|
||||
await getFavouriteRestaurant();
|
||||
}
|
||||
|
||||
Future<void> getFavouriteRestaurant() async {
|
||||
if (Constant.userModel?.id != null) {
|
||||
await FireStoreUtils.getFavouriteRestaurant().then((value) {
|
||||
favouriteList.value = value;
|
||||
});
|
||||
}
|
||||
log("Constant.userModel?.id :: ${favouriteList.length}");
|
||||
}
|
||||
|
||||
Future<void> getZone() async {
|
||||
await FireStoreUtils.getZone().then((value) {
|
||||
if (value != null) {
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
if (Constant.isPointInPolygon(LatLng(Constant.selectedLocation.location?.latitude ?? 0.0, Constant.selectedLocation.location?.longitude ?? 0.0), value[i].area!)) {
|
||||
Constant.selectedZone = value[i];
|
||||
Constant.isZoneAvailable = true;
|
||||
break;
|
||||
} else {
|
||||
Constant.selectedZone = value[i];
|
||||
Constant.isZoneAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
40
lib/controllers/forgot_password_controller.dart
Normal file
40
lib/controllers/forgot_password_controller.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class ForgotPasswordController extends GetxController {
|
||||
Rx<TextEditingController> emailEditingController =
|
||||
TextEditingController().obs;
|
||||
|
||||
Future<void> forgotPassword() async {
|
||||
final email = emailEditingController.value.text.trim();
|
||||
|
||||
if (email.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter your email address.".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetUtils.isEmail(email)) {
|
||||
ShowToastDialog.showToast("Please enter a valid email address.".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
await FirebaseAuth.instance.sendPasswordResetEmail(email: email);
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast(
|
||||
'reset_password_link_sent'.trParams({'email': email}),
|
||||
);
|
||||
Get.back();
|
||||
} on FirebaseAuthException catch (e) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (e.code == 'user-not-found') {
|
||||
ShowToastDialog.showToast('No user found for that email.'.tr);
|
||||
} else {
|
||||
ShowToastDialog.showToast(e.message?.tr ?? "something_went_wrong".tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
920
lib/controllers/gift_card_controller.dart
Normal file
920
lib/controllers/gift_card_controller.dart
Normal file
@@ -0,0 +1,920 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as maths;
|
||||
import 'dart:math';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/gift_cards_model.dart';
|
||||
import 'package:customer/themes/app_them_data.dart';
|
||||
import 'package:flutter_paypal/flutter_paypal.dart';
|
||||
import 'package:flutter_stripe/flutter_stripe.dart';
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import '../models/gift_cards_order_model.dart';
|
||||
import '../models/payment_model/cod_setting_model.dart';
|
||||
import '../models/payment_model/flutter_wave_model.dart';
|
||||
import '../models/payment_model/mercado_pago_model.dart';
|
||||
import '../models/payment_model/mid_trans.dart';
|
||||
import '../models/payment_model/orange_money.dart';
|
||||
import '../models/payment_model/pay_fast_model.dart';
|
||||
import '../models/payment_model/pay_stack_model.dart';
|
||||
import '../models/payment_model/paypal_model.dart';
|
||||
import '../models/payment_model/paytm_model.dart';
|
||||
import '../models/payment_model/razorpay_model.dart';
|
||||
import '../models/payment_model/stripe_model.dart';
|
||||
import '../models/payment_model/wallet_setting_model.dart';
|
||||
import '../models/payment_model/xendit.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../models/wallet_transaction_model.dart';
|
||||
import '../payment/MercadoPagoScreen.dart';
|
||||
import '../payment/PayFastScreen.dart';
|
||||
import '../payment/getPaytmTxtToken.dart';
|
||||
import '../payment/midtrans_screen.dart';
|
||||
import '../payment/orangePayScreen.dart';
|
||||
import '../payment/paystack/pay_stack_screen.dart';
|
||||
import '../payment/paystack/pay_stack_url_model.dart';
|
||||
import '../payment/paystack/paystack_url_genrater.dart';
|
||||
import '../payment/stripe_failed_model.dart';
|
||||
import '../payment/xenditModel.dart';
|
||||
import '../payment/xenditScreen.dart';
|
||||
import '../screen_ui/multi_vendor_service/gift_card/history_gift_card.dart';
|
||||
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class GiftCardController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxString selectedPaymentMethod = ''.obs;
|
||||
var pageController = PageController();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getGiftCard();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
List<GiftCardsModel> giftCardList = [];
|
||||
Rx<GiftCardsModel> selectedGiftCard = GiftCardsModel().obs;
|
||||
|
||||
List amountList = ["1000", "2000", "5000"];
|
||||
RxString selectedAmount = "1000".obs;
|
||||
var selectedPageIndex = 0.obs;
|
||||
|
||||
Rx<TextEditingController> amountController = TextEditingController().obs;
|
||||
Rx<TextEditingController> messageController = TextEditingController().obs;
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
|
||||
Future<void> getGiftCard() async {
|
||||
await FireStoreUtils.getGiftCard().then((value) {
|
||||
giftCardList = value;
|
||||
if (giftCardList.isNotEmpty) {
|
||||
selectedGiftCard.value = giftCardList.first;
|
||||
messageController.value.text = selectedGiftCard.value.message.toString();
|
||||
}
|
||||
});
|
||||
|
||||
isLoading.value = false;
|
||||
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then(
|
||||
(value) {
|
||||
if (value != null) {
|
||||
userModel.value = value;
|
||||
}
|
||||
},
|
||||
);
|
||||
await getPaymentSettings();
|
||||
}
|
||||
|
||||
Future<void> placeOrder() async {
|
||||
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
|
||||
if (double.parse(userModel.value.walletAmount.toString()) >= double.parse(amountController.value.text)) {
|
||||
setOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("You don't have sufficient wallet balance to purchase gift card".tr);
|
||||
}
|
||||
} else {
|
||||
setOrder();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setOrder() async {
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
GiftCardsOrderModel giftCardsOrderModel = GiftCardsOrderModel();
|
||||
giftCardsOrderModel.id = const Uuid().v4();
|
||||
giftCardsOrderModel.giftId = selectedGiftCard.value.id.toString();
|
||||
giftCardsOrderModel.giftTitle = selectedGiftCard.value.title.toString();
|
||||
giftCardsOrderModel.price = amountController.value.text;
|
||||
giftCardsOrderModel.redeem = false;
|
||||
giftCardsOrderModel.message = messageController.value.text;
|
||||
giftCardsOrderModel.giftPin = generateGiftPin();
|
||||
giftCardsOrderModel.giftCode = generateGiftCode();
|
||||
giftCardsOrderModel.paymentType = selectedPaymentMethod.value;
|
||||
giftCardsOrderModel.createdDate = Timestamp.now();
|
||||
DateTime dateTime = DateTime.now().add(Duration(days: int.parse(selectedGiftCard.value.expiryDay ?? "2")));
|
||||
giftCardsOrderModel.expireDate = Timestamp.fromDate(dateTime);
|
||||
giftCardsOrderModel.userid = FireStoreUtils.getCurrentUid();
|
||||
|
||||
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: double.parse(amountController.value.text),
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "user",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: false,
|
||||
orderId: giftCardsOrderModel.id,
|
||||
note: "Gift card purchase amount debited".tr,
|
||||
paymentStatus: "success".tr);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
if (value == true) {
|
||||
await FireStoreUtils.updateUserWallet(amount: "-${amountController.value.text.toString()}", userId: FireStoreUtils.getCurrentUid()).then((value) {});
|
||||
}
|
||||
});
|
||||
}
|
||||
await FireStoreUtils.placeGiftCardOrder(giftCardsOrderModel);
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.off(const HistoryGiftCard());
|
||||
ShowToastDialog.showToast("Gift card Purchases successfully".tr);
|
||||
}
|
||||
|
||||
String generateGiftCode() {
|
||||
var rng = Random();
|
||||
String generatedNumber = '';
|
||||
for (int i = 0; i < 16; i++) {
|
||||
generatedNumber += (rng.nextInt(9) + 1).toString();
|
||||
}
|
||||
return generatedNumber;
|
||||
}
|
||||
|
||||
String generateGiftPin() {
|
||||
var rng = Random();
|
||||
String generatedNumber = '';
|
||||
for (int i = 0; i < 6; i++) {
|
||||
generatedNumber += (rng.nextInt(9) + 1).toString();
|
||||
}
|
||||
return generatedNumber;
|
||||
}
|
||||
|
||||
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
|
||||
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
|
||||
Rx<PayFastModel> payFastModel = PayFastModel().obs;
|
||||
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
|
||||
Rx<PayPalModel> payPalModel = PayPalModel().obs;
|
||||
Rx<StripeModel> stripeModel = StripeModel().obs;
|
||||
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
|
||||
Rx<PayStackModel> payStackModel = PayStackModel().obs;
|
||||
Rx<PaytmModel> paytmModel = PaytmModel().obs;
|
||||
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
|
||||
|
||||
Rx<MidTrans> midTransModel = MidTrans().obs;
|
||||
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
|
||||
Rx<Xendit> xenditModel = Xendit().obs;
|
||||
|
||||
Future<void> getPaymentSettings() async {
|
||||
await FireStoreUtils.getPaymentSettingsData().then(
|
||||
(value) {
|
||||
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
|
||||
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
|
||||
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
|
||||
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
|
||||
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
|
||||
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
|
||||
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
|
||||
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
|
||||
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
|
||||
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
|
||||
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
|
||||
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
|
||||
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
|
||||
if (walletSettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.wallet.name;
|
||||
} else if (stripeModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.stripe.name;
|
||||
} else if (payPalModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.paypal.name;
|
||||
} else if (payStackModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payStack.name;
|
||||
} else if (mercadoPagoModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
|
||||
} else if (flutterWaveModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
|
||||
}else if (payFastModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payFast.name;
|
||||
} else if (razorPayModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
|
||||
} else if (midTransModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
|
||||
} else if (orangeMoneyModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
|
||||
} else if (xenditModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.xendit.name;
|
||||
}
|
||||
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
|
||||
Stripe.merchantIdentifier = 'GoRide';
|
||||
Stripe.instance.applySettings();
|
||||
setRef();
|
||||
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
|
||||
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// final _flutterPaypalNativePlugin = FlutterPaypalNative.instance;
|
||||
|
||||
// void initPayPal() async {
|
||||
// //set debugMode for error logging
|
||||
// FlutterPaypalNative.isDebugMode = paytmModel.value.isSandboxEnabled == true ? true : false;
|
||||
|
||||
// //initiate payPal plugin
|
||||
// await _flutterPaypalNativePlugin.init(
|
||||
// //your app id !!! No Underscore!!! see readme.md for help
|
||||
// returnUrl: "com.parkme://paypalpay",
|
||||
// //client id from developer dashboard
|
||||
// clientID: payPalModel.value.paypalClient.toString(),
|
||||
// //sandbox, staging, live etc
|
||||
// payPalEnvironment: payPalModel.value.isLive == false ? FPayPalEnvironment.sandbox : FPayPalEnvironment.live,
|
||||
// //what currency do you plan to use? default is US dollars
|
||||
// currencyCode: FPayPalCurrencyCode.usd,
|
||||
// //action paynow?
|
||||
// action: FPayPalUserAction.payNow,
|
||||
// );
|
||||
|
||||
// //call backs for payment
|
||||
// _flutterPaypalNativePlugin.setPayPalOrderCallback(
|
||||
// callback: FPayPalOrderCallback(
|
||||
// onCancel: () {
|
||||
// //user canceled the payment
|
||||
// ShowToastDialog.showToast("Payment canceled");
|
||||
// },
|
||||
// onSuccess: (data) {
|
||||
// //successfully paid
|
||||
// //remove all items from queue
|
||||
// // _flutterPaypalNativePlugin.removeAllPurchaseItems();
|
||||
// ShowToastDialog.showToast("Payment Successful!!");
|
||||
// placeOrder();
|
||||
// },
|
||||
// onError: (data) {
|
||||
// //an error occured
|
||||
// ShowToastDialog.showToast("error: ${data.reason}");
|
||||
// },
|
||||
// onShippingChange: (data) {
|
||||
// //the user updated the shipping address
|
||||
// ShowToastDialog.showToast("shipping change: ${data.shippingChangeAddress?.adminArea1 ?? ""}");
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
// paypalPaymentSheet(String amount) {
|
||||
// //add 1 item to cart. Max is 4!
|
||||
// if (_flutterPaypalNativePlugin.canAddMorePurchaseUnit) {
|
||||
// _flutterPaypalNativePlugin.addPurchaseUnit(
|
||||
// FPayPalPurchaseUnit(
|
||||
// // random prices
|
||||
// amount: double.parse(amount),
|
||||
|
||||
// ///please use your own algorithm for referenceId. Maybe ProductID?
|
||||
// referenceId: FPayPalStrHelper.getRandomString(16),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// // initPayPal();
|
||||
// _flutterPaypalNativePlugin.makeOrder(
|
||||
// action: FPayPalUserAction.payNow,
|
||||
// );
|
||||
// }
|
||||
|
||||
// Strip
|
||||
Future<void> stripeMakePayment({required String amount}) async {
|
||||
try {
|
||||
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
|
||||
if (paymentIntentData!.containsKey("error")) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.");
|
||||
} else {
|
||||
await Stripe.instance.initPaymentSheet(
|
||||
paymentSheetParameters: SetupPaymentSheetParameters(
|
||||
paymentIntentClientSecret: paymentIntentData['client_secret'],
|
||||
allowsDelayedPaymentMethods: false,
|
||||
googlePay: const PaymentSheetGooglePay(
|
||||
merchantCountryCode: 'US',
|
||||
testEnv: true,
|
||||
currencyCode: "USD",
|
||||
),
|
||||
customFlow: true,
|
||||
style: ThemeMode.system,
|
||||
appearance: PaymentSheetAppearance(
|
||||
colors: PaymentSheetAppearanceColors(
|
||||
primary: AppThemeData.primary300,
|
||||
),
|
||||
),
|
||||
merchantDisplayName: 'GoRide'));
|
||||
displayStripePaymentSheet(amount: amount);
|
||||
}
|
||||
} catch (e, s) {
|
||||
ShowToastDialog.showToast("exception:$e \n$s");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> displayStripePaymentSheet({required String amount}) async {
|
||||
try {
|
||||
await Stripe.instance.presentPaymentSheet().then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
placeOrder();
|
||||
});
|
||||
} on StripeException catch (e) {
|
||||
var lo1 = jsonEncode(e);
|
||||
var lo2 = jsonDecode(lo1);
|
||||
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
|
||||
ShowToastDialog.showToast(lom.error.message);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future createStripeIntent({required String amount}) async {
|
||||
try {
|
||||
Map<String, dynamic> body = {
|
||||
'amount': ((double.parse(amount) * 100).round()).toString(),
|
||||
'currency': "USD",
|
||||
'payment_method_types[]': 'card',
|
||||
"description": "Strip Payment",
|
||||
"shipping[name]": userModel.value.fullName(),
|
||||
"shipping[address][line1]": "510 Townsend St",
|
||||
"shipping[address][postal_code]": "98140",
|
||||
"shipping[address][city]": "San Francisco",
|
||||
"shipping[address][state]": "CA",
|
||||
"shipping[address][country]": "US",
|
||||
};
|
||||
var stripeSecret = stripeModel.value.stripeSecret;
|
||||
var response = await http.post(Uri.parse('https://api.stripe.com/v1/payment_intents'),
|
||||
body: body, headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'});
|
||||
|
||||
return jsonDecode(response.body);
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//mercadoo
|
||||
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
final body = jsonEncode({
|
||||
"items": [
|
||||
{
|
||||
"title": "Test",
|
||||
"description": "Test Payment",
|
||||
"quantity": 1,
|
||||
"currency_id": "BRL", // or your preferred currency
|
||||
"unit_price": double.parse(amount),
|
||||
}
|
||||
],
|
||||
"payer": {"email": userModel.value.email},
|
||||
"back_urls": {
|
||||
"failure": "${Constant.globalUrl}payment/failure",
|
||||
"pending": "${Constant.globalUrl}payment/pending",
|
||||
"success": "${Constant.globalUrl}payment/success",
|
||||
},
|
||||
"auto_return": "approved" // Automatically return after payment is approved
|
||||
});
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse("https://api.mercadopago.com/checkout/preferences"),
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Error creating preference: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
///PayStack Payment Method
|
||||
Future<void> payStackPayment(String totalAmount) async {
|
||||
await PayStackURLGen.payStackURLGen(
|
||||
amount: (double.parse(totalAmount) * 100).toString(), currency: "ZAR", secretKey: payStackModel.value.secretKey.toString(), userModel: userModel.value)
|
||||
.then((value) async {
|
||||
if (value != null) {
|
||||
PayStackUrlModel payStackModel0 = value;
|
||||
Get.to(PayStackScreen(
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
callBackUrl: payStackModel.value.callbackURL.toString(),
|
||||
initialURl: payStackModel0.data.authorizationUrl,
|
||||
amount: totalAmount,
|
||||
reference: payStackModel0.data.reference,
|
||||
))!
|
||||
.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//flutter wave Payment Method
|
||||
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
|
||||
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
|
||||
final headers = {
|
||||
'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
final body = jsonEncode({
|
||||
"tx_ref": _ref,
|
||||
"amount": amount,
|
||||
"currency": "NGN",
|
||||
"redirect_url": "${Constant.globalUrl}payment/success",
|
||||
"payment_options": "ussd, card, barter, payattitude",
|
||||
"customer": {
|
||||
"email": userModel.value.email.toString(),
|
||||
"phonenumber": userModel.value.phoneNumber, // Add a real phone number
|
||||
"name": userModel.value.fullName(), // Add a real customer name
|
||||
},
|
||||
"customizations": {
|
||||
"title": "Payment for Services",
|
||||
"description": "Payment for XYZ services",
|
||||
}
|
||||
});
|
||||
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Payment initialization failed: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? _ref;
|
||||
|
||||
void setRef() {
|
||||
maths.Random numRef = maths.Random();
|
||||
int year = DateTime.now().year;
|
||||
int refNumber = numRef.nextInt(20000);
|
||||
if (Platform.isAndroid) {
|
||||
_ref = "AndroidRef$year$refNumber";
|
||||
} else if (Platform.isIOS) {
|
||||
_ref = "IOSRef$year$refNumber";
|
||||
}
|
||||
}
|
||||
|
||||
// payFast
|
||||
void payFastPayment({required BuildContext context, required String amount}) {
|
||||
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: userModel.value).then((String? value) async {
|
||||
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
|
||||
if (isDone) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//PayPal
|
||||
void paypalPaymentSheet(String amount, context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) => UsePaypal(
|
||||
sandboxMode: payPalModel.value.isLive == true ? false : true,
|
||||
clientId: payPalModel.value.paypalClient ?? '',
|
||||
secretKey: payPalModel.value.paypalSecret ?? '',
|
||||
returnURL: "com.parkme://paypalpay",
|
||||
cancelURL: "com.parkme://paypalpay",
|
||||
transactions: [
|
||||
{
|
||||
"amount": {
|
||||
"total": amount,
|
||||
"currency": "USD",
|
||||
"details": {"subtotal": amount}
|
||||
},
|
||||
}
|
||||
],
|
||||
note: "Contact us for any questions on your order.",
|
||||
onSuccess: (Map params) async {
|
||||
placeOrder();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
},
|
||||
onError: (error) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
onCancel: (params) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///Paytm payment function
|
||||
Future<void> getPaytmCheckSum(context, {required double amount}) async {
|
||||
final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
getChecksum,
|
||||
),
|
||||
headers: {},
|
||||
body: {
|
||||
"mid": paytmModel.value.paytmMID.toString(),
|
||||
"order_id": orderId,
|
||||
"key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(),
|
||||
});
|
||||
|
||||
final data = jsonDecode(response.body);
|
||||
await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
|
||||
initiatePayment(amount: amount, orderId: orderId).then((value) {
|
||||
String callback = "";
|
||||
if (paytmModel.value.isSandboxEnabled == true) {
|
||||
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
} else {
|
||||
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
}
|
||||
|
||||
GetPaymentTxtTokenModel result = value;
|
||||
startTransaction(context, txnTokenBy: result.body.txnToken ?? '', orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> startTransaction(context, {required String txnTokenBy, required orderId, required double amount, required callBackURL, required isStaging}) async {
|
||||
// try {
|
||||
// var response = AllInOneSdk.startTransaction(
|
||||
// paytmModel.value.paytmMID.toString(),
|
||||
// orderId,
|
||||
// amount.toString(),
|
||||
// txnTokenBy,
|
||||
// callBackURL,
|
||||
// isStaging,
|
||||
// true,
|
||||
// true,
|
||||
// );
|
||||
//
|
||||
// response.then((value) {
|
||||
// if (value!["RESPMSG"] == "Txn Success") {
|
||||
// ShowToastDialog.showToast("Payment Successful!!");
|
||||
// placeOrder();
|
||||
// }
|
||||
// }).catchError((onError) {
|
||||
// if (onError is PlatformException) {
|
||||
// Get.back();
|
||||
//
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// } else {
|
||||
// print("======>>2");
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// }
|
||||
// });
|
||||
// } catch (err) {
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(err.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
|
||||
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
|
||||
final response = await http.post(
|
||||
Uri.parse(
|
||||
getChecksum,
|
||||
),
|
||||
headers: {},
|
||||
body: {
|
||||
"mid": paytmModel.value.paytmMID.toString(),
|
||||
"order_id": orderId,
|
||||
"key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(),
|
||||
"checksum_value": checkSum,
|
||||
});
|
||||
final data = jsonDecode(response.body);
|
||||
return data['status'];
|
||||
}
|
||||
|
||||
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
|
||||
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
|
||||
String callback = "";
|
||||
if (paytmModel.value.isSandboxEnabled == true) {
|
||||
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
} else {
|
||||
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
}
|
||||
final response = await http.post(Uri.parse(initiateURL), headers: {}, body: {
|
||||
"mid": paytmModel.value.paytmMID,
|
||||
"order_id": orderId,
|
||||
"key_secret": paytmModel.value.pAYTMMERCHANTKEY,
|
||||
"amount": amount.toString(),
|
||||
"currency": "INR",
|
||||
"callback_url": callback,
|
||||
"custId": FireStoreUtils.getCurrentUid(),
|
||||
"issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
|
||||
});
|
||||
print(response.body);
|
||||
final data = jsonDecode(response.body);
|
||||
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
}
|
||||
return GetPaymentTxtTokenModel.fromJson(data);
|
||||
}
|
||||
|
||||
///RazorPay payment function
|
||||
final Razorpay razorPay = Razorpay();
|
||||
|
||||
void openCheckout({required amount, required orderId}) async {
|
||||
var options = {
|
||||
'key': razorPayModel.value.razorpayKey,
|
||||
'amount': amount * 100,
|
||||
'name': 'GoRide',
|
||||
'order_id': orderId,
|
||||
"currency": "INR",
|
||||
'description': 'wallet Topup',
|
||||
'retry': {'enabled': true, 'max_count': 1},
|
||||
'send_sms_hash': true,
|
||||
'prefill': {
|
||||
'contact': userModel.value.phoneNumber,
|
||||
'email': userModel.value.email,
|
||||
},
|
||||
'external': {
|
||||
'wallets': ['paytm']
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
razorPay.open(options);
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void handlePaymentSuccess(PaymentSuccessResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
}
|
||||
|
||||
void handleExternalWaller(ExternalWalletResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Processing!! via".tr);
|
||||
}
|
||||
|
||||
void handlePaymentError(PaymentFailureResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed!!".tr);
|
||||
}
|
||||
|
||||
//Midtrans payment
|
||||
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
|
||||
await createPaymentLink(amount: amount).then((url) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (url != '') {
|
||||
Get.to(() => MidtransScreen(
|
||||
initialURl: url,
|
||||
))!
|
||||
.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> createPaymentLink({required var amount}) async {
|
||||
var ordersId = const Uuid().v1();
|
||||
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!),
|
||||
},
|
||||
body: jsonEncode({
|
||||
'transaction_details': {
|
||||
'order_id': ordersId,
|
||||
'gross_amount': double.parse(amount.toString()).toInt(),
|
||||
},
|
||||
'usage_limit': 2,
|
||||
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
String generateBasicAuthHeader(String apiKey) {
|
||||
String credentials = '$apiKey:';
|
||||
String base64Encoded = base64Encode(utf8.encode(credentials));
|
||||
return 'Basic $base64Encoded';
|
||||
}
|
||||
|
||||
//Orangepay payment
|
||||
static String accessToken = '';
|
||||
static String payToken = '';
|
||||
static String orderId = '';
|
||||
static String amount = '';
|
||||
|
||||
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
|
||||
reset();
|
||||
var id = const Uuid().v4();
|
||||
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
|
||||
ShowToastDialog.closeLoader();
|
||||
if (paymentURL.toString() != '') {
|
||||
Get.to(() => OrangeMoneyScreen(
|
||||
initialURl: paymentURL,
|
||||
accessToken: accessToken,
|
||||
amount: amount,
|
||||
orangePay: orangeMoneyModel.value,
|
||||
orderId: orderId,
|
||||
payToken: payToken,
|
||||
))!
|
||||
.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
}
|
||||
|
||||
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
|
||||
String apiUrl = 'https://api.orange.com/oauth/v3/token';
|
||||
Map<String, String> requestBody = {
|
||||
'grant_type': 'client_credentials',
|
||||
};
|
||||
|
||||
var response = await http.post(Uri.parse(apiUrl),
|
||||
headers: <String, String>{
|
||||
'Authorization': "Basic ${orangeMoneyModel.value.auth!}",
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: requestBody);
|
||||
|
||||
// Handle the response
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
|
||||
accessToken = responseData['access_token'];
|
||||
// ignore: use_build_context_synchronously
|
||||
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
|
||||
orderId = orderIdData;
|
||||
amount = amountData;
|
||||
String apiUrl =
|
||||
orangeMoneyModel.value.isSandbox! == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
|
||||
Map<String, String> requestBody = {
|
||||
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
|
||||
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
|
||||
"order_id": orderId,
|
||||
"amount": amount,
|
||||
"reference": 'Y-Note Test',
|
||||
"lang": "en",
|
||||
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
|
||||
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
|
||||
"notif_url": orangeMoneyModel.value.notifUrl!.toString(),
|
||||
};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
body: json.encode(requestBody),
|
||||
);
|
||||
|
||||
// Handle the response
|
||||
if (response.statusCode == 201) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
if (responseData['message'] == 'OK') {
|
||||
payToken = responseData['pay_token'];
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
accessToken = '';
|
||||
payToken = '';
|
||||
orderId = '';
|
||||
amount = '';
|
||||
}
|
||||
|
||||
//XenditPayment
|
||||
Future<void> xenditPayment(context, amount) async {
|
||||
await createXenditInvoice(amount: amount).then((model) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (model.id != null) {
|
||||
Get.to(() => XenditScreen(
|
||||
initialURl: model.invoiceUrl ?? '',
|
||||
transId: model.id ?? '',
|
||||
apiKey: xenditModel.value.apiKey!.toString(),
|
||||
))!
|
||||
.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<XenditModel> createXenditInvoice({required var amount}) async {
|
||||
const url = 'https://api.xendit.co/v2/invoices';
|
||||
var headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
|
||||
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
|
||||
};
|
||||
|
||||
final body = jsonEncode({
|
||||
'external_id': const Uuid().v1(),
|
||||
'amount': amount,
|
||||
'payer_email': 'customer@domain.com',
|
||||
'description': 'Test - VA Successful invoice payment',
|
||||
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(Uri.parse(url), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
|
||||
return model;
|
||||
} else {
|
||||
return XenditModel();
|
||||
}
|
||||
} catch (e) {
|
||||
return XenditModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
48
lib/controllers/global_setting_controller.dart
Normal file
48
lib/controllers/global_setting_controller.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
import 'dart:developer';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/currency_model.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/utils/notification_service.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../constant/collection_name.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class GlobalSettingController extends GetxController {
|
||||
@override
|
||||
void onInit() {
|
||||
notificationInit();
|
||||
getCurrentCurrency();
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getCurrentCurrency() async {
|
||||
FireStoreUtils.fireStore.collection(CollectionName.currencies).where("isActive", isEqualTo: true).snapshots().listen((event) {
|
||||
if (event.docs.isNotEmpty) {
|
||||
Constant.currencyModel = CurrencyModel.fromJson(event.docs.first.data());
|
||||
} else {
|
||||
Constant.currencyModel = CurrencyModel(id: "", code: "USD", decimal: 2, isactive: true, name: "US Dollar", symbol: "\$", symbolatright: false);
|
||||
}
|
||||
});
|
||||
await FireStoreUtils.getSettings();
|
||||
}
|
||||
|
||||
NotificationService notificationService = NotificationService();
|
||||
|
||||
void notificationInit() {
|
||||
notificationService.initInfo().then((value) async {
|
||||
String token = await NotificationService.getToken();
|
||||
log(":::::::TOKEN:::::: $token");
|
||||
if (FirebaseAuth.instance.currentUser != null) {
|
||||
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
|
||||
if (value != null) {
|
||||
UserModel driverUserModel = value;
|
||||
driverUserModel.fcmToken = token;
|
||||
FireStoreUtils.updateUser(driverUserModel);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
38
lib/controllers/history_gift_card_controller.dart
Normal file
38
lib/controllers/history_gift_card_controller.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/gift_cards_order_model.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class HistoryGiftCardController extends GetxController {
|
||||
RxList<GiftCardsOrderModel> giftCardsOrderList = <GiftCardsOrderModel>[].obs;
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
await FireStoreUtils.getGiftHistory().then((value) {
|
||||
giftCardsOrderList.value = value;
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
void updateList(int index) {
|
||||
GiftCardsOrderModel giftCardsOrderModel = giftCardsOrderList[index];
|
||||
giftCardsOrderModel.isPasswordShow = giftCardsOrderModel.isPasswordShow == true ? false : true;
|
||||
|
||||
giftCardsOrderList.removeAt(index);
|
||||
giftCardsOrderList.insert(index, giftCardsOrderModel);
|
||||
}
|
||||
|
||||
Future<void> share(String giftCode, String giftPin, String msg, String amount, Timestamp date) async {
|
||||
await Share.share(
|
||||
"${'Gift Code :'.tr} $giftCode\n${'Gift Pin :'.tr} $giftPin\n${'Price :'.tr} ${Constant.amountShow(amount: amount)}\n${'Expire Date :'.tr} ${date.toDate()}\n\n${'Message'.tr} : $msg",
|
||||
);
|
||||
}
|
||||
}
|
||||
132
lib/controllers/home_e_commerce_controller.dart
Normal file
132
lib/controllers/home_e_commerce_controller.dart
Normal file
@@ -0,0 +1,132 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/advertisement_model.dart';
|
||||
import 'package:customer/models/banner_model.dart';
|
||||
import 'package:customer/models/brands_model.dart';
|
||||
import 'package:customer/models/favourite_model.dart';
|
||||
import 'package:customer/models/vendor_category_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:customer/service/cart_provider.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../constant/constant.dart';
|
||||
|
||||
class HomeECommerceController extends GetxController {
|
||||
final CartProvider cartProvider = CartProvider();
|
||||
|
||||
Future<void> getCartData() async {
|
||||
cartProvider.cartStream.listen((event) async {
|
||||
cartItem.clear();
|
||||
cartItem.addAll(event);
|
||||
});
|
||||
update();
|
||||
}
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
RxBool isListView = true.obs;
|
||||
RxBool isPopular = true.obs;
|
||||
|
||||
Rx<PageController> pageController = PageController(viewportFraction: 0.877).obs;
|
||||
Rx<PageController> pageBottomController = PageController(viewportFraction: 0.877).obs;
|
||||
RxInt currentPage = 0.obs;
|
||||
RxInt currentBottomPage = 0.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getVendorCategory();
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
RxList<VendorCategoryModel> vendorCategoryModel = <VendorCategoryModel>[].obs;
|
||||
RxList<VendorCategoryModel> categoryWiseProductList = <VendorCategoryModel>[].obs;
|
||||
|
||||
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
|
||||
RxList<VendorModel> newArrivalRestaurantList = <VendorModel>[].obs;
|
||||
RxList<AdvertisementModel> advertisementList = <AdvertisementModel>[].obs;
|
||||
|
||||
RxList<BannerModel> bannerModel = <BannerModel>[].obs;
|
||||
RxList<BannerModel> bannerBottomModel = <BannerModel>[].obs;
|
||||
RxList<BrandsModel> brandList = <BrandsModel>[].obs;
|
||||
|
||||
Future<void> getData() async {
|
||||
isLoading.value = true;
|
||||
getCartData();
|
||||
FireStoreUtils.getAllNearestRestaurant().listen((event) async {
|
||||
print("=====>${event.length}");
|
||||
|
||||
newArrivalRestaurantList.clear();
|
||||
allNearestRestaurant.clear();
|
||||
advertisementList.clear();
|
||||
|
||||
allNearestRestaurant.addAll(event);
|
||||
newArrivalRestaurantList.addAll(event);
|
||||
Constant.restaurantList = allNearestRestaurant;
|
||||
List<String> usedCategoryIds = allNearestRestaurant.expand((vendor) => vendor.categoryID ?? []).whereType<String>().toSet().toList();
|
||||
vendorCategoryModel.value = vendorCategoryModel.where((category) => usedCategoryIds.contains(category.id)).toList();
|
||||
|
||||
newArrivalRestaurantList.sort((a, b) => (b.createdAt ?? Timestamp.now()).toDate().compareTo((a.createdAt ?? Timestamp.now()).toDate()));
|
||||
|
||||
if (Constant.isEnableAdsFeature == true) {
|
||||
await FireStoreUtils.getAllAdvertisement().then((value) {
|
||||
advertisementList.clear();
|
||||
for (var element1 in value) {
|
||||
for (var element in allNearestRestaurant) {
|
||||
if (element1.vendorId == element.id) {
|
||||
advertisementList.add(element1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
setLoading();
|
||||
}
|
||||
|
||||
Future<void> setLoading() async {
|
||||
await Future.delayed(Duration(seconds: 1), () async {
|
||||
if (allNearestRestaurant.isEmpty) {
|
||||
await Future.delayed(Duration(seconds: 2), () {
|
||||
isLoading.value = false;
|
||||
});
|
||||
} else {
|
||||
isLoading.value = false;
|
||||
}
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> getVendorCategory() async {
|
||||
await FireStoreUtils.getHomeVendorCategory().then((value) {
|
||||
vendorCategoryModel.value = value;
|
||||
});
|
||||
await FireStoreUtils.getHomePageShowCategory().then((value) {
|
||||
categoryWiseProductList.value = value;
|
||||
});
|
||||
|
||||
await FireStoreUtils.getHomeTopBanner().then((value) {
|
||||
bannerModel.value = value;
|
||||
});
|
||||
|
||||
await FireStoreUtils.getHomeBottomBanner().then((value) {
|
||||
bannerBottomModel.value = value;
|
||||
});
|
||||
|
||||
await FireStoreUtils.getBrandList().then((value) {
|
||||
brandList.value = value;
|
||||
});
|
||||
await getFavouriteRestaurant();
|
||||
}
|
||||
|
||||
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
|
||||
|
||||
Future<void> getFavouriteRestaurant() async {
|
||||
if (Constant.userModel?.id != null) {
|
||||
await FireStoreUtils.getFavouriteRestaurant().then((value) {
|
||||
favouriteList.value = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
42
lib/controllers/home_parcel_controller.dart
Normal file
42
lib/controllers/home_parcel_controller.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import '../models/banner_model.dart';
|
||||
import '../models/parcel_category.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class HomeParcelController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
RxList<BannerModel> bannerTopHome = <BannerModel>[].obs;
|
||||
RxList<ParcelCategory> parcelCategory = <ParcelCategory>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
loadData();
|
||||
}
|
||||
|
||||
void loadData() async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
|
||||
// Load banners
|
||||
await FireStoreUtils.getHomeTopBanner().then((value) {
|
||||
bannerTopHome.value = value;
|
||||
log('Banners loaded: ${bannerTopHome.length}');
|
||||
});
|
||||
|
||||
// Load parcel categories
|
||||
await FireStoreUtils.getParcelServiceCategory().then((value) {
|
||||
parcelCategory.value = value;
|
||||
log('Parcel categories loaded: ${parcelCategory.length}');
|
||||
});
|
||||
} catch (e) {
|
||||
bannerTopHome.clear();
|
||||
parcelCategory.clear();
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
256
lib/controllers/live_tracking_controller.dart
Normal file
256
lib/controllers/live_tracking_controller.dart
Normal file
@@ -0,0 +1,256 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:customer/constant/collection_name.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/order_model.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:latlong2/latlong.dart' as location;
|
||||
import 'package:flutter_map/flutter_map.dart' as flutterMap;
|
||||
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class LiveTrackingController extends GetxController {
|
||||
GoogleMapController? mapController;
|
||||
final flutterMap.MapController osmMapController = flutterMap.MapController();
|
||||
|
||||
Rx<OrderModel> orderModel = OrderModel().obs;
|
||||
Rx<UserModel> driverUserModel = UserModel().obs;
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
Rx<location.LatLng> source = location.LatLng(0, 0).obs;
|
||||
Rx<location.LatLng> destination = location.LatLng(0, 0).obs;
|
||||
Rx<location.LatLng> driverCurrent = location.LatLng(0, 0).obs;
|
||||
|
||||
RxList<location.LatLng> routePoints = <location.LatLng>[].obs;
|
||||
RxMap<MarkerId, Marker> markers = <MarkerId, Marker>{}.obs;
|
||||
RxMap<PolylineId, Polyline> polyLines = <PolylineId, Polyline>{}.obs;
|
||||
RxList<flutterMap.Marker> osmMarkers = <flutterMap.Marker>[].obs;
|
||||
|
||||
BitmapDescriptor? pickupIcon;
|
||||
BitmapDescriptor? dropoffIcon;
|
||||
BitmapDescriptor? driverIcon;
|
||||
|
||||
PolylinePoints polylinePoints = PolylinePoints(apiKey: Constant.mapAPIKey);
|
||||
|
||||
StreamSubscription? orderSub;
|
||||
StreamSubscription? driverSub;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
addMarkerIcons();
|
||||
getArguments();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
orderSub?.cancel();
|
||||
driverSub?.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<void> getArguments() async {
|
||||
final args = Get.arguments;
|
||||
if (args == null) return;
|
||||
|
||||
orderModel.value = args['orderModel'];
|
||||
|
||||
orderSub = FireStoreUtils.fireStore.collection(CollectionName.vendorOrders).doc(orderModel.value.id).snapshots().listen((orderSnap) {
|
||||
if (orderSnap.data() == null) return;
|
||||
orderModel.value = OrderModel.fromJson(orderSnap.data()!);
|
||||
|
||||
if (orderModel.value.driverID != null) {
|
||||
driverSub?.cancel();
|
||||
driverSub = FireStoreUtils.fireStore.collection(CollectionName.users).doc(orderModel.value.driverID).snapshots().listen((driverSnap) async {
|
||||
if (driverSnap.data() == null) return;
|
||||
driverUserModel.value = UserModel.fromJson(driverSnap.data()!);
|
||||
await updateLiveTracking();
|
||||
});
|
||||
}
|
||||
|
||||
if (orderModel.value.status == Constant.orderCompleted) {
|
||||
Get.back();
|
||||
}
|
||||
});
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> updateLiveTracking() async {
|
||||
driverCurrent.value = location.LatLng(driverUserModel.value.location?.latitude ?? 0.0, driverUserModel.value.location?.longitude ?? 0.0);
|
||||
|
||||
source.value = location.LatLng(orderModel.value.vendor?.latitude ?? 0.0, orderModel.value.vendor?.longitude ?? 0.0);
|
||||
|
||||
destination.value = location.LatLng(orderModel.value.address?.location?.latitude ?? 0.0, orderModel.value.address?.location?.longitude ?? 0.0);
|
||||
|
||||
if (orderModel.value.status == Constant.orderPlaced || orderModel.value.status == Constant.orderAccepted) {
|
||||
await showDriverToRestaurantRoute();
|
||||
} else if (orderModel.value.status == Constant.orderShipped || orderModel.value.status == Constant.orderInTransit) {
|
||||
await showDriverToCustomerRoute();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showDriverToRestaurantRoute() async {
|
||||
clearOldData();
|
||||
if (Constant.selectedMapType == 'osm') {
|
||||
await fetchRoute(driverCurrent.value, source.value);
|
||||
addOsmMarkers(showPickup: true, showDrop: false);
|
||||
animateToOSMLocation(driverCurrent.value);
|
||||
} else {
|
||||
await getPolyline(
|
||||
sourceLatitude: driverCurrent.value.latitude,
|
||||
sourceLongitude: driverCurrent.value.longitude,
|
||||
destinationLatitude: source.value.latitude,
|
||||
destinationLongitude: source.value.longitude,
|
||||
showPickup: true,
|
||||
showDrop: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showDriverToCustomerRoute() async {
|
||||
clearOldData();
|
||||
if (Constant.selectedMapType == 'osm') {
|
||||
await fetchRoute(driverCurrent.value, destination.value);
|
||||
addOsmMarkers(showPickup: false, showDrop: true);
|
||||
animateToOSMLocation(driverCurrent.value);
|
||||
} else {
|
||||
await getPolyline(
|
||||
sourceLatitude: driverCurrent.value.latitude,
|
||||
sourceLongitude: driverCurrent.value.longitude,
|
||||
destinationLatitude: destination.value.latitude,
|
||||
destinationLongitude: destination.value.longitude,
|
||||
showPickup: false,
|
||||
showDrop: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void clearOldData() {
|
||||
markers.clear();
|
||||
polyLines.clear();
|
||||
routePoints.clear();
|
||||
}
|
||||
|
||||
Future<void> fetchRoute(location.LatLng source, location.LatLng destination) async {
|
||||
final url = Uri.parse(
|
||||
'https://router.project-osrm.org/route/v1/driving/${source.longitude},${source.latitude};${destination.longitude},${destination.latitude}?overview=full&geometries=geojson',
|
||||
);
|
||||
final response = await http.get(url);
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
final coords = data['routes'][0]['geometry']['coordinates'];
|
||||
routePoints.value = coords.map<location.LatLng>((c) => location.LatLng(c[1].toDouble(), c[0].toDouble())).toList();
|
||||
}
|
||||
}
|
||||
|
||||
void animateToOSMLocation(location.LatLng loc) {
|
||||
osmMapController.move(loc, 15);
|
||||
}
|
||||
|
||||
void addOsmMarkers({bool showPickup = false, bool showDrop = false}) {
|
||||
final List<flutterMap.Marker> tempMarkers = [
|
||||
// Driver Marker
|
||||
flutterMap.Marker(point: driverCurrent.value, width: 40, height: 40, child: Image.asset('assets/images/food_delivery.png')),
|
||||
];
|
||||
|
||||
if (showPickup) {
|
||||
tempMarkers.add(flutterMap.Marker(point: source.value, width: 40, height: 40, child: Image.asset('assets/images/pickup.png')));
|
||||
}
|
||||
|
||||
if (showDrop) {
|
||||
tempMarkers.add(flutterMap.Marker(point: destination.value, width: 40, height: 40, child: Image.asset('assets/images/dropoff.png')));
|
||||
}
|
||||
|
||||
osmMarkers.value = tempMarkers;
|
||||
}
|
||||
|
||||
Future<void> getPolyline({
|
||||
required double sourceLatitude,
|
||||
required double sourceLongitude,
|
||||
required double destinationLatitude,
|
||||
required double destinationLongitude,
|
||||
bool showPickup = false,
|
||||
bool showDrop = false,
|
||||
}) async {
|
||||
List<LatLng> polylineCoordinates = [];
|
||||
|
||||
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
|
||||
request: PolylineRequest(origin: PointLatLng(sourceLatitude, sourceLongitude), destination: PointLatLng(destinationLatitude, destinationLongitude), mode: TravelMode.driving),
|
||||
);
|
||||
|
||||
if (result.points.isNotEmpty) {
|
||||
polylineCoordinates = result.points.map((e) => LatLng(e.latitude, e.longitude)).toList();
|
||||
}
|
||||
|
||||
addGoogleMarkers(showPickup: showPickup, showDrop: showDrop);
|
||||
_addPolyLine(polylineCoordinates);
|
||||
}
|
||||
|
||||
void addGoogleMarkers({bool showPickup = false, bool showDrop = false}) {
|
||||
markers.clear();
|
||||
|
||||
// Always show driver marker
|
||||
if (driverUserModel.value.location != null && driverIcon != null) {
|
||||
addMarker(
|
||||
id: "Driver",
|
||||
latitude: driverUserModel.value.location?.latitude ?? 0.0,
|
||||
longitude: driverUserModel.value.location?.longitude ?? 0.0,
|
||||
descriptor: driverIcon!,
|
||||
rotation: (driverUserModel.value.rotation ?? 0).toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
if (showPickup && orderModel.value.vendor?.latitude != null && pickupIcon != null) {
|
||||
addMarker(id: "Pickup", latitude: orderModel.value.vendor!.latitude ?? 0.0, longitude: orderModel.value.vendor!.longitude ?? 0.0, descriptor: pickupIcon!, rotation: 0.0);
|
||||
} else if (showDrop && orderModel.value.address?.location?.latitude != null && dropoffIcon != null) {
|
||||
addMarker(
|
||||
id: "Drop",
|
||||
latitude: orderModel.value.address!.location!.latitude ?? 0.0,
|
||||
longitude: orderModel.value.address!.location!.longitude ?? 0.0,
|
||||
descriptor: dropoffIcon!,
|
||||
rotation: 0.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void addMarker({required String id, required double latitude, required double longitude, required BitmapDescriptor descriptor, required double rotation}) {
|
||||
MarkerId markerId = MarkerId(id);
|
||||
markers[markerId] = Marker(markerId: markerId, icon: descriptor, position: LatLng(latitude, longitude), rotation: rotation, anchor: const Offset(0.5, 0.5));
|
||||
}
|
||||
|
||||
Future<void> addMarkerIcons() async {
|
||||
if (Constant.selectedMapType == 'osm') return;
|
||||
|
||||
pickupIcon = BitmapDescriptor.fromBytes(await Constant().getBytesFromAsset('assets/images/pickup.png', 100));
|
||||
dropoffIcon = BitmapDescriptor.fromBytes(await Constant().getBytesFromAsset('assets/images/dropoff.png', 100));
|
||||
driverIcon = BitmapDescriptor.fromBytes(await Constant().getBytesFromAsset('assets/images/food_delivery.png', 100));
|
||||
}
|
||||
|
||||
Future<void> _addPolyLine(List<LatLng> polylineCoordinates) async {
|
||||
if (polylineCoordinates.isEmpty) return;
|
||||
|
||||
PolylineId id = const PolylineId("poly");
|
||||
Polyline polyline = Polyline(polylineId: id, color: Colors.blue, width: 5, points: polylineCoordinates);
|
||||
|
||||
polyLines[id] = polyline;
|
||||
await updateCameraBounds(polylineCoordinates);
|
||||
}
|
||||
|
||||
Future<void> updateCameraBounds(List<LatLng> points) async {
|
||||
if (mapController == null || points.isEmpty) return;
|
||||
|
||||
double minLat = points.map((e) => e.latitude).reduce((a, b) => a < b ? a : b);
|
||||
double maxLat = points.map((e) => e.latitude).reduce((a, b) => a > b ? a : b);
|
||||
double minLng = points.map((e) => e.longitude).reduce((a, b) => a < b ? a : b);
|
||||
double maxLng = points.map((e) => e.longitude).reduce((a, b) => a > b ? a : b);
|
||||
|
||||
LatLngBounds bounds = LatLngBounds(southwest: LatLng(minLat, minLng), northeast: LatLng(maxLat, maxLng));
|
||||
|
||||
await mapController!.animateCamera(CameraUpdate.newLatLngBounds(bounds, 80));
|
||||
}
|
||||
}
|
||||
273
lib/controllers/login_controller.dart
Normal file
273
lib/controllers/login_controller.dart
Normal file
@@ -0,0 +1,273 @@
|
||||
import 'dart:convert';
|
||||
import 'package:customer/screen_ui/location_enable_screens/location_permission_screen.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_sign_in/google_sign_in.dart';
|
||||
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../screen_ui/auth_screens/login_screen.dart';
|
||||
import '../screen_ui/auth_screens/sign_up_screen.dart';
|
||||
import '../screen_ui/service_home_screen/service_list_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
import '../utils/notification_service.dart';
|
||||
import 'package:crypto/crypto.dart';
|
||||
|
||||
class LoginController extends GetxController {
|
||||
Rx<TextEditingController> emailController = TextEditingController().obs;
|
||||
Rx<TextEditingController> passwordController = TextEditingController().obs;
|
||||
|
||||
/// Focus nodes
|
||||
final FocusNode emailFocusNode = FocusNode();
|
||||
final FocusNode passwordFocusNode = FocusNode();
|
||||
|
||||
/// Loading indicator
|
||||
final RxBool isLoading = false.obs;
|
||||
|
||||
RxBool passwordVisible = true.obs;
|
||||
|
||||
Future<void> loginWithEmail() async {
|
||||
final email = emailController.value.text.trim();
|
||||
final password = passwordController.value.text.trim();
|
||||
if (email.isEmpty || !email.contains('@')) {
|
||||
ShowToastDialog.showToast("Please enter a valid email address".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter your password".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
isLoading.value = true;
|
||||
ShowToastDialog.showLoader("Logging in...".tr);
|
||||
|
||||
final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password);
|
||||
|
||||
final userModel = await FireStoreUtils.getUserProfile(credential.user!.uid);
|
||||
|
||||
if (userModel != null && userModel.role == Constant.userRoleCustomer) {
|
||||
if (userModel.active == true) {
|
||||
userModel.fcmToken = await NotificationService.getToken();
|
||||
await FireStoreUtils.updateUser(userModel);
|
||||
|
||||
if (userModel.shippingAddress != null && userModel.shippingAddress!.isNotEmpty) {
|
||||
final defaultAddress = userModel.shippingAddress!.firstWhere(
|
||||
(e) => e.isDefault == true,
|
||||
orElse: () => userModel.shippingAddress!.first,
|
||||
);
|
||||
|
||||
Constant.selectedLocation = defaultAddress;
|
||||
|
||||
Get.offAll(() => const ServiceListScreen());
|
||||
} else {
|
||||
Get.offAll(() => const LocationPermissionScreen());
|
||||
}
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
ShowToastDialog.showToast("This user is disabled. Please contact admin.".tr);
|
||||
Get.offAll(() => const LoginScreen());
|
||||
}
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
ShowToastDialog.showToast("This user does not exist in the customer app.".tr);
|
||||
Get.offAll(() => const LoginScreen());
|
||||
}
|
||||
} on FirebaseAuthException catch (e) {
|
||||
if (e.code == 'user-not-found') {
|
||||
ShowToastDialog.showToast("No user found for that email.".tr);
|
||||
} else if (e.code == 'wrong-password') {
|
||||
ShowToastDialog.showToast("Wrong password provided.".tr);
|
||||
} else if (e.code == 'invalid-email') {
|
||||
ShowToastDialog.showToast("Invalid email.".tr);
|
||||
} else {
|
||||
ShowToastDialog.showToast(e.message?.tr ?? "Login failed. Please try again.".tr);
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
ShowToastDialog.closeLoader();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loginWithGoogle() async {
|
||||
ShowToastDialog.showLoader("please wait...".tr);
|
||||
await signInWithGoogle().then((value) async {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (value != null) {
|
||||
if (value.additionalUserInfo!.isNewUser) {
|
||||
UserModel userModel = UserModel();
|
||||
userModel.id = value.user!.uid;
|
||||
userModel.email = value.user!.email;
|
||||
userModel.firstName = value.user!.displayName?.split(' ').first;
|
||||
userModel.lastName = value.user!.displayName?.split(' ').last;
|
||||
userModel.provider = 'google';
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.off(const SignUpScreen(), arguments: {"userModel": userModel, "type": "google"});
|
||||
} else {
|
||||
await FireStoreUtils.userExistOrNot(value.user!.uid).then((userExit) async {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (userExit == true) {
|
||||
UserModel? userModel = await FireStoreUtils.getUserProfile(value.user!.uid);
|
||||
if (userModel != null && userModel.role == Constant.userRoleCustomer) {
|
||||
if (userModel.active == true) {
|
||||
userModel.fcmToken = await NotificationService.getToken();
|
||||
await FireStoreUtils.updateUser(userModel);
|
||||
|
||||
if (userModel.shippingAddress != null && userModel.shippingAddress!.isNotEmpty) {
|
||||
final defaultAddress = userModel.shippingAddress!.firstWhere(
|
||||
(e) => e.isDefault == true,
|
||||
orElse: () => userModel.shippingAddress!.first,
|
||||
);
|
||||
|
||||
Constant.selectedLocation = defaultAddress;
|
||||
|
||||
Get.offAll(() => const ServiceListScreen());
|
||||
} else {
|
||||
Get.offAll(() => const LocationPermissionScreen());
|
||||
}
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
ShowToastDialog.showToast("This user is disabled. Please contact admin.".tr);
|
||||
Get.offAll(() => const LoginScreen());
|
||||
}
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
ShowToastDialog.showToast("This user does not exist in the customer app.".tr);
|
||||
Get.offAll(() => const LoginScreen());
|
||||
}
|
||||
} else {
|
||||
UserModel userModel = UserModel();
|
||||
userModel.id = value.user!.uid;
|
||||
userModel.email = value.user!.email;
|
||||
userModel.firstName = value.user!.displayName?.split(' ').first;
|
||||
userModel.lastName = value.user!.displayName?.split(' ').last;
|
||||
userModel.provider = 'google';
|
||||
|
||||
Get.off(const SignUpScreen(), arguments: {"userModel": userModel, "type": "google"});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> loginWithApple() async {
|
||||
ShowToastDialog.showLoader("please wait...".tr);
|
||||
await signInWithApple().then((value) async {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (value != null) {
|
||||
Map<String, dynamic> map = value;
|
||||
AuthorizationCredentialAppleID appleCredential = map['appleCredential'];
|
||||
UserCredential userCredential = map['userCredential'];
|
||||
|
||||
if (userCredential.additionalUserInfo!.isNewUser) {
|
||||
// New user → go to sign-up
|
||||
UserModel userModel = UserModel();
|
||||
userModel.id = userCredential.user!.uid;
|
||||
userModel.email = appleCredential.email;
|
||||
userModel.firstName = appleCredential.givenName;
|
||||
userModel.lastName = appleCredential.familyName;
|
||||
userModel.provider = 'apple';
|
||||
|
||||
Get.off(const SignUpScreen(), arguments: {"userModel": userModel, "type": "apple"});
|
||||
} else {
|
||||
// Existing user
|
||||
await FireStoreUtils.userExistOrNot(userCredential.user!.uid).then((userExit) async {
|
||||
if (userExit == true) {
|
||||
UserModel? userModel = await FireStoreUtils.getUserProfile(userCredential.user!.uid);
|
||||
if (userModel != null && userModel.role == Constant.userRoleCustomer) {
|
||||
if (userModel.active == true) {
|
||||
userModel.fcmToken = await NotificationService.getToken();
|
||||
await FireStoreUtils.updateUser(userModel);
|
||||
|
||||
if (userModel.shippingAddress != null && userModel.shippingAddress!.isNotEmpty) {
|
||||
final defaultAddress = userModel.shippingAddress!.firstWhere(
|
||||
(e) => e.isDefault == true,
|
||||
orElse: () => userModel.shippingAddress!.first,
|
||||
);
|
||||
|
||||
Constant.selectedLocation = defaultAddress;
|
||||
Get.offAll(() => const ServiceListScreen());
|
||||
} else {
|
||||
Get.offAll(() => const LocationPermissionScreen());
|
||||
}
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
ShowToastDialog.showToast("This user is disabled. Please contact admin.".tr);
|
||||
Get.offAll(() => const LoginScreen());
|
||||
}
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
ShowToastDialog.showToast("This user does not exist in the customer app.".tr);
|
||||
Get.offAll(() => const LoginScreen());
|
||||
}
|
||||
} else {
|
||||
// User not in DB → go to signup
|
||||
UserModel userModel = UserModel();
|
||||
userModel.id = userCredential.user!.uid;
|
||||
userModel.email = appleCredential.email;
|
||||
userModel.firstName = appleCredential.givenName;
|
||||
userModel.lastName = appleCredential.familyName;
|
||||
userModel.provider = 'apple';
|
||||
|
||||
Get.off(const SignUpScreen(), arguments: {"userModel": userModel, "type": "apple"});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<UserCredential?> signInWithGoogle() async {
|
||||
try {
|
||||
final GoogleSignIn googleSignIn = GoogleSignIn.instance;
|
||||
|
||||
await googleSignIn.initialize();
|
||||
|
||||
final GoogleSignInAccount googleUser = await googleSignIn.authenticate();
|
||||
if (googleUser.id.isEmpty) return null;
|
||||
|
||||
final GoogleSignInAuthentication googleAuth = googleUser.authentication;
|
||||
|
||||
final credential = GoogleAuthProvider.credential(idToken: googleAuth.idToken);
|
||||
final userCredential = await FirebaseAuth.instance.signInWithCredential(credential);
|
||||
|
||||
return userCredential;
|
||||
} catch (e) {
|
||||
print("Google Sign-In Error: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String sha256ofString(String input) {
|
||||
final bytes = utf8.encode(input);
|
||||
final digest = sha256.convert(bytes);
|
||||
return digest.toString();
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> signInWithApple() async {
|
||||
try {
|
||||
final rawNonce = generateNonce();
|
||||
final nonce = sha256ofString(rawNonce);
|
||||
|
||||
AuthorizationCredentialAppleID appleCredential = await SignInWithApple.getAppleIDCredential(
|
||||
scopes: [AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName],
|
||||
nonce: nonce,
|
||||
);
|
||||
|
||||
final oauthCredential = OAuthProvider(
|
||||
"apple.com",
|
||||
).credential(idToken: appleCredential.identityToken, rawNonce: rawNonce, accessToken: appleCredential.authorizationCode);
|
||||
|
||||
UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential);
|
||||
return {"appleCredential": appleCredential, "userCredential": userCredential};
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
110
lib/controllers/map_view_controller.dart
Normal file
110
lib/controllers/map_view_controller.dart
Normal file
@@ -0,0 +1,110 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart' as flutterMap;
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:latlong2/latlong.dart' as location;
|
||||
import '../screen_ui/multi_vendor_service/restaurant_details_screen/restaurant_details_screen.dart';
|
||||
import 'food_home_controller.dart';
|
||||
|
||||
class MapViewController extends GetxController {
|
||||
GoogleMapController? mapController;
|
||||
BitmapDescriptor? parkingMarker;
|
||||
BitmapDescriptor? currentLocationMarker;
|
||||
|
||||
FoodHomeController homeController = Get.find<FoodHomeController>();
|
||||
Image? departureOsmIcon; //OSM
|
||||
|
||||
RxList<flutterMap.Marker> osmMarker = <flutterMap.Marker>[].obs;
|
||||
final flutterMap.MapController osmMapController = flutterMap.MapController();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
addMarkerSetup();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> addMarkerSetup() async {
|
||||
if (Constant.selectedMapType == "osm") {
|
||||
departureOsmIcon = Image.asset(
|
||||
"assets/images/map_selected.png",
|
||||
width: 30,
|
||||
height: 30,
|
||||
); //OSM
|
||||
|
||||
for (var element in homeController.allNearestRestaurant) {
|
||||
osmMarker.add(
|
||||
flutterMap.Marker(
|
||||
point: location.LatLng(
|
||||
element.latitude ?? 0.0,
|
||||
element.longitude ?? 0.0,
|
||||
),
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Get.to(
|
||||
RestaurantDetailsScreen(),
|
||||
arguments: {"vendorModel": element},
|
||||
);
|
||||
},
|
||||
child: departureOsmIcon,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
final Uint8List parking = await Constant().getBytesFromAsset(
|
||||
"assets/images/map_selected.png",
|
||||
20,
|
||||
);
|
||||
parkingMarker = BitmapDescriptor.bytes(parking);
|
||||
for (var element in homeController.allNearestRestaurant) {
|
||||
addMarker(
|
||||
latitude: element.latitude,
|
||||
longitude: element.longitude,
|
||||
id: element.id.toString(),
|
||||
rotation: 0,
|
||||
descriptor: parkingMarker!,
|
||||
title: element.title.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RxMap<MarkerId, Marker> markers = <MarkerId, Marker>{}.obs;
|
||||
|
||||
void addMarker({
|
||||
required double? latitude,
|
||||
required double? longitude,
|
||||
required String id,
|
||||
required BitmapDescriptor descriptor,
|
||||
required double? rotation,
|
||||
required String title,
|
||||
}) {
|
||||
MarkerId markerId = MarkerId(id);
|
||||
Marker marker = Marker(
|
||||
markerId: markerId,
|
||||
icon: descriptor,
|
||||
infoWindow: InfoWindow(
|
||||
title: title,
|
||||
onTap: () {
|
||||
int index = homeController.allNearestRestaurant.indexWhere(
|
||||
(p0) => p0.id == id,
|
||||
);
|
||||
Get.to(
|
||||
const RestaurantDetailsScreen(),
|
||||
arguments: {
|
||||
"vendorModel": homeController.allNearestRestaurant[index],
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
position: LatLng(latitude ?? 0.0, longitude ?? 0.0),
|
||||
rotation: rotation ?? 0.0,
|
||||
);
|
||||
markers[markerId] = marker;
|
||||
}
|
||||
}
|
||||
63
lib/controllers/mobile_login_controller.dart
Normal file
63
lib/controllers/mobile_login_controller.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
import 'package:customer/themes/show_toast_dialog.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../constant/constant.dart';
|
||||
import '../screen_ui/auth_screens/otp_verification_screen.dart';
|
||||
|
||||
class MobileLoginController extends GetxController {
|
||||
final Rx<TextEditingController> mobileController = TextEditingController().obs;
|
||||
final Rx<TextEditingController> countryCodeController = TextEditingController(text: Constant.defaultCountryCode).obs;
|
||||
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
|
||||
/// Send OTP to the entered phone number
|
||||
Future<void> sendOtp() async {
|
||||
final mobile = mobileController.value.text.trim();
|
||||
final countryCode = countryCodeController.value.text.trim();
|
||||
|
||||
if (mobile.isEmpty || mobile.length != 10) {
|
||||
ShowToastDialog.showToast("Please enter a valid 10-digit mobile number".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ShowToastDialog.showLoader("Sending OTP...".tr);
|
||||
|
||||
await _auth.verifyPhoneNumber(
|
||||
phoneNumber: '$countryCode$mobile',
|
||||
verificationCompleted: (PhoneAuthCredential credential) {
|
||||
// Optionally handle auto-verification
|
||||
},
|
||||
verificationFailed: (FirebaseAuthException e) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (e.code == 'invalid-phone-number') {
|
||||
ShowToastDialog.showToast("Invalid phone number".tr);
|
||||
} else {
|
||||
ShowToastDialog.showToast(e.message ?? "OTP verification failed".tr);
|
||||
}
|
||||
},
|
||||
codeSent: (String verificationId, int? resendToken) {
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.to(() => const OtpVerificationScreen(), arguments: {'countryCode': countryCode, 'phoneNumber': mobile, 'verificationId': verificationId});
|
||||
},
|
||||
codeAutoRetrievalTimeout: (String verificationId) {
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("OTP timed out. Please try again.".tr);
|
||||
// Optional: Handle timeout
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Something went wrong. Please try again.".tr);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
mobileController.value.dispose();
|
||||
countryCodeController.value.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
73
lib/controllers/my_booking_on_demand_controller.dart
Normal file
73
lib/controllers/my_booking_on_demand_controller.dart
Normal file
@@ -0,0 +1,73 @@
|
||||
import 'package:get/get.dart';
|
||||
import '../models/onprovider_order_model.dart';
|
||||
import '../models/worker_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class MyBookingOnDemandController extends GetxController {
|
||||
RxList<OnProviderOrderModel> orders = <OnProviderOrderModel>[].obs;
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
RxString selectedTab = "Placed".obs;
|
||||
RxMap<String, WorkerModel> workers = <String, WorkerModel>{}.obs;
|
||||
|
||||
RxList<String> tabTitles = ["Placed", "Completed", "Cancelled"].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
listenOrders(); // Listen for real-time updates
|
||||
}
|
||||
|
||||
|
||||
void selectTab(String tab) {
|
||||
selectedTab.value = tab;
|
||||
}
|
||||
|
||||
void listenOrders() {
|
||||
isLoading.value = true;
|
||||
|
||||
FireStoreUtils.getProviderOrdersStream().listen(
|
||||
(updatedOrders) {
|
||||
orders.value = updatedOrders;
|
||||
|
||||
// Fetch worker info if not already fetched
|
||||
for (var order in updatedOrders) {
|
||||
if (order.workerId != null && order.workerId!.isNotEmpty && !workers.containsKey(order.workerId!)) {
|
||||
FireStoreUtils.getWorker(order.workerId!).then((worker) {
|
||||
if (worker != null) workers[order.workerId!] = worker;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
},
|
||||
onError: (error) {
|
||||
print("Error fetching orders stream: $error");
|
||||
isLoading.value = false;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<OnProviderOrderModel> get filteredParcelOrders => getOrdersForTab(selectedTab.value);
|
||||
|
||||
List<OnProviderOrderModel> getOrdersForTab(String tab) {
|
||||
switch (tab) {
|
||||
case "Placed":
|
||||
return orders.where((order) => ["Order Placed", "Order Accepted", "Order Assigned", "Order Ongoing", "In Transit"].contains(order.status)).toList();
|
||||
|
||||
case "Completed":
|
||||
return orders.where((order) => ["Order Completed"].contains(order.status)).toList();
|
||||
|
||||
case "Cancelled":
|
||||
return orders.where((order) => ["Order Rejected", "Order Cancelled", "Driver Rejected"].contains(order.status)).toList();
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
WorkerModel? getWorker(String? workerId) {
|
||||
if (workerId == null || workerId.isEmpty) return null;
|
||||
return workers[workerId];
|
||||
}
|
||||
}
|
||||
904
lib/controllers/my_cab_booking_controller.dart
Normal file
904
lib/controllers/my_cab_booking_controller.dart
Normal file
@@ -0,0 +1,904 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as maths;
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/cab_order_model.dart';
|
||||
import 'package:customer/models/payment_model/cod_setting_model.dart';
|
||||
import 'package:customer/models/payment_model/flutter_wave_model.dart';
|
||||
import 'package:customer/models/payment_model/mercado_pago_model.dart';
|
||||
import 'package:customer/models/payment_model/mid_trans.dart';
|
||||
import 'package:customer/models/payment_model/orange_money.dart';
|
||||
import 'package:customer/models/payment_model/pay_fast_model.dart';
|
||||
import 'package:customer/models/payment_model/pay_stack_model.dart';
|
||||
import 'package:customer/models/payment_model/paypal_model.dart';
|
||||
import 'package:customer/models/payment_model/paytm_model.dart';
|
||||
import 'package:customer/models/payment_model/razorpay_model.dart';
|
||||
import 'package:customer/models/payment_model/stripe_model.dart';
|
||||
import 'package:customer/models/payment_model/wallet_setting_model.dart';
|
||||
import 'package:customer/models/payment_model/xendit.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/models/wallet_transaction_model.dart';
|
||||
import 'package:customer/payment/MercadoPagoScreen.dart';
|
||||
import 'package:customer/payment/PayFastScreen.dart';
|
||||
import 'package:customer/payment/getPaytmTxtToken.dart';
|
||||
import 'package:customer/payment/midtrans_screen.dart';
|
||||
import 'package:customer/payment/orangePayScreen.dart';
|
||||
import 'package:customer/payment/paystack/pay_stack_screen.dart';
|
||||
import 'package:customer/payment/paystack/pay_stack_url_model.dart';
|
||||
import 'package:customer/payment/paystack/paystack_url_genrater.dart';
|
||||
import 'package:customer/payment/stripe_failed_model.dart';
|
||||
import 'package:customer/payment/xenditModel.dart';
|
||||
import 'package:customer/payment/xenditScreen.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:customer/themes/show_toast_dialog.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_paypal/flutter_paypal.dart';
|
||||
import 'package:flutter_stripe/flutter_stripe.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import '../themes/app_them_data.dart';
|
||||
|
||||
class MyCabBookingController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxString selectedTab = "New".obs;
|
||||
|
||||
RxList<CabOrderModel> cabOrder = <CabOrderModel>[].obs;
|
||||
|
||||
final List<String> tabKeys = ["New", "On Going", "Completed", "Cancelled"];
|
||||
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
|
||||
@override
|
||||
Future<void> onInit() async {
|
||||
super.onInit();
|
||||
fetchParcelData();
|
||||
}
|
||||
|
||||
Future<void> selectTab(String tab) async {
|
||||
selectedTab.value = tab;
|
||||
}
|
||||
|
||||
Future<void> fetchParcelData() async {
|
||||
isLoading.value = true;
|
||||
|
||||
if (FirebaseAuth.instance.currentUser != null) {
|
||||
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((user) {
|
||||
if (user != null) {
|
||||
userModel.value = user;
|
||||
}
|
||||
});
|
||||
|
||||
FireStoreUtils.getCabDriverOrders().listen((orders) {
|
||||
cabOrder.value = orders;
|
||||
});
|
||||
|
||||
await getPaymentSettings();
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
List<CabOrderModel> get filteredParcelOrders => getOrdersForTab(selectedTab.value);
|
||||
|
||||
List<CabOrderModel> getOrdersForTab(String tab) {
|
||||
switch (tab) {
|
||||
case "New":
|
||||
return cabOrder.where((order) => ["Order Placed", "Driver Pending"].contains(order.status)).toList();
|
||||
|
||||
case "On Going":
|
||||
return cabOrder.where((order) => ["Driver Accepted", "Order Shipped", "In Transit"].contains(order.status)).toList();
|
||||
|
||||
case "Completed":
|
||||
return cabOrder.where((order) => ["Order Completed"].contains(order.status)).toList();
|
||||
|
||||
case "Cancelled":
|
||||
return cabOrder.where((order) => ["Order Rejected", "Order Cancelled", "Driver Rejected"].contains(order.status)).toList();
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Get localized title for UI
|
||||
String getLocalizedTabTitle(String tabKey) {
|
||||
switch (tabKey) {
|
||||
case "New":
|
||||
return "New".tr;
|
||||
case "On Going":
|
||||
return "On Going".tr;
|
||||
case "Completed":
|
||||
return "Completed".tr;
|
||||
case "Cancelled":
|
||||
return "Cancelled".tr;
|
||||
default:
|
||||
return tabKey;
|
||||
}
|
||||
}
|
||||
|
||||
String formatDate(Timestamp timestamp) {
|
||||
final dateTime = timestamp.toDate();
|
||||
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
|
||||
}
|
||||
|
||||
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
|
||||
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
|
||||
Rx<PayFastModel> payFastModel = PayFastModel().obs;
|
||||
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
|
||||
Rx<PayPalModel> payPalModel = PayPalModel().obs;
|
||||
Rx<StripeModel> stripeModel = StripeModel().obs;
|
||||
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
|
||||
Rx<PayStackModel> payStackModel = PayStackModel().obs;
|
||||
Rx<PaytmModel> paytmModel = PaytmModel().obs;
|
||||
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
|
||||
|
||||
Rx<MidTrans> midTransModel = MidTrans().obs;
|
||||
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
|
||||
Rx<Xendit> xenditModel = Xendit().obs;
|
||||
|
||||
final RxString selectedPaymentMethod = ''.obs;
|
||||
|
||||
Rx<CabOrderModel> currentOrder = CabOrderModel().obs;
|
||||
|
||||
Rx<CabOrderModel> selectedOrder = CabOrderModel().obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble discount = 0.0.obs;
|
||||
RxDouble taxAmount = 0.0.obs;
|
||||
|
||||
void calculateTotalAmount(CabOrderModel order) {
|
||||
subTotal.value = 0.0;
|
||||
discount.value = 0.0;
|
||||
taxAmount.value = 0.0;
|
||||
totalAmount.value = 0.0;
|
||||
|
||||
selectedOrder.value = order;
|
||||
try {
|
||||
subTotal.value = double.tryParse(selectedOrder.value.subTotal?.toString() ?? "0") ?? 0.0;
|
||||
discount.value = double.tryParse(selectedOrder.value.discount?.toString() ?? "0") ?? 0.0;
|
||||
taxAmount.value = 0.0;
|
||||
|
||||
subTotal.value = subTotal.value;
|
||||
|
||||
if (selectedOrder.value.taxSetting != null) {
|
||||
for (var element in selectedOrder.value.taxSetting!) {
|
||||
taxAmount.value += Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element);
|
||||
}
|
||||
}
|
||||
|
||||
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("Failed to calculate total: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> completeOrder() async {
|
||||
if (selectedPaymentMethod.value == PaymentGateway.cod.name) {
|
||||
selectedOrder.value.paymentMethod = selectedPaymentMethod.value;
|
||||
await FireStoreUtils.cabOrderPlace(selectedOrder.value).then((value) {
|
||||
ShowToastDialog.showToast("Payment method changed".tr);
|
||||
Get.back();
|
||||
});
|
||||
} else {
|
||||
selectedOrder.value.paymentMethod = selectedPaymentMethod.value;
|
||||
userModel.value.inProgressOrderID ??= [];
|
||||
userModel.value.inProgressOrderID!.clear();
|
||||
await FireStoreUtils.updateUser(userModel.value);
|
||||
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: double.parse(totalAmount.toString()),
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: false,
|
||||
orderId: selectedOrder.value.id,
|
||||
note: "Cab Amount debited".tr,
|
||||
paymentStatus: "success".tr,
|
||||
serviceType: Constant.parcelServiceType,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid());
|
||||
});
|
||||
}
|
||||
selectedOrder.value.paymentStatus = true;
|
||||
await FireStoreUtils.cabOrderPlace(selectedOrder.value).then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
Get.back();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getPaymentSettings() async {
|
||||
await FireStoreUtils.getPaymentSettingsData().then((value) {
|
||||
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
|
||||
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
|
||||
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
|
||||
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
|
||||
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
|
||||
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
|
||||
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
|
||||
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
|
||||
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
|
||||
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
|
||||
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
|
||||
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
|
||||
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
|
||||
|
||||
if (walletSettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.wallet.name;
|
||||
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.cod.name;
|
||||
} else if (stripeModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.stripe.name;
|
||||
} else if (payPalModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.paypal.name;
|
||||
} else if (payStackModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payStack.name;
|
||||
} else if (mercadoPagoModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
|
||||
} else if (flutterWaveModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
|
||||
} else if (payFastModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payFast.name;
|
||||
} else if (razorPayModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
|
||||
} else if (midTransModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
|
||||
} else if (orangeMoneyModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
|
||||
} else if (xenditModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.xendit.name;
|
||||
}
|
||||
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
|
||||
Stripe.merchantIdentifier = 'eMart Customer';
|
||||
Stripe.instance.applySettings();
|
||||
setRef();
|
||||
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
|
||||
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
|
||||
});
|
||||
}
|
||||
|
||||
// Strip
|
||||
Future<void> stripeMakePayment({required String amount}) async {
|
||||
log(double.parse(amount).toStringAsFixed(0));
|
||||
try {
|
||||
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
|
||||
log("stripe Responce====>$paymentIntentData");
|
||||
if (paymentIntentData!.containsKey("error")) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
} else {
|
||||
await Stripe.instance.initPaymentSheet(
|
||||
paymentSheetParameters: SetupPaymentSheetParameters(
|
||||
paymentIntentClientSecret: paymentIntentData['client_secret'],
|
||||
allowsDelayedPaymentMethods: false,
|
||||
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
|
||||
customFlow: true,
|
||||
style: ThemeMode.system,
|
||||
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
|
||||
merchantDisplayName: 'GoRide',
|
||||
),
|
||||
);
|
||||
displayStripePaymentSheet(amount: amount);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log("$e \n$s");
|
||||
ShowToastDialog.showToast("exception:$e \n$s");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> displayStripePaymentSheet({required String amount}) async {
|
||||
try {
|
||||
await Stripe.instance.presentPaymentSheet().then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
completeOrder();
|
||||
});
|
||||
} on StripeException catch (e) {
|
||||
var lo1 = jsonEncode(e);
|
||||
var lo2 = jsonDecode(lo1);
|
||||
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
|
||||
ShowToastDialog.showToast(lom.error.message);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future createStripeIntent({required String amount}) async {
|
||||
try {
|
||||
Map<String, dynamic> body = {
|
||||
'amount': ((double.parse(amount) * 100).round()).toString(),
|
||||
'currency': "USD",
|
||||
'payment_method_types[]': 'card',
|
||||
"description": "Strip Payment",
|
||||
"shipping[name]": Constant.userModel!.fullName(),
|
||||
"shipping[address][line1]": "510 Townsend St",
|
||||
"shipping[address][postal_code]": "98140",
|
||||
"shipping[address][city]": "San Francisco",
|
||||
"shipping[address][state]": "CA",
|
||||
"shipping[address][country]": "US",
|
||||
};
|
||||
var stripeSecret = stripeModel.value.stripeSecret;
|
||||
var response = await http.post(
|
||||
Uri.parse('https://api.stripe.com/v1/payment_intents'),
|
||||
body: body,
|
||||
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
);
|
||||
|
||||
return jsonDecode(response.body);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//mercadoo
|
||||
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
|
||||
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"items": [
|
||||
{
|
||||
"title": "Test",
|
||||
"description": "Test Payment",
|
||||
"quantity": 1,
|
||||
"currency_id": "BRL", // or your preferred currency
|
||||
"unit_price": double.parse(amount),
|
||||
},
|
||||
],
|
||||
"payer": {"email": Constant.userModel!.email},
|
||||
"back_urls": {
|
||||
"failure": "${Constant.globalUrl}payment/failure",
|
||||
"pending": "${Constant.globalUrl}payment/pending",
|
||||
"success": "${Constant.globalUrl}payment/success",
|
||||
},
|
||||
"auto_return": "approved",
|
||||
// Automatically return after payment is approved
|
||||
});
|
||||
|
||||
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Error creating preference: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Paypal
|
||||
void paypalPaymentSheet(String amount, context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(BuildContext context) => UsePaypal(
|
||||
sandboxMode: payPalModel.value.isLive == true ? false : true,
|
||||
clientId: payPalModel.value.paypalClient ?? '',
|
||||
secretKey: payPalModel.value.paypalSecret ?? '',
|
||||
returnURL: "com.parkme://paypalpay",
|
||||
cancelURL: "com.parkme://paypalpay",
|
||||
transactions: [
|
||||
{
|
||||
"amount": {
|
||||
"total": amount,
|
||||
"currency": "USD",
|
||||
"details": {"subtotal": amount},
|
||||
},
|
||||
},
|
||||
],
|
||||
note: "Contact us for any questions on your order.",
|
||||
onSuccess: (Map params) async {
|
||||
completeOrder();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
},
|
||||
onError: (error) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
onCancel: (params) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///PayStack Payment Method
|
||||
Future<void> payStackPayment(String totalAmount) async {
|
||||
await PayStackURLGen.payStackURLGen(
|
||||
amount: (double.parse(totalAmount) * 100).toString(),
|
||||
currency: "ZAR",
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
userModel: Constant.userModel!,
|
||||
).then((value) async {
|
||||
if (value != null) {
|
||||
PayStackUrlModel payStackModel0 = value;
|
||||
Get.to(
|
||||
PayStackScreen(
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
callBackUrl: payStackModel.value.callbackURL.toString(),
|
||||
initialURl: payStackModel0.data.authorizationUrl,
|
||||
amount: totalAmount,
|
||||
reference: payStackModel0.data.reference,
|
||||
),
|
||||
)!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//flutter wave Payment Method
|
||||
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
|
||||
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
|
||||
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"tx_ref": _ref,
|
||||
"amount": amount,
|
||||
"currency": "NGN",
|
||||
"redirect_url": "${Constant.globalUrl}payment/success",
|
||||
"payment_options": "ussd, card, barter, payattitude",
|
||||
"customer": {
|
||||
"email": Constant.userModel!.email.toString(),
|
||||
"phonenumber": Constant.userModel!.phoneNumber, // Add a real phone number
|
||||
"name": Constant.userModel!.fullName(), // Add a real customer name
|
||||
},
|
||||
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
|
||||
});
|
||||
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Payment initialization failed: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? _ref;
|
||||
|
||||
void setRef() {
|
||||
maths.Random numRef = maths.Random();
|
||||
int year = DateTime.now().year;
|
||||
int refNumber = numRef.nextInt(20000);
|
||||
if (Platform.isAndroid) {
|
||||
_ref = "AndroidRef$year$refNumber";
|
||||
} else if (Platform.isIOS) {
|
||||
_ref = "IOSRef$year$refNumber";
|
||||
}
|
||||
}
|
||||
|
||||
// payFast
|
||||
void payFastPayment({required BuildContext context, required String amount}) {
|
||||
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: Constant.userModel!).then((
|
||||
String? value,
|
||||
) async {
|
||||
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
|
||||
if (isDone) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///Paytm payment function
|
||||
Future<void> getPaytmCheckSum(context, {required double amount}) async {
|
||||
// final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
// String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
|
||||
//
|
||||
// final response = await http.post(
|
||||
// Uri.parse(getChecksum),
|
||||
// headers: {},
|
||||
// body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString()},
|
||||
// );
|
||||
//
|
||||
// final data = jsonDecode(response.body);
|
||||
// await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
|
||||
// initiatePayment(amount: amount, orderId: orderId).then((value) {
|
||||
// String callback = "";
|
||||
// if (paytmModel.value.isSandboxEnabled == true) {
|
||||
// callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
// } else {
|
||||
// callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
// }
|
||||
//
|
||||
// GetPaymentTxtTokenModel result = value;
|
||||
// startTransaction(context, txnTokenBy: result.body.txnToken, orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
Future<void> startTransaction(
|
||||
context, {
|
||||
required String txnTokenBy,
|
||||
required orderId,
|
||||
required double amount,
|
||||
required callBackURL,
|
||||
required isStaging,
|
||||
}) async {
|
||||
// try {
|
||||
// var response = AllInOneSdk.startTransaction(
|
||||
// paytmModel.value.paytmMID.toString(),
|
||||
// orderId,
|
||||
// amount.toString(),
|
||||
// txnTokenBy,
|
||||
// callBackURL,
|
||||
// isStaging,
|
||||
// true,
|
||||
// true,
|
||||
// );
|
||||
//
|
||||
// response.then((value) {
|
||||
// if (value!["RESPMSG"] == "Txn Success") {
|
||||
// print("txt done!!");
|
||||
// ShowToastDialog.showToast("Payment Successful!!");
|
||||
// completeOrder();
|
||||
// }
|
||||
// }).catchError((onError) {
|
||||
// if (onError is PlatformException) {
|
||||
// Get.back();
|
||||
//
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// } else {
|
||||
// log("======>>2");
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// }
|
||||
// });
|
||||
// } catch (err) {
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(err.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
|
||||
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
|
||||
final response = await http.post(
|
||||
Uri.parse(getChecksum),
|
||||
headers: {},
|
||||
body: {
|
||||
"mid": paytmModel.value.paytmMID.toString(),
|
||||
"order_id": orderId,
|
||||
"key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(),
|
||||
"checksum_value": checkSum,
|
||||
},
|
||||
);
|
||||
final data = jsonDecode(response.body);
|
||||
return data['status'];
|
||||
}
|
||||
|
||||
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
|
||||
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
|
||||
String callback = "";
|
||||
if (paytmModel.value.isSandboxEnabled == true) {
|
||||
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
} else {
|
||||
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
}
|
||||
final response = await http.post(
|
||||
Uri.parse(initiateURL),
|
||||
headers: {},
|
||||
body: {
|
||||
"mid": paytmModel.value.paytmMID,
|
||||
"order_id": orderId,
|
||||
"key_secret": paytmModel.value.pAYTMMERCHANTKEY,
|
||||
"amount": amount.toString(),
|
||||
"currency": "INR",
|
||||
"callback_url": callback,
|
||||
"custId": FireStoreUtils.getCurrentUid(),
|
||||
"issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
|
||||
},
|
||||
);
|
||||
log(response.body);
|
||||
final data = jsonDecode(response.body);
|
||||
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
}
|
||||
return GetPaymentTxtTokenModel.fromJson(data);
|
||||
}
|
||||
|
||||
///RazorPay payment function
|
||||
final Razorpay razorPay = Razorpay();
|
||||
|
||||
void openCheckout({required amount, required orderId}) async {
|
||||
var options = {
|
||||
'key': razorPayModel.value.razorpayKey,
|
||||
'amount': amount * 100,
|
||||
'name': 'GoRide',
|
||||
'order_id': orderId,
|
||||
"currency": "INR",
|
||||
'description': 'wallet Topup',
|
||||
'retry': {'enabled': true, 'max_count': 1},
|
||||
'send_sms_hash': true,
|
||||
'prefill': {'contact': Constant.userModel!.phoneNumber, 'email': Constant.userModel!.email},
|
||||
'external': {
|
||||
'wallets': ['paytm'],
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
razorPay.open(options);
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void handlePaymentSuccess(PaymentSuccessResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
}
|
||||
|
||||
void handleExternalWaller(ExternalWalletResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Processing!! via".tr);
|
||||
}
|
||||
|
||||
void handlePaymentError(PaymentFailureResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed!!".tr);
|
||||
}
|
||||
|
||||
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
|
||||
final currentDate = DateTime.now();
|
||||
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
|
||||
}
|
||||
|
||||
//Midtrans payment
|
||||
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
|
||||
await createPaymentLink(amount: amount).then((url) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (url != '') {
|
||||
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> createPaymentLink({required var amount}) async {
|
||||
var ordersId = const Uuid().v1();
|
||||
final url = Uri.parse(
|
||||
midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links',
|
||||
);
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!),
|
||||
},
|
||||
body: jsonEncode({
|
||||
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
|
||||
'usage_limit': 2,
|
||||
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
String generateBasicAuthHeader(String apiKey) {
|
||||
String credentials = '$apiKey:';
|
||||
String base64Encoded = base64Encode(utf8.encode(credentials));
|
||||
return 'Basic $base64Encoded';
|
||||
}
|
||||
|
||||
//Orangepay payment
|
||||
static String accessToken = '';
|
||||
static String payToken = '';
|
||||
static String orderId = '';
|
||||
static String amount = '';
|
||||
|
||||
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
|
||||
reset();
|
||||
var id = const Uuid().v4();
|
||||
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
|
||||
ShowToastDialog.closeLoader();
|
||||
if (paymentURL.toString() != '') {
|
||||
Get.to(
|
||||
() => OrangeMoneyScreen(
|
||||
initialURl: paymentURL,
|
||||
accessToken: accessToken,
|
||||
amount: amount,
|
||||
orangePay: orangeMoneyModel.value,
|
||||
orderId: orderId,
|
||||
payToken: payToken,
|
||||
),
|
||||
)!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
}
|
||||
|
||||
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
|
||||
String apiUrl = 'https://api.orange.com/oauth/v3/token';
|
||||
Map<String, String> requestBody = {'grant_type': 'client_credentials'};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{
|
||||
'Authorization': "Basic ${orangeMoneyModel.value.auth!}",
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
// Handle the response
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
|
||||
accessToken = responseData['access_token'];
|
||||
// ignore: use_build_context_synchronously
|
||||
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future webpayment({
|
||||
required String orderIdData,
|
||||
required BuildContext context,
|
||||
required String currency,
|
||||
required String amountData,
|
||||
}) async {
|
||||
orderId = orderIdData;
|
||||
amount = amountData;
|
||||
String apiUrl =
|
||||
orangeMoneyModel.value.isSandbox! == true
|
||||
? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment'
|
||||
: 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
|
||||
Map<String, String> requestBody = {
|
||||
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
|
||||
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
|
||||
"order_id": orderId,
|
||||
"amount": amount,
|
||||
"reference": 'Y-Note Test',
|
||||
"lang": "en",
|
||||
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
|
||||
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
|
||||
"notif_url": orangeMoneyModel.value.notifUrl!.toString(),
|
||||
};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
body: json.encode(requestBody),
|
||||
);
|
||||
|
||||
// Handle the response
|
||||
if (response.statusCode == 201) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
if (responseData['message'] == 'OK') {
|
||||
payToken = responseData['pay_token'];
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
accessToken = '';
|
||||
payToken = '';
|
||||
orderId = '';
|
||||
amount = '';
|
||||
}
|
||||
|
||||
//XenditPayment
|
||||
Future<void> xenditPayment(context, amount) async {
|
||||
await createXenditInvoice(amount: amount).then((model) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (model.id != null) {
|
||||
Get.to(
|
||||
() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()),
|
||||
)!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<XenditModel> createXenditInvoice({required var amount}) async {
|
||||
const url = 'https://api.xendit.co/v2/invoices';
|
||||
var headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
|
||||
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
|
||||
};
|
||||
|
||||
final body = jsonEncode({
|
||||
'external_id': const Uuid().v1(),
|
||||
'amount': amount,
|
||||
'payer_email': 'customer@domain.com',
|
||||
'description': 'Test - VA Successful invoice payment',
|
||||
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(Uri.parse(url), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
|
||||
return model;
|
||||
} else {
|
||||
return XenditModel();
|
||||
}
|
||||
} catch (e) {
|
||||
return XenditModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
51
lib/controllers/my_profile_controller.dart
Normal file
51
lib/controllers/my_profile_controller.dart
Normal file
@@ -0,0 +1,51 @@
|
||||
import 'dart:developer';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/controllers/theme_controller.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class MyProfileController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
RxString isDarkMode = "Light".obs; // For UI text
|
||||
RxBool isDarkModeSwitch = false.obs; // For switch widget
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getTheme();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void getTheme() {
|
||||
bool isDark = Preferences.getBoolean(Preferences.themKey);
|
||||
isDarkMode.value = isDark ? "Dark" : "Light";
|
||||
isDarkModeSwitch.value = isDark;
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
void toggleDarkMode(bool value) {
|
||||
isDarkModeSwitch.value = value;
|
||||
isDarkMode.value = value ? "Dark" : "Light";
|
||||
Preferences.setBoolean(Preferences.themKey, value);
|
||||
|
||||
// Update ThemeController for instant app theme change
|
||||
if (Get.isRegistered<ThemeController>()) {
|
||||
final themeController = Get.find<ThemeController>();
|
||||
themeController.isDark.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete user API
|
||||
Future<bool> deleteUserFromServer() async {
|
||||
var url = '${Constant.websiteUrl}/api/delete-user';
|
||||
try {
|
||||
var response = await http.post(Uri.parse(url), body: {'uuid': FireStoreUtils.getCurrentUid()});
|
||||
log("deleteUserFromServer :: ${response.body}");
|
||||
return response.statusCode == 200;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
228
lib/controllers/my_rental_booking_controller.dart
Normal file
228
lib/controllers/my_rental_booking_controller.dart
Normal file
@@ -0,0 +1,228 @@
|
||||
import 'dart:async';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/wallet_transaction_model.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import 'package:customer/themes/show_toast_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../models/rental_order_model.dart';
|
||||
import '../models/tax_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class MyRentalBookingController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<RentalOrderModel> rentalOrders = <RentalOrderModel>[].obs;
|
||||
|
||||
RxString selectedTab = "New".obs;
|
||||
RxList<String> tabTitles = ["New", "On Going", "Completed", "Cancelled"].obs;
|
||||
|
||||
StreamSubscription<List<RentalOrderModel>>? _rentalSubscription;
|
||||
final RxString selectedPaymentMethod = ''.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
listenRentalOrders();
|
||||
}
|
||||
|
||||
void selectTab(String tab) {
|
||||
selectedTab.value = tab;
|
||||
}
|
||||
|
||||
/// Start listening to rental orders live. Cancel previous subscription first.
|
||||
void listenRentalOrders() {
|
||||
isLoading.value = true;
|
||||
_rentalSubscription?.cancel();
|
||||
if (Constant.userModel != null) {
|
||||
_rentalSubscription = FireStoreUtils.getRentalOrders().listen(
|
||||
(orders) {
|
||||
rentalOrders.assignAll(orders);
|
||||
},
|
||||
onError: (err) {
|
||||
isLoading.value = false;
|
||||
print("Error fetching rental orders: $err");
|
||||
},
|
||||
);
|
||||
}
|
||||
isLoading.value = false;
|
||||
|
||||
}
|
||||
|
||||
Rx<RentalOrderModel> selectedOrder = RentalOrderModel().obs;
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble discount = 0.0.obs;
|
||||
RxDouble taxAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
RxDouble extraKilometerCharge = 0.0.obs;
|
||||
RxDouble extraMinutesCharge = 0.0.obs;
|
||||
|
||||
void calculateTotalAmount(RentalOrderModel order) {
|
||||
subTotal.value = 0.0;
|
||||
discount.value = 0.0;
|
||||
taxAmount.value = 0.0;
|
||||
totalAmount.value = 0.0;
|
||||
extraKilometerCharge.value = 0.0;
|
||||
extraMinutesCharge.value = 0.0;
|
||||
|
||||
selectedOrder.value = order;
|
||||
try {
|
||||
subTotal.value = double.tryParse(selectedOrder.value.subTotal?.toString() ?? "0") ?? 0.0;
|
||||
discount.value = double.tryParse(selectedOrder.value.discount?.toString() ?? "0") ?? 0.0;
|
||||
taxAmount.value = 0.0;
|
||||
|
||||
if (selectedOrder.value.endTime != null) {
|
||||
DateTime start = selectedOrder.value.startTime!.toDate();
|
||||
DateTime end = selectedOrder.value.endTime!.toDate();
|
||||
int hours = end.difference(start).inHours;
|
||||
if (hours >= int.parse(selectedOrder.value.rentalPackageModel!.includedHours.toString())) {
|
||||
hours = hours - int.parse(selectedOrder.value.rentalPackageModel!.includedHours.toString());
|
||||
double hourlyRate = double.tryParse(selectedOrder.value.rentalPackageModel?.extraMinuteFare?.toString() ?? "0") ?? 0.0;
|
||||
extraMinutesCharge.value = (hours * 60) * hourlyRate;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedOrder.value.startKitoMetersReading != null && selectedOrder.value.endKitoMetersReading != null) {
|
||||
double startKm = double.tryParse(selectedOrder.value.startKitoMetersReading?.toString() ?? "0") ?? 0.0;
|
||||
double endKm = double.tryParse(selectedOrder.value.endKitoMetersReading?.toString() ?? "0") ?? 0.0;
|
||||
if (endKm > startKm) {
|
||||
double totalKm = endKm - startKm;
|
||||
if (totalKm > double.parse(selectedOrder.value.rentalPackageModel!.includedDistance!)) {
|
||||
totalKm = totalKm - double.parse(selectedOrder.value.rentalPackageModel!.includedDistance!);
|
||||
double extraKmRate = double.tryParse(selectedOrder.value.rentalPackageModel?.extraKmFare?.toString() ?? "0") ?? 0.0;
|
||||
extraKilometerCharge.value = totalKm * extraKmRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
subTotal.value = subTotal.value + extraKilometerCharge.value + extraMinutesCharge.value;
|
||||
|
||||
if (selectedOrder.value.taxSetting != null) {
|
||||
for (var element in selectedOrder.value.taxSetting!) {
|
||||
taxAmount.value += Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element);
|
||||
}
|
||||
}
|
||||
|
||||
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("Failed to calculate total: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> completeOrder() async {
|
||||
if (selectedPaymentMethod.value == PaymentGateway.cod.name) {
|
||||
selectedOrder.value.paymentMethod = selectedPaymentMethod.value;
|
||||
await FireStoreUtils.rentalOrderPlace(selectedOrder.value).then((value) {
|
||||
ShowToastDialog.showToast("Payment method changed".tr);
|
||||
Get.back();
|
||||
Get.back();
|
||||
});
|
||||
} else {
|
||||
selectedOrder.value.paymentStatus = true;
|
||||
selectedOrder.value.paymentMethod = selectedPaymentMethod.value;
|
||||
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: double.parse(totalAmount.toString()),
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: false,
|
||||
orderId: selectedOrder.value.id,
|
||||
note: "Rental Amount debited".tr,
|
||||
paymentStatus: "success".tr,
|
||||
serviceType: Constant.parcelServiceType,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
if (value == true) {
|
||||
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await FireStoreUtils.rentalOrderPlace(selectedOrder.value).then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
Get.back();
|
||||
Get.back();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Return filtered list for a specific tab title
|
||||
List<RentalOrderModel> getOrdersForTab(String tab) {
|
||||
switch (tab) {
|
||||
case "New":
|
||||
return rentalOrders.where((order) => ["Order Placed", "Order Accepted", "Driver Pending"].contains(order.status)).toList();
|
||||
|
||||
case "On Going":
|
||||
return rentalOrders.where((order) => ["Driver Accepted", "Order Shipped", "In Transit"].contains(order.status)).toList();
|
||||
|
||||
case "Completed":
|
||||
return rentalOrders.where((order) => ["Order Completed"].contains(order.status)).toList();
|
||||
|
||||
case "Cancelled":
|
||||
return rentalOrders.where((order) => ["Order Rejected", "Order Cancelled", "Driver Rejected"].contains(order.status)).toList();
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Old helper (optional)
|
||||
List<RentalOrderModel> get filteredRentalOrders => getOrdersForTab(selectedTab.value);
|
||||
|
||||
Future<void> cancelRentalRequest(RentalOrderModel order, {List<TaxModel>? taxList}) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
order.status = Constant.orderCancelled;
|
||||
await FireStoreUtils.rentalOrderPlace(order);
|
||||
|
||||
listenRentalOrders();
|
||||
|
||||
if (order.paymentMethod?.toLowerCase() != "cod") {
|
||||
double totalTax = 0.0;
|
||||
|
||||
if (taxList != null) {
|
||||
for (var element in taxList) {
|
||||
totalTax += Constant.calculateTax(
|
||||
amount: (double.parse(order.subTotal.toString()) - double.parse(order.discount.toString())).toString(),
|
||||
taxModel: element,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
double subTotal = double.parse(order.subTotal.toString()) - double.parse(order.discount.toString());
|
||||
double refundAmount = subTotal + totalTax;
|
||||
|
||||
WalletTransactionModel walletTransaction = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: refundAmount,
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: true,
|
||||
// refund
|
||||
orderId: order.id,
|
||||
note: "Refund for cancelled booking".tr,
|
||||
paymentStatus: "success".tr,
|
||||
serviceType: Constant.parcelServiceType,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(walletTransaction);
|
||||
await FireStoreUtils.updateUserWallet(amount: refundAmount.toString(), userId: FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
ShowToastDialog.showToast("Booking cancelled successfully".tr);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("Failed to cancel booking: $e".tr);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_rentalSubscription?.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
43
lib/controllers/on_boarding_controller.dart
Normal file
43
lib/controllers/on_boarding_controller.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../models/on_boarding_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class OnboardingController extends GetxController {
|
||||
RxInt currentPage = 0.obs;
|
||||
late PageController pageController;
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<OnBoardingModel> onboardingList = <OnBoardingModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
pageController = PageController();
|
||||
getOnBoardingData();
|
||||
}
|
||||
|
||||
void nextPage() {
|
||||
if (currentPage.value < onboardingList.length - 1) {
|
||||
pageController.nextPage(duration: 300.milliseconds, curve: Curves.ease);
|
||||
}
|
||||
}
|
||||
|
||||
void onPageChanged(int index) {
|
||||
currentPage.value = index;
|
||||
}
|
||||
|
||||
Future<void> getOnBoardingData() async {
|
||||
isLoading.value = true;
|
||||
await FireStoreUtils.getOnBoardingList().then((value) {
|
||||
onboardingList.value = value;
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
pageController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
214
lib/controllers/on_demand_booking_controller.dart
Normal file
214
lib/controllers/on_demand_booking_controller.dart
Normal file
@@ -0,0 +1,214 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../models/onprovider_order_model.dart';
|
||||
import '../models/provider_serivce_model.dart';
|
||||
import '../screen_ui/on_demand_service/on_demand_dashboard_screen.dart';
|
||||
import '../screen_ui/on_demand_service/on_demand_payment_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../service/send_notification.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
import 'on_demand_dashboard_controller.dart';
|
||||
|
||||
class OnDemandBookingController extends GetxController {
|
||||
Rxn<ProviderServiceModel> provider = Rxn<ProviderServiceModel>();
|
||||
RxString categoryTitle = ''.obs;
|
||||
|
||||
RxInt quantity = 1.obs;
|
||||
Rx<TextEditingController> descriptionController = TextEditingController().obs;
|
||||
Rx<TextEditingController> dateTimeController = TextEditingController().obs;
|
||||
Rx<TextEditingController> couponTextController = TextEditingController().obs;
|
||||
|
||||
Rx<DateTime> selectedDateTime = DateTime.now().obs;
|
||||
RxString dateTimeText = "".obs;
|
||||
|
||||
RxList<CouponModel> couponList = <CouponModel>[].obs;
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble price = 0.0.obs;
|
||||
RxDouble discountAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
|
||||
RxString discountType = "".obs;
|
||||
RxString discountLabel = "".obs;
|
||||
RxString offerCode = "".obs;
|
||||
|
||||
Rx<ShippingAddress> selectedAddress = ShippingAddress().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
final Map<String, dynamic>? args = Get.arguments;
|
||||
if (args != null) {
|
||||
provider.value = args['providerModel'];
|
||||
categoryTitle.value = args['categoryTitle'] ?? '';
|
||||
}
|
||||
selectedAddress.value = Constant.selectedLocation;
|
||||
fetchCoupons();
|
||||
calculatePrice();
|
||||
}
|
||||
|
||||
void fetchCoupons() {
|
||||
if (provider.value?.author != null && provider.value!.author!.isNotEmpty) {
|
||||
FireStoreUtils.getProviderCoupon(provider.value!.author!).then((activeCoupons) => couponList.assignAll(activeCoupons));
|
||||
FireStoreUtils.getProviderCouponAfterExpire(provider.value!.author!).then((expiredCoupons) => couponList.addAll(expiredCoupons));
|
||||
}
|
||||
}
|
||||
|
||||
void incrementQuantity() {
|
||||
quantity.value++;
|
||||
calculatePrice();
|
||||
}
|
||||
|
||||
void decrementQuantity() {
|
||||
if (quantity.value > 1) {
|
||||
quantity.value--;
|
||||
calculatePrice();
|
||||
}
|
||||
}
|
||||
|
||||
void setDateTime(DateTime dateTime) {
|
||||
selectedDateTime.value = dateTime;
|
||||
dateTimeText.value = DateFormat('dd-MM-yyyy HH:mm').format(dateTime);
|
||||
dateTimeController.value.text = dateTimeText.value;
|
||||
}
|
||||
|
||||
void applyCoupon(CouponModel coupon) {
|
||||
double discount = 0.0;
|
||||
if (coupon.discountType == "Percentage" || coupon.discountType == "Percent") {
|
||||
discount = price.value * (double.tryParse(coupon.discount.toString()) ?? 0) / 100;
|
||||
} else {
|
||||
discount = double.tryParse(coupon.discount.toString()) ?? 0;
|
||||
}
|
||||
|
||||
if (subTotal.value > discount) {
|
||||
discountType.value = coupon.discountType ?? '';
|
||||
discountLabel.value = coupon.discount.toString();
|
||||
offerCode.value = coupon.code ?? '';
|
||||
calculatePrice();
|
||||
} else {
|
||||
Get.snackbar("Error", "Coupon cannot be applied");
|
||||
}
|
||||
}
|
||||
|
||||
String getDate(String date) {
|
||||
try {
|
||||
DateTime dt = DateTime.parse(date);
|
||||
return "${dt.day}-${dt.month}-${dt.year}";
|
||||
} catch (e) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
void calculatePrice() {
|
||||
double basePrice =
|
||||
(provider.value?.disPrice == "" || provider.value?.disPrice == "0")
|
||||
? double.tryParse(provider.value?.price.toString() ?? "0") ?? 0
|
||||
: double.tryParse(provider.value?.disPrice.toString() ?? "0") ?? 0;
|
||||
|
||||
price.value = basePrice * quantity.value;
|
||||
|
||||
// discount
|
||||
if (discountType.value == "Percentage" || discountType.value == "Percent") {
|
||||
discountAmount.value = price.value * (double.tryParse(discountLabel.value) ?? 0) / 100;
|
||||
} else {
|
||||
discountAmount.value = double.tryParse(discountLabel.value.isEmpty ? '0' : discountLabel.value) ?? 0;
|
||||
}
|
||||
|
||||
subTotal.value = price.value - discountAmount.value;
|
||||
|
||||
// tax calculation
|
||||
double total = subTotal.value;
|
||||
for (var element in Constant.taxList) {
|
||||
total += Constant.getTaxValue(amount: subTotal.value.toString(), taxModel: element);
|
||||
}
|
||||
|
||||
totalAmount.value = total;
|
||||
}
|
||||
|
||||
Future<void> confirmBooking(BuildContext context) async {
|
||||
if (selectedAddress.value.getFullAddress().isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter address".tr);
|
||||
} else if (dateTimeController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please select time slot.".tr);
|
||||
} else {
|
||||
UserModel? providerUser = await FireStoreUtils.getUserProfile(provider.value!.author!);
|
||||
|
||||
if (provider.value?.priceUnit == "Fixed") {
|
||||
OnProviderOrderModel onDemandOrderModel = OnProviderOrderModel(
|
||||
authorID: FireStoreUtils.getCurrentUid(),
|
||||
author: Constant.userModel!,
|
||||
quantity: double.parse(quantity.value.toString()),
|
||||
sectionId: Constant.sectionConstantModel!.id,
|
||||
address: selectedAddress.value,
|
||||
taxModel: Constant.taxList,
|
||||
provider: provider.value,
|
||||
status: Constant.orderPlaced,
|
||||
scheduleDateTime: Timestamp.fromDate(selectedDateTime.value),
|
||||
notes: descriptionController.value.text,
|
||||
discount: discountAmount.toString(),
|
||||
discountType: discountType.toString(),
|
||||
discountLabel: discountLabel.toString(),
|
||||
adminCommission:
|
||||
Constant.sectionConstantModel?.adminCommision?.isEnabled == false
|
||||
? '0'
|
||||
: "${providerUser?.adminCommissionModel?.amount ?? Constant.sectionConstantModel?.adminCommision?.amount ?? 0}",
|
||||
adminCommissionType:
|
||||
Constant.sectionConstantModel?.adminCommision?.isEnabled == false
|
||||
? 'fixed'
|
||||
: providerUser?.adminCommissionModel?.commissionType ?? Constant.sectionConstantModel?.adminCommision?.commissionType,
|
||||
otp: Constant.getReferralCode(),
|
||||
couponCode: offerCode.toString(),
|
||||
);
|
||||
print('totalAmount ::::::: ${double.tryParse(Constant.amountShow(amount: totalAmount.value.toString())) ?? 0.0}');
|
||||
print('totalAmount value ::::::: ${totalAmount.value}');
|
||||
|
||||
Get.to(() => OnDemandPaymentScreen(), arguments: {'onDemandOrderModel': Rxn<OnProviderOrderModel>(onDemandOrderModel), 'totalAmount': totalAmount.value, 'isExtra': false});
|
||||
} else {
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
OnProviderOrderModel onDemandOrder = OnProviderOrderModel(
|
||||
otp: Constant.getReferralCode(),
|
||||
authorID: FireStoreUtils.getCurrentUid(),
|
||||
author: Constant.userModel!,
|
||||
sectionId: Constant.sectionConstantModel!.id,
|
||||
address: selectedAddress.value,
|
||||
taxModel: Constant.taxList,
|
||||
status: Constant.orderPlaced,
|
||||
createdAt: Timestamp.now(),
|
||||
quantity: double.parse(quantity.value.toString()),
|
||||
provider: provider.value,
|
||||
extraPaymentStatus: true,
|
||||
scheduleDateTime: Timestamp.fromDate(selectedDateTime.value),
|
||||
notes: descriptionController.value.text,
|
||||
adminCommission:
|
||||
Constant.sectionConstantModel?.adminCommision?.isEnabled == false
|
||||
? '0'
|
||||
: "${providerUser?.adminCommissionModel?.amount ?? Constant.sectionConstantModel?.adminCommision?.amount ?? 0}",
|
||||
adminCommissionType:
|
||||
Constant.sectionConstantModel?.adminCommision?.isEnabled == false
|
||||
? 'fixed'
|
||||
: providerUser?.adminCommissionModel?.commissionType ?? Constant.sectionConstantModel?.adminCommision?.commissionType,
|
||||
paymentStatus: true,
|
||||
);
|
||||
|
||||
await FireStoreUtils.onDemandOrderPlace(onDemandOrder, 0.0);
|
||||
await FireStoreUtils.sendOrderOnDemandServiceEmail(orderModel: onDemandOrder);
|
||||
|
||||
if (providerUser != null) {
|
||||
Map<String, dynamic> payLoad = {"type": 'provider_order', "orderId": onDemandOrder.id};
|
||||
await SendNotification.sendFcmMessage(Constant.bookingPlaced, providerUser.fcmToken.toString(), payLoad);
|
||||
}
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.offAll(const OnDemandDashboardScreen());
|
||||
OnDemandDashboardController controller = Get.put(OnDemandDashboardController());
|
||||
controller.selectedIndex.value = 2;
|
||||
ShowToastDialog.showToast("OnDemand Service successfully booked".tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
lib/controllers/on_demand_category_controller.dart
Normal file
29
lib/controllers/on_demand_category_controller.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../models/category_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class OnDemandCategoryController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<CategoryModel> categories = <CategoryModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
fetchCategories();
|
||||
}
|
||||
|
||||
void fetchCategories() async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
// Fetch categories
|
||||
FireStoreUtils.getOnDemandCategory().then((catValue) {
|
||||
categories.value = catValue;
|
||||
});
|
||||
} catch (e) {
|
||||
print("Error fetching categories: $e");
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
lib/controllers/on_demand_dashboard_controller.dart
Normal file
40
lib/controllers/on_demand_dashboard_controller.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import 'package:customer/screen_ui/on_demand_service/favourite_ondemand_screen.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../screen_ui/on_demand_service/my_booking_on_demand_screen.dart';
|
||||
import '../screen_ui/on_demand_service/on_demand_home_screen.dart';
|
||||
|
||||
class OnDemandDashboardController extends GetxController {
|
||||
RxInt selectedIndex = 0.obs;
|
||||
|
||||
RxList pageList = [].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getTaxList();
|
||||
if (Constant.walletSetting == false) {
|
||||
pageList.value = [OnDemandHomeScreen(), FavouriteOndemandScreen(), const MyBookingOnDemandScreen(), const ProfileScreen()];
|
||||
} else {
|
||||
pageList.value = [
|
||||
OnDemandHomeScreen(),
|
||||
FavouriteOndemandScreen(),
|
||||
const MyBookingOnDemandScreen(),
|
||||
const WalletScreen(),
|
||||
const ProfileScreen(),
|
||||
];
|
||||
}
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getTaxList() async {
|
||||
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
|
||||
if (value != null) {
|
||||
Constant.taxList = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
100
lib/controllers/on_demand_details_controller.dart
Normal file
100
lib/controllers/on_demand_details_controller.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../models/favorite_ondemand_service_model.dart';
|
||||
import '../models/provider_serivce_model.dart';
|
||||
import '../models/rating_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class OnDemandDetailsController extends GetxController {
|
||||
late ProviderServiceModel provider;
|
||||
|
||||
final Rxn<UserModel> userModel = Rxn<UserModel>();
|
||||
final RxString subCategoryTitle = ''.obs;
|
||||
final RxString categoryTitle = ''.obs;
|
||||
final RxList<RatingModel> ratingService = <RatingModel>[].obs;
|
||||
final RxList<FavouriteOndemandServiceModel> lstFav = <FavouriteOndemandServiceModel>[].obs;
|
||||
final RxBool isLoading = true.obs;
|
||||
final RxBool isOpen = false.obs;
|
||||
final RxString tabString = "About".obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
provider = Get.arguments['providerModel'];
|
||||
timeCheck();
|
||||
getData();
|
||||
}
|
||||
|
||||
|
||||
Future<void> getData() async {
|
||||
await getReviewList();
|
||||
await getAuthor(); //fetch and set provider author here
|
||||
if (Constant.userModel != null) {
|
||||
lstFav.value = await FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getReviewList() async {
|
||||
await FireStoreUtils.getCategoryById(provider.categoryId.toString()).then((value) {
|
||||
if (value != null) {
|
||||
categoryTitle.value = value.title.toString();
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getSubCategoryById(provider.subCategoryId.toString()).then((value) {
|
||||
if (value != null) {
|
||||
subCategoryTitle.value = value.title.toString();
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getReviewByProviderServiceId(provider.id.toString()).then((value) {
|
||||
ratingService.value = value;
|
||||
});
|
||||
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid()).then((value) {
|
||||
lstFav.value = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getAuthor() async {
|
||||
final authorId = provider.author?.toString();
|
||||
if (authorId != null && authorId.isNotEmpty) {
|
||||
final user = await FireStoreUtils.getUserProfile(authorId);
|
||||
if (user != null) {
|
||||
userModel.value = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void timeCheck() {
|
||||
final now = DateTime.now();
|
||||
final day = DateFormat('EEEE', 'en_US').format(now);
|
||||
final date = DateFormat('dd-MM-yyyy').format(now);
|
||||
|
||||
for (var element in provider.days) {
|
||||
if (day == element.toString()) {
|
||||
final start = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${provider.startTime}");
|
||||
final end = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${provider.endTime}");
|
||||
if (isCurrentDateInRange(start, end)) {
|
||||
isOpen.value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
|
||||
final currentDate = DateTime.now();
|
||||
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
|
||||
}
|
||||
|
||||
void changeTab(String tab) {
|
||||
tabString.value = tab;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
142
lib/controllers/on_demand_home_controller.dart
Normal file
142
lib/controllers/on_demand_home_controller.dart
Normal file
@@ -0,0 +1,142 @@
|
||||
import 'package:customer/models/banner_model.dart';
|
||||
import 'package:customer/models/category_model.dart';
|
||||
import 'package:customer/models/favorite_ondemand_service_model.dart';
|
||||
import 'package:customer/models/provider_serivce_model.dart';
|
||||
import 'package:customer/screen_ui/auth_screens/login_screen.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import '../constant/constant.dart';
|
||||
|
||||
class OnDemandHomeController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<BannerModel> bannerTopHome = <BannerModel>[].obs;
|
||||
RxList<CategoryModel> categories = <CategoryModel>[].obs;
|
||||
RxList<ProviderServiceModel> providerList = <ProviderServiceModel>[].obs;
|
||||
|
||||
/// Store last fetched category
|
||||
Rx<CategoryModel?> categoryModel = Rx<CategoryModel?>(null);
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
isLoading.value = true;
|
||||
await getZone();
|
||||
|
||||
// Fetch banners
|
||||
FireStoreUtils.getHomeTopBanner().then((value) {
|
||||
bannerTopHome.value = value;
|
||||
});
|
||||
|
||||
// Fetch categories
|
||||
FireStoreUtils.getOnDemandCategory().then((catValue) {
|
||||
categories.value = catValue;
|
||||
});
|
||||
|
||||
// Fetch provider services
|
||||
FireStoreUtils.getProviderFuture()
|
||||
.then((providerServiceList) {
|
||||
Set<String?> uniqueAuthorIds = providerServiceList.map((service) => service.author).toSet();
|
||||
List<String?> listOfUniqueProviders = uniqueAuthorIds.toList();
|
||||
|
||||
List<ProviderServiceModel> filteredProviders = [];
|
||||
|
||||
for (var provider in listOfUniqueProviders) {
|
||||
List<ProviderServiceModel> filteredList = providerServiceList.where((service) => service.author == provider).toList();
|
||||
|
||||
filteredList.sort((a, b) => a.createdAt!.compareTo(b.createdAt!));
|
||||
|
||||
for (int index = 0; index < filteredList.length; index++) {
|
||||
final service = filteredList[index];
|
||||
|
||||
if (Constant.isSubscriptionModelApplied == true || Constant.sectionConstantModel?.adminCommision?.isEnabled == true) {
|
||||
if (service.subscriptionPlan?.itemLimit == "-1") {
|
||||
filteredProviders.add(service);
|
||||
} else {
|
||||
if (index < int.parse(service.subscriptionPlan?.itemLimit ?? '0')) {
|
||||
filteredProviders.add(service);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filteredProviders.add(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
providerList.value = filteredProviders;
|
||||
isLoading.value = false;
|
||||
})
|
||||
.catchError((e) {
|
||||
print("Provider error: $e");
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid()).then((favList) {
|
||||
lstFav.value = favList;
|
||||
});
|
||||
}
|
||||
|
||||
/// Get category by id safely from cached categories
|
||||
Future<CategoryModel?> getCategory(String? categoryId) async {
|
||||
if (categoryId == null || categoryId.isEmpty) return null;
|
||||
|
||||
// Try to find category from cached list
|
||||
CategoryModel? cat = categories.firstWhereOrNull((element) => element.id == categoryId);
|
||||
|
||||
// If not found, fetch from Firestore
|
||||
cat ??= await FireStoreUtils.getCategoryById(categoryId);
|
||||
|
||||
categoryModel.value = cat;
|
||||
return cat;
|
||||
}
|
||||
|
||||
RxList<FavouriteOndemandServiceModel> lstFav = <FavouriteOndemandServiceModel>[].obs;
|
||||
|
||||
void toggleFavourite(ProviderServiceModel provider) {
|
||||
if (Constant.userModel == null) {
|
||||
Get.to(LoginScreen());
|
||||
} else {
|
||||
var contain = lstFav.where((element) => element.service_id == provider.id);
|
||||
if (contain.isNotEmpty) {
|
||||
FavouriteOndemandServiceModel favouriteModel = FavouriteOndemandServiceModel(
|
||||
section_id: provider.sectionId,
|
||||
service_id: provider.id,
|
||||
user_id: FireStoreUtils.getCurrentUid(),
|
||||
serviceAuthorId: provider.author,
|
||||
);
|
||||
FireStoreUtils.removeFavouriteOndemandService(favouriteModel);
|
||||
lstFav.removeWhere((item) => item.service_id == provider.id);
|
||||
} else {
|
||||
FavouriteOndemandServiceModel favouriteModel = FavouriteOndemandServiceModel(
|
||||
section_id: provider.sectionId,
|
||||
service_id: provider.id,
|
||||
user_id: FireStoreUtils.getCurrentUid(),
|
||||
serviceAuthorId: provider.author,
|
||||
);
|
||||
FireStoreUtils.setFavouriteOndemandSection(favouriteModel);
|
||||
lstFav.add(favouriteModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getZone() async {
|
||||
await FireStoreUtils.getZone().then((value) {
|
||||
if (value != null) {
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
if (Constant.isPointInPolygon(LatLng(Constant.selectedLocation.location?.latitude ?? 0.0, Constant.selectedLocation.location?.longitude ?? 0.0), value[i].area!)) {
|
||||
Constant.selectedZone = value[i];
|
||||
Constant.isZoneAvailable = true;
|
||||
break;
|
||||
} else {
|
||||
Constant.selectedZone = value[i];
|
||||
Constant.isZoneAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
254
lib/controllers/on_demand_order_details_controller.dart
Normal file
254
lib/controllers/on_demand_order_details_controller.dart
Normal file
@@ -0,0 +1,254 @@
|
||||
import 'dart:developer';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../models/onprovider_order_model.dart';
|
||||
import '../models/wallet_transaction_model.dart';
|
||||
import '../models/worker_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../service/send_notification.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class OnDemandOrderDetailsController extends GetxController {
|
||||
Rx<UserModel?> providerUser = Rx<UserModel?>(null);
|
||||
Rxn<OnProviderOrderModel> onProviderOrder = Rxn<OnProviderOrderModel>();
|
||||
Rxn<WorkerModel> worker = Rxn<WorkerModel>();
|
||||
|
||||
Rx<TextEditingController> couponTextController = TextEditingController().obs;
|
||||
Rx<TextEditingController> cancelBookingController = TextEditingController().obs;
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble price = 0.0.obs;
|
||||
RxDouble discountAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
RxDouble quantity = 0.0.obs;
|
||||
|
||||
RxString discountType = "".obs;
|
||||
RxString discountLabel = "".obs;
|
||||
RxString offerCode = "".obs;
|
||||
|
||||
RxList<CouponModel> couponList = <CouponModel>[].obs;
|
||||
|
||||
final RxBool isLoading = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
final args = Get.arguments;
|
||||
if (args != null && args is OnProviderOrderModel) {
|
||||
onProviderOrder.value = args;
|
||||
}
|
||||
getData();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
try {
|
||||
final order = await FireStoreUtils.getProviderOrderById(onProviderOrder.value!.id);
|
||||
if (order != null) {
|
||||
onProviderOrder.value = order;
|
||||
|
||||
discountType.value = order.discountType ?? "";
|
||||
discountLabel.value = order.discountLabel ?? "";
|
||||
discountAmount.value = double.tryParse(order.discount.toString()) ?? 0.0;
|
||||
offerCode.value = order.couponCode ?? "";
|
||||
|
||||
// Fetch provider
|
||||
providerUser.value = await FireStoreUtils.getUserProfile(order.provider.author.toString());
|
||||
|
||||
// Fetch worker (if exists)
|
||||
if (order.workerId != null && order.workerId!.isNotEmpty) {
|
||||
worker.value = await FireStoreUtils.getWorker(order.workerId!);
|
||||
} else {
|
||||
worker.value = null;
|
||||
}
|
||||
|
||||
calculatePrice();
|
||||
|
||||
// Load available coupons
|
||||
FireStoreUtils.getProviderCouponAfterExpire(order.provider.author.toString()).then((expiredCoupons) {
|
||||
couponList.assignAll(expiredCoupons);
|
||||
});
|
||||
} else {
|
||||
onProviderOrder.value = null;
|
||||
providerUser.value = null;
|
||||
worker.value = null;
|
||||
couponList.clear();
|
||||
}
|
||||
} catch (e, st) {
|
||||
log("Error in getData: $e\n$st");
|
||||
onProviderOrder.value = null;
|
||||
providerUser.value = null;
|
||||
worker.value = null;
|
||||
couponList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void applyCoupon(CouponModel coupon) {
|
||||
double discount = 0.0;
|
||||
if (coupon.discountType == "Percentage" || coupon.discountType == "Percent") {
|
||||
discount = price.value * (double.tryParse(coupon.discount.toString()) ?? 0) / 100;
|
||||
} else {
|
||||
discount = double.tryParse(coupon.discount.toString()) ?? 0;
|
||||
}
|
||||
|
||||
if (subTotal.value > discount) {
|
||||
discountType.value = coupon.discountType ?? '';
|
||||
discountLabel.value = coupon.discount.toString();
|
||||
offerCode.value = coupon.code ?? '';
|
||||
calculatePrice();
|
||||
} else {
|
||||
Get.snackbar("Error", "Coupon cannot be applied");
|
||||
}
|
||||
}
|
||||
|
||||
void calculatePrice() {
|
||||
double basePrice =
|
||||
(onProviderOrder.value?.provider.disPrice == "" || onProviderOrder.value?.provider.disPrice == "0")
|
||||
? double.tryParse(onProviderOrder.value?.provider.price.toString() ?? "0") ?? 0
|
||||
: double.tryParse(onProviderOrder.value?.provider.disPrice.toString() ?? "0") ?? 0;
|
||||
|
||||
price.value = basePrice * (onProviderOrder.value?.quantity ?? 0.0);
|
||||
|
||||
// discount
|
||||
if (discountType.value == "Percentage" || discountType.value == "Percent") {
|
||||
discountAmount.value = price.value * (double.tryParse(discountLabel.value) ?? 0) / 100;
|
||||
} else {
|
||||
discountAmount.value = double.tryParse(discountLabel.value.isEmpty ? '0' : discountLabel.value) ?? 0;
|
||||
}
|
||||
|
||||
subTotal.value = price.value - discountAmount.value;
|
||||
|
||||
// tax calculation
|
||||
double total = subTotal.value;
|
||||
for (var element in Constant.taxList) {
|
||||
total += Constant.getTaxValue(amount: subTotal.value.toString(), taxModel: element);
|
||||
}
|
||||
|
||||
totalAmount.value = total;
|
||||
}
|
||||
|
||||
String getDate(String date) {
|
||||
try {
|
||||
DateTime dt = DateTime.parse(date);
|
||||
return "${dt.day}-${dt.month}-${dt.year}";
|
||||
} catch (e) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> cancelBooking() async {
|
||||
final order = onProviderOrder.value;
|
||||
if (order == null) return;
|
||||
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
|
||||
try {
|
||||
double total = 0.0;
|
||||
|
||||
// Calculate total
|
||||
final pricePerUnit =
|
||||
(order.provider.disPrice == "" || order.provider.disPrice == "0") ? double.tryParse(order.provider.price.toString()) ?? 0 : double.tryParse(order.provider.disPrice.toString()) ?? 0;
|
||||
|
||||
total = pricePerUnit * (order.quantity);
|
||||
|
||||
// Add tax
|
||||
if (Constant.taxList.isNotEmpty) {
|
||||
for (var tax in Constant.taxList) {
|
||||
total += Constant.getTaxValue(amount: total.toString(), taxModel: tax);
|
||||
}
|
||||
}
|
||||
|
||||
// Admin commission
|
||||
double adminComm = 0.0;
|
||||
if ((order.adminCommission ?? '0') != '0' && (order.adminCommissionType ?? '').isNotEmpty) {
|
||||
if (order.adminCommissionType!.toLowerCase() == 'percentage' || order.adminCommissionType!.toLowerCase() == 'percent') {
|
||||
adminComm = (total * (double.tryParse(order.adminCommission!) ?? 0)) / 100;
|
||||
} else {
|
||||
adminComm = double.tryParse(order.adminCommission!) ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Refund customer wallet if not COD
|
||||
if ((order.payment_method).toLowerCase() != 'cod') {
|
||||
await FireStoreUtils.setWalletTransaction(
|
||||
WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
serviceType: 'ondemand-service',
|
||||
amount: total,
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: 'wallet',
|
||||
transactionUser: 'customer',
|
||||
userId: Constant.userModel?.id,
|
||||
isTopup: true,
|
||||
orderId: order.id,
|
||||
note: 'Booking Amount Refund',
|
||||
paymentStatus: "success".tr,
|
||||
),
|
||||
);
|
||||
|
||||
// Deduct from provider if accepted
|
||||
if (order.status == Constant.orderAccepted) {
|
||||
await FireStoreUtils.setWalletTransaction(
|
||||
WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
serviceType: 'ondemand-service',
|
||||
amount: total,
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: 'wallet',
|
||||
transactionUser: 'provider',
|
||||
userId: order.provider.author ?? '',
|
||||
isTopup: false,
|
||||
orderId: order.id,
|
||||
note: 'Booking Amount Refund',
|
||||
paymentStatus: "success".tr,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Refund admin commission
|
||||
if (order.status == Constant.orderAccepted && adminComm > 0) {
|
||||
await FireStoreUtils.setWalletTransaction(
|
||||
WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
serviceType: 'ondemand-service',
|
||||
amount: adminComm,
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: 'wallet',
|
||||
transactionUser: 'provider',
|
||||
userId: order.provider.author ?? '',
|
||||
isTopup: true,
|
||||
orderId: order.id,
|
||||
note: 'Admin commission refund',
|
||||
paymentStatus: "success".tr,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Update order status & reason
|
||||
order.status = Constant.orderCancelled;
|
||||
order.reason = cancelBookingController.value.text;
|
||||
|
||||
await FireStoreUtils.updateOnDemandOrder(order); // Ensure this completes
|
||||
|
||||
// Notify provider
|
||||
final provider = await FireStoreUtils.getUserProfile(order.provider.author ?? '');
|
||||
if (provider != null) {
|
||||
Map<String, dynamic> payload = {"type": 'provider_order', "orderId": order.id};
|
||||
await SendNotification.sendFcmMessage(Constant.bookingPlaced, provider.fcmToken ?? '', payload);
|
||||
}
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Booking cancelled successfully".tr);
|
||||
} catch (e, st) {
|
||||
log("Cancel error: $e\n$st");
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Something went wrong".tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
169
lib/controllers/on_demand_review_controller.dart
Normal file
169
lib/controllers/on_demand_review_controller.dart
Normal file
@@ -0,0 +1,169 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../constant/collection_name.dart';
|
||||
import '../models/onprovider_order_model.dart';
|
||||
import '../models/provider_serivce_model.dart';
|
||||
import '../models/rating_model.dart';
|
||||
import '../models/worker_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class OnDemandReviewController extends GetxController {
|
||||
final Rxn<OnProviderOrderModel> order = Rxn<OnProviderOrderModel>();
|
||||
final RxString reviewFor = "".obs;
|
||||
final Rxn<RatingModel> ratingModel = Rxn<RatingModel>();
|
||||
final RxDouble ratings = 0.0.obs;
|
||||
final TextEditingController comment = TextEditingController();
|
||||
|
||||
final Rxn<UserModel> provider = Rxn<UserModel>();
|
||||
final Rxn<ProviderServiceModel> providerServiceModel = Rxn<ProviderServiceModel>();
|
||||
final Rxn<WorkerModel> workerModel = Rxn<WorkerModel>();
|
||||
|
||||
final RxInt providerReviewCount = 0.obs;
|
||||
final RxDouble providerReviewSum = 0.0.obs;
|
||||
final RxInt serviceReviewCount = 0.obs;
|
||||
final RxDouble serviceReviewSum = 0.0.obs;
|
||||
final RxInt workerReviewCount = 0.obs;
|
||||
final RxDouble workerReviewSum = 0.0.obs;
|
||||
|
||||
final FirebaseFirestore firestore = FirebaseFirestore.instance;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
final args = Get.arguments;
|
||||
if (args != null) {
|
||||
order.value = args['order'];
|
||||
reviewFor.value = args['reviewFor'];
|
||||
getReview();
|
||||
}
|
||||
}
|
||||
|
||||
void getReview() async {
|
||||
// Get existing rating
|
||||
if (reviewFor.value == "Provider") {
|
||||
RatingModel? value = await FireStoreUtils.getReviewsByProviderID(order.value!.id, order.value!.provider.author.toString());
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
ratings.value = value.rating ?? 0.0;
|
||||
comment.text = value.comment ?? '';
|
||||
}
|
||||
} else {
|
||||
RatingModel? value = await FireStoreUtils.getReviewsByWorkerID(order.value!.id, order.value!.workerId.toString());
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
ratings.value = value.rating ?? 0.0;
|
||||
comment.text = value.comment ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
// Worker review logic
|
||||
if (reviewFor.value == "Worker") {
|
||||
WorkerModel? value = await FireStoreUtils.getWorker(order.value!.workerId.toString());
|
||||
if (value != null) {
|
||||
workerModel.value = value;
|
||||
|
||||
final int existingCount = (value.reviewsCount ?? 0).toInt();
|
||||
final double existingSum = (value.reviewsSum ?? 0.0).toDouble();
|
||||
final double oldRating = ratingModel.value?.rating ?? 0.0;
|
||||
|
||||
workerReviewCount.value = ratingModel.value != null ? (existingCount - 1) : existingCount;
|
||||
workerReviewSum.value = ratingModel.value != null ? (existingSum - oldRating) : existingSum;
|
||||
}
|
||||
}
|
||||
// Provider & service review logic
|
||||
else {
|
||||
UserModel? user = await FireStoreUtils.getUserProfile(order.value!.provider.author.toString());
|
||||
if (user != null) {
|
||||
provider.value = user;
|
||||
|
||||
final int existingCount = int.tryParse(user.reviewsCount?.toString() ?? '0') ?? 0;
|
||||
final double existingSum = double.tryParse(user.reviewsSum?.toString() ?? '0.0') ?? 0.0;
|
||||
final double oldRating = ratingModel.value?.rating ?? 0.0;
|
||||
|
||||
providerReviewCount.value = ratingModel.value != null ? (existingCount - 1) : existingCount;
|
||||
providerReviewSum.value = ratingModel.value != null ? (existingSum - oldRating) : existingSum;
|
||||
}
|
||||
|
||||
ProviderServiceModel? service = await FireStoreUtils.getCurrentProvider(order.value!.provider.id.toString());
|
||||
if (service != null) {
|
||||
providerServiceModel.value = service;
|
||||
|
||||
final int existingCount = (service.reviewsCount ?? 0).toInt();
|
||||
final double existingSum = (service.reviewsSum ?? 0.0).toDouble();
|
||||
final double oldRating = ratingModel.value?.rating ?? 0.0;
|
||||
|
||||
serviceReviewCount.value = ratingModel.value != null ? (existingCount - 1) : existingCount;
|
||||
serviceReviewSum.value = ratingModel.value != null ? (existingSum - oldRating) : existingSum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void submitReview() async {
|
||||
if (reviewFor.value == "Provider") {
|
||||
await _providerReviewSubmit();
|
||||
} else {
|
||||
await _workerReviewSubmit();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _providerReviewSubmit() async {
|
||||
ShowToastDialog.showLoader("Submit in...".tr);
|
||||
providerServiceModel.value!.reviewsCount = serviceReviewCount.value + 1;
|
||||
providerServiceModel.value!.reviewsSum = serviceReviewSum.value + ratings.value;
|
||||
|
||||
// Convert to string only if your model field is String
|
||||
provider.value!.reviewsCount = (providerReviewCount.value + 1).toString();
|
||||
provider.value!.reviewsSum = (providerReviewSum.value + ratings.value).toString();
|
||||
|
||||
RatingModel rate = RatingModel(
|
||||
id: ratingModel.value?.id ?? firestore.collection(CollectionName.itemsReview).doc().id,
|
||||
productId: ratingModel.value?.productId ?? order.value!.provider.id,
|
||||
comment: comment.text,
|
||||
photos: ratingModel.value?.photos ?? [],
|
||||
rating: ratings.value,
|
||||
orderId: ratingModel.value?.orderId ?? order.value!.id,
|
||||
vendorId: ratingModel.value?.vendorId ?? order.value!.provider.author.toString(),
|
||||
customerId: Constant.userModel?.id,
|
||||
uname: '${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}',
|
||||
profile: Constant.userModel?.profilePictureURL,
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
await FireStoreUtils.updateReviewById(rate);
|
||||
await FireStoreUtils.updateUser(provider.value!);
|
||||
await FireStoreUtils.updateProvider(providerServiceModel.value!);
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.back(result: true);
|
||||
}
|
||||
|
||||
Future<void> _workerReviewSubmit() async {
|
||||
ShowToastDialog.showLoader("Submit in...".tr);
|
||||
workerModel.value!.reviewsCount = workerReviewCount.value + 1;
|
||||
workerModel.value!.reviewsSum = workerReviewSum.value + ratings.value;
|
||||
|
||||
RatingModel rate = RatingModel(
|
||||
id: ratingModel.value?.id ?? firestore.collection(CollectionName.itemsReview).doc().id,
|
||||
productId: ratingModel.value?.productId ?? order.value!.provider.id,
|
||||
comment: comment.text,
|
||||
photos: ratingModel.value?.photos ?? [],
|
||||
rating: ratings.value,
|
||||
orderId: ratingModel.value?.orderId ?? order.value!.id,
|
||||
driverId: ratingModel.value?.driverId ?? order.value!.workerId.toString(),
|
||||
customerId: Constant.userModel?.id,
|
||||
uname: '${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}',
|
||||
profile: Constant.userModel?.profilePictureURL,
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
await FireStoreUtils.updateReviewById(rate);
|
||||
await FireStoreUtils.updateWorker(workerModel.value!);
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.back(result: true);
|
||||
}
|
||||
}
|
||||
51
lib/controllers/order_controller.dart
Normal file
51
lib/controllers/order_controller.dart
Normal file
@@ -0,0 +1,51 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/cart_product_model.dart';
|
||||
import 'package:customer/models/order_model.dart';
|
||||
import '../service/cart_provider.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class OrderController extends GetxController {
|
||||
RxList<OrderModel> allList = <OrderModel>[].obs;
|
||||
RxList<OrderModel> inProgressList = <OrderModel>[].obs;
|
||||
RxList<OrderModel> deliveredList = <OrderModel>[].obs;
|
||||
RxList<OrderModel> rejectedList = <OrderModel>[].obs;
|
||||
RxList<OrderModel> cancelledList = <OrderModel>[].obs;
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getOrder();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getOrder() async {
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getAllOrder().then((value) {
|
||||
allList.value = value;
|
||||
|
||||
rejectedList.value = allList.where((p0) => p0.status == Constant.orderRejected).toList();
|
||||
inProgressList.value =
|
||||
allList
|
||||
.where(
|
||||
(p0) => p0.status == Constant.orderAccepted || p0.status == Constant.driverPending || p0.status == Constant.orderShipped || p0.status == Constant.orderInTransit,
|
||||
)
|
||||
.toList();
|
||||
|
||||
deliveredList.value = allList.where((p0) => p0.status == Constant.orderCompleted).toList();
|
||||
cancelledList.value = allList.where((p0) => p0.status == Constant.orderCancelled).toList();
|
||||
});
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
final CartProvider cartProvider = CartProvider();
|
||||
|
||||
void addToCart({required CartProductModel cartProductModel}) {
|
||||
cartProvider.addToCart(Get.context!, cartProductModel, cartProductModel.quantity!);
|
||||
update();
|
||||
}
|
||||
}
|
||||
77
lib/controllers/order_details_controller.dart
Normal file
77
lib/controllers/order_details_controller.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/cart_product_model.dart';
|
||||
import 'package:customer/models/order_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../service/cart_provider.dart';
|
||||
|
||||
class OrderDetailsController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Rx<OrderModel> orderModel = OrderModel().obs;
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
orderModel.value = argumentData['orderModel'];
|
||||
}
|
||||
calculatePrice();
|
||||
update();
|
||||
}
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble specialDiscountAmount = 0.0.obs;
|
||||
RxDouble taxAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
|
||||
Future<void> calculatePrice() async {
|
||||
subTotal.value = 0.0;
|
||||
specialDiscountAmount.value = 0.0;
|
||||
taxAmount.value = 0.0;
|
||||
totalAmount.value = 0.0;
|
||||
|
||||
for (var element in orderModel.value.products!) {
|
||||
if (double.parse(element.discountPrice.toString()) <= 0) {
|
||||
subTotal.value = subTotal.value +
|
||||
double.parse(element.price.toString()) * double.parse(element.quantity.toString()) +
|
||||
(double.parse(element.extrasPrice.toString()) * double.parse(element.quantity.toString()));
|
||||
} else {
|
||||
subTotal.value = subTotal.value +
|
||||
double.parse(element.discountPrice.toString()) * double.parse(element.quantity.toString()) +
|
||||
(double.parse(element.extrasPrice.toString()) * double.parse(element.quantity.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
if (orderModel.value.specialDiscount != null && orderModel.value.specialDiscount!['special_discount'] != null) {
|
||||
specialDiscountAmount.value = double.parse(orderModel.value.specialDiscount!['special_discount'].toString());
|
||||
}
|
||||
|
||||
if (orderModel.value.taxSetting != null) {
|
||||
for (var element in orderModel.value.taxSetting!) {
|
||||
taxAmount.value = taxAmount.value +
|
||||
Constant.calculateTax(amount: (subTotal.value - double.parse(orderModel.value.discount.toString()) - specialDiscountAmount.value).toString(), taxModel: element);
|
||||
}
|
||||
}
|
||||
|
||||
totalAmount.value = (subTotal.value - double.parse(orderModel.value.discount.toString()) - specialDiscountAmount.value) +
|
||||
taxAmount.value +
|
||||
double.parse(orderModel.value.deliveryCharge.toString()) +
|
||||
double.parse(orderModel.value.tipAmount.toString());
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
final CartProvider cartProvider = CartProvider();
|
||||
|
||||
void addToCart({required CartProductModel cartProductModel}) {
|
||||
cartProvider.addToCart(Get.context!, cartProductModel, cartProductModel.quantity!);
|
||||
update();
|
||||
}
|
||||
}
|
||||
43
lib/controllers/order_placing_controller.dart
Normal file
43
lib/controllers/order_placing_controller.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'dart:async';
|
||||
import 'package:customer/models/order_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../service/database_helper.dart';
|
||||
|
||||
class OrderPlacingController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
startTimer();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Rx<OrderModel> orderModel = OrderModel().obs;
|
||||
|
||||
Future<void> getArgument() async {
|
||||
DatabaseHelper.instance.deleteAllCartProducts();
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
orderModel.value = argumentData['orderModel'];
|
||||
}
|
||||
isLoading.value = false;
|
||||
update();
|
||||
}
|
||||
|
||||
Timer? timer;
|
||||
RxInt counter = 0.obs;
|
||||
|
||||
RxBool isPlacing = false.obs;
|
||||
|
||||
void startTimer() {
|
||||
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (counter.value == 3) {
|
||||
timer.cancel();
|
||||
isPlacing.value = true;
|
||||
}
|
||||
counter++;
|
||||
});
|
||||
}
|
||||
}
|
||||
36
lib/controllers/osm_search_place_controller.dart
Normal file
36
lib/controllers/osm_search_place_controller.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'dart:developer';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class OsmSearchPlaceController extends GetxController {
|
||||
Rx<TextEditingController> searchTxtController = TextEditingController().obs;
|
||||
RxList<SearchInfo> suggestionsList = <SearchInfo>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
searchTxtController.value.addListener(() {
|
||||
_onChanged();
|
||||
});
|
||||
}
|
||||
|
||||
void _onChanged() {
|
||||
fetchAddress(searchTxtController.value.text);
|
||||
}
|
||||
|
||||
Future<void> fetchAddress(text) async {
|
||||
log(":: fetchAddress :: $text");
|
||||
try {
|
||||
String locale = 'en';
|
||||
SharedPreferences sp = await SharedPreferences.getInstance();
|
||||
if (sp.getString("languageCode") != null || sp.getString("languageCode")?.isNotEmpty == true) {
|
||||
locale = sp.getString("languageCode") ?? "en";
|
||||
}
|
||||
suggestionsList.value = await addressSuggestion(text, locale: locale);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
131
lib/controllers/otp_verification_controller.dart
Normal file
131
lib/controllers/otp_verification_controller.dart
Normal file
@@ -0,0 +1,131 @@
|
||||
import 'package:customer/screen_ui/location_enable_screens/location_permission_screen.dart';
|
||||
import 'package:customer/themes/show_toast_dialog.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../screen_ui/auth_screens/login_screen.dart';
|
||||
import '../screen_ui/auth_screens/sign_up_screen.dart';
|
||||
import '../screen_ui/service_home_screen/service_list_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../utils/notification_service.dart';
|
||||
|
||||
class OtpVerifyController extends GetxController {
|
||||
/// Use a normal controller (NOT obs)
|
||||
final Rx<TextEditingController> otpController = TextEditingController().obs;
|
||||
|
||||
/// Reactive Strings
|
||||
final RxString countryCode = "".obs;
|
||||
final RxString phoneNumber = "".obs;
|
||||
final RxString verificationId = "".obs;
|
||||
RxInt resendToken = 0.obs;
|
||||
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
final args = Get.arguments ?? {};
|
||||
|
||||
countryCode.value = args['countryCode'] ?? "";
|
||||
phoneNumber.value = args['phoneNumber'] ?? "";
|
||||
verificationId.value = args['verificationId'] ?? "";
|
||||
}
|
||||
|
||||
Future<bool> sendOTP() async {
|
||||
await FirebaseAuth.instance.verifyPhoneNumber(
|
||||
phoneNumber: countryCode.value + phoneNumber.value,
|
||||
verificationCompleted: (PhoneAuthCredential credential) {},
|
||||
verificationFailed: (FirebaseAuthException e) {},
|
||||
codeSent: (String verificationId0, int? resendToken0) async {
|
||||
verificationId.value = verificationId0;
|
||||
resendToken.value = resendToken0!;
|
||||
ShowToastDialog.showToast("OTP sent".tr);
|
||||
},
|
||||
timeout: const Duration(seconds: 25),
|
||||
forceResendingToken: resendToken.value,
|
||||
codeAutoRetrievalTimeout: (String verificationId0) {
|
||||
verificationId0 = verificationId.value;
|
||||
},
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
void verifyOtp() async {
|
||||
if (otpController.value.text.length != 6) {
|
||||
ShowToastDialog.showToast("Enter valid 6-digit OTP".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ShowToastDialog.showLoader("Verifying OTP...".tr);
|
||||
|
||||
final credential = PhoneAuthProvider.credential(verificationId: verificationId.value, smsCode: otpController.value.text.trim());
|
||||
|
||||
final fcmToken = await NotificationService.getToken();
|
||||
final result = await _auth.signInWithCredential(credential);
|
||||
|
||||
if (result.additionalUserInfo?.isNewUser == true) {
|
||||
final userModel = UserModel(id: result.user!.uid, countryCode: countryCode.value, phoneNumber: phoneNumber.value, fcmToken: fcmToken, active: true);
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.to(() => const SignUpScreen(), arguments: {'type': 'mobileNumber', 'userModel': userModel});
|
||||
return;
|
||||
}
|
||||
|
||||
final exists = await FireStoreUtils.userExistOrNot(result.user!.uid);
|
||||
ShowToastDialog.closeLoader();
|
||||
|
||||
if (!exists) {
|
||||
final userModel = UserModel(id: result.user!.uid, countryCode: countryCode.value, phoneNumber: phoneNumber.value, fcmToken: fcmToken);
|
||||
Get.off(() => const SignUpScreen(), arguments: {'type': 'mobileNumber', 'userModel': userModel});
|
||||
return;
|
||||
}
|
||||
|
||||
final userModel = await FireStoreUtils.getUserProfile(result.user!.uid);
|
||||
if (userModel == null || userModel.role != 'customer') {
|
||||
await _auth.signOut();
|
||||
Get.offAll(() => const LoginScreen());
|
||||
return;
|
||||
}
|
||||
|
||||
if (userModel.active == false) {
|
||||
ShowToastDialog.showToast("This user is disabled".tr);
|
||||
await _auth.signOut();
|
||||
Get.offAll(() => const LoginScreen());
|
||||
return;
|
||||
}
|
||||
|
||||
userModel.fcmToken = fcmToken;
|
||||
await FireStoreUtils.updateUser(userModel);
|
||||
|
||||
if (userModel.shippingAddress?.isNotEmpty ?? false) {
|
||||
final defaultAddress = userModel.shippingAddress!.firstWhere((e) => e.isDefault == true, orElse: () => userModel.shippingAddress!.first);
|
||||
Constant.selectedLocation = defaultAddress;
|
||||
|
||||
Get.offAll(() => const ServiceListScreen());
|
||||
} else {
|
||||
Get.offAll(() => const LocationPermissionScreen());
|
||||
}
|
||||
} catch (e) {
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Invalid OTP or Verification Failed".tr);
|
||||
}
|
||||
}
|
||||
|
||||
String maskPhoneNumber(String phone) {
|
||||
if (phone.length < 4) return phone;
|
||||
|
||||
final first = phone.substring(0, 2);
|
||||
final last = phone.substring(phone.length - 2);
|
||||
return "$first*** ***$last";
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
otpController.value.dispose();
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
29
lib/controllers/parcel_coupon_controller.dart
Normal file
29
lib/controllers/parcel_coupon_controller.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ParcelCouponController extends GetxController{
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
|
||||
void getData(){
|
||||
getCouponCode();
|
||||
}
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<CouponModel> cabCouponList = <CouponModel>[].obs;
|
||||
|
||||
Future<void> getCouponCode() async {
|
||||
await FireStoreUtils.getParcelCoupon().then((value) {
|
||||
cabCouponList.value = value;
|
||||
// Handle the retrieved coupon code
|
||||
});
|
||||
print("cabCouponList ${cabCouponList.length}");
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
35
lib/controllers/parcel_dashboard_controller.dart
Normal file
35
lib/controllers/parcel_dashboard_controller.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/profile_screen/profile_screen.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import 'package:customer/screen_ui/parcel_service/home_parcel_screen.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../screen_ui/parcel_service/my_booking_screen.dart';
|
||||
|
||||
class ParcelDashboardController extends GetxController {
|
||||
RxInt selectedIndex = 0.obs;
|
||||
|
||||
RxList pageList = [].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getTaxList();
|
||||
if (Constant.walletSetting == false) {
|
||||
pageList.value = [const HomeParcelScreen(), const MyBookingScreen(), const ProfileScreen()];
|
||||
} else {
|
||||
pageList.value = [const HomeParcelScreen(), const MyBookingScreen(), const WalletScreen(), const ProfileScreen()];
|
||||
}
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getTaxList() async {
|
||||
await FireStoreUtils.getTaxList(Constant.sectionConstantModel!.id).then((value) {
|
||||
if (value != null) {
|
||||
Constant.taxList = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DateTime? currentBackPressTime;
|
||||
RxBool canPopNow = false.obs;
|
||||
}
|
||||
140
lib/controllers/parcel_my_booking_controller.dart
Normal file
140
lib/controllers/parcel_my_booking_controller.dart
Normal file
@@ -0,0 +1,140 @@
|
||||
import 'dart:async';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../models/parcel_order_model.dart';
|
||||
import '../models/wallet_transaction_model.dart';
|
||||
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class ParcelMyBookingController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<ParcelOrderModel> parcelOrder = <ParcelOrderModel>[].obs;
|
||||
|
||||
RxString selectedTab = "New".obs;
|
||||
RxList<String> tabTitles = ["New", "In Transit", "Delivered", "Cancelled"].obs;
|
||||
|
||||
StreamSubscription<List<ParcelOrderModel>>? _parcelSubscription;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
listenParcelOrders();
|
||||
}
|
||||
|
||||
void selectTab(String tab) {
|
||||
selectedTab.value = tab;
|
||||
}
|
||||
|
||||
/// Start listening to orders live. Cancel previous subscription first.
|
||||
void listenParcelOrders() {
|
||||
isLoading.value = true;
|
||||
if (Constant.userModel == null) {
|
||||
isLoading.value = false;
|
||||
return;
|
||||
}
|
||||
_parcelSubscription?.cancel();
|
||||
_parcelSubscription = FireStoreUtils.listenParcelOrders().listen(
|
||||
(orders) {
|
||||
parcelOrder.assignAll(orders);
|
||||
isLoading.value = false;
|
||||
},
|
||||
onError: (err) {
|
||||
isLoading.value = false;
|
||||
// optionally handle error
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Return filtered list for a specific tab title
|
||||
List<ParcelOrderModel> getOrdersForTab(String tab) {
|
||||
switch (tab) {
|
||||
case "New":
|
||||
return parcelOrder.where((order) => ["Order Placed"].contains(order.status)).toList();
|
||||
|
||||
case "In Transit":
|
||||
return parcelOrder.where((order) => ["Order Accepted", "Driver Accepted", "Driver Pending", "Order Shipped", "In Transit"].contains(order.status)).toList();
|
||||
|
||||
case "Delivered":
|
||||
return parcelOrder.where((order) => ["Order Completed"].contains(order.status)).toList();
|
||||
|
||||
case "Cancelled":
|
||||
return parcelOrder.where((order) => ["Order Rejected", "Order Cancelled", "Driver Rejected"].contains(order.status)).toList();
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// Old helper (optional)
|
||||
List<ParcelOrderModel> get filteredParcelOrders => getOrdersForTab(selectedTab.value);
|
||||
|
||||
String formatDate(Timestamp timestamp) {
|
||||
final dateTime = timestamp.toDate();
|
||||
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
|
||||
}
|
||||
|
||||
Future<void> cancelParcelOrder(ParcelOrderModel order) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
|
||||
if (order.status != Constant.orderPlaced) {
|
||||
ShowToastDialog.showToast("You can only cancel before pickup.".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
order.status = Constant.orderCancelled;
|
||||
await FireStoreUtils.parcelOrderPlace(order);
|
||||
|
||||
listenParcelOrders();
|
||||
|
||||
if (order.paymentMethod?.toLowerCase() != "cod") {
|
||||
double totalTax = 0.0;
|
||||
|
||||
final taxSettings = order.taxSetting ?? [];
|
||||
|
||||
for (var element in taxSettings) {
|
||||
totalTax += Constant.calculateTax(amount: (double.parse(order.subTotal.toString()) - double.parse(order.discount.toString())).toString(), taxModel: element);
|
||||
}
|
||||
|
||||
double subTotal = double.parse(order.subTotal.toString()) - double.parse(order.discount.toString());
|
||||
double refundAmount = subTotal + totalTax;
|
||||
|
||||
WalletTransactionModel walletTransaction = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: refundAmount,
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: true,
|
||||
// refund
|
||||
orderId: order.id,
|
||||
note: "Refund for cancelled parcel order",
|
||||
paymentStatus: "success",
|
||||
serviceType: Constant.parcelServiceType,
|
||||
);
|
||||
|
||||
// Save wallet transaction
|
||||
await FireStoreUtils.setWalletTransaction(walletTransaction);
|
||||
|
||||
// Update wallet balance
|
||||
await FireStoreUtils.updateUserWallet(amount: refundAmount.toString(), userId: FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
|
||||
ShowToastDialog.showToast("Order cancelled successfully".tr);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("${'Failed to cancel order:'.tr} $e".tr);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_parcelSubscription?.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
983
lib/controllers/parcel_order_confirmation_controller.dart
Normal file
983
lib/controllers/parcel_order_confirmation_controller.dart
Normal file
@@ -0,0 +1,983 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as maths;
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/models/wallet_transaction_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_paypal/flutter_paypal.dart';
|
||||
import 'package:flutter_stripe/flutter_stripe.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import '../../../models/parcel_order_model.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../models/payment_model/cod_setting_model.dart';
|
||||
import '../models/payment_model/flutter_wave_model.dart';
|
||||
import '../models/payment_model/mercado_pago_model.dart';
|
||||
import '../models/payment_model/mid_trans.dart';
|
||||
import '../models/payment_model/orange_money.dart';
|
||||
import '../models/payment_model/pay_fast_model.dart';
|
||||
import '../models/payment_model/pay_stack_model.dart';
|
||||
import '../models/payment_model/paypal_model.dart';
|
||||
import '../models/payment_model/paytm_model.dart';
|
||||
import '../models/payment_model/razorpay_model.dart';
|
||||
import '../models/payment_model/stripe_model.dart';
|
||||
import '../models/payment_model/wallet_setting_model.dart';
|
||||
import '../models/payment_model/xendit.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../payment/MercadoPagoScreen.dart';
|
||||
import '../payment/PayFastScreen.dart';
|
||||
import '../payment/getPaytmTxtToken.dart';
|
||||
import '../payment/midtrans_screen.dart';
|
||||
import '../payment/orangePayScreen.dart';
|
||||
import '../payment/paystack/pay_stack_screen.dart';
|
||||
import '../payment/paystack/pay_stack_url_model.dart';
|
||||
import '../payment/paystack/paystack_url_genrater.dart';
|
||||
import '../payment/stripe_failed_model.dart';
|
||||
import '../payment/xenditModel.dart';
|
||||
import '../payment/xenditScreen.dart';
|
||||
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import '../screen_ui/parcel_service/order_successfully_placed.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/app_them_data.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
import '../utils/preferences.dart';
|
||||
|
||||
class ParcelOrderConfirmationController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
final Rx<ParcelOrderModel> parcelOrder = ParcelOrderModel().obs;
|
||||
final RxList<XFile> images = <XFile>[].obs;
|
||||
final RxString paymentBy = "Receiver".obs;
|
||||
|
||||
RxString selectedPaymentMethod = ''.obs;
|
||||
RxBool isOrderPlaced = false.obs;
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble discount = 0.0.obs;
|
||||
RxDouble taxAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
|
||||
Rx<TextEditingController> couponController = TextEditingController().obs;
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
getArgument();
|
||||
}
|
||||
|
||||
Rx<CouponModel> selectedCouponModel = CouponModel().obs;
|
||||
|
||||
Future<void> getArgument() async {
|
||||
final dynamic args = Get.arguments;
|
||||
if (args != null) {
|
||||
parcelOrder.value = args['parcelOrder'];
|
||||
images.value = List<XFile>.from(args['images'] ?? []);
|
||||
calculatePrice();
|
||||
}
|
||||
|
||||
userModel.value = Constant.userModel!;
|
||||
await fetchCoupons();
|
||||
await getPaymentSettings();
|
||||
isLoading.value = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void calculatePrice() {
|
||||
subTotal.value = 0;
|
||||
discount.value = 0;
|
||||
taxAmount.value = 0;
|
||||
|
||||
subTotal.value = double.tryParse(parcelOrder.value.subTotal ?? '0') ?? 0.0;
|
||||
|
||||
if (selectedCouponModel.value.id != null) {
|
||||
discount.value = Constant.calculateDiscount(amount: subTotal.value.toString(), offerModel: selectedCouponModel.value);
|
||||
}
|
||||
|
||||
for (var element in Constant.taxList) {
|
||||
taxAmount.value = (taxAmount.value + Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element));
|
||||
}
|
||||
|
||||
print("Tax: ${taxAmount.value}");
|
||||
print("Discount: ${discount.value}");
|
||||
|
||||
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
|
||||
}
|
||||
|
||||
RxList<CouponModel> couponList = <CouponModel>[].obs;
|
||||
|
||||
Future<void> fetchCoupons() async {
|
||||
try {
|
||||
await FireStoreUtils.getParcelCoupon().then((value) {
|
||||
couponList.value = value;
|
||||
});
|
||||
} catch (e) {
|
||||
print("Error fetching coupons: $e");
|
||||
}
|
||||
}
|
||||
|
||||
String formatDate(Timestamp timestamp) {
|
||||
final dateTime = timestamp.toDate();
|
||||
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
|
||||
}
|
||||
|
||||
Future<void> placeOrder() async {
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
|
||||
try {
|
||||
List<String> parcelImages = [];
|
||||
if (images.isNotEmpty) {
|
||||
for (var image in images) {
|
||||
final upload = await FireStoreUtils.uploadChatImageToFireStorage(File(image.path), Get.context!);
|
||||
parcelImages.add(upload.url);
|
||||
}
|
||||
}
|
||||
|
||||
parcelOrder.value.parcelImages = parcelImages;
|
||||
parcelOrder.value.discount = discount.value.toString();
|
||||
parcelOrder.value.discountType = selectedCouponModel.value.discountType.toString();
|
||||
parcelOrder.value.discountLabel = selectedCouponModel.value.code.toString();
|
||||
parcelOrder.value.adminCommission = Constant.sectionConstantModel?.adminCommision?.amount?.toString();
|
||||
parcelOrder.value.adminCommissionType = Constant.sectionConstantModel?.adminCommision?.commissionType;
|
||||
parcelOrder.value.status = Constant.orderPlaced;
|
||||
parcelOrder.value.createdAt = Timestamp.now();
|
||||
parcelOrder.value.author = userModel.value;
|
||||
parcelOrder.value.authorID = FireStoreUtils.getCurrentUid();
|
||||
parcelOrder.value.paymentMethod = paymentBy.value == "Receiver" ? "cod" : selectedPaymentMethod.value;
|
||||
parcelOrder.value.paymentCollectByReceiver = paymentBy.value == "Receiver";
|
||||
parcelOrder.value.senderZoneId = Constant.getZoneId(parcelOrder.value.senderLatLong!.latitude ?? 0.0, parcelOrder.value.senderLatLong!.longitude ?? 0.0);
|
||||
parcelOrder.value.receiverZoneId = Constant.getZoneId(parcelOrder.value.receiverLatLong!.latitude ?? 0.0, parcelOrder.value.receiverLatLong!.longitude ?? 0.0);
|
||||
|
||||
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: double.parse(totalAmount.value.toString()),
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: false,
|
||||
orderId: parcelOrder.value.id,
|
||||
note: "Parcel Amount debited",
|
||||
paymentStatus: "success",
|
||||
serviceType: Constant.parcelServiceType,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
if (value == true) {
|
||||
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.value.toString()}", userId: FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
});
|
||||
}
|
||||
await FireStoreUtils.parcelOrderPlace(parcelOrder.value).then((value) async {
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Order placed successfully".tr);
|
||||
Get.offAll(() => OrderSuccessfullyPlaced(), arguments: {'parcelOrder': parcelOrder.value});
|
||||
await FireStoreUtils.sendParcelBookEmail(orderModel: parcelOrder.value);
|
||||
});
|
||||
} catch (e) {
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Something went wrong. Please try again.".tr);
|
||||
}
|
||||
}
|
||||
|
||||
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
|
||||
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
|
||||
Rx<PayFastModel> payFastModel = PayFastModel().obs;
|
||||
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
|
||||
Rx<PayPalModel> payPalModel = PayPalModel().obs;
|
||||
Rx<StripeModel> stripeModel = StripeModel().obs;
|
||||
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
|
||||
Rx<PayStackModel> payStackModel = PayStackModel().obs;
|
||||
Rx<PaytmModel> paytmModel = PaytmModel().obs;
|
||||
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
|
||||
|
||||
Rx<MidTrans> midTransModel = MidTrans().obs;
|
||||
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
|
||||
Rx<Xendit> xenditModel = Xendit().obs;
|
||||
|
||||
Future<void> getPaymentSettings() async {
|
||||
await FireStoreUtils.getPaymentSettingsData().then((value) {
|
||||
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
|
||||
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
|
||||
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
|
||||
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
|
||||
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
|
||||
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
|
||||
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
|
||||
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
|
||||
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
|
||||
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
|
||||
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
|
||||
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
|
||||
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
|
||||
|
||||
if (walletSettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.wallet.name;
|
||||
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.cod.name;
|
||||
} else if (stripeModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.stripe.name;
|
||||
} else if (payPalModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.paypal.name;
|
||||
} else if (payStackModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payStack.name;
|
||||
} else if (mercadoPagoModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
|
||||
} else if (flutterWaveModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
|
||||
} else if (payFastModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payFast.name;
|
||||
} else if (razorPayModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
|
||||
} else if (midTransModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
|
||||
} else if (orangeMoneyModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
|
||||
} else if (xenditModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.xendit.name;
|
||||
}
|
||||
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
|
||||
Stripe.merchantIdentifier = 'eMart Customer';
|
||||
Stripe.instance.applySettings();
|
||||
setRef();
|
||||
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
|
||||
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
|
||||
});
|
||||
}
|
||||
|
||||
// Strip
|
||||
Future<void> stripeMakePayment({required String amount}) async {
|
||||
log(double.parse(amount).toStringAsFixed(0));
|
||||
try {
|
||||
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
|
||||
log("stripe Responce====>$paymentIntentData");
|
||||
if (paymentIntentData!.containsKey("error")) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
} else {
|
||||
await Stripe.instance.initPaymentSheet(
|
||||
paymentSheetParameters: SetupPaymentSheetParameters(
|
||||
paymentIntentClientSecret: paymentIntentData['client_secret'],
|
||||
allowsDelayedPaymentMethods: false,
|
||||
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
|
||||
customFlow: true,
|
||||
style: ThemeMode.system,
|
||||
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
|
||||
merchantDisplayName: 'GoRide',
|
||||
),
|
||||
);
|
||||
displayStripePaymentSheet(amount: amount);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log("$e \n$s");
|
||||
ShowToastDialog.showToast("exception:$e \n$s");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> displayStripePaymentSheet({required String amount}) async {
|
||||
try {
|
||||
await Stripe.instance.presentPaymentSheet().then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
placeOrder();
|
||||
});
|
||||
} on StripeException catch (e) {
|
||||
var lo1 = jsonEncode(e);
|
||||
var lo2 = jsonDecode(lo1);
|
||||
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
|
||||
ShowToastDialog.showToast(lom.error.message);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future createStripeIntent({required String amount}) async {
|
||||
try {
|
||||
Map<String, dynamic> body = {
|
||||
'amount': ((double.parse(amount) * 100).round()).toString(),
|
||||
'currency': "USD",
|
||||
'payment_method_types[]': 'card',
|
||||
"description": "Strip Payment",
|
||||
"shipping[name]": Constant.userModel?.fullName(),
|
||||
"shipping[address][line1]": "510 Townsend St",
|
||||
"shipping[address][postal_code]": "98140",
|
||||
"shipping[address][city]": "San Francisco",
|
||||
"shipping[address][state]": "CA",
|
||||
"shipping[address][country]": "US",
|
||||
};
|
||||
var stripeSecret = stripeModel.value.stripeSecret;
|
||||
var response = await http.post(
|
||||
Uri.parse('https://api.stripe.com/v1/payment_intents'),
|
||||
body: body,
|
||||
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
);
|
||||
|
||||
return jsonDecode(response.body);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//mercadoo
|
||||
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
|
||||
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"items": [
|
||||
{
|
||||
"title": "Test",
|
||||
"description": "Test Payment",
|
||||
"quantity": 1,
|
||||
"currency_id": "BRL", // or your preferred currency
|
||||
"unit_price": double.parse(amount),
|
||||
},
|
||||
],
|
||||
"payer": {"email": Constant.userModel?.email},
|
||||
"back_urls": {"failure": "${Constant.globalUrl}payment/failure", "pending": "${Constant.globalUrl}payment/pending", "success": "${Constant.globalUrl}payment/success"},
|
||||
"auto_return": "approved",
|
||||
// Automatically return after payment is approved
|
||||
});
|
||||
|
||||
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Error creating preference: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Paypal
|
||||
void paypalPaymentSheet(String amount, BuildContext context) {
|
||||
// ✅ Ensure amount format is correct (e.g. 10.00)
|
||||
final formattedAmount = double.parse(amount).toStringAsFixed(2);
|
||||
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(BuildContext context) => UsePaypal(
|
||||
sandboxMode: payPalModel.value.isLive == true ? false : true,
|
||||
clientId: payPalModel.value.paypalClient ?? '',
|
||||
secretKey: payPalModel.value.paypalSecret ?? '',
|
||||
returnURL: "com.emart.customer://paypalpay",
|
||||
cancelURL: "com.emart.customer://paypalcancel",
|
||||
|
||||
transactions: [
|
||||
{
|
||||
"amount": {
|
||||
"total": formattedAmount,
|
||||
"currency": "USD",
|
||||
"details": {"subtotal": formattedAmount},
|
||||
},
|
||||
},
|
||||
],
|
||||
note: "Contact us for any questions on your order.",
|
||||
onSuccess: (Map params) async {
|
||||
debugPrint("✅ PayPal Payment Success: $params");
|
||||
placeOrder();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
},
|
||||
onError: (error) {
|
||||
debugPrint("❌ PayPal Payment Error: $error");
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
onCancel: (params) {
|
||||
debugPrint("⚠️ PayPal Payment Canceled: $params");
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// void paypalPaymentSheet(String amount, context) {
|
||||
// Navigator.of(context).push(
|
||||
// MaterialPageRoute(
|
||||
// builder:
|
||||
// (BuildContext context) => UsePaypal(
|
||||
// sandboxMode: payPalModel.value.isLive == true ? false : true,
|
||||
// clientId: payPalModel.value.paypalClient ?? '',
|
||||
// secretKey: payPalModel.value.paypalSecret ?? '',
|
||||
// returnURL: "https://success.emart.com/return",
|
||||
// cancelURL: "https://cancel.emart.com/cancel",
|
||||
// // returnURL: "com.emart.customer://paypalpay",
|
||||
// // cancelURL: "com.emart.customer://paypalpay",
|
||||
// transactions: [
|
||||
// {
|
||||
// "amount": {
|
||||
// "total": amount,
|
||||
// "currency": "USD",
|
||||
// "details": {"subtotal": amount},
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// note: "Contact us for any questions on your order.",
|
||||
// onSuccess: (Map params) async {
|
||||
// placeOrder();
|
||||
// ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
// },
|
||||
// onError: (error) {
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
// },
|
||||
// onCancel: (params) {
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
///PayStack Payment Method
|
||||
Future<void> payStackPayment(String totalAmount) async {
|
||||
// Convert to int (kobo/cents)
|
||||
int amountInCents = (double.parse(totalAmount) * 100).round();
|
||||
|
||||
await PayStackURLGen.payStackURLGen(
|
||||
amount: amountInCents.toString(), //integer string
|
||||
currency: "ZAR",
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
userModel: Constant.userModel!,
|
||||
).then((value) async {
|
||||
if (value != null) {
|
||||
PayStackUrlModel payStackModel0 = value;
|
||||
Get.to(
|
||||
PayStackScreen(
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
callBackUrl: payStackModel.value.callbackURL.toString(),
|
||||
initialURl: payStackModel0.data.authorizationUrl,
|
||||
amount: totalAmount,
|
||||
reference: payStackModel0.data.reference,
|
||||
),
|
||||
)!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///flutter wave Payment Method
|
||||
Future<void> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
|
||||
setRef(); // make sure you generate reference
|
||||
|
||||
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
|
||||
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"tx_ref": _ref,
|
||||
"amount": amount,
|
||||
"currency": "NGN",
|
||||
"redirect_url": "${Constant.globalUrl}payment/success",
|
||||
"payment_options": "ussd, card, barter, payattitude",
|
||||
"customer": {"email": Constant.userModel?.email.toString(), "phonenumber": Constant.userModel?.phoneNumber, "name": Constant.userModel?.fullName()},
|
||||
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
|
||||
});
|
||||
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
|
||||
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) async {
|
||||
bool isVerified = await verifyFlutterWavePayment(_ref!);
|
||||
|
||||
if (isVerified) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
Get.back();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
debugPrint('Payment initialization failed: ${response.body}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> verifyFlutterWavePayment(String txRef) async {
|
||||
try {
|
||||
final url = Uri.parse("https://api.flutterwave.com/v3/transactions/verify_by_reference?tx_ref=$txRef");
|
||||
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
|
||||
|
||||
final response = await http.get(url, headers: headers);
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
if (data['status'] == 'success' && data['data']['status'] == 'successful') {
|
||||
return true; // ✅ Payment confirmed
|
||||
}
|
||||
}
|
||||
return false; // ❌ Payment not verified
|
||||
} catch (e) {
|
||||
debugPrint("Error verifying payment: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String? _ref;
|
||||
|
||||
void setRef() {
|
||||
maths.Random numRef = maths.Random();
|
||||
int year = DateTime.now().year;
|
||||
int refNumber = numRef.nextInt(20000);
|
||||
if (Platform.isAndroid) {
|
||||
_ref = "AndroidRef$year$refNumber";
|
||||
} else if (Platform.isIOS) {
|
||||
_ref = "IOSRef$year$refNumber";
|
||||
}
|
||||
}
|
||||
|
||||
// payFast
|
||||
void payFastPayment({required BuildContext context, required String amount}) {
|
||||
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: Constant.userModel!).then((String? value) async {
|
||||
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
|
||||
if (isDone) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///Paytm payment function
|
||||
|
||||
Future<void> getPaytmCheckSum(context, {required double amount}) async {
|
||||
final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(getChecksum),
|
||||
headers: {},
|
||||
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString()},
|
||||
);
|
||||
|
||||
final data = jsonDecode(response.body);
|
||||
await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
|
||||
initiatePayment(amount: amount, orderId: orderId).then((value) {
|
||||
String callback = "";
|
||||
if (paytmModel.value.isSandboxEnabled == true) {
|
||||
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
} else {
|
||||
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
}
|
||||
|
||||
GetPaymentTxtTokenModel result = value;
|
||||
startTransaction(context, txnTokenBy: result.body.txnToken ?? '', orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> startTransaction(context, {required String txnTokenBy, required orderId, required double amount, required callBackURL, required isStaging}) async {
|
||||
// try {
|
||||
// var response = AllInOneSdk.startTransaction(
|
||||
// paytmModel.value.paytmMID.toString(),
|
||||
// orderId,
|
||||
// amount.toString(),
|
||||
// txnTokenBy,
|
||||
// callBackURL,
|
||||
// isStaging,
|
||||
// true,
|
||||
// true,
|
||||
// );
|
||||
//
|
||||
// response.then((value) {
|
||||
// if (value!["RESPMSG"] == "Txn Success") {
|
||||
// print("txt done!!");
|
||||
// ShowToastDialog.showToast("Payment Successful!!");
|
||||
// placeOrder();
|
||||
// }
|
||||
// }).catchError((onError) {
|
||||
// if (onError is PlatformException) {
|
||||
// Get.back();
|
||||
//
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// } else {
|
||||
// log("======>>2");
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// }
|
||||
// });
|
||||
// } catch (err) {
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(err.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
|
||||
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
|
||||
final response = await http.post(
|
||||
Uri.parse(getChecksum),
|
||||
headers: {},
|
||||
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(), "checksum_value": checkSum},
|
||||
);
|
||||
final data = jsonDecode(response.body);
|
||||
return data['status'];
|
||||
}
|
||||
|
||||
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required String orderId}) async {
|
||||
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
|
||||
|
||||
String callback =
|
||||
(paytmModel.value.isSandboxEnabled ?? false) ? "https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId" : "https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
|
||||
print("INITIATE PAYMENT CALL:");
|
||||
print("MID: ${paytmModel.value.paytmMID}");
|
||||
print("OrderId: $orderId");
|
||||
print("Amount: $amount");
|
||||
print("Env: ${(paytmModel.value.isSandboxEnabled ?? false) ? "STAGING" : "LIVE"}");
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(initiateURL),
|
||||
body: {
|
||||
"mid": paytmModel.value.paytmMID ?? "",
|
||||
"order_id": orderId,
|
||||
"key_secret": paytmModel.value.pAYTMMERCHANTKEY ?? "",
|
||||
"amount": amount.toStringAsFixed(0), // Paytm requires integer
|
||||
"currency": "INR",
|
||||
"callback_url": callback,
|
||||
"custId": FireStoreUtils.getCurrentUid(),
|
||||
"issandbox": (paytmModel.value.isSandboxEnabled ?? false) ? "1" : "0",
|
||||
},
|
||||
);
|
||||
|
||||
log("Paytm Initiate Response: ${response.body}");
|
||||
|
||||
final data = jsonDecode(response.body);
|
||||
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
}
|
||||
|
||||
return GetPaymentTxtTokenModel.fromJson(data);
|
||||
}
|
||||
|
||||
// Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
|
||||
// String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
|
||||
// String callback = "";
|
||||
// if (paytmModel.value.isSandboxEnabled == true) {
|
||||
// callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
// } else {
|
||||
// callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
// }
|
||||
// final response = await http.post(
|
||||
// Uri.parse(initiateURL),
|
||||
// headers: {},
|
||||
// body: {
|
||||
// "mid": paytmModel.value.paytmMID,
|
||||
// "order_id": orderId,
|
||||
// "key_secret": paytmModel.value.pAYTMMERCHANTKEY,
|
||||
// "amount": amount.toString(),
|
||||
// "currency": "INR",
|
||||
// "callback_url": callback,
|
||||
// "custId": FireStoreUtils.getCurrentUid(),
|
||||
// "issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
|
||||
// },
|
||||
// );
|
||||
// log(response.body);
|
||||
// final data = jsonDecode(response.body);
|
||||
// if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
// }
|
||||
// return GetPaymentTxtTokenModel.fromJson(data);
|
||||
// }
|
||||
|
||||
///RazorPay payment function
|
||||
final Razorpay razorPay = Razorpay();
|
||||
|
||||
void openCheckout({required amount, required orderId}) async {
|
||||
var options = {
|
||||
'key': razorPayModel.value.razorpayKey,
|
||||
'amount': amount * 100,
|
||||
'name': 'GoRide',
|
||||
'order_id': orderId,
|
||||
"currency": "INR",
|
||||
'description': 'wallet Topup',
|
||||
'retry': {'enabled': true, 'max_count': 1},
|
||||
'send_sms_hash': true,
|
||||
'prefill': {'contact': Constant.userModel?.phoneNumber, 'email': Constant.userModel?.email},
|
||||
'external': {
|
||||
'wallets': ['paytm'],
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
razorPay.open(options);
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void handlePaymentSuccess(PaymentSuccessResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
}
|
||||
|
||||
void handleExternalWaller(ExternalWalletResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Processing!! via".tr);
|
||||
}
|
||||
|
||||
void handlePaymentError(PaymentFailureResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed!!".tr);
|
||||
}
|
||||
|
||||
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
|
||||
final currentDate = DateTime.now();
|
||||
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
|
||||
}
|
||||
|
||||
//Midtrans payment
|
||||
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
|
||||
await createPaymentLink(amount: amount).then((url) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (url != '') {
|
||||
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> createPaymentLink({required var amount}) async {
|
||||
var ordersId = const Uuid().v1();
|
||||
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!)},
|
||||
body: jsonEncode({
|
||||
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
|
||||
'usage_limit': 2,
|
||||
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
String generateBasicAuthHeader(String apiKey) {
|
||||
String credentials = '$apiKey:';
|
||||
String base64Encoded = base64Encode(utf8.encode(credentials));
|
||||
return 'Basic $base64Encoded';
|
||||
}
|
||||
|
||||
// 🟠 ORANGE MONEY PAYMENT INTEGRATION
|
||||
static String accessToken = '';
|
||||
static String payToken = '';
|
||||
static String orderId = '';
|
||||
static String amount = '';
|
||||
|
||||
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
|
||||
reset();
|
||||
var id = const Uuid().v4();
|
||||
debugPrint('🟩 Starting OrangePay Payment...');
|
||||
debugPrint('💰 Amount: $amount | 🆔 Order ID: $id');
|
||||
|
||||
ShowToastDialog.showLoader("Initializing payment...".tr);
|
||||
|
||||
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
|
||||
if (paymentURL.toString().isNotEmpty) {
|
||||
debugPrint('✅ Payment URL fetched successfully: $paymentURL');
|
||||
|
||||
Get.to(() => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken))?.then((value) async {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
debugPrint('🎉 Payment Successful for Order ID: $orderId');
|
||||
|
||||
if (Get.isBottomSheetOpen ?? false) Get.back();
|
||||
await placeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
debugPrint('⚠️ Payment flow closed without success.');
|
||||
|
||||
if (Get.isBottomSheetOpen ?? false) Get.back();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
if (Get.isBottomSheetOpen ?? false) Get.back();
|
||||
}
|
||||
}
|
||||
|
||||
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
|
||||
const String apiUrl = 'https://api.orange.com/oauth/v3/token';
|
||||
final Map<String, String> requestBody = {'grant_type': 'client_credentials'};
|
||||
|
||||
debugPrint('🔐 Fetching access token from Orange API...');
|
||||
debugPrint('📡 POST $apiUrl');
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: {'Authorization': "Basic ${orangeMoneyModel.value.auth!}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
debugPrint('🔍 Response Code: ${response.statusCode}');
|
||||
debugPrint('📨 Response Body: ${response.body}');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
accessToken = responseData['access_token'];
|
||||
debugPrint('✅ Access Token Received: $accessToken');
|
||||
|
||||
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
|
||||
} else {
|
||||
debugPrint('❌ Failed to fetch access token.');
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
|
||||
orderId = orderIdData;
|
||||
amount = amountData;
|
||||
|
||||
String apiUrl = orangeMoneyModel.value.isSandbox == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
|
||||
|
||||
// ✅ Ensure amount formatted correctly
|
||||
String formattedAmount = double.parse(amountData).toStringAsFixed(2);
|
||||
|
||||
Map<String, String> requestBody = {
|
||||
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
|
||||
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
|
||||
"order_id": orderId,
|
||||
"amount": formattedAmount,
|
||||
"reference": 'Y-Note Test',
|
||||
"lang": "en",
|
||||
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
|
||||
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
|
||||
"notif_url": orangeMoneyModel.value.notifyUrl ?? '',
|
||||
};
|
||||
|
||||
debugPrint('💳 Creating Web Payment...');
|
||||
debugPrint('📡 POST $apiUrl');
|
||||
debugPrint('📦 Request Body: ${jsonEncode(requestBody)}');
|
||||
|
||||
final response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: {'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
body: json.encode(requestBody),
|
||||
);
|
||||
|
||||
debugPrint('🔍 Response Code: ${response.statusCode}');
|
||||
debugPrint('📨 Response Body: ${response.body}');
|
||||
|
||||
if (response.statusCode == 201) {
|
||||
final Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
if (responseData['message'] == 'OK') {
|
||||
payToken = responseData['pay_token'];
|
||||
debugPrint('✅ Payment Token: $payToken');
|
||||
debugPrint('🌍 Payment URL: ${responseData['payment_url']}');
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
debugPrint('⚠️ Unexpected message: ${responseData['message']}');
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
debugPrint('❌ Payment request failed.');
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
accessToken = '';
|
||||
payToken = '';
|
||||
orderId = '';
|
||||
amount = '';
|
||||
debugPrint('🌀 OrangePay reset completed.');
|
||||
}
|
||||
|
||||
//XenditPayment
|
||||
Future<void> xenditPayment(context, amount) async {
|
||||
await createXenditInvoice(amount: amount).then((model) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (model.id != null) {
|
||||
Get.to(() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
placeOrder();
|
||||
();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<XenditModel> createXenditInvoice({required var amount}) async {
|
||||
const url = 'https://api.xendit.co/v2/invoices';
|
||||
var headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
|
||||
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
|
||||
};
|
||||
|
||||
final body = jsonEncode({
|
||||
'external_id': const Uuid().v1(),
|
||||
'amount': amount,
|
||||
'payer_email': 'customer@domain.com',
|
||||
'description': 'Test - VA Successful invoice payment',
|
||||
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(Uri.parse(url), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
|
||||
return model;
|
||||
} else {
|
||||
return XenditModel();
|
||||
}
|
||||
} catch (e) {
|
||||
return XenditModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
139
lib/controllers/parcel_order_details_controller.dart
Normal file
139
lib/controllers/parcel_order_details_controller.dart
Normal file
@@ -0,0 +1,139 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/rating_model.dart';
|
||||
import 'package:customer/models/wallet_transaction_model.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import 'package:customer/themes/show_toast_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../models/parcel_category.dart';
|
||||
import '../models/parcel_order_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class ParcelOrderDetailsController extends GetxController {
|
||||
Rx<ParcelOrderModel> parcelOrder = ParcelOrderModel().obs;
|
||||
RxList<ParcelCategory> parcelCategory = <ParcelCategory>[].obs;
|
||||
RxBool isLoading = false.obs;
|
||||
|
||||
Rx<UserModel?> driverUser = Rx<UserModel?>(null);
|
||||
Rx<RatingModel> ratingModel = RatingModel().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
final args = Get.arguments;
|
||||
if (args != null && args is ParcelOrderModel) {
|
||||
parcelOrder.value = args;
|
||||
setStatusHistoryFromString(parcelOrder.value);
|
||||
}
|
||||
loadParcelCategories();
|
||||
calculateTotalAmount();
|
||||
fetchDriverDetails();
|
||||
}
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble discount = 0.0.obs;
|
||||
RxDouble taxAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
|
||||
void calculateTotalAmount() {
|
||||
taxAmount = 0.0.obs;
|
||||
discount = 0.0.obs;
|
||||
subTotal.value = double.parse(parcelOrder.value.subTotal.toString());
|
||||
discount.value = double.parse(parcelOrder.value.discount ?? '0.0');
|
||||
|
||||
for (var element in parcelOrder.value.taxSetting!) {
|
||||
taxAmount.value = (taxAmount.value + Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element));
|
||||
}
|
||||
|
||||
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> fetchDriverDetails() async {
|
||||
if (parcelOrder.value.driverId != null) {
|
||||
await FireStoreUtils.getUserProfile(parcelOrder.value.driverId ?? '').then((value) {
|
||||
if (value != null) {
|
||||
driverUser.value = value;
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getReviewsbyID(parcelOrder.value.id.toString()).then((value) {
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void setStatusHistoryFromString(ParcelOrderModel order) {
|
||||
final steps = ["Order Placed", "Driver Accepted", "Pickup Done", "In Transit", "Delivered"];
|
||||
|
||||
final history = <ParcelStatus>[];
|
||||
|
||||
DateTime baseTime = order.createdAt?.toDate() ?? DateTime.now();
|
||||
int minutesGap = 30;
|
||||
|
||||
for (int i = 0; i < steps.length; i++) {
|
||||
final step = steps[i];
|
||||
|
||||
history.add(ParcelStatus(status: step, time: baseTime.add(Duration(minutes: i * minutesGap))));
|
||||
|
||||
if (step == order.status) break;
|
||||
}
|
||||
|
||||
order.statusHistory = history;
|
||||
}
|
||||
|
||||
Future<void> cancelParcelOrder() async {
|
||||
ShowToastDialog.showLoader("Cancelling order...".tr);
|
||||
parcelOrder.value.status = Constant.orderCancelled;
|
||||
if (parcelOrder.value.paymentMethod?.toLowerCase() != "cod") {
|
||||
WalletTransactionModel walletTransaction = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: totalAmount.value,
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: true,
|
||||
orderId: parcelOrder.value.id,
|
||||
note: "Refund for cancelled parcel order",
|
||||
paymentStatus: "success",
|
||||
serviceType: Constant.parcelServiceType,
|
||||
);
|
||||
|
||||
// Save wallet transaction
|
||||
await FireStoreUtils.setWalletTransaction(walletTransaction);
|
||||
|
||||
// Update wallet balance
|
||||
await FireStoreUtils.updateUserWallet(amount: totalAmount.value.toString(), userId: FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
|
||||
await FireStoreUtils.parcelOrderPlace(parcelOrder.value);
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Order cancelled successfully".tr);
|
||||
Get.back(result: true);
|
||||
}
|
||||
|
||||
void loadParcelCategories() async {
|
||||
isLoading.value = true;
|
||||
final categories = await FireStoreUtils.getParcelServiceCategory();
|
||||
parcelCategory.value = categories;
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
String formatDate(Timestamp timestamp) {
|
||||
final dateTime = timestamp.toDate();
|
||||
return DateFormat("dd MMM yyyy, hh:mm a").format(dateTime);
|
||||
}
|
||||
|
||||
ParcelCategory? getSelectedCategory() {
|
||||
try {
|
||||
return parcelCategory.firstWhere((cat) => cat.title?.toLowerCase().trim() == parcelOrder.value.parcelType?.toLowerCase().trim(), orElse: () => ParcelCategory());
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
135
lib/controllers/parcel_review_controller.dart
Normal file
135
lib/controllers/parcel_review_controller.dart
Normal file
@@ -0,0 +1,135 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/parcel_order_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../models/rating_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class ParcelReviewController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
/// Order from arguments
|
||||
final Rx<ParcelOrderModel?> order = Rx<ParcelOrderModel?>(null);
|
||||
|
||||
/// Rating data
|
||||
final Rx<RatingModel?> ratingModel = Rx<RatingModel?>(null);
|
||||
final RxDouble ratings = 0.0.obs;
|
||||
final Rx<TextEditingController> comment = TextEditingController().obs;
|
||||
|
||||
/// Driver (to be reviewed)
|
||||
final Rx<UserModel?> driverUser = Rx<UserModel?>(null);
|
||||
|
||||
/// Review stats
|
||||
final RxInt futureCount = 0.obs;
|
||||
final RxInt futureSum = 0.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
final args = Get.arguments;
|
||||
if (args != null && args['order'] != null) {
|
||||
order.value = args['order'] as ParcelOrderModel;
|
||||
getReview();
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch old review + driver stats
|
||||
Future<void> getReview() async {
|
||||
await FireStoreUtils.getReviewsbyID(order.value?.id ?? "").then((value) {
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
ratings.value = value.rating ?? 0;
|
||||
comment.value.text = value.comment ?? "";
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getUserProfile(order.value?.driverId ?? '').then((value) {
|
||||
if (value != null) {
|
||||
driverUser.value = value;
|
||||
|
||||
final int userReviewsCount = int.tryParse(driverUser.value!.reviewsCount?.toString() ?? "0") ?? 0;
|
||||
final int userReviewsSum = int.tryParse(driverUser.value!.reviewsSum?.toString() ?? "0") ?? 0;
|
||||
|
||||
if (ratingModel.value != null) {
|
||||
final int oldRating = ratingModel.value?.rating?.toInt() ?? 0;
|
||||
futureCount.value = userReviewsCount - 1;
|
||||
futureSum.value = userReviewsSum - oldRating;
|
||||
} else {
|
||||
futureCount.value = userReviewsCount;
|
||||
futureSum.value = userReviewsSum;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
/// Save / update review
|
||||
Future<void> submitReview() async {
|
||||
if (comment.value.text.trim().isEmpty || ratings.value == 0) {
|
||||
ShowToastDialog.showToast("Please provide rating and comment".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowToastDialog.showLoader("Submit in...".tr);
|
||||
|
||||
final user = await FireStoreUtils.getUserProfile(order.value?.driverId ?? '');
|
||||
|
||||
if (user != null) {
|
||||
user.reviewsCount = (futureCount.value + 1).toString();
|
||||
user.reviewsSum = (futureSum.value + ratings.value.toInt()).toString();
|
||||
}
|
||||
if (ratingModel.value != null && ratingModel.value!.id!.isNotEmpty) {
|
||||
/// Update existing review
|
||||
final updatedRating = RatingModel(
|
||||
id: ratingModel.value!.id,
|
||||
comment: comment.value.text,
|
||||
photos: ratingModel.value?.photos ?? [],
|
||||
rating: ratings.value,
|
||||
orderId: ratingModel.value!.orderId,
|
||||
driverId: ratingModel.value!.driverId,
|
||||
customerId: ratingModel.value!.customerId,
|
||||
vendorId: ratingModel.value?.vendorId,
|
||||
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
|
||||
profile: Constant.userModel?.profilePictureURL,
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
await FireStoreUtils.updateReviewById(updatedRating);
|
||||
if (user != null) {
|
||||
await FireStoreUtils.updateUser(user);
|
||||
}
|
||||
} else {
|
||||
/// New review
|
||||
final newRating = RatingModel(
|
||||
id: Constant.getUuid(),
|
||||
comment: comment.value.text,
|
||||
photos: [],
|
||||
rating: ratings.value,
|
||||
orderId: order.value?.id,
|
||||
driverId: order.value?.driverId.toString(),
|
||||
customerId: Constant.userModel?.id,
|
||||
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
|
||||
profile: Constant.userModel?.profilePictureURL,
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
await FireStoreUtils.updateReviewById(newRating);
|
||||
if (user != null) {
|
||||
await FireStoreUtils.updateUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.back(result: true);
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
comment.value.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
40
lib/controllers/provider_controller.dart
Normal file
40
lib/controllers/provider_controller.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'package:customer/controllers/on_demand_home_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../models/provider_serivce_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class ProviderController extends GetxController {
|
||||
RxList<ProviderServiceModel> providerList = <ProviderServiceModel>[].obs;
|
||||
final Rxn<UserModel> userModel = Rxn<UserModel>();
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
late final String providerId;
|
||||
Rx<OnDemandHomeController> onDemandHomeController = Get.put(OnDemandHomeController()).obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
//Get providerId from arguments
|
||||
providerId = Get.arguments['providerId'];
|
||||
|
||||
getProvider();
|
||||
getAuthor();
|
||||
}
|
||||
|
||||
void getProvider() async {
|
||||
FireStoreUtils.getProviderServiceByProviderId(providerId: providerId).then((catValue) {
|
||||
providerList.value = catValue;
|
||||
});
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getAuthor() async {
|
||||
final user = await FireStoreUtils.getUserProfile(providerId);
|
||||
if (user != null) {
|
||||
userModel.value = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
194
lib/controllers/rate_product_controller.dart
Normal file
194
lib/controllers/rate_product_controller.dart
Normal file
@@ -0,0 +1,194 @@
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/order_model.dart';
|
||||
import 'package:customer/models/product_model.dart';
|
||||
import 'package:customer/models/vendor_category_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../models/rating_model.dart';
|
||||
import '../models/review_attribute_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class RateProductController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Rx<TextEditingController> commentController = TextEditingController().obs;
|
||||
|
||||
Rx<OrderModel> orderModel = OrderModel().obs;
|
||||
RxString productId = "".obs;
|
||||
Rx<RatingModel> ratingModel = RatingModel().obs;
|
||||
Rx<ProductModel> productModel = ProductModel().obs;
|
||||
Rx<VendorModel> vendorModel = VendorModel().obs;
|
||||
Rx<VendorCategoryModel> vendorCategoryModel = VendorCategoryModel().obs;
|
||||
|
||||
RxList<ReviewAttributeModel> reviewAttributeList = <ReviewAttributeModel>[].obs;
|
||||
|
||||
RxDouble ratings = 0.0.obs;
|
||||
|
||||
RxMap<String, dynamic> reviewAttribute = <String, dynamic>{}.obs;
|
||||
RxMap<String, dynamic> reviewProductAttributes = <String, dynamic>{}.obs;
|
||||
|
||||
RxDouble vendorReviewSum = 0.0.obs;
|
||||
RxDouble vendorReviewCount = 0.0.obs;
|
||||
|
||||
RxDouble productReviewSum = 0.0.obs;
|
||||
RxDouble productReviewCount = 0.0.obs;
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
orderModel.value = argumentData['orderModel'];
|
||||
productId.value = argumentData['productId'];
|
||||
|
||||
await FireStoreUtils.getOrderReviewsByID(orderModel.value.id.toString(), productId.value).then((value) {
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
ratings.value = value.rating ?? 0.0;
|
||||
commentController.value.text = value.comment.toString();
|
||||
reviewAttribute.value = value.reviewAttributes!;
|
||||
images.addAll(value.photos ?? []);
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getProductById(productId.value.split('~').first).then((value) {
|
||||
if (value != null) {
|
||||
productModel.value = value;
|
||||
if (ratingModel.value.id != null && ratingModel.value.id!.isNotEmpty) {
|
||||
productReviewCount.value = value.reviewsCount! - 1;
|
||||
productReviewSum.value = value.reviewsSum! - ratings.value;
|
||||
|
||||
if (value.reviewAttributes != null) {
|
||||
value.reviewAttributes!.forEach((key, value) {
|
||||
ReviewsAttribute reviewsAttributeModel = ReviewsAttribute.fromJson(value);
|
||||
reviewsAttributeModel.reviewsCount = reviewsAttributeModel.reviewsCount! - 1;
|
||||
reviewsAttributeModel.reviewsSum = reviewsAttributeModel.reviewsSum! - reviewAttribute[key];
|
||||
reviewProductAttributes.addEntries([MapEntry(key, reviewsAttributeModel.toJson())]);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
productReviewCount.value = double.parse(value.reviewsCount.toString());
|
||||
productReviewSum.value = double.parse(value.reviewsSum.toString());
|
||||
if (value.reviewAttributes != null) {
|
||||
reviewProductAttributes.value = value.reviewAttributes!;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getVendorById(productModel.value.vendorID.toString()).then((value) {
|
||||
if (value != null) {
|
||||
vendorModel.value = value;
|
||||
if (ratingModel.value.id != null && ratingModel.value.id!.isNotEmpty) {
|
||||
vendorReviewCount.value = value.reviewsCount! - 1;
|
||||
vendorReviewSum.value = value.reviewsSum! - ratings.value;
|
||||
} else {
|
||||
vendorReviewCount.value = double.parse(value.reviewsCount.toString());
|
||||
vendorReviewSum.value = double.parse(value.reviewsSum.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getVendorCategoryByCategoryId(productModel.value.categoryID.toString()).then((value) async {
|
||||
if (value != null) {
|
||||
vendorCategoryModel.value = value;
|
||||
for (var element in vendorCategoryModel.value.reviewAttributes!) {
|
||||
await FireStoreUtils.getVendorReviewAttribute(element).then((value) {
|
||||
reviewAttributeList.add(value!);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> saveRating() async {
|
||||
if (ratings.value != 0.0) {
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
productModel.value.reviewsCount = productReviewCount.value + 1;
|
||||
productModel.value.reviewsSum = productReviewSum.value + ratings.value;
|
||||
productModel.value.reviewAttributes = reviewProductAttributes;
|
||||
|
||||
vendorModel.value.reviewsCount = vendorReviewCount.value + 1;
|
||||
vendorModel.value.reviewsSum = vendorReviewSum.value + ratings.value;
|
||||
|
||||
if (reviewProductAttributes.isEmpty) {
|
||||
reviewAttribute.forEach((key, value) {
|
||||
ReviewsAttribute reviewsAttributeModel = ReviewsAttribute(reviewsCount: 1, reviewsSum: value);
|
||||
reviewProductAttributes.addEntries([MapEntry(key, reviewsAttributeModel.toJson())]);
|
||||
});
|
||||
} else {
|
||||
reviewProductAttributes.forEach((key, value) {
|
||||
ReviewsAttribute reviewsAttributeModel = ReviewsAttribute.fromJson(value);
|
||||
reviewsAttributeModel.reviewsCount = reviewsAttributeModel.reviewsCount! + 1;
|
||||
reviewsAttributeModel.reviewsSum = reviewsAttributeModel.reviewsSum! + reviewAttribute[key];
|
||||
reviewProductAttributes.addEntries([MapEntry(key, reviewsAttributeModel.toJson())]);
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < images.length; i++) {
|
||||
if (images[i].runtimeType == XFile) {
|
||||
String url = await Constant.uploadUserImageToFireStorage(File(images[i].path), "profileImage/${FireStoreUtils.getCurrentUid()}", File(images[i].path).path.split('/').last);
|
||||
images.removeAt(i);
|
||||
images.insert(i, url);
|
||||
}
|
||||
}
|
||||
|
||||
RatingModel ratingProduct = RatingModel(
|
||||
productId: productId.value,
|
||||
comment: commentController.value.text,
|
||||
photos: images,
|
||||
rating: ratings.value,
|
||||
customerId: FireStoreUtils.getCurrentUid(),
|
||||
id: ratingModel.value.id != null && ratingModel.value.id!.isNotEmpty ? ratingModel.value.id : Constant.getUuid(),
|
||||
orderId: orderModel.value.id,
|
||||
vendorId: productModel.value.vendorID,
|
||||
createdAt: Timestamp.now(),
|
||||
uname: Constant.userModel!.fullName(),
|
||||
profile: Constant.userModel!.profilePictureURL,
|
||||
reviewAttributes: reviewAttribute,
|
||||
);
|
||||
|
||||
print("vendor model");
|
||||
log(vendorModel.value.toJson().toString());
|
||||
await FireStoreUtils.updateReviewById(ratingProduct);
|
||||
print("Rating Saved");
|
||||
print(ratingProduct.toJson());
|
||||
await FireStoreUtils.updateVendor(vendorModel.value);
|
||||
await FireStoreUtils.setProduct(productModel.value);
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Rating saved successfully.".tr);
|
||||
Get.back();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Please add rate for food item.".tr);
|
||||
}
|
||||
}
|
||||
|
||||
final ImagePicker _imagePicker = ImagePicker();
|
||||
RxList images = <dynamic>[].obs;
|
||||
|
||||
Future pickFile({required ImageSource source}) async {
|
||||
try {
|
||||
XFile? image = await _imagePicker.pickImage(source: source);
|
||||
if (image == null) return;
|
||||
images.add(image);
|
||||
Get.back();
|
||||
} on PlatformException catch (e) {
|
||||
ShowToastDialog.showToast("Failed to Pick : \n $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
13
lib/controllers/redeem_gift_card_controller.dart
Normal file
13
lib/controllers/redeem_gift_card_controller.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class RedeemGiftCardController extends GetxController {
|
||||
Rx<TextEditingController> giftCodeController = TextEditingController().obs;
|
||||
Rx<TextEditingController> giftPinController = TextEditingController().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
super.onInit();
|
||||
}
|
||||
}
|
||||
25
lib/controllers/refer_friend_controller.dart
Normal file
25
lib/controllers/refer_friend_controller.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:customer/models/referral_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ReferFriendController extends GetxController {
|
||||
Rx<ReferralModel> referralModel = ReferralModel().obs;
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
await FireStoreUtils.getReferralUserBy().then((value) {
|
||||
if (value != null) {
|
||||
referralModel.value = value;
|
||||
}
|
||||
});
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
89
lib/controllers/rental_conformation_controller.dart
Normal file
89
lib/controllers/rental_conformation_controller.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
import 'dart:math' as maths;
|
||||
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/models/rental_order_model.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:customer/themes/show_toast_dialog.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../screen_ui/rental_service/rental_dashboard_screen.dart';
|
||||
import 'cab_rental_dashboard_controllers.dart';
|
||||
|
||||
class RentalConformationController extends GetxController {
|
||||
RxBool isLoading = false.obs;
|
||||
|
||||
Rx<RentalOrderModel> rentalOrderModel = RentalOrderModel().obs;
|
||||
Rx<TextEditingController> couponController = TextEditingController().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getArguments();
|
||||
fetchCoupons();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void getArguments() {
|
||||
final args = Get.arguments;
|
||||
if (args.containsKey('rentalOrderModel') && args['rentalOrderModel'] is RentalOrderModel) {
|
||||
rentalOrderModel.value = args['rentalOrderModel'] as RentalOrderModel;
|
||||
calculateAmount();
|
||||
} else {
|
||||
debugPrint('No rental order found in arguments or invalid format.');
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble discount = 0.0.obs;
|
||||
RxDouble taxAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
Rx<CouponModel> selectedCouponModel = CouponModel().obs;
|
||||
|
||||
void calculateAmount() {
|
||||
subTotal.value = 0.0;
|
||||
discount.value = 0.0;
|
||||
taxAmount.value = 0.0;
|
||||
totalAmount.value = 0.0;
|
||||
|
||||
subTotal.value = double.tryParse(rentalOrderModel.value.subTotal ?? '0') ?? 0.0;
|
||||
if (selectedCouponModel.value.id != null) {
|
||||
discount.value = Constant.calculateDiscount(amount: subTotal.value.toString(), offerModel: selectedCouponModel.value);
|
||||
}
|
||||
for (var element in rentalOrderModel.value.taxSetting ?? []) {
|
||||
taxAmount.value = (taxAmount.value + Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element));
|
||||
}
|
||||
|
||||
totalAmount.value = subTotal.value - discount.value + taxAmount.value;
|
||||
}
|
||||
|
||||
RxList<CouponModel> couponList = <CouponModel>[].obs;
|
||||
|
||||
Future<void> fetchCoupons() async {
|
||||
try {
|
||||
await FireStoreUtils.getRentalCoupon().then((value) {
|
||||
couponList.value = value;
|
||||
});
|
||||
} catch (e) {
|
||||
print("Error fetching coupons: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> placeOrder() async {
|
||||
ShowToastDialog.showLoader("Placing booking...".tr);
|
||||
rentalOrderModel.value.discount = discount.value.toString();
|
||||
rentalOrderModel.value.couponCode = selectedCouponModel.value.code;
|
||||
rentalOrderModel.value.couponId = selectedCouponModel.value.id;
|
||||
rentalOrderModel.value.subTotal = subTotal.value.toString();
|
||||
rentalOrderModel.value.otpCode = (maths.Random().nextInt(9000) + 1000).toString();
|
||||
await FireStoreUtils.rentalOrderPlace(rentalOrderModel.value).then((value) async {
|
||||
ShowToastDialog.closeLoader();
|
||||
ShowToastDialog.showToast("Order placed successfully".tr);
|
||||
Get.offAll(const RentalDashboardScreen());
|
||||
CabRentalDashboardControllers controller = Get.put(CabRentalDashboardControllers());
|
||||
controller.selectedIndex.value = 1;
|
||||
// Get.back();
|
||||
});
|
||||
}
|
||||
}
|
||||
28
lib/controllers/rental_coupon_controller.dart
Normal file
28
lib/controllers/rental_coupon_controller.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class RentalCouponController extends GetxController{
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
|
||||
void getData(){
|
||||
getCouponCode();
|
||||
}
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<CouponModel> cabCouponList = <CouponModel>[].obs;
|
||||
|
||||
Future<void> getCouponCode() async {
|
||||
await FireStoreUtils.getRentalCoupon().then((value) {
|
||||
cabCouponList.value = value;
|
||||
});
|
||||
print("cabCouponList ${cabCouponList.length}");
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
237
lib/controllers/rental_home_controller.dart
Normal file
237
lib/controllers/rental_home_controller.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/rental_order_model.dart';
|
||||
import 'package:customer/models/rental_package_model.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import 'package:customer/screen_ui/rental_service/rental_conformation_screen.dart';
|
||||
import 'package:customer/widget/geoflutterfire/src/geoflutterfire.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart' as latlong;
|
||||
import '../constant/constant.dart';
|
||||
import '../models/payment_model/cod_setting_model.dart';
|
||||
import '../models/payment_model/flutter_wave_model.dart';
|
||||
import '../models/payment_model/mercado_pago_model.dart';
|
||||
import '../models/payment_model/mid_trans.dart';
|
||||
import '../models/payment_model/orange_money.dart';
|
||||
import '../models/payment_model/pay_fast_model.dart';
|
||||
import '../models/payment_model/pay_stack_model.dart';
|
||||
import '../models/payment_model/paypal_model.dart';
|
||||
import '../models/payment_model/paytm_model.dart';
|
||||
import '../models/payment_model/razorpay_model.dart';
|
||||
import '../models/payment_model/stripe_model.dart';
|
||||
import '../models/payment_model/wallet_setting_model.dart';
|
||||
import '../models/payment_model/xendit.dart';
|
||||
import '../models/rental_vehicle_type.dart';
|
||||
import '../screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
import '../utils/preferences.dart';
|
||||
import '../utils/utils.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart' as gmaps;
|
||||
|
||||
class RentalHomeController extends GetxController {
|
||||
RxBool isLoading = false.obs;
|
||||
|
||||
// Location input
|
||||
final Rx<TextEditingController> sourceTextEditController = TextEditingController().obs;
|
||||
|
||||
// Selected date
|
||||
Rx<DateTime> selectedDate = DateTime.now().obs;
|
||||
|
||||
// Vehicle list + selected vehicle
|
||||
RxList<RentalVehicleType> vehicleTypes = <RentalVehicleType>[].obs;
|
||||
Rx<RentalVehicleType?> selectedVehicleType = Rx<RentalVehicleType?>(null);
|
||||
|
||||
RxList<RentalPackageModel> rentalPackages = <RentalPackageModel>[].obs;
|
||||
Rx<RentalPackageModel?> selectedPackage = Rx<RentalPackageModel?>(null);
|
||||
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
|
||||
final RxString selectedPaymentMethod = ''.obs;
|
||||
|
||||
final Rx<gmaps.LatLng> departureLatLong = gmaps.LatLng(0.0, 0.0).obs;
|
||||
final Rx<latlong.LatLng> departureLatLongOsm = latlong.LatLng(0.0, 0.0).obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
if (Constant.userModel != null) {
|
||||
userModel.value = Constant.userModel!;
|
||||
}
|
||||
getVehicleType();
|
||||
fetchCurrentLocation();
|
||||
}
|
||||
|
||||
void fetchCurrentLocation() async {
|
||||
try {
|
||||
Position? position = await Utils.getCurrentLocation();
|
||||
if (position != null) {
|
||||
Constant.currentLocation = position;
|
||||
|
||||
// Set default coordinates for Google or OSM
|
||||
departureLatLong.value = gmaps.LatLng(position.latitude, position.longitude);
|
||||
departureLatLongOsm.value = latlong.LatLng(position.latitude, position.longitude);
|
||||
|
||||
// Get readable address
|
||||
String address = await Utils.getAddressFromCoordinates(position.latitude, position.longitude);
|
||||
sourceTextEditController.value.text = address;
|
||||
}
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("Unable to fetch current location".tr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch Vehicle Types
|
||||
Future<void> getVehicleType() async {
|
||||
isLoading.value = true;
|
||||
await FireStoreUtils.getRentalVehicleType().then((value) async {
|
||||
vehicleTypes.value = value;
|
||||
if (vehicleTypes.isNotEmpty) {
|
||||
selectedVehicleType.value = vehicleTypes[0];
|
||||
await getRentalPackage();
|
||||
}
|
||||
});
|
||||
await getPaymentSettings();
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
/// Date Picker
|
||||
Future<void> pickDate(BuildContext context) async {
|
||||
final DateTime? picked = await showDatePicker(context: context, initialDate: selectedDate.value, firstDate: DateTime.now(), lastDate: DateTime(2100));
|
||||
|
||||
if (picked != null) {
|
||||
selectedDate.value = picked;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getRentalPackage() async {
|
||||
await FireStoreUtils.getRentalPackage(selectedVehicleType.value!.id.toString()).then((value) {
|
||||
rentalPackages.value = value;
|
||||
if (rentalPackages.isNotEmpty) {
|
||||
selectedPackage.value = rentalPackages[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void completeOrder() {
|
||||
DestinationLocation sourceLocation = DestinationLocation(
|
||||
latitude: Constant.selectedMapType == 'osm' ? departureLatLongOsm.value.latitude : departureLatLong.value.latitude,
|
||||
longitude: Constant.selectedMapType == 'osm' ? departureLatLongOsm.value.longitude : departureLatLong.value.longitude,
|
||||
);
|
||||
|
||||
print("=====>");
|
||||
print(sourceTextEditController.value.text);
|
||||
|
||||
RentalOrderModel rentalOrderModel = RentalOrderModel();
|
||||
rentalOrderModel.id = Constant.getUuid();
|
||||
rentalOrderModel.authorID = userModel.value.id;
|
||||
rentalOrderModel.author = userModel.value;
|
||||
rentalOrderModel.rentalVehicleType = selectedVehicleType.value;
|
||||
rentalOrderModel.vehicleId = selectedVehicleType.value!.id;
|
||||
rentalOrderModel.sectionId = Constant.sectionConstantModel!.id;
|
||||
rentalOrderModel.sourceLocationName = sourceTextEditController.value.text;
|
||||
rentalOrderModel.bookingDateTime = Timestamp.fromDate(selectedDate.value);
|
||||
rentalOrderModel.paymentMethod = selectedPaymentMethod.value;
|
||||
rentalOrderModel.paymentStatus = false;
|
||||
rentalOrderModel.status = Constant.orderPlaced;
|
||||
rentalOrderModel.subTotal = selectedPackage.value!.baseFare;
|
||||
rentalOrderModel.rentalPackageModel = selectedPackage.value;
|
||||
rentalOrderModel.taxSetting = Constant.taxList;
|
||||
rentalOrderModel.createdAt = Timestamp.now();
|
||||
rentalOrderModel.sourceLocation = sourceLocation;
|
||||
rentalOrderModel.adminCommission = Constant.sectionConstantModel!.adminCommision!.amount;
|
||||
rentalOrderModel.adminCommissionType = Constant.sectionConstantModel!.adminCommision!.commissionType;
|
||||
rentalOrderModel.sourcePoint = G(
|
||||
geopoint: GeoPoint(sourceLocation.latitude ?? 0.0, sourceLocation.longitude ?? 0.0),
|
||||
geohash: Geoflutterfire().point(latitude: sourceLocation.latitude ?? 0.0, longitude: sourceLocation.longitude ?? 0.0).hash,
|
||||
);
|
||||
rentalOrderModel.zoneId = Constant.getZoneId(sourceLocation.latitude ?? 0.0, sourceLocation.longitude ?? 0.0);
|
||||
log(rentalOrderModel.toJson().toString());
|
||||
Get.back();
|
||||
Get.back();
|
||||
|
||||
Get.to(() => RentalConformationScreen(), arguments: {"rentalOrderModel": rentalOrderModel});
|
||||
}
|
||||
|
||||
void setDepartureMarker(double lat, double lng) {
|
||||
if (Constant.selectedMapType == 'osm') {
|
||||
departureLatLongOsm.value = latlong.LatLng(lat, lng);
|
||||
} else {
|
||||
departureLatLong.value = gmaps.LatLng(lat, lng);
|
||||
}
|
||||
}
|
||||
|
||||
// final Rx<LatLng> departureLatLong = const LatLng(0.0, 0.0).obs;
|
||||
// final Rx<latlong.LatLng> departureLatLongOsm = latlong.LatLng(0.0, 0.0).obs;
|
||||
|
||||
// void setDepartureMarker(double lat, double long) {
|
||||
// if (Constant.selectedMapType == 'osm') {
|
||||
// departureLatLongOsm.value = latlong.LatLng(lat, long);
|
||||
// } else {
|
||||
// departureLatLong.value = LatLng(lat, long);
|
||||
// }
|
||||
// }
|
||||
|
||||
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
|
||||
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
|
||||
Rx<PayFastModel> payFastModel = PayFastModel().obs;
|
||||
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
|
||||
Rx<PayPalModel> payPalModel = PayPalModel().obs;
|
||||
Rx<StripeModel> stripeModel = StripeModel().obs;
|
||||
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
|
||||
Rx<PayStackModel> payStackModel = PayStackModel().obs;
|
||||
Rx<PaytmModel> paytmModel = PaytmModel().obs;
|
||||
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
|
||||
|
||||
Rx<MidTrans> midTransModel = MidTrans().obs;
|
||||
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
|
||||
Rx<Xendit> xenditModel = Xendit().obs;
|
||||
|
||||
Future<void> getPaymentSettings() async {
|
||||
await FireStoreUtils.getPaymentSettingsData().then((value) {
|
||||
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
|
||||
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
|
||||
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
|
||||
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
|
||||
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
|
||||
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
|
||||
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
|
||||
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
|
||||
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
|
||||
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
|
||||
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
|
||||
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
|
||||
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
|
||||
|
||||
if (walletSettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.wallet.name;
|
||||
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.cod.name;
|
||||
} else if (stripeModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.stripe.name;
|
||||
} else if (payPalModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.paypal.name;
|
||||
} else if (payStackModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payStack.name;
|
||||
} else if (mercadoPagoModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
|
||||
} else if (flutterWaveModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
|
||||
} else if (payFastModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payFast.name;
|
||||
} else if (razorPayModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
|
||||
} else if (midTransModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
|
||||
} else if (orangeMoneyModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
|
||||
} else if (xenditModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.xendit.name;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
904
lib/controllers/rental_order_details_controller.dart
Normal file
904
lib/controllers/rental_order_details_controller.dart
Normal file
@@ -0,0 +1,904 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as maths;
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/payment_model/cod_setting_model.dart';
|
||||
import 'package:customer/models/payment_model/flutter_wave_model.dart';
|
||||
import 'package:customer/models/payment_model/mercado_pago_model.dart';
|
||||
import 'package:customer/models/payment_model/mid_trans.dart';
|
||||
import 'package:customer/models/payment_model/orange_money.dart';
|
||||
import 'package:customer/models/payment_model/pay_fast_model.dart';
|
||||
import 'package:customer/models/payment_model/pay_stack_model.dart';
|
||||
import 'package:customer/models/payment_model/paypal_model.dart';
|
||||
import 'package:customer/models/payment_model/paytm_model.dart';
|
||||
import 'package:customer/models/payment_model/razorpay_model.dart';
|
||||
import 'package:customer/models/payment_model/stripe_model.dart';
|
||||
import 'package:customer/models/payment_model/wallet_setting_model.dart';
|
||||
import 'package:customer/models/payment_model/xendit.dart';
|
||||
import 'package:customer/models/rating_model.dart';
|
||||
import 'package:customer/models/rental_order_model.dart';
|
||||
import 'package:customer/models/wallet_transaction_model.dart';
|
||||
import 'package:customer/payment/MercadoPagoScreen.dart';
|
||||
import 'package:customer/payment/PayFastScreen.dart';
|
||||
import 'package:customer/payment/getPaytmTxtToken.dart';
|
||||
import 'package:customer/payment/midtrans_screen.dart';
|
||||
import 'package:customer/payment/orangePayScreen.dart';
|
||||
import 'package:customer/payment/paystack/pay_stack_screen.dart';
|
||||
import 'package:customer/payment/paystack/pay_stack_url_model.dart';
|
||||
import 'package:customer/payment/paystack/paystack_url_genrater.dart';
|
||||
import 'package:customer/payment/stripe_failed_model.dart';
|
||||
import 'package:customer/payment/xenditModel.dart';
|
||||
import 'package:customer/payment/xenditScreen.dart';
|
||||
import 'package:customer/screen_ui/multi_vendor_service/wallet_screen/wallet_screen.dart';
|
||||
import 'package:customer/themes/app_them_data.dart';
|
||||
import 'package:customer/themes/show_toast_dialog.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_paypal/flutter_paypal.dart';
|
||||
import 'package:flutter_stripe/flutter_stripe.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../constant/constant.dart';
|
||||
import '../models/tax_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class RentalOrderDetailsController extends GetxController {
|
||||
Rx<RentalOrderModel> order = RentalOrderModel().obs;
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
Rx<UserModel?> driverUser = Rx<UserModel?>(null);
|
||||
|
||||
RxDouble subTotal = 0.0.obs;
|
||||
RxDouble discount = 0.0.obs;
|
||||
RxDouble taxAmount = 0.0.obs;
|
||||
RxDouble totalAmount = 0.0.obs;
|
||||
RxDouble extraKilometerCharge = 0.0.obs;
|
||||
RxDouble extraMinutesCharge = 0.0.obs;
|
||||
|
||||
final RxString selectedPaymentMethod = ''.obs;
|
||||
Rx<RatingModel> ratingModel = RatingModel().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
final args = Get.arguments;
|
||||
if (args != null) {
|
||||
order.value = args as RentalOrderModel;
|
||||
calculateTotalAmount();
|
||||
await fetchDriverDetails();
|
||||
await getPaymentSettings();
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> fetchDriverDetails() async {
|
||||
if (order.value.driverId != null) {
|
||||
await FireStoreUtils.getUserProfile(order.value.driverId ?? '').then((value) {
|
||||
if (value != null) {
|
||||
driverUser.value = value;
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getReviewsbyID(order.value.id.toString()).then((value) {
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
String getExtraKm() {
|
||||
try {
|
||||
final double start = double.tryParse(order.value.startKitoMetersReading ?? '0') ?? 0.0;
|
||||
final double end = double.tryParse(order.value.endKitoMetersReading ?? '0') ?? 0.0;
|
||||
final double included = double.tryParse(order.value.rentalPackageModel?.includedDistance?.toString() ?? '0') ?? 0.0;
|
||||
|
||||
// Calculate extra km safely
|
||||
final double extra = (end - start - included);
|
||||
final double validExtra = extra > 0 ? extra : 0;
|
||||
|
||||
return "${validExtra.toStringAsFixed(2)} ${Constant.distanceType}";
|
||||
} catch (e) {
|
||||
return "0 ${Constant.distanceType}";
|
||||
}
|
||||
}
|
||||
|
||||
///Safe calculation after order is loaded
|
||||
void calculateTotalAmount() {
|
||||
try {
|
||||
subTotal.value = double.tryParse(order.value.subTotal?.toString() ?? "0") ?? 0.0;
|
||||
discount.value = double.tryParse(order.value.discount?.toString() ?? "0") ?? 0.0;
|
||||
taxAmount.value = 0.0;
|
||||
|
||||
if (order.value.endTime != null) {
|
||||
DateTime start = order.value.startTime!.toDate();
|
||||
DateTime end = order.value.endTime!.toDate();
|
||||
|
||||
// Total rented minutes
|
||||
int totalMinutes = end.difference(start).inMinutes;
|
||||
|
||||
int includedMinutes = (int.tryParse(order.value.rentalPackageModel?.includedHours.toString() ?? "0") ?? 0) * 60;
|
||||
|
||||
if (totalMinutes > includedMinutes) {
|
||||
int extraMinutes = totalMinutes - includedMinutes;
|
||||
|
||||
double minuteFare = double.tryParse(order.value.rentalPackageModel?.extraMinuteFare?.toString() ?? "0") ?? 0.0;
|
||||
|
||||
extraMinutesCharge.value = extraMinutes * minuteFare;
|
||||
} else {
|
||||
extraMinutesCharge.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (order.value.startKitoMetersReading != null && order.value.endKitoMetersReading != null) {
|
||||
double startKm = double.tryParse(order.value.startKitoMetersReading?.toString() ?? "0") ?? 0.0;
|
||||
double endKm = double.tryParse(order.value.endKitoMetersReading?.toString() ?? "0") ?? 0.0;
|
||||
if (endKm > startKm) {
|
||||
double totalKm = endKm - startKm;
|
||||
if (totalKm > double.parse(order.value.rentalPackageModel!.includedDistance!)) {
|
||||
totalKm = totalKm - double.parse(order.value.rentalPackageModel!.includedDistance!);
|
||||
double extraKmRate = double.tryParse(order.value.rentalPackageModel?.extraKmFare?.toString() ?? "0") ?? 0.0;
|
||||
extraKilometerCharge.value = totalKm * extraKmRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subTotal.value = subTotal.value + extraKilometerCharge.value + extraMinutesCharge.value;
|
||||
|
||||
if (order.value.taxSetting != null) {
|
||||
for (var element in order.value.taxSetting!) {
|
||||
taxAmount.value += Constant.calculateTax(amount: (subTotal.value - discount.value).toString(), taxModel: element);
|
||||
}
|
||||
}
|
||||
|
||||
totalAmount.value = (subTotal.value - discount.value) + taxAmount.value;
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("${'Failed to calculate total:'.tr} $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> completeOrder() async {
|
||||
if (selectedPaymentMethod.value == PaymentGateway.cod.name) {
|
||||
order.value.paymentMethod = selectedPaymentMethod.value;
|
||||
await FireStoreUtils.rentalOrderPlace(order.value).then((value) {
|
||||
ShowToastDialog.showToast("Payment method changed".tr);
|
||||
Get.back();
|
||||
Get.back();
|
||||
});
|
||||
} else {
|
||||
order.value.paymentStatus = true;
|
||||
order.value.paymentMethod = selectedPaymentMethod.value;
|
||||
if (selectedPaymentMethod.value == PaymentGateway.wallet.name) {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: double.parse(totalAmount.toString()),
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: false,
|
||||
orderId: order.value.id,
|
||||
note: "Rental Amount debited",
|
||||
paymentStatus: "success",
|
||||
serviceType: Constant.parcelServiceType,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
if (value == true) {
|
||||
await FireStoreUtils.updateUserWallet(amount: "-${totalAmount.toString()}", userId: FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await FireStoreUtils.rentalOrderPlace(order.value).then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
Get.back();
|
||||
Get.back();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> cancelRentalRequest(RentalOrderModel order, {List<TaxModel>? taxList}) async {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
|
||||
order.status = Constant.orderCancelled;
|
||||
await FireStoreUtils.rentalOrderPlace(order);
|
||||
|
||||
if (order.paymentMethod?.toLowerCase() != "cod") {
|
||||
double totalTax = 0.0;
|
||||
|
||||
if (taxList != null) {
|
||||
for (var element in taxList) {
|
||||
totalTax += Constant.calculateTax(amount: (double.parse(order.subTotal.toString()) - double.parse(order.discount.toString())).toString(), taxModel: element);
|
||||
}
|
||||
}
|
||||
|
||||
double subTotal = double.parse(order.subTotal.toString()) - double.parse(order.discount.toString());
|
||||
double refundAmount = subTotal + totalTax;
|
||||
|
||||
WalletTransactionModel walletTransaction = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: refundAmount,
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: PaymentGateway.wallet.name,
|
||||
transactionUser: "customer",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: true,
|
||||
// refund
|
||||
orderId: order.id,
|
||||
note: "Refund for cancelled booking",
|
||||
paymentStatus: "success",
|
||||
serviceType: Constant.parcelServiceType,
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(walletTransaction);
|
||||
await FireStoreUtils.updateUserWallet(amount: refundAmount.toString(), userId: FireStoreUtils.getCurrentUid());
|
||||
}
|
||||
ShowToastDialog.showToast("Booking cancelled successfully".tr);
|
||||
Get.back();
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("${'Failed to cancel booking:'.tr} $e".tr);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Rx<WalletSettingModel> walletSettingModel = WalletSettingModel().obs;
|
||||
Rx<CodSettingModel> cashOnDeliverySettingModel = CodSettingModel().obs;
|
||||
Rx<PayFastModel> payFastModel = PayFastModel().obs;
|
||||
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
|
||||
Rx<PayPalModel> payPalModel = PayPalModel().obs;
|
||||
Rx<StripeModel> stripeModel = StripeModel().obs;
|
||||
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
|
||||
Rx<PayStackModel> payStackModel = PayStackModel().obs;
|
||||
Rx<PaytmModel> paytmModel = PaytmModel().obs;
|
||||
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
|
||||
|
||||
Rx<MidTrans> midTransModel = MidTrans().obs;
|
||||
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
|
||||
Rx<Xendit> xenditModel = Xendit().obs;
|
||||
|
||||
Future<void> getPaymentSettings() async {
|
||||
await FireStoreUtils.getPaymentSettingsData().then((value) {
|
||||
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
|
||||
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
|
||||
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
|
||||
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
|
||||
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
|
||||
paytmModel.value = PaytmModel.fromJson(jsonDecode(Preferences.getString(Preferences.paytmSettings)));
|
||||
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
|
||||
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
|
||||
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
|
||||
orangeMoneyModel.value = OrangeMoney.fromJson(jsonDecode(Preferences.getString(Preferences.orangeMoneySettings)));
|
||||
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
|
||||
walletSettingModel.value = WalletSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.walletSettings)));
|
||||
cashOnDeliverySettingModel.value = CodSettingModel.fromJson(jsonDecode(Preferences.getString(Preferences.codSettings)));
|
||||
|
||||
if (walletSettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.wallet.name;
|
||||
} else if (cashOnDeliverySettingModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.cod.name;
|
||||
} else if (stripeModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.stripe.name;
|
||||
} else if (payPalModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.paypal.name;
|
||||
} else if (payStackModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payStack.name;
|
||||
} else if (mercadoPagoModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.mercadoPago.name;
|
||||
} else if (flutterWaveModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.flutterWave.name;
|
||||
} else if (payFastModel.value.isEnable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.payFast.name;
|
||||
} else if (razorPayModel.value.isEnabled == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.razorpay.name;
|
||||
} else if (midTransModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.midTrans.name;
|
||||
} else if (orangeMoneyModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.orangeMoney.name;
|
||||
} else if (xenditModel.value.enable == true) {
|
||||
selectedPaymentMethod.value = PaymentGateway.xendit.name;
|
||||
}
|
||||
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
|
||||
Stripe.merchantIdentifier = 'eMart Customer';
|
||||
Stripe.instance.applySettings();
|
||||
setRef();
|
||||
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
|
||||
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
|
||||
});
|
||||
}
|
||||
|
||||
// Strip
|
||||
Future<void> stripeMakePayment({required String amount}) async {
|
||||
log(double.parse(amount).toStringAsFixed(0));
|
||||
try {
|
||||
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
|
||||
log("stripe Responce====>$paymentIntentData");
|
||||
if (paymentIntentData!.containsKey("error")) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
} else {
|
||||
await Stripe.instance.initPaymentSheet(
|
||||
paymentSheetParameters: SetupPaymentSheetParameters(
|
||||
paymentIntentClientSecret: paymentIntentData['client_secret'],
|
||||
allowsDelayedPaymentMethods: false,
|
||||
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
|
||||
customFlow: true,
|
||||
style: ThemeMode.system,
|
||||
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
|
||||
merchantDisplayName: 'GoRide',
|
||||
),
|
||||
);
|
||||
displayStripePaymentSheet(amount: amount);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log("$e \n$s");
|
||||
ShowToastDialog.showToast("exception:$e \n$s");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> displayStripePaymentSheet({required String amount}) async {
|
||||
try {
|
||||
await Stripe.instance.presentPaymentSheet().then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
completeOrder();
|
||||
});
|
||||
} on StripeException catch (e) {
|
||||
var lo1 = jsonEncode(e);
|
||||
var lo2 = jsonDecode(lo1);
|
||||
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
|
||||
ShowToastDialog.showToast(lom.error.message);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future createStripeIntent({required String amount}) async {
|
||||
try {
|
||||
Map<String, dynamic> body = {
|
||||
'amount': ((double.parse(amount) * 100).round()).toString(),
|
||||
'currency': "USD",
|
||||
'payment_method_types[]': 'card',
|
||||
"description": "Strip Payment",
|
||||
"shipping[name]": Constant.userModel!.fullName(),
|
||||
"shipping[address][line1]": "510 Townsend St",
|
||||
"shipping[address][postal_code]": "98140",
|
||||
"shipping[address][city]": "San Francisco",
|
||||
"shipping[address][state]": "CA",
|
||||
"shipping[address][country]": "US",
|
||||
};
|
||||
var stripeSecret = stripeModel.value.stripeSecret;
|
||||
var response = await http.post(
|
||||
Uri.parse('https://api.stripe.com/v1/payment_intents'),
|
||||
body: body,
|
||||
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
);
|
||||
|
||||
return jsonDecode(response.body);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//mercadoo
|
||||
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
|
||||
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"items": [
|
||||
{
|
||||
"title": "Test",
|
||||
"description": "Test Payment",
|
||||
"quantity": 1,
|
||||
"currency_id": "BRL", // or your preferred currency
|
||||
"unit_price": double.parse(amount),
|
||||
},
|
||||
],
|
||||
"payer": {"email": Constant.userModel!.email},
|
||||
"back_urls": {"failure": "${Constant.globalUrl}payment/failure", "pending": "${Constant.globalUrl}payment/pending", "success": "${Constant.globalUrl}payment/success"},
|
||||
"auto_return": "approved",
|
||||
// Automatically return after payment is approved
|
||||
});
|
||||
|
||||
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Error creating preference: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Paypal
|
||||
void paypalPaymentSheet(String amount, context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(BuildContext context) => UsePaypal(
|
||||
sandboxMode: payPalModel.value.isLive == true ? false : true,
|
||||
clientId: payPalModel.value.paypalClient ?? '',
|
||||
secretKey: payPalModel.value.paypalSecret ?? '',
|
||||
returnURL: "com.parkme://paypalpay",
|
||||
cancelURL: "com.parkme://paypalpay",
|
||||
transactions: [
|
||||
{
|
||||
"amount": {
|
||||
"total": amount,
|
||||
"currency": "USD",
|
||||
"details": {"subtotal": amount},
|
||||
},
|
||||
},
|
||||
],
|
||||
note: "Contact us for any questions on your order.",
|
||||
onSuccess: (Map params) async {
|
||||
completeOrder();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
},
|
||||
onError: (error) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
onCancel: (params) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///PayStack Payment Method
|
||||
Future<void> payStackPayment(String totalAmount) async {
|
||||
await PayStackURLGen.payStackURLGen(
|
||||
amount: (double.parse(totalAmount) * 100).toString(),
|
||||
currency: "ZAR",
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
userModel: Constant.userModel!,
|
||||
).then((value) async {
|
||||
if (value != null) {
|
||||
PayStackUrlModel payStackModel0 = value;
|
||||
Get.to(
|
||||
PayStackScreen(
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
callBackUrl: payStackModel.value.callbackURL.toString(),
|
||||
initialURl: payStackModel0.data.authorizationUrl,
|
||||
amount: totalAmount,
|
||||
reference: payStackModel0.data.reference,
|
||||
),
|
||||
)!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//flutter wave Payment Method
|
||||
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
|
||||
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
|
||||
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"tx_ref": _ref,
|
||||
"amount": amount,
|
||||
"currency": "NGN",
|
||||
"redirect_url": "${Constant.globalUrl}payment/success",
|
||||
"payment_options": "ussd, card, barter, payattitude",
|
||||
"customer": {
|
||||
"email": Constant.userModel!.email.toString(),
|
||||
"phonenumber": Constant.userModel!.phoneNumber, // Add a real phone number
|
||||
"name": Constant.userModel!.fullName(), // Add a real customer name
|
||||
},
|
||||
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
|
||||
});
|
||||
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Payment initialization failed: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? _ref;
|
||||
|
||||
void setRef() {
|
||||
maths.Random numRef = maths.Random();
|
||||
int year = DateTime.now().year;
|
||||
int refNumber = numRef.nextInt(20000);
|
||||
if (Platform.isAndroid) {
|
||||
_ref = "AndroidRef$year$refNumber";
|
||||
} else if (Platform.isIOS) {
|
||||
_ref = "IOSRef$year$refNumber";
|
||||
}
|
||||
}
|
||||
|
||||
// payFast
|
||||
void payFastPayment({required BuildContext context, required String amount}) {
|
||||
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: Constant.userModel!).then((String? value) async {
|
||||
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
|
||||
if (isDone) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///Paytm payment function
|
||||
Future<void> getPaytmCheckSum(context, {required double amount}) async {
|
||||
// final String orderId = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
// String getChecksum = "${Constant.globalUrl}payments/getpaytmchecksum";
|
||||
//
|
||||
// final response = await http.post(
|
||||
// Uri.parse(getChecksum),
|
||||
// headers: {},
|
||||
// body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString()},
|
||||
// );
|
||||
//
|
||||
// final data = jsonDecode(response.body);
|
||||
// await verifyCheckSum(checkSum: data["code"], amount: amount, orderId: orderId).then((value) {
|
||||
// initiatePayment(amount: amount, orderId: orderId).then((value) {
|
||||
// String callback = "";
|
||||
// if (paytmModel.value.isSandboxEnabled == true) {
|
||||
// callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
// } else {
|
||||
// callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
// }
|
||||
//
|
||||
// GetPaymentTxtTokenModel result = value;
|
||||
// startTransaction(context, txnTokenBy: result.body.txnToken, orderId: orderId, amount: amount, callBackURL: callback, isStaging: paytmModel.value.isSandboxEnabled);
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
Future<void> startTransaction(context, {required String txnTokenBy, required orderId, required double amount, required callBackURL, required isStaging}) async {
|
||||
// try {
|
||||
// var response = AllInOneSdk.startTransaction(
|
||||
// paytmModel.value.paytmMID.toString(),
|
||||
// orderId,
|
||||
// amount.toString(),
|
||||
// txnTokenBy,
|
||||
// callBackURL,
|
||||
// isStaging,
|
||||
// true,
|
||||
// true,
|
||||
// );
|
||||
//
|
||||
// response.then((value) {
|
||||
// if (value!["RESPMSG"] == "Txn Success") {
|
||||
// print("txt done!!");
|
||||
// ShowToastDialog.showToast("Payment Successful!!");
|
||||
// completeOrder();
|
||||
// }
|
||||
// }).catchError((onError) {
|
||||
// if (onError is PlatformException) {
|
||||
// Get.back();
|
||||
//
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// } else {
|
||||
// log("======>>2");
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(onError.message.toString());
|
||||
// }
|
||||
// });
|
||||
// } catch (err) {
|
||||
// Get.back();
|
||||
// ShowToastDialog.showToast(err.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future verifyCheckSum({required String checkSum, required double amount, required orderId}) async {
|
||||
String getChecksum = "${Constant.globalUrl}payments/validatechecksum";
|
||||
final response = await http.post(
|
||||
Uri.parse(getChecksum),
|
||||
headers: {},
|
||||
body: {"mid": paytmModel.value.paytmMID.toString(), "order_id": orderId, "key_secret": paytmModel.value.pAYTMMERCHANTKEY.toString(), "checksum_value": checkSum},
|
||||
);
|
||||
final data = jsonDecode(response.body);
|
||||
return data['status'];
|
||||
}
|
||||
|
||||
Future<GetPaymentTxtTokenModel> initiatePayment({required double amount, required orderId}) async {
|
||||
String initiateURL = "${Constant.globalUrl}payments/initiatepaytmpayment";
|
||||
String callback = "";
|
||||
if (paytmModel.value.isSandboxEnabled == true) {
|
||||
callback = "${callback}https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
} else {
|
||||
callback = "${callback}https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId";
|
||||
}
|
||||
final response = await http.post(
|
||||
Uri.parse(initiateURL),
|
||||
headers: {},
|
||||
body: {
|
||||
"mid": paytmModel.value.paytmMID,
|
||||
"order_id": orderId,
|
||||
"key_secret": paytmModel.value.pAYTMMERCHANTKEY,
|
||||
"amount": amount.toString(),
|
||||
"currency": "INR",
|
||||
"callback_url": callback,
|
||||
"custId": FireStoreUtils.getCurrentUid(),
|
||||
"issandbox": paytmModel.value.isSandboxEnabled == true ? "1" : "2",
|
||||
},
|
||||
);
|
||||
log(response.body);
|
||||
final data = jsonDecode(response.body);
|
||||
if (data["body"]["txnToken"] == null || data["body"]["txnToken"].toString().isEmpty) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
}
|
||||
return GetPaymentTxtTokenModel.fromJson(data);
|
||||
}
|
||||
|
||||
///RazorPay payment function
|
||||
final Razorpay razorPay = Razorpay();
|
||||
|
||||
void openCheckout({required amount, required orderId}) async {
|
||||
var options = {
|
||||
'key': razorPayModel.value.razorpayKey,
|
||||
'amount': amount * 100,
|
||||
'name': 'GoRide',
|
||||
'order_id': orderId,
|
||||
"currency": "INR",
|
||||
'description': 'wallet Topup',
|
||||
'retry': {'enabled': true, 'max_count': 1},
|
||||
'send_sms_hash': true,
|
||||
'prefill': {'contact': Constant.userModel!.phoneNumber, 'email': Constant.userModel!.email},
|
||||
'external': {
|
||||
'wallets': ['paytm'],
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
razorPay.open(options);
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void handlePaymentSuccess(PaymentSuccessResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
}
|
||||
|
||||
void handleExternalWaller(ExternalWalletResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Processing!! via".tr);
|
||||
}
|
||||
|
||||
void handlePaymentError(PaymentFailureResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed!!".tr);
|
||||
}
|
||||
|
||||
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
|
||||
final currentDate = DateTime.now();
|
||||
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
|
||||
}
|
||||
|
||||
//Midtrans payment
|
||||
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
|
||||
await createPaymentLink(amount: amount).then((url) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (url != '') {
|
||||
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> createPaymentLink({required var amount}) async {
|
||||
var ordersId = const Uuid().v1();
|
||||
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!)},
|
||||
body: jsonEncode({
|
||||
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
|
||||
'usage_limit': 2,
|
||||
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
String generateBasicAuthHeader(String apiKey) {
|
||||
String credentials = '$apiKey:';
|
||||
String base64Encoded = base64Encode(utf8.encode(credentials));
|
||||
return 'Basic $base64Encoded';
|
||||
}
|
||||
|
||||
//Orangepay payment
|
||||
static String accessToken = '';
|
||||
static String payToken = '';
|
||||
static String orderId = '';
|
||||
static String amount = '';
|
||||
|
||||
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
|
||||
reset();
|
||||
var id = const Uuid().v4();
|
||||
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
|
||||
ShowToastDialog.closeLoader();
|
||||
if (paymentURL.toString() != '') {
|
||||
Get.to(() => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
}
|
||||
|
||||
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
|
||||
String apiUrl = 'https://api.orange.com/oauth/v3/token';
|
||||
Map<String, String> requestBody = {'grant_type': 'client_credentials'};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{'Authorization': "Basic ${orangeMoneyModel.value.auth!}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
// Handle the response
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
|
||||
accessToken = responseData['access_token'];
|
||||
// ignore: use_build_context_synchronously
|
||||
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
|
||||
orderId = orderIdData;
|
||||
amount = amountData;
|
||||
String apiUrl = orangeMoneyModel.value.isSandbox! == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
|
||||
Map<String, String> requestBody = {
|
||||
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
|
||||
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
|
||||
"order_id": orderId,
|
||||
"amount": amount,
|
||||
"reference": 'Y-Note Test',
|
||||
"lang": "en",
|
||||
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
|
||||
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
|
||||
"notif_url": orangeMoneyModel.value.notifUrl!.toString(),
|
||||
};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
body: json.encode(requestBody),
|
||||
);
|
||||
|
||||
// Handle the response
|
||||
if (response.statusCode == 201) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
if (responseData['message'] == 'OK') {
|
||||
payToken = responseData['pay_token'];
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
accessToken = '';
|
||||
payToken = '';
|
||||
amount = '';
|
||||
}
|
||||
|
||||
//XenditPayment
|
||||
Future<void> xenditPayment(context, amount) async {
|
||||
await createXenditInvoice(amount: amount).then((model) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (model.id != null) {
|
||||
Get.to(() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
completeOrder();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<XenditModel> createXenditInvoice({required var amount}) async {
|
||||
const url = 'https://api.xendit.co/v2/invoices';
|
||||
var headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
|
||||
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
|
||||
};
|
||||
|
||||
final body = jsonEncode({
|
||||
'external_id': const Uuid().v1(),
|
||||
'amount': amount,
|
||||
'payer_email': 'customer@domain.com',
|
||||
'description': 'Test - VA Successful invoice payment',
|
||||
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(Uri.parse(url), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
|
||||
return model;
|
||||
} else {
|
||||
return XenditModel();
|
||||
}
|
||||
} catch (e) {
|
||||
return XenditModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
137
lib/controllers/rental_review_controller.dart
Normal file
137
lib/controllers/rental_review_controller.dart
Normal file
@@ -0,0 +1,137 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../constant/collection_name.dart';
|
||||
import '../models/rating_model.dart';
|
||||
import '../models/rental_order_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../constant/constant.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class RentalReviewController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
/// Order from arguments
|
||||
final Rx<RentalOrderModel?> order = Rx<RentalOrderModel?>(null);
|
||||
|
||||
/// Rating data
|
||||
final Rx<RatingModel?> ratingModel = Rx<RatingModel?>(null);
|
||||
final RxDouble ratings = 0.0.obs;
|
||||
final Rx<TextEditingController> comment = TextEditingController().obs;
|
||||
|
||||
/// Driver (to be reviewed)
|
||||
final Rx<UserModel?> driverUser = Rx<UserModel?>(null);
|
||||
|
||||
/// Review stats
|
||||
final RxInt futureCount = 0.obs;
|
||||
final RxInt futureSum = 0.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
final args = Get.arguments;
|
||||
if (args != null && args['order'] != null) {
|
||||
order.value = args['order'] as RentalOrderModel;
|
||||
getReview();
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch old review + driver stats
|
||||
Future<void> getReview() async {
|
||||
await FireStoreUtils.getReviewsbyID(order.value?.id ?? "").then((value) {
|
||||
if (value != null) {
|
||||
ratingModel.value = value;
|
||||
ratings.value = value.rating ?? 0;
|
||||
comment.value.text = value.comment ?? "";
|
||||
}
|
||||
});
|
||||
|
||||
await FireStoreUtils.getUserProfile(order.value?.driverId ?? '').then((value) {
|
||||
if (value != null) {
|
||||
driverUser.value = value;
|
||||
|
||||
final int userReviewsCount = int.tryParse(driverUser.value!.reviewsCount?.toString() ?? "0") ?? 0;
|
||||
final int userReviewsSum = int.tryParse(driverUser.value!.reviewsSum?.toString() ?? "0") ?? 0;
|
||||
|
||||
if (ratingModel.value != null) {
|
||||
final int oldRating = ratingModel.value?.rating?.toInt() ?? 0;
|
||||
futureCount.value = userReviewsCount - 1;
|
||||
futureSum.value = userReviewsSum - oldRating;
|
||||
} else {
|
||||
futureCount.value = userReviewsCount;
|
||||
futureSum.value = userReviewsSum;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
/// Save / update review
|
||||
Future<void> submitReview() async {
|
||||
if (comment.value.text.trim().isEmpty || ratings.value == 0) {
|
||||
ShowToastDialog.showToast("Please provide rating and comment".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowToastDialog.showLoader("Submit in...".tr);
|
||||
|
||||
final user = await FireStoreUtils.getUserProfile(order.value?.driverId ?? '');
|
||||
|
||||
if (user != null) {
|
||||
user.reviewsCount = (futureCount.value + 1).toString();
|
||||
user.reviewsSum = (futureSum.value + ratings.value.toInt()).toString();
|
||||
}
|
||||
if (ratingModel.value != null) {
|
||||
/// Update existing review
|
||||
final updatedRating = RatingModel(
|
||||
id: ratingModel.value!.id,
|
||||
comment: comment.value.text,
|
||||
photos: ratingModel.value?.photos ?? [],
|
||||
rating: ratings.value,
|
||||
orderId: ratingModel.value!.orderId,
|
||||
driverId: ratingModel.value!.driverId,
|
||||
customerId: ratingModel.value!.customerId,
|
||||
vendorId: ratingModel.value?.vendorId,
|
||||
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
|
||||
profile: Constant.userModel?.profilePictureURL,
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
await FireStoreUtils.updateReviewById(updatedRating);
|
||||
if (user != null) {
|
||||
await FireStoreUtils.updateUser(user);
|
||||
}
|
||||
} else {
|
||||
/// New review
|
||||
final docRef = FireStoreUtils.fireStore.collection(CollectionName.itemsReview).doc();
|
||||
final newRating = RatingModel(
|
||||
id: docRef.id,
|
||||
comment: comment.value.text,
|
||||
photos: [],
|
||||
rating: ratings.value,
|
||||
orderId: order.value?.id,
|
||||
driverId: order.value?.driverId.toString(),
|
||||
customerId: Constant.userModel?.id,
|
||||
uname: "${Constant.userModel?.firstName ?? ''} ${Constant.userModel?.lastName ?? ''}",
|
||||
profile: Constant.userModel?.profilePictureURL,
|
||||
createdAt: Timestamp.now(),
|
||||
);
|
||||
|
||||
await FireStoreUtils.updateReviewById(newRating);
|
||||
if (user != null) {
|
||||
await FireStoreUtils.updateUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.back(result: true);
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
comment.value.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
300
lib/controllers/restaurant_details_controller.dart
Normal file
300
lib/controllers/restaurant_details_controller.dart
Normal file
@@ -0,0 +1,300 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/brands_model.dart';
|
||||
import 'package:customer/models/cart_product_model.dart';
|
||||
import 'package:customer/models/coupon_model.dart';
|
||||
import 'package:customer/models/favourite_item_model.dart';
|
||||
import 'package:customer/models/favourite_model.dart';
|
||||
import 'package:customer/models/product_model.dart';
|
||||
import 'package:customer/models/vendor_category_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../models/attributes_model.dart';
|
||||
import '../service/cart_provider.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class RestaurantDetailsController extends GetxController {
|
||||
Rx<TextEditingController> searchEditingController = TextEditingController().obs;
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
Rx<PageController> pageController = PageController().obs;
|
||||
RxInt currentPage = 0.obs;
|
||||
|
||||
RxBool isVag = false.obs;
|
||||
RxBool isNonVag = false.obs;
|
||||
RxBool isMenuOpen = false.obs;
|
||||
|
||||
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
|
||||
RxList<FavouriteItemModel> favouriteItemList = <FavouriteItemModel>[].obs;
|
||||
RxList<ProductModel> allProductList = <ProductModel>[].obs;
|
||||
RxList<ProductModel> productList = <ProductModel>[].obs;
|
||||
RxList<VendorCategoryModel> vendorCategoryList = <VendorCategoryModel>[].obs;
|
||||
|
||||
RxList<CouponModel> couponList = <CouponModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void animateSlider() {
|
||||
if (vendorModel.value.photos != null && vendorModel.value.photos!.isNotEmpty) {
|
||||
Timer.periodic(const Duration(seconds: 2), (Timer timer) {
|
||||
if (currentPage < vendorModel.value.photos!.length - 1) {
|
||||
currentPage++;
|
||||
} else {
|
||||
currentPage.value = 0;
|
||||
}
|
||||
|
||||
if (pageController.value.hasClients) {
|
||||
pageController.value.animateToPage(currentPage.value, duration: const Duration(milliseconds: 300), curve: Curves.easeIn);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Rx<VendorModel> vendorModel = VendorModel().obs;
|
||||
|
||||
final CartProvider cartProvider = CartProvider();
|
||||
|
||||
Future<void> getArgument() async {
|
||||
cartProvider.cartStream.listen((event) async {
|
||||
cartItem.clear();
|
||||
cartItem.addAll(event);
|
||||
});
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
vendorModel.value = argumentData['vendorModel'];
|
||||
}
|
||||
animateSlider();
|
||||
statusCheck();
|
||||
|
||||
await getProduct();
|
||||
|
||||
isLoading.value = false;
|
||||
await getFavouriteList();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
RxList<BrandsModel> brandList = <BrandsModel>[].obs;
|
||||
|
||||
Future<void> getProduct() async {
|
||||
await FireStoreUtils.getProductByVendorId(vendorModel.value.id.toString()).then((value) {
|
||||
if ((Constant.isSubscriptionModelApplied == true || vendorModel.value.adminCommission?.isEnabled == true) && vendorModel.value.subscriptionPlan != null) {
|
||||
if (vendorModel.value.subscriptionPlan?.itemLimit == '-1') {
|
||||
allProductList.value = value;
|
||||
productList.value = value;
|
||||
} else {
|
||||
int selectedProduct =
|
||||
value.length < int.parse(vendorModel.value.subscriptionPlan?.itemLimit ?? '0') ? (value.isEmpty ? 0 : (value.length)) : int.parse(vendorModel.value.subscriptionPlan?.itemLimit ?? '0');
|
||||
allProductList.value = value.sublist(0, selectedProduct);
|
||||
productList.value = value.sublist(0, selectedProduct);
|
||||
}
|
||||
} else {
|
||||
allProductList.value = value;
|
||||
productList.value = value;
|
||||
}
|
||||
});
|
||||
|
||||
for (var element in productList) {
|
||||
await FireStoreUtils.getVendorCategoryById(element.categoryID.toString()).then((value) {
|
||||
if (value != null) {
|
||||
vendorCategoryList.add(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await FireStoreUtils.getBrandList().then((value) {
|
||||
brandList.value = value;
|
||||
});
|
||||
|
||||
var seen = <String>{};
|
||||
vendorCategoryList.value = vendorCategoryList.where((element) => seen.add(element.id.toString())).toList();
|
||||
}
|
||||
|
||||
void searchProduct(String name) {
|
||||
if (name.isEmpty) {
|
||||
productList.clear();
|
||||
productList.addAll(allProductList);
|
||||
} else {
|
||||
isVag.value = false;
|
||||
isNonVag.value = false;
|
||||
productList.value = allProductList.where((p0) => p0.name!.toLowerCase().contains(name.toLowerCase())).toList();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void filterRecord() {
|
||||
if (isVag.value == true && isNonVag.value == true) {
|
||||
productList.value = allProductList.where((p0) => p0.nonveg == true || p0.nonveg == false).toList();
|
||||
} else if (isVag.value == true && isNonVag.value == false) {
|
||||
productList.value = allProductList.where((p0) => p0.nonveg == false).toList();
|
||||
} else if (isVag.value == false && isNonVag.value == true) {
|
||||
productList.value = allProductList.where((p0) => p0.nonveg == true).toList();
|
||||
} else if (isVag.value == false && isNonVag.value == false) {
|
||||
productList.value = allProductList.where((p0) => p0.nonveg == true || p0.nonveg == false).toList();
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<ProductModel>> getProductByCategory(VendorCategoryModel vendorCategoryModel) async {
|
||||
return productList.where((p0) => p0.categoryID == vendorCategoryModel.id).toList();
|
||||
}
|
||||
|
||||
Future<void> getFavouriteList() async {
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getFavouriteRestaurant().then((value) {
|
||||
favouriteList.value = value;
|
||||
});
|
||||
|
||||
await FireStoreUtils.getFavouriteItem().then((value) {
|
||||
favouriteItemList.value = value;
|
||||
});
|
||||
|
||||
await FireStoreUtils.getOfferByVendorId(vendorModel.value.id.toString()).then((value) {
|
||||
couponList.value = value;
|
||||
});
|
||||
}
|
||||
await getAttributeData();
|
||||
update();
|
||||
}
|
||||
|
||||
RxBool isOpen = false.obs;
|
||||
|
||||
void statusCheck() {
|
||||
final now = DateTime.now();
|
||||
var day = DateFormat('EEEE', 'en_US').format(now);
|
||||
var date = DateFormat('dd-MM-yyyy').format(now);
|
||||
for (var element in vendorModel.value.workingHours ?? []) {
|
||||
if (day == element.day.toString()) {
|
||||
if (element.timeslot!.isNotEmpty) {
|
||||
for (var element in element.timeslot!) {
|
||||
var start = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.from}");
|
||||
var end = DateFormat("dd-MM-yyyy HH:mm").parse("$date ${element.to}");
|
||||
if (isCurrentDateInRange(start, end)) {
|
||||
isOpen.value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getBrandName(String brandId) {
|
||||
String brandName = '';
|
||||
for (var element in brandList) {
|
||||
if (element.id == brandId) {
|
||||
brandName = element.title ?? '';
|
||||
}
|
||||
}
|
||||
return brandName;
|
||||
}
|
||||
|
||||
bool isCurrentDateInRange(DateTime startDate, DateTime endDate) {
|
||||
print(startDate);
|
||||
print(endDate);
|
||||
final currentDate = DateTime.now();
|
||||
print(currentDate);
|
||||
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
|
||||
}
|
||||
|
||||
RxList<AttributesModel> attributesList = <AttributesModel>[].obs;
|
||||
RxList selectedVariants = [].obs;
|
||||
RxList selectedIndexVariants = [].obs;
|
||||
RxList selectedIndexArray = [].obs;
|
||||
|
||||
RxList selectedAddOns = [].obs;
|
||||
|
||||
RxInt quantity = 1.obs;
|
||||
|
||||
String calculatePrice(ProductModel productModel) {
|
||||
String mainPrice = "0";
|
||||
String variantPrice = "0";
|
||||
String adOnsPrice = "0";
|
||||
|
||||
if (productModel.itemAttribute != null) {
|
||||
if (productModel.itemAttribute!.variants!.where((element) => element.variantSku == selectedVariants.join('-')).isNotEmpty) {
|
||||
variantPrice = Constant.productCommissionPrice(
|
||||
vendorModel.value,
|
||||
productModel.itemAttribute!.variants!.where((element) => element.variantSku == selectedVariants.join('-')).first.variantPrice ?? '0',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
String price = Constant.productCommissionPrice(vendorModel.value, productModel.price.toString());
|
||||
String disPrice = double.parse(productModel.disPrice.toString()) <= 0 ? "0" : Constant.productCommissionPrice(vendorModel.value, productModel.disPrice.toString());
|
||||
if (double.parse(disPrice) <= 0) {
|
||||
variantPrice = price;
|
||||
} else {
|
||||
variantPrice = disPrice;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < productModel.addOnsPrice!.length; i++) {
|
||||
if (selectedAddOns.contains(productModel.addOnsTitle![i]) == true) {
|
||||
adOnsPrice = (double.parse(adOnsPrice.toString()) + double.parse(Constant.productCommissionPrice(vendorModel.value, productModel.addOnsPrice![i].toString()))).toString();
|
||||
}
|
||||
}
|
||||
adOnsPrice = (quantity.value * double.parse(adOnsPrice)).toString();
|
||||
mainPrice = ((double.parse(variantPrice.toString()) * double.parse(quantity.value.toString())) + double.parse(adOnsPrice.toString())).toString();
|
||||
return mainPrice;
|
||||
}
|
||||
|
||||
Future<void> getAttributeData() async {
|
||||
await FireStoreUtils.getAttributes().then((value) {
|
||||
if (value != null) {
|
||||
attributesList.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> addToCart({required ProductModel productModel, required String price, required String discountPrice, required bool isIncrement, required int quantity, VariantInfo? variantInfo}) async {
|
||||
CartProductModel cartProductModel = CartProductModel();
|
||||
|
||||
String adOnsPrice = "0";
|
||||
for (int i = 0; i < productModel.addOnsPrice!.length; i++) {
|
||||
if (selectedAddOns.contains(productModel.addOnsTitle![i]) == true && productModel.addOnsPrice![i] != '0') {
|
||||
adOnsPrice = (double.parse(adOnsPrice.toString()) + double.parse(Constant.productCommissionPrice(vendorModel.value, productModel.addOnsPrice![i].toString()))).toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (variantInfo != null) {
|
||||
cartProductModel.id = "${productModel.id!}~${variantInfo.variantId.toString()}";
|
||||
cartProductModel.name = productModel.name!;
|
||||
cartProductModel.photo = productModel.photo!;
|
||||
cartProductModel.categoryId = productModel.categoryID!;
|
||||
cartProductModel.price = price;
|
||||
cartProductModel.discountPrice = discountPrice;
|
||||
cartProductModel.vendorID = vendorModel.value.id;
|
||||
cartProductModel.quantity = quantity;
|
||||
cartProductModel.variantInfo = variantInfo;
|
||||
cartProductModel.extrasPrice = adOnsPrice;
|
||||
cartProductModel.extras = selectedAddOns.isEmpty ? [] : selectedAddOns;
|
||||
} else {
|
||||
cartProductModel.id = productModel.id!;
|
||||
cartProductModel.name = productModel.name!;
|
||||
cartProductModel.photo = productModel.photo!;
|
||||
cartProductModel.categoryId = productModel.categoryID!;
|
||||
cartProductModel.price = price;
|
||||
cartProductModel.discountPrice = discountPrice;
|
||||
cartProductModel.vendorID = vendorModel.value.id;
|
||||
cartProductModel.quantity = quantity;
|
||||
cartProductModel.variantInfo = VariantInfo();
|
||||
cartProductModel.extrasPrice = adOnsPrice;
|
||||
cartProductModel.extras = selectedAddOns.isEmpty ? [] : selectedAddOns;
|
||||
}
|
||||
|
||||
if (isIncrement) {
|
||||
await cartProvider.addToCart(Get.context!, cartProductModel, quantity);
|
||||
} else {
|
||||
await cartProvider.removeFromCart(cartProductModel, quantity);
|
||||
}
|
||||
log("===> new ${cartItem.length}");
|
||||
update();
|
||||
}
|
||||
}
|
||||
49
lib/controllers/restaurant_list_controller.dart
Normal file
49
lib/controllers/restaurant_list_controller.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/favourite_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class RestaurantListController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<VendorModel> vendorList = <VendorModel>[].obs;
|
||||
RxList<VendorModel> vendorSearchList = <VendorModel>[].obs;
|
||||
|
||||
RxString title = "Restaurants".obs;
|
||||
|
||||
RxList<FavouriteModel> favouriteList = <FavouriteModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
vendorList.value = argumentData['vendorList'];
|
||||
vendorSearchList.value = argumentData['vendorList'];
|
||||
title.value = argumentData['title'] ?? "Restaurants";
|
||||
}
|
||||
|
||||
await getFavouriteRestaurant();
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getFavouriteRestaurant() async {
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getFavouriteRestaurant().then((value) {
|
||||
favouriteList.value = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
vendorSearchList.clear();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
36
lib/controllers/review_list_controller.dart
Normal file
36
lib/controllers/review_list_controller.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'package:customer/models/rating_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ReviewListController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Rx<VendorModel> vendorModel = VendorModel().obs;
|
||||
RxList<RatingModel> ratingList = <RatingModel>[].obs;
|
||||
|
||||
void getArgument() {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
vendorModel.value = argumentData['vendorModel'];
|
||||
getAllReview();
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getAllReview() async {
|
||||
await FireStoreUtils.getVendorReviews(vendorModel.value.id.toString()).then(
|
||||
(value) {
|
||||
ratingList.value = value;
|
||||
},
|
||||
);
|
||||
update();
|
||||
}
|
||||
}
|
||||
26
lib/controllers/scan_qr_code_controller.dart
Normal file
26
lib/controllers/scan_qr_code_controller.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ScanQrCodeController extends GetxController {
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
RxList<VendorModel> allNearestRestaurant = <VendorModel>[].obs;
|
||||
|
||||
void getData() {
|
||||
FireStoreUtils.getAllNearestRestaurant().listen((event) async {
|
||||
allNearestRestaurant.addAll(event);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
72
lib/controllers/search_controller.dart
Normal file
72
lib/controllers/search_controller.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/product_model.dart';
|
||||
import 'package:customer/models/vendor_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class SearchScreenController extends GetxController {
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getArgument();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<VendorModel> vendorList = <VendorModel>[].obs;
|
||||
RxList<VendorModel> vendorSearchList = <VendorModel>[].obs;
|
||||
|
||||
RxList<ProductModel> productList = <ProductModel>[].obs;
|
||||
RxList<ProductModel> productSearchList = <ProductModel>[].obs;
|
||||
|
||||
Future<void> getArgument() async {
|
||||
dynamic argumentData = Get.arguments;
|
||||
if (argumentData != null) {
|
||||
vendorList.value = argumentData['vendorList'];
|
||||
productList.clear();
|
||||
}
|
||||
isLoading.value = false;
|
||||
|
||||
for (var element in vendorList) {
|
||||
await FireStoreUtils.getProductByVendorId(element.id.toString()).then((value) {
|
||||
if ((Constant.isSubscriptionModelApplied == true || element.adminCommission?.isEnabled == true) && element.subscriptionPlan != null) {
|
||||
if (element.subscriptionPlan?.itemLimit == '-1') {
|
||||
productList.addAll(value);
|
||||
} else {
|
||||
int selectedProduct =
|
||||
value.length < int.parse(element.subscriptionPlan?.itemLimit ?? '0') ? (value.isEmpty ? 0 : (value.length)) : int.parse(element.subscriptionPlan?.itemLimit ?? '0');
|
||||
productList.addAll(value.sublist(0, selectedProduct));
|
||||
}
|
||||
} else {
|
||||
productList.addAll(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void onSearchTextChanged(String text) {
|
||||
if (text.isEmpty) {
|
||||
return;
|
||||
}
|
||||
vendorSearchList.clear();
|
||||
productSearchList.clear();
|
||||
for (var element in vendorList) {
|
||||
if (element.title!.toLowerCase().contains(text.toLowerCase())) {
|
||||
vendorSearchList.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
for (var element in productList) {
|
||||
if (element.name!.toLowerCase().contains(text.toLowerCase())) {
|
||||
productSearchList.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
vendorSearchList.clear();
|
||||
productSearchList.clear();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
180
lib/controllers/service_list_controller.dart
Normal file
180
lib/controllers/service_list_controller.dart
Normal file
@@ -0,0 +1,180 @@
|
||||
import 'package:customer/models/section_model.dart';
|
||||
import 'package:customer/screen_ui/cab_service_screens/cab_dashboard_screen.dart';
|
||||
import 'package:customer/screen_ui/ecommarce/dash_board_e_commerce_screen.dart';
|
||||
import 'package:customer/screen_ui/parcel_service/parcel_dashboard_screen.dart';
|
||||
import 'package:customer/screen_ui/rental_service/rental_dashboard_screen.dart';
|
||||
import 'package:customer/service/cart_provider.dart';
|
||||
import 'package:customer/service/database_helper.dart';
|
||||
import 'package:customer/service/fire_store_utils.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/models/currency_model.dart';
|
||||
import 'package:customer/themes/app_them_data.dart';
|
||||
import 'package:customer/themes/round_button_fill.dart';
|
||||
import 'package:customer/themes/show_toast_dialog.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart' as auth;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../screen_ui/auth_screens/login_screen.dart';
|
||||
import '../screen_ui/multi_vendor_service/dash_board_screens/dash_board_screen.dart';
|
||||
import '../screen_ui/on_demand_service/on_demand_dashboard_screen.dart';
|
||||
import '../service/notification_service.dart';
|
||||
|
||||
class ServiceListController extends GetxController {
|
||||
var isLoading = false.obs;
|
||||
var serviceListBanner = <dynamic>[].obs;
|
||||
var sectionList = <SectionModel>[].obs;
|
||||
var currencyData = CurrencyModel().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
loadData();
|
||||
}
|
||||
|
||||
Future<void> loadData() async {
|
||||
isLoading.value = true;
|
||||
|
||||
// fetch currency
|
||||
CurrencyModel? currency = await FireStoreUtils.getCurrency();
|
||||
|
||||
currencyData.value = currency ?? CurrencyModel(id: "", code: "USD", decimal: 2, isactive: true, name: "US Dollar", symbol: "\$", symbolatright: false);
|
||||
|
||||
// Load sections
|
||||
List<SectionModel> sections = await FireStoreUtils.getSections();
|
||||
sectionList.assignAll(sections);
|
||||
|
||||
await FireStoreUtils.getSectionBannerList().then((value) {
|
||||
serviceListBanner.assignAll(value);
|
||||
});
|
||||
await getZone();
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> getZone() async {
|
||||
await FireStoreUtils.getZone().then((value) {
|
||||
if (value != null) {
|
||||
Constant.zoneList = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> onServiceTap(BuildContext context, SectionModel sectionModel) async {
|
||||
try {
|
||||
ShowToastDialog.showLoader("Please wait...".tr);
|
||||
Constant.sectionConstantModel = sectionModel;
|
||||
AppThemeData.primary300 = Color(int.tryParse(sectionModel.color?.replaceFirst("#", "0xff") ?? '') ?? 0xff2196F3);
|
||||
if (auth.FirebaseAuth.instance.currentUser != null) {
|
||||
String uid = auth.FirebaseAuth.instance.currentUser!.uid;
|
||||
UserModel? user = await FireStoreUtils.getUserProfile(uid);
|
||||
if (user != null && user.role == Constant.userRoleCustomer) {
|
||||
user.fcmToken = await NotificationService.getToken();
|
||||
await FireStoreUtils.updateUser(user);
|
||||
ShowToastDialog.closeLoader();
|
||||
await _navigate(sectionModel);
|
||||
} else {
|
||||
ShowToastDialog.closeLoader();
|
||||
Get.offAll(() => const LoginScreen());
|
||||
}
|
||||
} else {
|
||||
ShowToastDialog.closeLoader();
|
||||
await _navigate(sectionModel);
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error during service tap: $e");
|
||||
ShowToastDialog.closeLoader();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _navigate(SectionModel sectionModel) async {
|
||||
await FireStoreUtils.getTaxList(sectionModel.id ?? "").then((value) {
|
||||
if (value != null) {
|
||||
Constant.taxList = value;
|
||||
}
|
||||
});
|
||||
|
||||
if (sectionModel.serviceTypeFlag == "ecommerce-service" || sectionModel.serviceTypeFlag == "delivery-service") {
|
||||
if (cartItem.isNotEmpty) {
|
||||
showAlertDialog(Get.context!, UserModel(), sectionModel);
|
||||
} else {
|
||||
if (sectionModel.serviceTypeFlag == "ecommerce-service") {
|
||||
Get.to(DashBoardEcommerceScreen());
|
||||
} else if (sectionModel.serviceTypeFlag == "cab-service") {
|
||||
Get.to(CabDashboardScreen());
|
||||
} else if (sectionModel.serviceTypeFlag == "rental-service") {
|
||||
Get.to(RentalDashboardScreen());
|
||||
} else if (sectionModel.serviceTypeFlag == "parcel_delivery") {
|
||||
Get.to(ParcelDashboardScreen());
|
||||
} else if (sectionModel.serviceTypeFlag == "ondemand-service") {
|
||||
Get.to(OnDemandDashboardScreen());
|
||||
} else {
|
||||
Get.to(() => DashBoardScreen());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (sectionModel.serviceTypeFlag == "ecommerce-service") {
|
||||
Get.to(DashBoardEcommerceScreen());
|
||||
} else if (sectionModel.serviceTypeFlag == "cab-service") {
|
||||
Get.to(CabDashboardScreen());
|
||||
} else if (sectionModel.serviceTypeFlag == "rental-service") {
|
||||
Get.to(RentalDashboardScreen());
|
||||
} else if (sectionModel.serviceTypeFlag == "parcel_delivery") {
|
||||
Get.to(ParcelDashboardScreen());
|
||||
} else if (sectionModel.serviceTypeFlag == "ondemand-service") {
|
||||
Get.to(OnDemandDashboardScreen());
|
||||
} else {
|
||||
Get.to(() => DashBoardScreen());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final CartProvider cartProvider = CartProvider();
|
||||
|
||||
void showAlertDialog(BuildContext context, UserModel user, SectionModel sectionModel) {
|
||||
Get.defaultDialog(
|
||||
title: "Alert!",
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text("If you select this Section/Service, your previously added items will be removed from the cart.".tr, textAlign: TextAlign.center),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: RoundedButtonFill(
|
||||
height: 5.5,
|
||||
title: "Cancel".tr,
|
||||
onPress: () {
|
||||
Get.back();
|
||||
},
|
||||
color: AppThemeData.grey900,
|
||||
textColor: AppThemeData.surface,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: RoundedButtonFill(
|
||||
title: "OK".tr,
|
||||
height: 5.5,
|
||||
onPress: () async {
|
||||
DatabaseHelper.instance.deleteAllCartProducts();
|
||||
cartProvider.clearDatabase();
|
||||
Get.back();
|
||||
if (sectionModel.serviceTypeFlag == "ecommerce-service") {
|
||||
Get.off(() => DashBoardEcommerceScreen());
|
||||
} else {
|
||||
Get.to(() => DashBoardScreen());
|
||||
}
|
||||
},
|
||||
color: AppThemeData.primary300,
|
||||
textColor: AppThemeData.surface,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [], // 👈 keep this empty since we put buttons in content
|
||||
);
|
||||
}
|
||||
}
|
||||
195
lib/controllers/sign_up_controller.dart
Normal file
195
lib/controllers/sign_up_controller.dart
Normal file
@@ -0,0 +1,195 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/screen_ui/location_enable_screens/location_permission_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart' as auth;
|
||||
import '../constant/constant.dart';
|
||||
import '../models/referral_model.dart';
|
||||
import '../screen_ui/service_home_screen/service_list_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
import '../utils/notification_service.dart';
|
||||
|
||||
class SignUpController extends GetxController {
|
||||
Rx<TextEditingController> firstNameController = TextEditingController().obs;
|
||||
Rx<TextEditingController> lastNameController = TextEditingController().obs;
|
||||
Rx<TextEditingController> emailController = TextEditingController().obs;
|
||||
Rx<TextEditingController> mobileController = TextEditingController().obs;
|
||||
Rx<TextEditingController> countryCodeController = TextEditingController(text: Constant.defaultCountryCode).obs;
|
||||
Rx<TextEditingController> passwordController = TextEditingController().obs;
|
||||
Rx<TextEditingController> confirmPasswordController = TextEditingController().obs;
|
||||
Rx<TextEditingController> referralController = TextEditingController().obs;
|
||||
|
||||
final FocusNode emailFocusNode = FocusNode();
|
||||
final FocusNode passwordFocusNode = FocusNode();
|
||||
|
||||
// State
|
||||
final RxBool isLoading = false.obs;
|
||||
final auth.FirebaseAuth _firebaseAuth = auth.FirebaseAuth.instance;
|
||||
|
||||
RxString type = "email".obs;
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
|
||||
RxBool passwordVisible = true.obs;
|
||||
RxBool conformPasswordVisible = true.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
getArgument();
|
||||
}
|
||||
|
||||
void getArgument() {
|
||||
final args = Get.arguments;
|
||||
type.value = args?['type'] ?? 'email';
|
||||
userModel.value = args?['userModel'] ?? UserModel();
|
||||
|
||||
//Pre-fill fields for Google/Apple signup
|
||||
if (type.value == "google" || type.value == "apple") {
|
||||
firstNameController.value.text = userModel.value.firstName ?? "";
|
||||
lastNameController.value.text = userModel.value.lastName ?? "";
|
||||
emailController.value.text = userModel.value.email ?? "";
|
||||
}
|
||||
|
||||
//mobile number signup
|
||||
if (type.value == "mobileNumber") {
|
||||
mobileController.value.text = userModel.value.phoneNumber ?? "";
|
||||
countryCodeController.value.text = userModel.value.countryCode ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
/// Main Sign-Up Trigger
|
||||
void signUp() async {
|
||||
debugPrint("SIGNUP CALLED!");
|
||||
try {
|
||||
if (!_validateInputs()) return;
|
||||
|
||||
ShowToastDialog.showLoader("Creating account...".tr);
|
||||
|
||||
if (type.value == "mobileNumber") {
|
||||
await _signUpWithMobile();
|
||||
} else {
|
||||
await _signUpWithEmail();
|
||||
}
|
||||
|
||||
ShowToastDialog.closeLoader();
|
||||
} catch (e, st) {
|
||||
ShowToastDialog.closeLoader();
|
||||
debugPrint("SIGNUP OUTER EXCEPTION: $e\n$st");
|
||||
ShowToastDialog.showToast("${'signup_failed'.tr}: $e");
|
||||
}
|
||||
}
|
||||
|
||||
/// Validation Logic
|
||||
bool _validateInputs() {
|
||||
if (firstNameController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter first name".tr);
|
||||
return false;
|
||||
} else if (lastNameController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter last name".tr);
|
||||
return false;
|
||||
} else if (emailController.value.text.isEmpty || !emailController.value.text.isEmail) {
|
||||
ShowToastDialog.showToast("Please enter a valid email address".tr);
|
||||
return false;
|
||||
} else if (mobileController.value.text.isEmpty) {
|
||||
ShowToastDialog.showToast("Please enter a valid phone number".tr);
|
||||
return false;
|
||||
} else if (passwordController.value.text.length < 6) {
|
||||
ShowToastDialog.showToast("Password must be at least 6 characters".tr);
|
||||
return false;
|
||||
} else if (passwordController.value.text != confirmPasswordController.value.text) {
|
||||
ShowToastDialog.showToast("Password and Confirm password do not match".tr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Email Sign-up Flow
|
||||
Future<void> _signUpWithEmail() async {
|
||||
try {
|
||||
final credential = await _firebaseAuth.createUserWithEmailAndPassword(email: emailController.value.text.trim(), password: passwordController.value.text.trim());
|
||||
|
||||
if (credential.user != null) {
|
||||
final newUser = await _buildUserModel(credential.user?.uid ?? '');
|
||||
await _handleReferral(newUser.id ?? '');
|
||||
await FireStoreUtils.updateUser(newUser);
|
||||
// appController.currentUser.value = newUser;
|
||||
_navigateBasedOnAddress(newUser);
|
||||
}
|
||||
} on auth.FirebaseAuthException catch (e) {
|
||||
debugPrint("FirebaseAuthException caught: code=${e.code}, message=${e.message}");
|
||||
if (e.code == 'email-already-in-use') {
|
||||
ShowToastDialog.showToast("Email already in use".tr);
|
||||
} else if (e.code == 'weak-password') {
|
||||
ShowToastDialog.showToast("Password is too weak".tr);
|
||||
} else if (e.code == 'invalid-email') {
|
||||
ShowToastDialog.showToast("Invalid email address".tr);
|
||||
} else {
|
||||
ShowToastDialog.showToast(e.message ?? "signup_failed".tr);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Something went wrong: ${e.toString()}");
|
||||
ShowToastDialog.showToast("${'something_went_wrong'.tr}: ${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Mobile Sign-up Flow
|
||||
Future<void> _signUpWithMobile() async {
|
||||
debugPrint("Signup with mobile called...");
|
||||
try {
|
||||
final uid = FireStoreUtils.getCurrentUid();
|
||||
|
||||
userModel.value = await _buildUserModel(uid);
|
||||
|
||||
await _handleReferral(uid);
|
||||
await FireStoreUtils.updateUser(userModel.value);
|
||||
|
||||
_navigateBasedOnAddress(userModel.value);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast("${'signup_failed'.tr}: $e");
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct UserModel
|
||||
Future<UserModel> _buildUserModel(String uid) async {
|
||||
final fcmToken = await NotificationService.getToken();
|
||||
|
||||
return UserModel(
|
||||
id: uid,
|
||||
firstName: firstNameController.value.text.trim(),
|
||||
lastName: lastNameController.value.text.trim(),
|
||||
email: emailController.value.text.trim().toLowerCase(),
|
||||
phoneNumber: mobileController.value.text.trim(),
|
||||
countryCode: countryCodeController.value.text.trim(),
|
||||
fcmToken: fcmToken,
|
||||
active: true,
|
||||
createdAt: Timestamp.now(),
|
||||
role: Constant.userRoleCustomer,
|
||||
);
|
||||
}
|
||||
|
||||
/// Handle Referral Logic
|
||||
Future<void> _handleReferral(String userId) async {
|
||||
final referralCode = referralController.value.text.trim();
|
||||
final referralBy = referralCode.isNotEmpty ? (await FireStoreUtils.getReferralUserByCode(referralCode))?.id ?? '' : '';
|
||||
|
||||
final referral = ReferralModel(id: userId, referralBy: referralBy, referralCode: Constant.getReferralCode());
|
||||
|
||||
await FireStoreUtils.referralAdd(referral);
|
||||
}
|
||||
|
||||
/// Navigate Based on Shipping Address
|
||||
void _navigateBasedOnAddress(UserModel user) {
|
||||
if (user.shippingAddress?.isNotEmpty == true) {
|
||||
final defaultAddress = user.shippingAddress!.firstWhere((e) => e.isDefault == true, orElse: () => user.shippingAddress!.first);
|
||||
|
||||
/// Save the default address to global constant
|
||||
Constant.selectedLocation = defaultAddress;
|
||||
|
||||
Get.offAll(() => const ServiceListScreen());
|
||||
} else {
|
||||
Get.offAll(() => const LocationPermissionScreen());
|
||||
}
|
||||
}
|
||||
}
|
||||
67
lib/controllers/splash_controller.dart
Normal file
67
lib/controllers/splash_controller.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/screen_ui/maintenance_mode_screen/maintenance_mode_screen.dart';
|
||||
import 'package:customer/screen_ui/service_home_screen/service_list_screen.dart';
|
||||
import 'package:customer/utils/notification_service.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../screen_ui/auth_screens/login_screen.dart';
|
||||
import '../screen_ui/location_enable_screens/location_permission_screen.dart';
|
||||
import '../screen_ui/on_boarding_screen/on_boarding_screen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class SplashController extends GetxController {
|
||||
@override
|
||||
void onInit() {
|
||||
Timer(const Duration(seconds: 3), () => redirectScreen());
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> redirectScreen() async {
|
||||
if (Constant.isMaintenanceModeForCustomer == true) {
|
||||
Get.offAll(const MaintenanceModeScreen());
|
||||
return;
|
||||
}
|
||||
if (Preferences.getBoolean(Preferences.isFinishOnBoardingKey) == false) {
|
||||
Get.offAll(const OnboardingScreen());
|
||||
} else {
|
||||
bool isLogin = await FireStoreUtils.isLogin();
|
||||
if (isLogin == true) {
|
||||
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) async {
|
||||
if (value != null) {
|
||||
UserModel userModel = value;
|
||||
log(userModel.toJson().toString());
|
||||
if (userModel.role == Constant.userRoleCustomer) {
|
||||
if (userModel.active == true) {
|
||||
userModel.fcmToken = await NotificationService.getToken();
|
||||
await FireStoreUtils.updateUser(userModel);
|
||||
if (userModel.shippingAddress != null && userModel.shippingAddress!.isNotEmpty) {
|
||||
if (userModel.shippingAddress!.where((element) => element.isDefault == true).isNotEmpty) {
|
||||
Constant.selectedLocation = userModel.shippingAddress!.where((element) => element.isDefault == true).single;
|
||||
} else {
|
||||
Constant.selectedLocation = userModel.shippingAddress!.first;
|
||||
}
|
||||
Get.offAll(const ServiceListScreen());
|
||||
} else {
|
||||
Get.offAll(const LocationPermissionScreen());
|
||||
}
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
Get.offAll(const LoginScreen());
|
||||
}
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
Get.offAll(const LoginScreen());
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await FirebaseAuth.instance.signOut();
|
||||
Get.offAll(const LoginScreen());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
lib/controllers/theme_controller.dart
Normal file
27
lib/controllers/theme_controller.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../utils/preferences.dart';
|
||||
|
||||
class ThemeController extends GetxController {
|
||||
RxBool isDark = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
loadTheme();
|
||||
}
|
||||
|
||||
void loadTheme() {
|
||||
// Use safe getBoolean from Preferences
|
||||
isDark.value = Preferences.getBoolean(Preferences.themKey);
|
||||
}
|
||||
|
||||
void toggleTheme() {
|
||||
isDark.value = !isDark.value;
|
||||
Preferences.setBoolean(Preferences.themKey, isDark.value);
|
||||
}
|
||||
|
||||
ThemeMode get themeMode => isDark.value ? ThemeMode.dark : ThemeMode.light;
|
||||
}
|
||||
|
||||
|
||||
31
lib/controllers/view_all_category_controller.dart
Normal file
31
lib/controllers/view_all_category_controller.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/vendor_category_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ViewAllCategoryController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
RxList<VendorCategoryModel> vendorCategoryModel = <VendorCategoryModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getCategoryData();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<void> getCategoryData() async {
|
||||
await FireStoreUtils.getVendorCategory().then((value) {
|
||||
vendorCategoryModel.value = value;
|
||||
|
||||
});
|
||||
|
||||
if (Constant.restaurantList != null) {
|
||||
List<String> usedCategoryIds = Constant.restaurantList!.expand((vendor) => vendor.categoryID ?? []).whereType<String>().toSet().toList();
|
||||
vendorCategoryModel.value = vendorCategoryModel.where((category) => usedCategoryIds.contains(category.id)).toList();
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
83
lib/controllers/view_all_popular_service_controller.dart
Normal file
83
lib/controllers/view_all_popular_service_controller.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/controllers/on_demand_home_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../models/favorite_ondemand_service_model.dart';
|
||||
import '../models/provider_serivce_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class ViewAllPopularServiceController extends GetxController {
|
||||
RxList<ProviderServiceModel> providerList = <ProviderServiceModel>[].obs;
|
||||
RxList<ProviderServiceModel> allProviderList = <ProviderServiceModel>[].obs;
|
||||
RxBool isLoading = true.obs;
|
||||
Rx<OnDemandHomeController> onDemandHomeController = Get.find<OnDemandHomeController>().obs;
|
||||
|
||||
final OnDemandHomeController onDemandController = Get.find<OnDemandHomeController>();
|
||||
|
||||
Rx<TextEditingController> searchTextFiledController = TextEditingController().obs;
|
||||
|
||||
RxList<FavouriteOndemandServiceModel> lstFav = <FavouriteOndemandServiceModel>[].obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
getData();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
isLoading.value = true;
|
||||
|
||||
await FireStoreUtils.getProviderFuture()
|
||||
.then((providerServiceList) {
|
||||
Set<String?> uniqueAuthorIds = providerServiceList.map((service) => service.author).toSet();
|
||||
List<String?> listOfUniqueProviders = uniqueAuthorIds.toList();
|
||||
|
||||
List<ProviderServiceModel> filteredProviders = [];
|
||||
|
||||
for (var provider in listOfUniqueProviders) {
|
||||
List<ProviderServiceModel> filteredList = providerServiceList.where((service) => service.author == provider).toList();
|
||||
|
||||
filteredList.sort((a, b) => a.createdAt!.compareTo(b.createdAt!));
|
||||
|
||||
for (int index = 0; index < filteredList.length; index++) {
|
||||
final service = filteredList[index];
|
||||
|
||||
if (Constant.isSubscriptionModelApplied == true || Constant.sectionConstantModel?.adminCommision?.isEnabled == true) {
|
||||
if (service.subscriptionPlan?.itemLimit == "-1") {
|
||||
filteredProviders.add(service);
|
||||
} else {
|
||||
if (index < int.parse(service.subscriptionPlan?.itemLimit ?? '0')) {
|
||||
filteredProviders.add(service);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filteredProviders.add(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allProviderList.value = filteredProviders;
|
||||
providerList.value = filteredProviders;
|
||||
isLoading.value = false;
|
||||
})
|
||||
.catchError((e) {
|
||||
print("Provider error: $e");
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getFavouritesServiceList(FireStoreUtils.getCurrentUid()).then((value) {
|
||||
lstFav.value = value;
|
||||
});
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
void getFilterData(String value) {
|
||||
if (value.isNotEmpty) {
|
||||
providerList.value = allProviderList.where((e) => e.title!.toLowerCase().contains(value.toLowerCase()) || e.title!.startsWith(value)).toList();
|
||||
} else {
|
||||
providerList.assignAll(allProviderList);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
lib/controllers/view_category_service_controller.dart
Normal file
65
lib/controllers/view_category_service_controller.dart
Normal file
@@ -0,0 +1,65 @@
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/controllers/on_demand_home_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../models/provider_serivce_model.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
|
||||
class ViewCategoryServiceController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
RxList<ProviderServiceModel> providerList = <ProviderServiceModel>[].obs;
|
||||
|
||||
RxString categoryId = "".obs, categoryTitle = "".obs;
|
||||
Rx<OnDemandHomeController> onDemandHomeController = Get.find<OnDemandHomeController>().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
final args = Get.arguments as Map<String, dynamic>;
|
||||
categoryId.value = args['categoryId'] ?? "";
|
||||
categoryTitle.value = args['categoryTitle'] ?? "";
|
||||
|
||||
getData();
|
||||
}
|
||||
|
||||
Future<void> getData() async {
|
||||
providerList.clear();
|
||||
isLoading.value = true;
|
||||
|
||||
List<ProviderServiceModel> providerServiceList = await FireStoreUtils.getProviderFuture(categoryId: categoryId.value);
|
||||
|
||||
List<String?> uniqueAuthId = providerServiceList.map((service) => service.author).toList();
|
||||
List<String?> uniqueServiceId = providerServiceList.map((service) => service.id).toList();
|
||||
|
||||
List<ProviderServiceModel> filterByItemLimit = <ProviderServiceModel>[];
|
||||
List<String?> uniqueId = <String>[];
|
||||
|
||||
if ((Constant.isSubscriptionModelApplied == true || Constant.sectionConstantModel!.adminCommision?.isEnabled == true)) {
|
||||
for (var authUser in uniqueAuthId) {
|
||||
List<ProviderServiceModel> listofAllServiceByAuth = await FireStoreUtils.getAllProviderServiceByAuthorId(authUser!);
|
||||
|
||||
for (int i = 0; i < listofAllServiceByAuth.length; i++) {
|
||||
if (listofAllServiceByAuth[i].subscriptionPlan?.itemLimit != null &&
|
||||
(i < int.parse(listofAllServiceByAuth[i].subscriptionPlan?.itemLimit ?? '0') || listofAllServiceByAuth[i].subscriptionPlan?.itemLimit == '-1')) {
|
||||
if (uniqueServiceId.contains(listofAllServiceByAuth[i].id)) {
|
||||
filterByItemLimit.add(listofAllServiceByAuth[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var service in filterByItemLimit) {
|
||||
for (var unique in uniqueServiceId) {
|
||||
if (service.id == unique && !uniqueId.contains(service.id) && service.subscriptionTotalOrders != '0') {
|
||||
uniqueId.add(service.id);
|
||||
providerList.add(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
providerList.addAll(providerServiceList);
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
601
lib/controllers/wallet_controller.dart
Normal file
601
lib/controllers/wallet_controller.dart
Normal file
@@ -0,0 +1,601 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as maths;
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/constant/constant.dart';
|
||||
import 'package:customer/models/payment_model/flutter_wave_model.dart';
|
||||
import 'package:customer/models/payment_model/mercado_pago_model.dart';
|
||||
import 'package:customer/models/payment_model/mid_trans.dart';
|
||||
import 'package:customer/models/payment_model/orange_money.dart';
|
||||
import 'package:customer/models/payment_model/pay_fast_model.dart';
|
||||
import 'package:customer/models/payment_model/pay_stack_model.dart';
|
||||
import 'package:customer/models/payment_model/paypal_model.dart';
|
||||
import 'package:customer/models/payment_model/razorpay_model.dart';
|
||||
import 'package:customer/models/payment_model/stripe_model.dart';
|
||||
import 'package:customer/models/payment_model/xendit.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/models/wallet_transaction_model.dart';
|
||||
import 'package:customer/themes/app_them_data.dart';
|
||||
import 'package:flutter_paypal/flutter_paypal.dart';
|
||||
import 'package:flutter_stripe/flutter_stripe.dart';
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import '../payment/MercadoPagoScreen.dart';
|
||||
import '../payment/PayFastScreen.dart';
|
||||
import '../payment/midtrans_screen.dart';
|
||||
import '../payment/orangePayScreen.dart';
|
||||
import '../payment/paystack/pay_stack_screen.dart';
|
||||
import '../payment/paystack/pay_stack_url_model.dart';
|
||||
import '../payment/paystack/paystack_url_genrater.dart';
|
||||
import '../payment/stripe_failed_model.dart';
|
||||
import '../payment/xenditModel.dart';
|
||||
import '../payment/xenditScreen.dart';
|
||||
import '../service/fire_store_utils.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../themes/show_toast_dialog.dart';
|
||||
|
||||
class WalletController extends GetxController {
|
||||
RxBool isLoading = true.obs;
|
||||
|
||||
Rx<TextEditingController> topUpAmountController = TextEditingController().obs;
|
||||
|
||||
RxList<WalletTransactionModel> walletTransactionList = <WalletTransactionModel>[].obs;
|
||||
|
||||
Rx<UserModel> userModel = UserModel().obs;
|
||||
RxString selectedPaymentMethod = "".obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
getPaymentSettings();
|
||||
getWalletTransaction();
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Rx<PayFastModel> payFastModel = PayFastModel().obs;
|
||||
Rx<MercadoPagoModel> mercadoPagoModel = MercadoPagoModel().obs;
|
||||
Rx<PayPalModel> payPalModel = PayPalModel().obs;
|
||||
Rx<StripeModel> stripeModel = StripeModel().obs;
|
||||
Rx<FlutterWaveModel> flutterWaveModel = FlutterWaveModel().obs;
|
||||
Rx<PayStackModel> payStackModel = PayStackModel().obs;
|
||||
Rx<RazorPayModel> razorPayModel = RazorPayModel().obs;
|
||||
Rx<MidTrans> midTransModel = MidTrans().obs;
|
||||
Rx<OrangeMoney> orangeMoneyModel = OrangeMoney().obs;
|
||||
Rx<Xendit> xenditModel = Xendit().obs;
|
||||
|
||||
Future<void> getPaymentSettings() async {
|
||||
await FireStoreUtils.getPaymentSettingsData().then((value) {
|
||||
payFastModel.value = PayFastModel.fromJson(jsonDecode(Preferences.getString(Preferences.payFastSettings)));
|
||||
mercadoPagoModel.value = MercadoPagoModel.fromJson(jsonDecode(Preferences.getString(Preferences.mercadoPago)));
|
||||
payPalModel.value = PayPalModel.fromJson(jsonDecode(Preferences.getString(Preferences.paypalSettings)));
|
||||
stripeModel.value = StripeModel.fromJson(jsonDecode(Preferences.getString(Preferences.stripeSettings)));
|
||||
flutterWaveModel.value = FlutterWaveModel.fromJson(jsonDecode(Preferences.getString(Preferences.flutterWave)));
|
||||
payStackModel.value = PayStackModel.fromJson(jsonDecode(Preferences.getString(Preferences.payStack)));
|
||||
razorPayModel.value = RazorPayModel.fromJson(jsonDecode(Preferences.getString(Preferences.razorpaySettings)));
|
||||
|
||||
midTransModel.value = MidTrans.fromJson(jsonDecode(Preferences.getString(Preferences.midTransSettings)));
|
||||
orangeMoneyModel.value = OrangeMoney.fromJson(json.decode(Preferences.getString(Preferences.orangeMoneySettings)));
|
||||
xenditModel.value = Xendit.fromJson(jsonDecode(Preferences.getString(Preferences.xenditSettings)));
|
||||
|
||||
Stripe.publishableKey = stripeModel.value.clientpublishableKey.toString();
|
||||
Stripe.merchantIdentifier = 'GoRide';
|
||||
Stripe.instance.applySettings();
|
||||
setRef();
|
||||
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_SUCCESS, handlePaymentSuccess);
|
||||
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET, handleExternalWaller);
|
||||
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, handlePaymentError);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> getWalletTransaction() async {
|
||||
if (Constant.userModel != null) {
|
||||
await FireStoreUtils.getWalletTransaction().then((value) {
|
||||
if (value != null) {
|
||||
walletTransactionList.value = value;
|
||||
}
|
||||
});
|
||||
await FireStoreUtils.getUserProfile(FireStoreUtils.getCurrentUid()).then((value) {
|
||||
if (value != null) {
|
||||
userModel.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
Future<void> walletTopUp() async {
|
||||
WalletTransactionModel transactionModel = WalletTransactionModel(
|
||||
id: Constant.getUuid(),
|
||||
amount: double.parse(topUpAmountController.value.text),
|
||||
date: Timestamp.now(),
|
||||
paymentMethod: selectedPaymentMethod.value,
|
||||
transactionUser: "user",
|
||||
userId: FireStoreUtils.getCurrentUid(),
|
||||
isTopup: true,
|
||||
note: "Wallet Top-up",
|
||||
paymentStatus: "success",
|
||||
);
|
||||
|
||||
await FireStoreUtils.setWalletTransaction(transactionModel).then((value) async {
|
||||
if (value == true) {
|
||||
await FireStoreUtils.updateUserWallet(amount: topUpAmountController.value.text, userId: FireStoreUtils.getCurrentUid()).then((value) {
|
||||
getWalletTransaction();
|
||||
Get.back();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ShowToastDialog.showToast("Amount Top-up successfully".tr);
|
||||
}
|
||||
|
||||
// Strip
|
||||
Future<void> stripeMakePayment({required String amount}) async {
|
||||
log(double.parse(amount).toStringAsFixed(0));
|
||||
try {
|
||||
Map<String, dynamic>? paymentIntentData = await createStripeIntent(amount: amount);
|
||||
log("stripe Responce====>$paymentIntentData");
|
||||
if (paymentIntentData!.containsKey("error")) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
} else {
|
||||
await Stripe.instance.initPaymentSheet(
|
||||
paymentSheetParameters: SetupPaymentSheetParameters(
|
||||
paymentIntentClientSecret: paymentIntentData['client_secret'],
|
||||
allowsDelayedPaymentMethods: false,
|
||||
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'US', testEnv: true, currencyCode: "USD"),
|
||||
customFlow: true,
|
||||
style: ThemeMode.system,
|
||||
appearance: PaymentSheetAppearance(colors: PaymentSheetAppearanceColors(primary: AppThemeData.primary300)),
|
||||
merchantDisplayName: 'GoRide',
|
||||
),
|
||||
);
|
||||
displayStripePaymentSheet(amount: amount);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log("$e \n$s");
|
||||
ShowToastDialog.showToast("exception:$e \n$s");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> displayStripePaymentSheet({required String amount}) async {
|
||||
try {
|
||||
await Stripe.instance.presentPaymentSheet().then((value) {
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
walletTopUp();
|
||||
});
|
||||
} on StripeException catch (e) {
|
||||
var lo1 = jsonEncode(e);
|
||||
var lo2 = jsonDecode(lo1);
|
||||
StripePayFailedModel lom = StripePayFailedModel.fromJson(lo2);
|
||||
ShowToastDialog.showToast(lom.error.message);
|
||||
} catch (e) {
|
||||
ShowToastDialog.showToast(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future createStripeIntent({required String amount}) async {
|
||||
try {
|
||||
Map<String, dynamic> body = {
|
||||
'amount': ((double.parse(amount) * 100).round()).toString(),
|
||||
'currency': "USD",
|
||||
'payment_method_types[]': 'card',
|
||||
"description": "Strip Payment",
|
||||
"shipping[name]": userModel.value.fullName(),
|
||||
"shipping[address][line1]": "510 Townsend St",
|
||||
"shipping[address][postal_code]": "98140",
|
||||
"shipping[address][city]": "San Francisco",
|
||||
"shipping[address][state]": "CA",
|
||||
"shipping[address][country]": "US",
|
||||
};
|
||||
var stripeSecret = stripeModel.value.stripeSecret;
|
||||
var response = await http.post(
|
||||
Uri.parse('https://api.stripe.com/v1/payment_intents'),
|
||||
body: body,
|
||||
headers: {'Authorization': 'Bearer $stripeSecret', 'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
);
|
||||
|
||||
return jsonDecode(response.body);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//mercadoo
|
||||
Future<Null> mercadoPagoMakePayment({required BuildContext context, required String amount}) async {
|
||||
final headers = {'Authorization': 'Bearer ${mercadoPagoModel.value.accessToken}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"items": [
|
||||
{
|
||||
"title": "Test",
|
||||
"description": "Test Payment",
|
||||
"quantity": 1,
|
||||
"currency_id": "BRL", // or your preferred currency
|
||||
"unit_price": double.parse(amount),
|
||||
},
|
||||
],
|
||||
"payer": {"email": userModel.value.email},
|
||||
"back_urls": {"failure": "${Constant.globalUrl}payment/failure", "pending": "${Constant.globalUrl}payment/pending", "success": "${Constant.globalUrl}payment/success"},
|
||||
"auto_return": "approved", // Automatically return after payment is approved
|
||||
});
|
||||
|
||||
final response = await http.post(Uri.parse("https://api.mercadopago.com/checkout/preferences"), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['init_point']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
walletTopUp();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something want wrong please contact administrator".tr);
|
||||
print('Error creating preference: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void paypalPaymentSheet(String amount, context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder:
|
||||
(BuildContext context) => UsePaypal(
|
||||
sandboxMode: payPalModel.value.isLive == true ? false : true,
|
||||
clientId: payPalModel.value.paypalClient ?? '',
|
||||
secretKey: payPalModel.value.paypalSecret ?? '',
|
||||
returnURL: "com.parkme://paypalpay",
|
||||
cancelURL: "com.parkme://paypalpay",
|
||||
transactions: [
|
||||
{
|
||||
"amount": {
|
||||
"total": amount,
|
||||
"currency": "USD",
|
||||
"details": {"subtotal": amount},
|
||||
},
|
||||
},
|
||||
],
|
||||
note: "Contact us for any questions on your order.",
|
||||
onSuccess: (Map params) async {
|
||||
walletTopUp();
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
},
|
||||
onError: (error) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
onCancel: (params) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
///PayStack Payment Method
|
||||
Future<void> payStackPayment(String totalAmount) async {
|
||||
await PayStackURLGen.payStackURLGen(amount: (double.parse(totalAmount) * 100).toString(), currency: "ZAR", secretKey: payStackModel.value.secretKey.toString(), userModel: userModel.value).then((
|
||||
value,
|
||||
) async {
|
||||
if (value != null) {
|
||||
PayStackUrlModel payStackModel0 = value;
|
||||
Get.to(
|
||||
PayStackScreen(
|
||||
secretKey: payStackModel.value.secretKey.toString(),
|
||||
callBackUrl: payStackModel.value.callbackURL.toString(),
|
||||
initialURl: payStackModel0.data.authorizationUrl,
|
||||
amount: totalAmount,
|
||||
reference: payStackModel0.data.reference,
|
||||
),
|
||||
)!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
walletTopUp();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//flutter wave Payment Method
|
||||
Future<Null> flutterWaveInitiatePayment({required BuildContext context, required String amount}) async {
|
||||
final url = Uri.parse('https://api.flutterwave.com/v3/payments');
|
||||
final headers = {'Authorization': 'Bearer ${flutterWaveModel.value.secretKey}', 'Content-Type': 'application/json'};
|
||||
|
||||
final body = jsonEncode({
|
||||
"tx_ref": _ref,
|
||||
"amount": amount,
|
||||
"currency": "NGN",
|
||||
"redirect_url": "${Constant.globalUrl}payment/success",
|
||||
"payment_options": "ussd, card, barter, payattitude",
|
||||
"customer": {
|
||||
"email": userModel.value.email.toString(),
|
||||
"phonenumber": userModel.value.phoneNumber, // Add a real phone number
|
||||
"name": userModel.value.fullName(), // Add a real customer name
|
||||
},
|
||||
"customizations": {"title": "Payment for Services", "description": "Payment for XYZ services"},
|
||||
});
|
||||
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
Get.to(MercadoPagoScreen(initialURl: data['data']['link']))!.then((value) {
|
||||
if (value) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
walletTopUp();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment UnSuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
print('Payment initialization failed: ${response.body}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? _ref;
|
||||
|
||||
void setRef() {
|
||||
maths.Random numRef = maths.Random();
|
||||
int year = DateTime.now().year;
|
||||
int refNumber = numRef.nextInt(20000);
|
||||
if (Platform.isAndroid) {
|
||||
_ref = "AndroidRef$year$refNumber";
|
||||
} else if (Platform.isIOS) {
|
||||
_ref = "IOSRef$year$refNumber";
|
||||
}
|
||||
}
|
||||
|
||||
// payFast
|
||||
void payFastPayment({required BuildContext context, required String amount}) {
|
||||
PayStackURLGen.getPayHTML(payFastSettingData: payFastModel.value, amount: amount.toString(), userModel: userModel.value).then((String? value) async {
|
||||
bool isDone = await Get.to(PayFastScreen(htmlData: value!, payFastSettingData: payFastModel.value));
|
||||
if (isDone) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment successfully".tr);
|
||||
walletTopUp();
|
||||
} else {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///RazorPay payment function
|
||||
final Razorpay razorPay = Razorpay();
|
||||
|
||||
void openCheckout({required amount, required orderId}) async {
|
||||
var options = {
|
||||
'key': razorPayModel.value.razorpayKey,
|
||||
'amount': amount * 100,
|
||||
'name': 'GoRide',
|
||||
'order_id': orderId,
|
||||
"currency": "INR",
|
||||
'description': 'wallet Topup',
|
||||
'retry': {'enabled': true, 'max_count': 1},
|
||||
'send_sms_hash': true,
|
||||
'prefill': {'contact': userModel.value.phoneNumber, 'email': userModel.value.email},
|
||||
'external': {
|
||||
'wallets': ['paytm'],
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
razorPay.open(options);
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void handlePaymentSuccess(PaymentSuccessResponse response) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
walletTopUp();
|
||||
}
|
||||
|
||||
void handleExternalWaller(ExternalWalletResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Processing!! via".tr);
|
||||
}
|
||||
|
||||
void handlePaymentError(PaymentFailureResponse response) {
|
||||
Get.back();
|
||||
ShowToastDialog.showToast("Payment Failed!!".tr);
|
||||
}
|
||||
|
||||
//Midtrans payment
|
||||
Future<void> midtransMakePayment({required String amount, required BuildContext context}) async {
|
||||
await createPaymentLink(amount: amount).then((url) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (url != '') {
|
||||
Get.to(() => MidtransScreen(initialURl: url))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
walletTopUp();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> createPaymentLink({required var amount}) async {
|
||||
var ordersId = const Uuid().v1();
|
||||
final url = Uri.parse(midTransModel.value.isSandbox! ? 'https://api.sandbox.midtrans.com/v1/payment-links' : 'https://api.midtrans.com/v1/payment-links');
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': generateBasicAuthHeader(midTransModel.value.serverKey!)},
|
||||
body: jsonEncode({
|
||||
'transaction_details': {'order_id': ordersId, 'gross_amount': double.parse(amount.toString()).toInt()},
|
||||
'usage_limit': 2,
|
||||
"callbacks": {"finish": "https://www.google.com?merchant_order_id=$ordersId"},
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
ShowToastDialog.showToast("something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
String generateBasicAuthHeader(String apiKey) {
|
||||
String credentials = '$apiKey:';
|
||||
String base64Encoded = base64Encode(utf8.encode(credentials));
|
||||
return 'Basic $base64Encoded';
|
||||
}
|
||||
|
||||
//Orangepay payment
|
||||
static String accessToken = '';
|
||||
static String payToken = '';
|
||||
static String orderId = '';
|
||||
static String amount = '';
|
||||
|
||||
Future<void> orangeMakePayment({required String amount, required BuildContext context}) async {
|
||||
reset();
|
||||
var id = const Uuid().v4();
|
||||
var paymentURL = await fetchToken(context: context, orderId: id, amount: amount, currency: 'USD');
|
||||
ShowToastDialog.closeLoader();
|
||||
if (paymentURL.toString() != '') {
|
||||
Get.to(() => OrangeMoneyScreen(initialURl: paymentURL, accessToken: accessToken, amount: amount, orangePay: orangeMoneyModel.value, orderId: orderId, payToken: payToken))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
walletTopUp();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
}
|
||||
|
||||
Future fetchToken({required String orderId, required String currency, required BuildContext context, required String amount}) async {
|
||||
String apiUrl = 'https://api.orange.com/oauth/v3/token';
|
||||
Map<String, String> requestBody = {'grant_type': 'client_credentials'};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{'Authorization': "Basic ${orangeMoneyModel.value.auth!}", 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'},
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
|
||||
accessToken = responseData['access_token'];
|
||||
return await webpayment(context: context, amountData: amount, currency: currency, orderIdData: orderId);
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future webpayment({required String orderIdData, required BuildContext context, required String currency, required String amountData}) async {
|
||||
orderId = orderIdData;
|
||||
amount = amountData;
|
||||
String apiUrl = orangeMoneyModel.value.isSandbox! == true ? 'https://api.orange.com/orange-money-webpay/dev/v1/webpayment' : 'https://api.orange.com/orange-money-webpay/cm/v1/webpayment';
|
||||
Map<String, String> requestBody = {
|
||||
"merchant_key": orangeMoneyModel.value.merchantKey ?? '',
|
||||
"currency": orangeMoneyModel.value.isSandbox == true ? "OUV" : currency,
|
||||
"order_id": orderId,
|
||||
"amount": amount,
|
||||
"reference": 'Y-Note Test',
|
||||
"lang": "en",
|
||||
"return_url": orangeMoneyModel.value.returnUrl!.toString(),
|
||||
"cancel_url": orangeMoneyModel.value.cancelUrl!.toString(),
|
||||
"notif_url": orangeMoneyModel.value.notifUrl!.toString(),
|
||||
};
|
||||
|
||||
var response = await http.post(
|
||||
Uri.parse(apiUrl),
|
||||
headers: <String, String>{'Authorization': 'Bearer $accessToken', 'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
body: json.encode(requestBody),
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.body);
|
||||
|
||||
// Handle the response
|
||||
if (response.statusCode == 201) {
|
||||
Map<String, dynamic> responseData = jsonDecode(response.body);
|
||||
if (responseData['message'] == 'OK') {
|
||||
payToken = responseData['pay_token'];
|
||||
return responseData['payment_url'];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
ShowToastDialog.showToast("Something went wrong, please contact admin.".tr);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
accessToken = '';
|
||||
payToken = '';
|
||||
orderId = '';
|
||||
amount = '';
|
||||
}
|
||||
|
||||
//XenditPayment
|
||||
Future<void> xenditPayment(context, amount) async {
|
||||
await createXenditInvoice(amount: amount).then((model) {
|
||||
ShowToastDialog.closeLoader();
|
||||
if (model.id != null) {
|
||||
Get.to(() => XenditScreen(initialURl: model.invoiceUrl ?? '', transId: model.id ?? '', apiKey: xenditModel.value.apiKey!.toString()))!.then((value) {
|
||||
if (value == true) {
|
||||
ShowToastDialog.showToast("Payment Successful!!".tr);
|
||||
walletTopUp();
|
||||
} else {
|
||||
ShowToastDialog.showToast("Payment Unsuccessful!!".tr);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<XenditModel> createXenditInvoice({required var amount}) async {
|
||||
const url = 'https://api.xendit.co/v2/invoices';
|
||||
var headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': generateBasicAuthHeader(xenditModel.value.apiKey!.toString()),
|
||||
// 'Cookie': '__cf_bm=yERkrx3xDITyFGiou0bbKY1bi7xEwovHNwxV1vCNbVc-1724155511-1.0.1.1-jekyYQmPCwY6vIJ524K0V6_CEw6O.dAwOmQnHtwmaXO_MfTrdnmZMka0KZvjukQgXu5B.K_6FJm47SGOPeWviQ',
|
||||
};
|
||||
|
||||
final body = jsonEncode({
|
||||
'external_id': const Uuid().v1(),
|
||||
'amount': amount,
|
||||
'payer_email': 'customer@domain.com',
|
||||
'description': 'Test - VA Successful invoice payment',
|
||||
'currency': 'IDR', //IDR, PHP, THB, VND, MYR
|
||||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(Uri.parse(url), headers: headers, body: body);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
XenditModel model = XenditModel.fromJson(jsonDecode(response.body));
|
||||
return model;
|
||||
} else {
|
||||
return XenditModel();
|
||||
}
|
||||
} catch (e) {
|
||||
return XenditModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
71
lib/firebase_options.dart
Normal file
71
lib/firebase_options.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
// File generated by FlutterFire CLI.
|
||||
// ignore_for_file: type=lint
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// import 'firebase_options.dart';
|
||||
/// // ...
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
/// ```
|
||||
class DefaultFirebaseOptions {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for web - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
return android;
|
||||
case TargetPlatform.iOS:
|
||||
return ios;
|
||||
case TargetPlatform.macOS:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for macos - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.windows:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for windows - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const FirebaseOptions android = FirebaseOptions(
|
||||
apiKey: 'AIzaSyALZhdy7Rw3jffipxsDvvz7_C_b4teVg1k',
|
||||
appId: '1:893074789710:android:05002c15a64cf1e0c4ba1f',
|
||||
messagingSenderId: '893074789710',
|
||||
projectId: 'fondexuzb',
|
||||
databaseURL: 'https://fondexuzb-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'fondexuzb.firebasestorage.app',
|
||||
);
|
||||
|
||||
static const FirebaseOptions ios = FirebaseOptions(
|
||||
apiKey: 'AIzaSyD6Khoz4y93GCj3mOPi2FoluDipplH1av0',
|
||||
appId: '1:893074789710:ios:510ebf9e4ebed6a8c4ba1f',
|
||||
messagingSenderId: '893074789710',
|
||||
projectId: 'fondexuzb',
|
||||
databaseURL: 'https://fondexuzb-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'fondexuzb.firebasestorage.app',
|
||||
iosClientId: '893074789710-pv12m4nhe82a4ueg9sb2pgt42r0e5da3.apps.googleusercontent.com',
|
||||
iosBundleId: 'com.emart.customer',
|
||||
);
|
||||
|
||||
}
|
||||
784
lib/lang/app_en.dart
Normal file
784
lib/lang/app_en.dart
Normal file
@@ -0,0 +1,784 @@
|
||||
const Map<String, String> enUS = {
|
||||
'Let’s Get Started': 'Let’s Get Started',
|
||||
'Skip': 'Skip',
|
||||
'Next': 'Next',
|
||||
'Log in to explore your all in one vendor app favourites and shop effortlessly.': 'Log in to explore your all in one vendor app favourites and shop effortlessly.',
|
||||
'Email Address*': 'Email Address*',
|
||||
'jerome014@gmail.com': 'jerome014@gmail.com',
|
||||
'Password*': 'Password*',
|
||||
'Enter password': 'Enter password',
|
||||
'Forgot Password': 'Forgot Password',
|
||||
'Log in': 'Log in',
|
||||
'or continue with': 'or continue with',
|
||||
'Mobile number': 'Mobile number',
|
||||
'with Google': 'with Google',
|
||||
'with Apple': 'with Apple',
|
||||
"Didn't have an account?": "Didn't have an account?",
|
||||
'Sign up': 'Sign up',
|
||||
'Please enter a valid email address': 'Please enter a valid email address',
|
||||
'Please enter your password': 'Please enter your password',
|
||||
'Logging in...': 'Logging in...',
|
||||
'This user is disabled. Please contact admin.': 'This user is disabled. Please contact admin.',
|
||||
'This user does not exist in the customer app.': 'This user does not exist in the customer app.',
|
||||
'No user found for that email.': 'No user found for that email.',
|
||||
'Wrong password provided.': 'Wrong password provided.',
|
||||
'Invalid email.': 'Invalid email.',
|
||||
'Login failed. Please try again.': 'Login failed. Please try again.',
|
||||
'please wait...': 'please wait...',
|
||||
'Sign up to explore all our services and start shopping, riding, and more.': 'Sign up to explore all our services and start shopping, riding, and more.',
|
||||
'First Name*': 'First Name*',
|
||||
'Jerome': 'Jerome',
|
||||
'KM': 'KM',
|
||||
'Last Name*': 'Last Name*',
|
||||
'Bell': 'Bell',
|
||||
'Mobile Number*': 'Mobile Number*',
|
||||
'Enter Mobile number': 'Enter Mobile number',
|
||||
'Confirm Password*': 'Confirm Password*',
|
||||
'Enter confirm password': 'Enter confirm password',
|
||||
'Referral Code': 'Referral Code',
|
||||
'Enter referral code': 'Enter referral code',
|
||||
'Already have an account?': 'Already have an account?',
|
||||
'Creating account...': 'Creating account...',
|
||||
'signup_failed': 'Signup failed',
|
||||
'Please enter first name': 'Please enter first name',
|
||||
'Please enter last name': 'Please enter last name',
|
||||
'Please enter a valid phone number': 'Please enter a valid phone number',
|
||||
'Password must be at least 6 characters': 'Password must be at least 6 characters',
|
||||
'Password and Confirm password do not match': 'Password and Confirm password do not match',
|
||||
'Email already in use': 'Email already in use',
|
||||
'Password is too weak': 'Password is too weak',
|
||||
'Invalid email address': 'Invalid email address',
|
||||
'something_went_wrong': 'Something went wrong',
|
||||
'Enter your registered email to receive a reset link.': 'Enter your registered email to receive a reset link.',
|
||||
'Send Link': 'Send Link',
|
||||
'Remember Password?': 'Remember Password?',
|
||||
'Please enter your email address.': 'Please enter your email address.',
|
||||
'Please enter a valid email address.': 'Please enter a valid email address.',
|
||||
"reset_password_link_sent": "Reset password link sent to @email",
|
||||
'Use your mobile number to Log in easily and securely.': 'Use your mobile number to Log in easily and securely.',
|
||||
'Send Code': 'Send Code',
|
||||
'Email address': 'Email address',
|
||||
'Please enter a valid 10-digit mobile number': 'Please enter a valid 10-digit mobile number',
|
||||
'Sending OTP...': 'Sending OTP...',
|
||||
'Invalid phone number': 'Invalid phone number',
|
||||
'OTP verification failed': 'OTP verification failed',
|
||||
'Something went wrong. Please try again.': 'Something went wrong. Please try again.',
|
||||
'Enter the OTP sent to your mobile': 'Enter the OTP sent to your mobile',
|
||||
'Resend OTP': 'Resend OTP',
|
||||
'Verify': 'Verify',
|
||||
'OTP sent': 'OTP sent',
|
||||
'Enter valid 6-digit OTP': 'Enter valid 6-digit OTP',
|
||||
'Verifying OTP...': 'Verifying OTP...',
|
||||
'This user is disabled': 'This user is disabled',
|
||||
'Invalid OTP or Verification Failed': 'Invalid OTP or Verification Failed',
|
||||
'eMart': 'eMart',
|
||||
'All Your Needs in One App!': 'All Your Needs in One App!',
|
||||
'Explore Our Services': 'Explore Our Services',
|
||||
'Alert!': 'Alert!',
|
||||
'Alert': 'Alert',
|
||||
'If you select this Section/Service, your previously added items will be removed from the cart.': 'If you select this Section/Service, your previously added items will be removed from the cart.',
|
||||
'Cancel': 'Cancel',
|
||||
'OK': 'OK',
|
||||
'Home': 'Home',
|
||||
'My Bookings': 'My Bookings',
|
||||
'Favourites': 'Favourites',
|
||||
'Orders': 'Orders',
|
||||
'Profile': 'Profile',
|
||||
'Wallet': 'Wallet',
|
||||
'Service is unavailable at the selected address.': 'Service is unavailable at the selected address.',
|
||||
'Pickup Location': 'Pickup Location',
|
||||
'Destination Location': 'Destination Location',
|
||||
'Continue': 'Continue',
|
||||
'Please select source location': 'Please select source location',
|
||||
'Please select destination location': 'Please select destination location',
|
||||
'Select Your Vehicle Type': 'Select Your Vehicle Type',
|
||||
"pay_amount": "Pay @amount",
|
||||
'Please select a vehicle type first.': 'Please select a vehicle type first.',
|
||||
'Select Payment Method': 'Select Payment Method',
|
||||
'Preferred Payment': 'Preferred Payment',
|
||||
'Other Payment Options': 'Other Payment Options',
|
||||
'Please select a payment method': 'Please select a payment method',
|
||||
'Insufficient wallet balance. Please select another payment method.': 'Insufficient wallet balance. Please select another payment method.',
|
||||
'Promo code': 'Promo code',
|
||||
'Promo Code': 'Promo Code',
|
||||
'Apply promo code': 'Apply promo code',
|
||||
'This offer not eligible for this booking': 'This offer not eligible for this booking',
|
||||
'View All': 'View All',
|
||||
'Write coupon Code': 'Write coupon Code',
|
||||
'Redeem now': 'Redeem now',
|
||||
'Please enter a coupon code': 'Please enter a coupon code',
|
||||
'Coupon applied successfully': 'Coupon applied successfully',
|
||||
'This coupon code has been expired': 'This coupon code has been expired',
|
||||
'Invalid coupon code': 'Invalid coupon code',
|
||||
'Order Summary': 'Order Summary',
|
||||
'Subtotal': 'Subtotal',
|
||||
'SubTotal': 'SubTotal',
|
||||
'Discount': 'Discount',
|
||||
'Order Total': 'Order Total',
|
||||
'Confirm Booking': 'Confirm Booking',
|
||||
'Waiting for driver....': 'Waiting for driver....',
|
||||
'Cancel Ride': 'Cancel Ride',
|
||||
'Ride cancelled successfully': 'Ride cancelled successfully',
|
||||
'Failed to cancel ride': 'Failed to cancel ride',
|
||||
'Otp :': 'Otp :',
|
||||
'SOS': 'SOS',
|
||||
'Please wait...': 'Please wait...',
|
||||
'Your SOS request has been submitted to admin': 'Your SOS request has been submitted to admin',
|
||||
'Your SOS request is already submitted': 'Your SOS request is already submitted',
|
||||
'Pay Now': 'Pay Now',
|
||||
'Something went wrong, please contact admin.': 'Something went wrong, please contact admin.',
|
||||
'Please select payment method': 'Please select payment method',
|
||||
'Driver at Pickup': 'Driver at Pickup',
|
||||
'Driver Location': 'Driver Location',
|
||||
'Payment method changed': 'Payment method changed',
|
||||
'Payment successfully': 'Payment successfully',
|
||||
'Payment Successful!!': 'Payment Successful!!',
|
||||
'Payment UnSuccessful!!': 'Payment UnSuccessful!!',
|
||||
'Payment Failed': 'Payment Failed',
|
||||
'Payment Processing!! via': 'Payment Processing!! via',
|
||||
'Payment Failed!!': 'Payment Failed!!',
|
||||
'Coupon': 'Coupon',
|
||||
'Coupon not found': 'Coupon not found',
|
||||
'Tap To Apply': 'Tap To Apply',
|
||||
'My Booking': 'My Booking',
|
||||
'Login': 'Login',
|
||||
'Where are you going for?': 'Where are you going for?',
|
||||
'Ride': 'Ride',
|
||||
'City rides, 24x7 availability': 'City rides, 24x7 availability',
|
||||
'Intercity/Outstation': 'Intercity/Outstation',
|
||||
'Long trips, prepaid options': 'Long trips, prepaid options',
|
||||
'Every Ride. Every Driver. Verified.': 'Every Ride. Every Driver. Verified.',
|
||||
'All drivers go through ID checks and background verification for your safety.': 'All drivers go through ID checks and background verification for your safety.',
|
||||
'Ride Details': 'Ride Details',
|
||||
'Order Id:': 'Order Id:',
|
||||
'Booking Date:': 'Booking Date:',
|
||||
'Ride & Fare Summary': 'Ride & Fare Summary',
|
||||
'Add Review': 'Add Review',
|
||||
'Complain': 'Complain',
|
||||
'Distance': 'Distance',
|
||||
'Duration': 'Duration',
|
||||
'Update Review': 'Update Review',
|
||||
'How is your trip?': 'How is your trip?',
|
||||
'Your feedback will help us improve \n driving experience better': 'Your feedback will help us improve \n driving experience better',
|
||||
'Rate for': 'Rate for',
|
||||
'Type comment....': 'Type comment....',
|
||||
'Please provide rating and comment': 'Please provide rating and comment',
|
||||
'Submit in...': 'Submit in...',
|
||||
'Title': 'Title',
|
||||
'Save': 'Save',
|
||||
'Type Description....': 'Type Description....',
|
||||
'Order data not found': 'Order data not found',
|
||||
'Failed to load complaint': 'Failed to load complaint',
|
||||
'Please enter complaint title': 'Please enter complaint title',
|
||||
'Please enter complaint description': 'Please enter complaint description',
|
||||
'Your complaint has been submitted to admin': 'Your complaint has been submitted to admin',
|
||||
'Your complaint is already submitted': 'Your complaint is already submitted',
|
||||
'Something went wrong, please try again': 'Something went wrong, please try again',
|
||||
'Popular Destinations': 'Popular Destinations',
|
||||
'Ride History': 'Ride History',
|
||||
'No order found': 'No order found',
|
||||
'You do not have sufficient wallet balance': 'You do not have sufficient wallet balance',
|
||||
"new_tab": "New",
|
||||
"on_going_tab": "On Going",
|
||||
"completed_tab": "Completed",
|
||||
"cancelled_tab": "Cancelled",
|
||||
'New': 'New',
|
||||
'On Going': 'On Going',
|
||||
'Completed': 'Completed',
|
||||
'Cancelled': 'Cancelled',
|
||||
'My Addresses': 'My Addresses',
|
||||
'Allows users to view, manage, add, or edit delivery addresses': 'Allows users to view, manage, add, or edit delivery addresses',
|
||||
'Address not found': 'Address not found',
|
||||
'Default': 'Default',
|
||||
'Add New Address': 'Add New Address',
|
||||
'Edit Address': 'Edit Address',
|
||||
'Add a New Address': 'Add a New Address',
|
||||
'Enter your location details so we can deliver your orders quickly and accurately.': 'Enter your location details so we can deliver your orders quickly and accurately.',
|
||||
'Set as Default Address': 'Set as Default Address',
|
||||
'Choose Location': 'Choose Location',
|
||||
'Flat/House/Floor/Building*': 'Flat/House/Floor/Building*',
|
||||
'Area/Sector/Locality*': 'Area/Sector/Locality*',
|
||||
'Nearby Landmark': 'Nearby Landmark',
|
||||
'Save Address As': 'Save Address As',
|
||||
'Enter address details': 'Enter address details',
|
||||
'Enter area/locality': 'Enter area/locality',
|
||||
'Add a landmark': 'Add a landmark',
|
||||
'Save Address': 'Save Address',
|
||||
'Please select Location': 'Please select Location',
|
||||
'Please Enter Flat / House / Floor / Building': 'Please Enter Flat / House / Floor / Building',
|
||||
'Please Enter Area / Sector / Locality': 'Please Enter Area / Sector / Locality',
|
||||
'Enable Location for a Personalized Experience': 'Enable Location for a Personalized Experience',
|
||||
'Allow location access to discover beauty stores and services near you.': 'Allow location access to discover beauty stores and services near you.',
|
||||
'Use current location': 'Use current location',
|
||||
'Set from map': 'Set from map',
|
||||
'Enter Manually location': 'Enter Manually location',
|
||||
'Search the store, item and more...': 'Search the store, item and more...',
|
||||
'Category': 'Category',
|
||||
'Highlights for you': 'Highlights for you',
|
||||
'New Arrivals': 'New Arrivals',
|
||||
'View All Arrivals': 'View All Arrivals',
|
||||
'Top Brands': 'Top Brands',
|
||||
'Brand': 'Brand',
|
||||
'Style up with the latest fits, now at unbeatable prices.': 'Style up with the latest fits, now at unbeatable prices.',
|
||||
'View All Products': 'View All Products',
|
||||
'All Store': 'All Store',
|
||||
'View All Stores': 'View All Stores',
|
||||
'Could not launch': 'Could not launch',
|
||||
'Highlights for you not found.': 'Highlights for you not found.',
|
||||
'Item Not available': 'Item Not available',
|
||||
'Service not available in this area': 'Service not available in this area',
|
||||
'Out of stock': 'Out of stock',
|
||||
'Variants': 'Variants',
|
||||
'Addons': 'Addons',
|
||||
'Delivery Type': 'Delivery Type',
|
||||
'Instant Delivery': 'Instant Delivery',
|
||||
'Standard': 'Standard',
|
||||
'instant': 'instant',
|
||||
'schedule': 'schedule',
|
||||
'Schedule Time': 'Schedule Time',
|
||||
'Your preferred time': 'Your preferred time',
|
||||
'Offers & Benefits': 'Offers & Benefits',
|
||||
'Apply Coupons': 'Apply Coupons',
|
||||
'Bill Details': 'Bill Details',
|
||||
'Item totals': 'Item totals',
|
||||
'Delivery Fee': 'Delivery Fee',
|
||||
'Free Delivery': 'Free Delivery',
|
||||
'Coupon Discount': 'Coupon Discount',
|
||||
'Special Discount': 'Special Discount',
|
||||
'Delivery Tips': 'Delivery Tips',
|
||||
'Remove': 'Remove',
|
||||
'To Pay': 'To Pay',
|
||||
'Thanks with a tip!': 'Thanks with a tip!',
|
||||
'Around the clock, our delivery partners make it happen. Show gratitude with a tip..': 'Around the clock, our delivery partners make it happen. Show gratitude with a tip..',
|
||||
'Other': 'Other',
|
||||
'Remarks': 'Remarks',
|
||||
'Write remarks for the store': 'Write remarks for the store',
|
||||
'Cashback Offer': 'Cashback Offer',
|
||||
'Cashback Name :': 'Cashback Name :',
|
||||
'You will get': 'You will get',
|
||||
|
||||
'Pay Via': 'Pay Via',
|
||||
'The total price must be greater than or equal to the coupon discount value for the code to apply. Please review your cart total.':
|
||||
'The total price must be greater than or equal to the coupon discount value for the code to apply. Please review your cart total.',
|
||||
'The total price must be greater than or equal to the special discount value for the code to apply. Please review your cart total.':
|
||||
'The total price must be greater than or equal to the special discount value for the code to apply. Please review your cart total.',
|
||||
'Tips Amount': 'Tips Amount',
|
||||
'Enter Tips Amount': 'Enter Tips Amount',
|
||||
'Add': 'Add',
|
||||
'Please enter tips Amount': 'Please enter tips Amount',
|
||||
"You don't have sufficient wallet balance to place order": "You don't have sufficient wallet balance to place order",
|
||||
'This vendor has reached their maximum order capacity. Please select a different vendor or try again later.':
|
||||
'This vendor has reached their maximum order capacity. Please select a different vendor or try again later.',
|
||||
'Coupon Code': 'Coupon Code',
|
||||
'Enter coupon code': 'Enter coupon code',
|
||||
'Invalid Coupon': 'Invalid Coupon',
|
||||
'Apply': 'Apply',
|
||||
'Coupon code not applied': 'Coupon code not applied',
|
||||
'Order Placed': 'Order Placed',
|
||||
'Hang tight — your items are being delivered quickly and safely!': 'Hang tight — your items are being delivered quickly and safely!',
|
||||
'Order ID': 'Order ID',
|
||||
'Placing your order': 'Placing your order',
|
||||
'Take a moment to review your order before proceeding to checkout.': 'Take a moment to review your order before proceeding to checkout.',
|
||||
'Delivery Address': 'Delivery Address',
|
||||
'Track Order': 'Track Order',
|
||||
'Payment Option': 'Payment Option',
|
||||
'Cashback Offers': 'Cashback Offers',
|
||||
'Min spent': 'Min spent',
|
||||
'Maximum cashback up to': 'Maximum cashback up to',
|
||||
'Valid till': 'Valid till',
|
||||
'Change Language': 'Change Language',
|
||||
'Select your preferred language for a personalized app experience.': 'Select your preferred language for a personalized app experience.',
|
||||
'No Conversion found': 'No Conversion found',
|
||||
'Type message here....': 'Type message here....',
|
||||
'Send Media': 'Send Media',
|
||||
'Choose image from gallery': 'Choose image from gallery',
|
||||
'Choose video from gallery': 'Choose video from gallery',
|
||||
'Take a picture': 'Take a picture',
|
||||
'sent a message': 'sent a message',
|
||||
'Sent a video': 'Sent a video',
|
||||
'Sent a audio': 'Sent a audio',
|
||||
'Driver Inbox': 'Driver Inbox',
|
||||
'Store Inbox': 'Store Inbox',
|
||||
'Dine in Bookings': 'Dine in Bookings',
|
||||
'Order': 'Order',
|
||||
'Peoples': 'Peoples',
|
||||
'View in Map': 'View in Map',
|
||||
'Call Now': 'Call Now',
|
||||
'Booking Details': 'Booking Details',
|
||||
'Name': 'Name',
|
||||
'Phone number': 'Phone number',
|
||||
'Date and Time': 'Date and Time',
|
||||
'Guest': 'Guest',
|
||||
'Upcoming': 'Upcoming',
|
||||
'History': 'History',
|
||||
'Upcoming Booking not found.': 'Upcoming Booking not found.',
|
||||
'History not found.': 'History not found.',
|
||||
'Guest Number': 'Guest Number',
|
||||
'Book Table': 'Book Table',
|
||||
'Numbers of Guests': 'Numbers of Guests',
|
||||
'When are you visiting?': 'When are you visiting?',
|
||||
'Today': 'Today',
|
||||
'Tomorrow': 'Tomorrow',
|
||||
'Select time slot and scroll to see offers': 'Select time slot and scroll to see offers',
|
||||
'Special Occasion': 'Special Occasion',
|
||||
'Clear': 'Clear',
|
||||
'Is this your first visit?': 'Is this your first visit?',
|
||||
'Personal Details': 'Personal Details',
|
||||
'Additional Requests': 'Additional Requests',
|
||||
'Add message here....': 'Add message here....',
|
||||
'Book Now': 'Book Now',
|
||||
'Dine-In Request submitted successfully.': 'Dine-In Request submitted successfully.',
|
||||
"Birthday": "Birthday",
|
||||
"Anniversary": "Anniversary",
|
||||
'Ratings': 'Ratings',
|
||||
'Open': 'Open',
|
||||
'Close': 'Close',
|
||||
'View Timing': 'View Timing',
|
||||
'View Timings': 'View Timings',
|
||||
'Also applicable on food delivery': 'Also applicable on food delivery',
|
||||
'Please log in to the application. You are not logged in.': 'Please log in to the application. You are not logged in.',
|
||||
'Table Booking': 'Table Booking',
|
||||
'Quick Conformations': 'Quick Conformations',
|
||||
'Available food delivery': 'Available food delivery',
|
||||
'in 30-45 mins.': 'in 30-45 mins.',
|
||||
'Menu': 'Menu',
|
||||
'Location, Timing & Costs': 'Location, Timing & Costs',
|
||||
'View on Map': 'View on Map',
|
||||
'Timing': 'Timing',
|
||||
'To': 'To',
|
||||
'Cost for Two': 'Cost for Two',
|
||||
'for two': 'for two',
|
||||
'(approx)': '(approx)',
|
||||
'Cuisines': 'Cuisines',
|
||||
'Dine-In Reservations': 'Dine-In Reservations',
|
||||
'Book a table at your favorite restaurant and enjoy a delightful dining experience.': 'Book a table at your favorite restaurant and enjoy a delightful dining experience.',
|
||||
'No Store Found in Your Area': 'No Store Found in Your Area',
|
||||
'Currently, there are no available store in your zone. Try changing your location to find nearby options.':
|
||||
'Currently, there are no available store in your zone. Try changing your location to find nearby options.',
|
||||
'Change Zone': 'Change Zone',
|
||||
'Explore the Categories': 'Explore the Categories',
|
||||
'View all': 'View all',
|
||||
'Popular Stores': 'Popular Stores',
|
||||
'All Stores': 'All Stores',
|
||||
'Categories': 'Categories',
|
||||
'Profile Information': 'Profile Information',
|
||||
'View and update your personal details, contact information, and preferences.': 'View and update your personal details, contact information, and preferences.',
|
||||
'First Name': 'First Name',
|
||||
'Last Name': 'Last Name',
|
||||
'Email': 'Email',
|
||||
'Phone Number': 'Phone Number',
|
||||
'Save Details': 'Save Details',
|
||||
'camera': 'camera',
|
||||
'gallery': 'gallery',
|
||||
"failed_to_pick": "Failed to pick image",
|
||||
'Your Favourites, All in One Place': 'Your Favourites, All in One Place',
|
||||
'Please Log In to Continue': 'Please Log In to Continue',
|
||||
"You’re not logged in. Please sign in to access your account and explore all features.": "You’re not logged in. Please sign in to access your account and explore all features.",
|
||||
'Favourite Store': 'Favourite Store',
|
||||
'Favourite Item': 'Favourite Item',
|
||||
'Favourite Store not found.': 'Favourite Store not found.',
|
||||
'Favourite Item not found.': 'Favourite Item not found.',
|
||||
'error': 'error',
|
||||
'Non Veg.': 'Non Veg.',
|
||||
'Pure veg.': 'Pure veg.',
|
||||
'Amount': 'Amount',
|
||||
'No worries!! We’ll send you reset instructions': 'No worries!! We’ll send you reset instructions',
|
||||
'Email Address': 'Email Address',
|
||||
'Enter email address': 'Enter email address',
|
||||
'Please enter valid email': 'Please enter valid email',
|
||||
'Customize Gift Card': 'Customize Gift Card',
|
||||
'Choose an amount': 'Choose an amount',
|
||||
'Enter gift card amount': 'Enter gift card amount',
|
||||
'Add Message (Optional)': 'Add Message (Optional)',
|
||||
'Please enter Amount': 'Please enter Amount',
|
||||
'Enter Amount': 'Enter Amount',
|
||||
'Complete payment and share this e-gift card with loved ones using any app': 'Complete payment and share this e-gift card with loved ones using any app',
|
||||
'Sub Total': 'Sub Total',
|
||||
'Grand Total': 'Grand Total',
|
||||
'Gift Card expire': 'Gift Card expire',
|
||||
'days after purchase': 'days after purchase',
|
||||
"You don't have sufficient wallet balance to purchase gift card": "You don't have sufficient wallet balance to purchase gift card",
|
||||
'Gift card Purchases successfully': 'Gift card Purchases successfully',
|
||||
'Purchased Gift card not found': 'Purchased Gift card not found',
|
||||
'Gift Code': 'Gift Code',
|
||||
'Gift Pin': 'Gift Pin',
|
||||
'Share': 'Share',
|
||||
'Redeemed': 'Redeemed',
|
||||
'Not Redeem': 'Not Redeem',
|
||||
'Gift Code :': 'Gift Code :',
|
||||
'Gift Pin :': 'Gift Pin :',
|
||||
'Price :': 'Price :',
|
||||
'Expire Date :': 'Expire Date :',
|
||||
'Message': 'Message',
|
||||
'Redeem Gift Card': 'Redeem Gift Card',
|
||||
'Enter your gift card code to enjoy discounts and special offers on your orders.': 'Enter your gift card code to enjoy discounts and special offers on your orders.',
|
||||
'Enter gift code': 'Enter gift code',
|
||||
'Enter gift pin': 'Enter gift pin',
|
||||
'Redeem': 'Redeem',
|
||||
'Please Enter Gift Code': 'Please Enter Gift Code',
|
||||
'Please Enter Gift Pin': 'Please Enter Gift Pin',
|
||||
'Gift voucher already redeemed': 'Gift voucher already redeemed',
|
||||
'Gift Pin Invalid': 'Gift Pin Invalid',
|
||||
'Gift Voucher expire': 'Gift Voucher expire',
|
||||
'Voucher redeem successfully': 'Voucher redeem successfully',
|
||||
'Invalid Gift Code': 'Invalid Gift Code',
|
||||
'No Restaurant found': 'No Restaurant found',
|
||||
"% off": "% OFF",
|
||||
" off": " OFF",
|
||||
'Off': 'Off',
|
||||
'Search the restaurant, food and more...': 'Search the restaurant, food and more...',
|
||||
'Largest Discounts': 'Largest Discounts',
|
||||
'Delivery': 'Delivery',
|
||||
'TakeAway': 'TakeAway',
|
||||
'Do you really want to change the delivery option? Your cart will be empty.': 'Do you really want to change the delivery option? Your cart will be empty.',
|
||||
'Ok': 'Ok',
|
||||
'Upto': 'Upto',
|
||||
"Error": "Error",
|
||||
'Search the dish, foo and more...': 'Search the dish, foo and more...',
|
||||
'See all': 'See all',
|
||||
'Our Categories': 'Our Categories',
|
||||
'Best Servings Food': 'Best Servings Food',
|
||||
'Large Discounts': 'Large Discounts',
|
||||
'Discounts Restaurants': 'Discounts Restaurants',
|
||||
'Save Upto 50% Off': 'Save Upto 50% Off',
|
||||
'% OFF': '% OFF',
|
||||
'OFF': 'OFF',
|
||||
'Stories': 'Stories',
|
||||
'Best Food Stories Ever': 'Best Food Stories Ever',
|
||||
'Best Restaurants': 'Best Restaurants',
|
||||
'Live Tracking': 'Live Tracking',
|
||||
'Order Details': 'Order Details',
|
||||
'Order Delivered.': 'Order Delivered.',
|
||||
'Your Order has been Preparing and assign to the driver': 'Your Order has been Preparing and assign to the driver',
|
||||
'Preparation Time': 'Preparation Time',
|
||||
'Your Order': 'Your Order',
|
||||
'Rate us': 'Rate us',
|
||||
'Schedule': 'Schedule',
|
||||
'Payment Method': 'Payment Method',
|
||||
'Reorder': 'Reorder',
|
||||
'Item Added In a cart': 'Item Added In a cart',
|
||||
'You’re not logged in. Please sign in to access your account and explore all features': 'You’re not logged in. Please sign in to access your account and explore all features',
|
||||
'My Order': 'My Order',
|
||||
'Keep track your delivered, In Progress and Rejected item all in just one place.': 'Keep track your delivered, In Progress and Rejected item all in just one place.',
|
||||
'All': 'All',
|
||||
'In Progress': 'In Progress',
|
||||
'Delivered': 'Delivered',
|
||||
'Rejected': 'Rejected',
|
||||
'Order Not Found': 'Order Not Found',
|
||||
'View Details': 'View Details',
|
||||
'My Profile': 'My Profile',
|
||||
'Manage your personal information, preferences, and settings all in one place.': 'Manage your personal information, preferences, and settings all in one place.',
|
||||
'General Information': 'General Information',
|
||||
'Dine-In': 'Dine-In',
|
||||
'Gift Card': 'Gift Card',
|
||||
'Bookings Information': 'Bookings Information',
|
||||
'Dine-In Booking': 'Dine-In Booking',
|
||||
'Preferences': 'Preferences',
|
||||
'Dark Mode': 'Dark Mode',
|
||||
'Social': 'Social',
|
||||
'Refer a Friend': 'Refer a Friend',
|
||||
'Share app': 'Share app',
|
||||
'Check out Foodie, your ultimate food delivery application!': 'Check out Foodie, your ultimate food delivery application!',
|
||||
'Google Play:': 'Google Play:',
|
||||
'App Store:': 'App Store:',
|
||||
'Look what I made!': 'Look what I made!',
|
||||
'Rate the app': 'Rate the app',
|
||||
'Communication': 'Communication',
|
||||
'Provider Inbox': 'Provider Inbox',
|
||||
'Worker Inbox': 'Worker Inbox',
|
||||
'Top up Wallet': 'Top up Wallet',
|
||||
'Legal': 'Legal',
|
||||
'Terms & Conditions': 'Terms & Conditions',
|
||||
'Privacy Policy': 'Privacy Policy',
|
||||
'Terms and Conditions': 'Terms and Conditions',
|
||||
'Log out': 'Log out',
|
||||
'Are you sure you want to log out? You will need to enter your credentials to log back in.': 'Are you sure you want to log out? You will need to enter your credentials to log back in.',
|
||||
'Delete Account': 'Delete Account',
|
||||
'Are you sure you want to delete your account? This action is irreversible and will permanently remove all your data.':
|
||||
'Are you sure you want to delete your account? This action is irreversible and will permanently remove all your data.',
|
||||
'Delete': 'Delete',
|
||||
'Account deleted successfully': 'Account deleted successfully',
|
||||
'Contact Administrator': 'Contact Administrator',
|
||||
'V :': 'V :',
|
||||
'Cashbacks': 'Cashbacks',
|
||||
'Rate the item': 'Rate the item',
|
||||
'Choose a image and upload here': 'Choose a image and upload here',
|
||||
'JPEG, PNG': 'JPEG, PNG',
|
||||
'Brows Image': 'Brows Image',
|
||||
'Type comment': 'Type comment',
|
||||
'Submit Review': 'Submit Review',
|
||||
'Please Select': 'Please Select',
|
||||
'Camera': 'Camera',
|
||||
'Gallery': 'Gallery',
|
||||
'Failed to pick image:': 'Failed to pick image:',
|
||||
'Refer your friend and earn': 'Refer your friend and earn',
|
||||
'Invite Friends & Businesses': 'Invite Friends & Businesses',
|
||||
'Invite your friends to sign up with Foodie using your code, and you’ll earn': 'Invite your friends to sign up with Foodie using your code, and you’ll earn',
|
||||
'after their Success the first order!': 'after their Success the first order!',
|
||||
'Copied': 'Copied',
|
||||
'or': 'or',
|
||||
'Share Code': 'Share Code',
|
||||
'Hey there, thanks for choosing Foodie. Hope you love our product. If you do, share it with your friends using code':
|
||||
'Hey there, thanks for choosing Foodie. Hope you love our product. If you do, share it with your friends using code',
|
||||
'and get': 'and get',
|
||||
'when order completed': 'when order completed',
|
||||
'items': 'items',
|
||||
'View Cart': 'View Cart',
|
||||
'Timing is not added by store': 'Timing is not added by store',
|
||||
'Also applicable on table booking': 'Also applicable on table booking',
|
||||
'Additional Offers': 'Additional Offers',
|
||||
'Search the item and more...': 'Search the item and more...',
|
||||
'Veg': 'Veg',
|
||||
'Non Veg': 'Non Veg',
|
||||
'Info': 'Info',
|
||||
"Product Information's": "Product Information's",
|
||||
'Gram': 'Gram',
|
||||
'Calories': 'Calories',
|
||||
'Proteins': 'Proteins',
|
||||
'Fats': 'Fats',
|
||||
'Specification': 'Specification',
|
||||
'Back': 'Back',
|
||||
'Required • Select any 1 option': 'Required • Select any 1 option',
|
||||
'Add item': 'Add item',
|
||||
'Reviews': 'Reviews',
|
||||
'reviews': 'reviews',
|
||||
'No Review found': 'No Review found',
|
||||
'Scan QR Code': 'Scan QR Code',
|
||||
'Store is not available': 'Store is not available',
|
||||
'km': 'km',
|
||||
"Change": "Change",
|
||||
'Picked from Map': 'Picked from Map',
|
||||
'Allows users to view, manage, add, or edit delivery addresses.': 'Allows users to view, manage, add, or edit delivery addresses.',
|
||||
"We'll be back soon!": "We'll be back soon!",
|
||||
"Sorry for the inconvenience but we're performing some maintenance at the moment. We'll be back online shortly!":
|
||||
"Sorry for the inconvenience but we're performing some maintenance at the moment. We'll be back online shortly!",
|
||||
'cashback after completing the order.': 'cashback after completing the order.',
|
||||
'Please enter coupon code': 'Please enter coupon code',
|
||||
'Pay': 'Pay',
|
||||
'after their Success the first order! 💸🍔': 'after their Success the first order! 💸🍔',
|
||||
'Find your favorite products and nearby stores': 'Find your favorite products and nearby stores',
|
||||
'Search Item & Store': 'Search Item & Store',
|
||||
'Search the store and item': 'Search the store and item',
|
||||
'Store': 'Store',
|
||||
'Select Top up Options': 'Select Top up Options',
|
||||
'Top-up': 'Top-up',
|
||||
'Please Enter minimum amount of': 'Please Enter minimum amount of',
|
||||
'My Wallet': 'My Wallet',
|
||||
'Keep track of your balance, transactions, and payment methods all in one place.': 'Keep track of your balance, transactions, and payment methods all in one place.',
|
||||
'Top up': 'Top up',
|
||||
'Transaction not found': 'Transaction not found',
|
||||
'Order details not available': 'Order details not available',
|
||||
'Favourite Services': 'Favourite Services',
|
||||
'Favourite Service not found.': 'Favourite Service not found.',
|
||||
'hr': 'hr',
|
||||
'Booking History': 'Booking History',
|
||||
'No ride found': 'No ride found',
|
||||
'OTP :': 'OTP :',
|
||||
'Date & Time': 'Date & Time',
|
||||
'Provider': 'Provider',
|
||||
'Start Time': 'Start Time',
|
||||
'End Time': 'End Time',
|
||||
'Worker': 'Worker',
|
||||
'Book Service': 'Book Service',
|
||||
'Services': 'Services',
|
||||
'Address': 'Address',
|
||||
'Description': 'Description',
|
||||
'Enter Description': 'Enter Description',
|
||||
'Booking Date & Slot': 'Booking Date & Slot',
|
||||
'Choose Date and Time': 'Choose Date and Time',
|
||||
'Price Detail': 'Price Detail',
|
||||
'Confirm': 'Confirm',
|
||||
'% Off': '% Off',
|
||||
'valid till ': 'valid till ',
|
||||
'Redeem Your Coupons': 'Redeem Your Coupons',
|
||||
'Voucher or Coupon code': 'Voucher or Coupon code',
|
||||
'REDEEM NOW': 'REDEEM NOW',
|
||||
'Applied coupon not valid.': 'Applied coupon not valid.',
|
||||
'Price': 'Price',
|
||||
'Total Amount': 'Total Amount',
|
||||
'Explore services': 'Explore services',
|
||||
'Explore services tailored for you—quick, easy, and personalized.': 'Explore services tailored for you—quick, easy, and personalized.',
|
||||
'No Categories': 'No Categories',
|
||||
'About': 'About',
|
||||
'Review': 'Review',
|
||||
'No Image Found': 'No Image Found',
|
||||
'No review Found': 'No review Found',
|
||||
'Service Timing': 'Service Timing',
|
||||
'Start Time : ': 'Start Time : ',
|
||||
'End Time : ': 'End Time : ',
|
||||
'Service Days': 'Service Days',
|
||||
'No Service Found': 'No Service Found',
|
||||
'All Services': 'All Services',
|
||||
'Search Service': 'Search Service',
|
||||
'No Services Found': 'No Services Found',
|
||||
'Wallet balance is 0. Please recharge wallet.': 'Wallet balance is 0. Please recharge wallet.',
|
||||
'Insufficient wallet balance. Please add funds.': 'Insufficient wallet balance. Please add funds.',
|
||||
'Cancel Reason': 'Cancel Reason',
|
||||
'Booking ID': 'Booking ID',
|
||||
'Booking ID Copied': 'Booking ID Copied',
|
||||
'Booking Address :': 'Booking Address :',
|
||||
'Date:': 'Date:',
|
||||
'Time:': 'Time:',
|
||||
'About Worker': 'About Worker',
|
||||
'Call': 'Call',
|
||||
'Chat': 'Chat',
|
||||
'About provider': 'About provider',
|
||||
'Total Extra Charges : ': 'Total Extra Charges : ',
|
||||
'Extra charge Notes : ': 'Extra charge Notes : ',
|
||||
'New Date : ': 'New Date : ',
|
||||
'Cancel Booking': 'Cancel Booking',
|
||||
'Pay Extra Amount': 'Pay Extra Amount',
|
||||
'Please give reason for canceling this Booking': 'Please give reason for canceling this Booking',
|
||||
'Specify your reason here': 'Specify your reason here',
|
||||
'Please enter reason': 'Please enter reason',
|
||||
'Most Popular services': 'Most Popular services',
|
||||
'"Total Amount': '"Total Amount',
|
||||
'Book Your Document Delivery': 'Book Your Document Delivery',
|
||||
'Schedule a secure and timely pickup & delivery': 'Schedule a secure and timely pickup & delivery',
|
||||
'Sender Information': 'Sender Information',
|
||||
'Receiver Information': 'Receiver Information',
|
||||
'Select delivery type': 'Select delivery type',
|
||||
'As soon as possible': 'As soon as possible',
|
||||
'Scheduled': 'Scheduled',
|
||||
'When to pickup at this address': 'When to pickup at this address',
|
||||
'Upload parcel image': 'Upload parcel image',
|
||||
'Upload Parcel Image': 'Upload Parcel Image',
|
||||
'Supported: .jpg, .jpeg, .png': 'Supported: .jpg, .jpeg, .png',
|
||||
'Max size 1MB': 'Max size 1MB',
|
||||
'Browse Image': 'Browse Image',
|
||||
'Your Location': 'Your Location',
|
||||
'Select parcel Weight': 'Select parcel Weight',
|
||||
'Normal': 'Normal',
|
||||
'Notes (Optional)': 'Notes (Optional)',
|
||||
'What are you sending?': 'What are you sending?',
|
||||
'Parcel History': 'Parcel History',
|
||||
'No orders found': 'No orders found',
|
||||
'Order Date:': 'Order Date:',
|
||||
'Pickup Address (Sender):': 'Pickup Address (Sender):',
|
||||
'Delivery Address (Receiver):': 'Delivery Address (Receiver):',
|
||||
'Your Order Has Been Placed!': 'Your Order Has Been Placed!',
|
||||
'We’ve received your parcel booking and it’s now being processed. You can track its status in real time.':
|
||||
'We’ve received your parcel booking and it’s now being processed. You can track its status in real time.',
|
||||
'Track Your Order': 'Track Your Order',
|
||||
'Order Confirmation': 'Order Confirmation',
|
||||
'Weight': 'Weight',
|
||||
'Rate': 'Rate',
|
||||
'Coupons': 'Coupons',
|
||||
'Write coupon code': 'Write coupon code',
|
||||
'Payment by': 'Payment by',
|
||||
'Sender': 'Sender',
|
||||
'Receiver': 'Receiver',
|
||||
'Insufficient wallet balance': 'Insufficient wallet balance',
|
||||
'Your parcel is on the way. Track it in real time below.': 'Your parcel is on the way. Track it in real time below.',
|
||||
'Schedule Pickup time:': 'Schedule Pickup time:',
|
||||
'Parcel Type:': 'Parcel Type:',
|
||||
'About Driver': 'About Driver',
|
||||
'Cancel Parcel': 'Cancel Parcel',
|
||||
'Parcel Status Timeline': 'Parcel Status Timeline',
|
||||
'No status updates yet': 'No status updates yet',
|
||||
'Rental History': 'Rental History',
|
||||
'Vehicle Type :': 'Vehicle Type :',
|
||||
'Package info :': 'Package info :',
|
||||
'Confirm Rent a Car': 'Confirm Rent a Car',
|
||||
'Your Preference': 'Your Preference',
|
||||
'Your current location': 'Your current location',
|
||||
'Please login to continue': 'Please login to continue',
|
||||
'Please select a vehicle type': 'Please select a vehicle type',
|
||||
'No preference available for the selected vehicle type': 'No preference available for the selected vehicle type',
|
||||
'Select Preferences': 'Select Preferences',
|
||||
'Booking Id :': 'Booking Id :',
|
||||
'Booking ID copied to clipboard': 'Booking ID copied to clipboard',
|
||||
'Rental Details': 'Rental Details',
|
||||
'Rental Package': 'Rental Package',
|
||||
'Rental Package Price': 'Rental Package Price',
|
||||
'Including': 'Including',
|
||||
'Including Hours': 'Including Hours',
|
||||
'Hr': 'Hr',
|
||||
'Extra': 'Extra',
|
||||
'Extra Minutes': 'Extra Minutes',
|
||||
'You are not able to pay now until driver adds kilometer': 'You are not able to pay now until driver adds kilometer',
|
||||
'OnDemand Service successfully booked': 'OnDemand Service successfully booked',
|
||||
'Booking Extra charge debited': 'Booking Extra charge debited',
|
||||
'Extra Charge Amount Credited': 'Extra Charge Amount Credited',
|
||||
'Failed to get access token': 'Failed to get access token',
|
||||
'Add your parcel image.': 'Add your parcel image.',
|
||||
'Please enter sender name': 'Please enter sender name',
|
||||
'Please enter sender mobile': 'Please enter sender mobile',
|
||||
'Please enter sender address': 'Please enter sender address',
|
||||
'Please enter receiver name': 'Please enter receiver name',
|
||||
'Please enter receiver mobile': 'Please enter receiver mobile',
|
||||
'Please enter receiver address': 'Please enter receiver address',
|
||||
'Please select scheduled date': 'Please select scheduled date',
|
||||
'Please select scheduled time': 'Please select scheduled time',
|
||||
'Please select parcel weight': 'Please select parcel weight',
|
||||
'Please select both sender and receiver locations': 'Please select both sender and receiver locations',
|
||||
"Sender's location to receiver's location should be more than 1 km.": "Sender's location to receiver's location should be more than 1 km.",
|
||||
"Something went wrong while booking.": "Something went wrong while booking.",
|
||||
"Cab Amount debited": "Cab Amount debited",
|
||||
"Stop": "Stop",
|
||||
'Departure': 'Departure',
|
||||
'Destination': 'Destination',
|
||||
'In Transit': 'In Transit',
|
||||
'Order Accepted': 'Order Accepted',
|
||||
'Driver Accepted': 'Driver Accepted',
|
||||
'Driver Pending': 'Driver Pending',
|
||||
'Order Shipped': 'Order Shipped',
|
||||
'Order Completed': 'Order Completed',
|
||||
'Order Rejected': 'Order Rejected',
|
||||
'Order Cancelled': 'Order Cancelled',
|
||||
'Driver Rejected': 'Driver Rejected',
|
||||
'You can only cancel before pickup.': 'You can only cancel before pickup.',
|
||||
'Refund for cancelled parcel order': 'Refund for cancelled parcel order',
|
||||
'success': 'success',
|
||||
'Order cancelled successfully': 'Order cancelled successfully',
|
||||
'Failed to cancel order:': 'Failed to cancel order:',
|
||||
'Parcel Amount debited': 'Parcel Amount debited',
|
||||
'Order placed successfully': 'Order placed successfully',
|
||||
'Initializing payment...': 'Initializing payment...',
|
||||
'Payment Unsuccessful!!': 'Payment Unsuccessful!!',
|
||||
'Rating saved successfully.': 'Rating saved successfully.',
|
||||
'Please add rate for food item.': 'Please add rate for food item.',
|
||||
'Placing booking...': 'Placing booking...',
|
||||
'Unable to fetch current location': 'Unable to fetch current location',
|
||||
'Failed to calculate total:': 'Failed to calculate total:',
|
||||
'Rental Amount debited': 'Rental Amount debited',
|
||||
'Refund for cancelled booking': 'Refund for cancelled booking',
|
||||
'Success': 'Success',
|
||||
'Booking cancelled successfully': 'Booking cancelled successfully',
|
||||
'Failed to cancel booking:': 'Failed to cancel booking:',
|
||||
'email': 'email',
|
||||
'Restaurants': 'Restaurants',
|
||||
'Amount Top-up successfully': 'Amount Top-up successfully',
|
||||
'Something want wrong please contact administrator': 'Something want wrong please contact administrator',
|
||||
'Payment': 'Payment',
|
||||
'Cancel Payment': 'Cancel Payment',
|
||||
'Cancel Payment?': 'Cancel Payment?',
|
||||
'Orange Money Payment': 'Orange Money Payment',
|
||||
'Are you sure you want to cancel this payment?': 'Are you sure you want to cancel this payment?',
|
||||
'No': 'No',
|
||||
'Yes': 'Yes',
|
||||
'Continue Payment': 'Continue Payment',
|
||||
'Exit': 'Exit',
|
||||
'Your cart already contains items from another restaurant. Would you like to replace them with items from this restaurant instead?':
|
||||
'Your cart already contains items from another restaurant. Would you like to replace them with items from this restaurant instead?',
|
||||
'Google map is not installed': 'Google map is not installed',
|
||||
'Google Go map is not installed': 'Google Go map is not installed',
|
||||
'Waze is not installed': 'Waze is not installed',
|
||||
'Mapswithme is not installed': 'Mapswithme is not installed',
|
||||
'YandexNavi is not installed': 'YandexNavi is not installed',
|
||||
'yandexMaps map is not installed': 'yandexMaps map is not installed',
|
||||
'Image failed to load.': 'Image failed to load.',
|
||||
'You denied location permission forever. Please allow location permission from your app settings and receive more accurate delivery.':
|
||||
'You denied location permission forever. Please allow location permission from your app settings and receive more accurate delivery.',
|
||||
'close': 'close',
|
||||
'Settings': 'Settings',
|
||||
'Move the map to select a location': 'Move the map to select a location',
|
||||
'Search place...': 'Search place...',
|
||||
'Confirm Location': 'Confirm Location',
|
||||
'PickUp Location': 'PickUp Location',
|
||||
'Search location...': 'Search location...',
|
||||
'Picked Location:': 'Picked Location:',
|
||||
'No Location Picked': 'No Location Picked',
|
||||
'Email is Required': 'Email is Required',
|
||||
'Invalid Email': 'Invalid Email',
|
||||
};
|
||||
87
lib/main.dart
Normal file
87
lib/main.dart
Normal file
@@ -0,0 +1,87 @@
|
||||
import 'package:customer/screen_ui/splash_screen/splash_screen.dart';
|
||||
import 'package:customer/service/localization_service.dart';
|
||||
import 'package:customer/themes/app_them_data.dart';
|
||||
import 'package:customer/themes/easy_loading_config.dart';
|
||||
import 'package:customer/utils/preferences.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'controllers/global_setting_controller.dart';
|
||||
import 'controllers/theme_controller.dart';
|
||||
import 'firebase_options.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp(name: 'default', options: DefaultFirebaseOptions.currentPlatform);
|
||||
|
||||
await Preferences.initPref();
|
||||
|
||||
Get.put(ThemeController());
|
||||
await configEasyLoading();
|
||||
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
MyApp({super.key});
|
||||
|
||||
final themeController = Get.find<ThemeController>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(ThemeController());
|
||||
return Obx(
|
||||
() => GetMaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
builder: (context, child) {
|
||||
return SafeArea(bottom: true, top: false, child: EasyLoading.init()(context, child));
|
||||
},
|
||||
translations: LocalizationService(),
|
||||
locale: LocalizationService.locale,
|
||||
fallbackLocale: LocalizationService.locale,
|
||||
themeMode: themeController.themeMode,
|
||||
theme: ThemeData(
|
||||
scaffoldBackgroundColor: AppThemeData.surface,
|
||||
textTheme: TextTheme(bodyLarge: TextStyle(color: AppThemeData.grey900)),
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: AppThemeData.surface,
|
||||
foregroundColor: AppThemeData.grey900,
|
||||
iconTheme: IconThemeData(color: AppThemeData.grey900),
|
||||
),
|
||||
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
||||
backgroundColor: AppThemeData.surface,
|
||||
selectedItemColor: AppThemeData.primary300,
|
||||
unselectedItemColor: AppThemeData.grey600,
|
||||
selectedLabelStyle: TextStyle(fontFamily: AppThemeData.bold, fontSize: 12),
|
||||
unselectedLabelStyle: TextStyle(fontFamily: AppThemeData.bold, fontSize: 12),
|
||||
type: BottomNavigationBarType.fixed,
|
||||
),
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
scaffoldBackgroundColor: AppThemeData.surfaceDark,
|
||||
textTheme: TextTheme(bodyLarge: TextStyle(color: AppThemeData.greyDark900)),
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: AppThemeData.surfaceDark,
|
||||
foregroundColor: AppThemeData.greyDark900,
|
||||
iconTheme: IconThemeData(color: AppThemeData.greyDark900),
|
||||
),
|
||||
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
||||
backgroundColor: AppThemeData.grey900,
|
||||
selectedItemColor: AppThemeData.primary300,
|
||||
unselectedItemColor: AppThemeData.grey300,
|
||||
selectedLabelStyle: TextStyle(fontFamily: AppThemeData.bold, fontSize: 12),
|
||||
unselectedLabelStyle: TextStyle(fontFamily: AppThemeData.bold, fontSize: 12),
|
||||
type: BottomNavigationBarType.fixed,
|
||||
),
|
||||
),
|
||||
home: GetBuilder<GlobalSettingController>(
|
||||
init: GlobalSettingController(),
|
||||
builder: (context) {
|
||||
return const SplashScreen();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
21
lib/models/admin_commission_model.dart
Normal file
21
lib/models/admin_commission_model.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
class AdminCommission {
|
||||
String? amount;
|
||||
bool? isEnabled;
|
||||
String? commissionType;
|
||||
|
||||
AdminCommission({this.amount, this.isEnabled, this.commissionType});
|
||||
|
||||
AdminCommission.fromJson(Map<String, dynamic> json) {
|
||||
amount = json['commission'].toString();
|
||||
isEnabled = json['enable'];
|
||||
commissionType = json['type'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['commission'] = amount;
|
||||
data['enable'] = isEnabled;
|
||||
data['type'] = commissionType;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
97
lib/models/advertisement_model.dart
Normal file
97
lib/models/advertisement_model.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
|
||||
class AdvertisementModel {
|
||||
String? coverImage;
|
||||
Timestamp? createdAt;
|
||||
String? description;
|
||||
Timestamp? endDate;
|
||||
String? id;
|
||||
bool? paymentStatus;
|
||||
String? priority;
|
||||
String? profileImage;
|
||||
bool? showRating;
|
||||
bool? showReview;
|
||||
Timestamp? startDate;
|
||||
String? status;
|
||||
String? title;
|
||||
String? type;
|
||||
String? vendorId;
|
||||
String? video;
|
||||
bool? isPaused;
|
||||
Timestamp? updatedAt;
|
||||
String? canceledNote;
|
||||
String? pauseNote;
|
||||
|
||||
AdvertisementModel({
|
||||
this.coverImage,
|
||||
this.createdAt,
|
||||
this.description,
|
||||
this.endDate,
|
||||
this.id,
|
||||
this.paymentStatus,
|
||||
this.priority,
|
||||
this.profileImage,
|
||||
this.showRating,
|
||||
this.showReview,
|
||||
this.startDate,
|
||||
this.status,
|
||||
this.title,
|
||||
this.type,
|
||||
this.vendorId,
|
||||
this.video,
|
||||
this.isPaused,
|
||||
this.updatedAt,
|
||||
this.canceledNote,
|
||||
this.pauseNote,
|
||||
});
|
||||
|
||||
factory AdvertisementModel.fromJson(Map<String, dynamic> json) {
|
||||
return AdvertisementModel(
|
||||
coverImage: json['coverImage'],
|
||||
createdAt: json['createdAt'],
|
||||
description: json['description'],
|
||||
endDate: json['endDate'],
|
||||
id: json['id'],
|
||||
paymentStatus: json['paymentStatus'],
|
||||
priority: json['priority'],
|
||||
profileImage: json['profileImage'],
|
||||
showRating: json['showRating'],
|
||||
showReview: json['showReview'],
|
||||
startDate: json['startDate'],
|
||||
status: json['status'],
|
||||
title: json['title'],
|
||||
type: json['type'],
|
||||
vendorId: json['vendorId'],
|
||||
video: json['video'],
|
||||
isPaused: json['isPaused'],
|
||||
updatedAt: json['updatedAt'],
|
||||
canceledNote: json['canceledNote'],
|
||||
pauseNote: json['pauseNote']);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'coverImage': coverImage,
|
||||
'createdAt': createdAt,
|
||||
'description': description,
|
||||
'endDate': endDate,
|
||||
'id': id,
|
||||
'paymentStatus': paymentStatus,
|
||||
'priority': priority,
|
||||
'profileImage': profileImage,
|
||||
'showRating': showRating,
|
||||
'showReview': showReview,
|
||||
'startDate': startDate,
|
||||
'status': status,
|
||||
'title': title,
|
||||
'type': type,
|
||||
'vendorId': vendorId,
|
||||
'video': video,
|
||||
'isPaused': isPaused,
|
||||
'updatedAt': updatedAt,
|
||||
'canceledNote': canceledNote,
|
||||
'pauseNote': pauseNote,
|
||||
};
|
||||
}
|
||||
}
|
||||
18
lib/models/attributes_model.dart
Normal file
18
lib/models/attributes_model.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
class AttributesModel {
|
||||
String? id;
|
||||
String? title;
|
||||
|
||||
AttributesModel({this.id, this.title});
|
||||
|
||||
AttributesModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
title = json['title'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['title'] = title;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
39
lib/models/banner_model.dart
Normal file
39
lib/models/banner_model.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
class BannerModel {
|
||||
String? id;
|
||||
int? setOrder;
|
||||
String? position;
|
||||
String? sectionId;
|
||||
String? photo;
|
||||
String? title;
|
||||
String? redirect_type;
|
||||
String? redirect_id;
|
||||
bool? isPublish;
|
||||
|
||||
BannerModel({this.id, this.setOrder, this.position, this.redirect_type, this.redirect_id, this.sectionId, this.photo, this.title, this.isPublish});
|
||||
|
||||
BannerModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
position = json['position'];
|
||||
sectionId = json['sectionId'];
|
||||
setOrder = json['set_order'];
|
||||
photo = json['photo'];
|
||||
title = json['title'];
|
||||
isPublish = json['is_publish'];
|
||||
redirect_type = json['redirect_type'];
|
||||
redirect_id = json['redirect_id'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['position'] = position;
|
||||
data['sectionId'] = sectionId;
|
||||
data['set_order'] = setOrder;
|
||||
data['photo'] = photo;
|
||||
data['title'] = title;
|
||||
data['is_publish'] = isPublish;
|
||||
data['redirect_type'] = redirect_type;
|
||||
data['redirect_id'] = redirect_id;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
27
lib/models/brands_model.dart
Normal file
27
lib/models/brands_model.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
class BrandsModel {
|
||||
String? photo;
|
||||
String? sectionId;
|
||||
String? id;
|
||||
String? title;
|
||||
bool? isPublish;
|
||||
|
||||
BrandsModel({this.photo, this.sectionId, this.id, this.title, this.isPublish});
|
||||
|
||||
BrandsModel.fromJson(Map<String, dynamic> json) {
|
||||
photo = json['photo'];
|
||||
sectionId = json['sectionId'];
|
||||
id = json['id'];
|
||||
title = json['title'];
|
||||
isPublish = json['is_publish'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['photo'] = photo;
|
||||
data['sectionId'] = sectionId;
|
||||
data['id'] = id;
|
||||
data['title'] = title;
|
||||
data['is_publish'] = isPublish;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
192
lib/models/cab_order_model.dart
Normal file
192
lib/models/cab_order_model.dart
Normal file
@@ -0,0 +1,192 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:customer/models/tax_model.dart';
|
||||
import 'package:customer/models/user_model.dart';
|
||||
import 'package:customer/models/vehicle_type.dart';
|
||||
|
||||
class CabOrderModel {
|
||||
String? status;
|
||||
List<dynamic>? rejectedByDrivers;
|
||||
String? couponId;
|
||||
Timestamp? scheduleDateTime;
|
||||
String? duration;
|
||||
bool? roundTrip;
|
||||
bool? paymentStatus;
|
||||
String? discount;
|
||||
String? destinationLocationName;
|
||||
String? authorID;
|
||||
Timestamp? createdAt;
|
||||
DestinationLocation? destinationLocation;
|
||||
String? adminCommissionType;
|
||||
String? sourceLocationName;
|
||||
String? rideType;
|
||||
List<TaxModel>? taxSetting;
|
||||
Timestamp? triggerDelevery;
|
||||
String? id;
|
||||
String? adminCommission;
|
||||
String? couponCode;
|
||||
Timestamp? scheduleReturnDateTime;
|
||||
String? sectionId;
|
||||
String? tipAmount;
|
||||
String? distance;
|
||||
String? vehicleId;
|
||||
String? paymentMethod;
|
||||
VehicleType? vehicleType;
|
||||
String? otpCode;
|
||||
DestinationLocation? sourceLocation;
|
||||
UserModel? author;
|
||||
UserModel? driver;
|
||||
String? driverId;
|
||||
String? subTotal;
|
||||
|
||||
CabOrderModel({
|
||||
this.status,
|
||||
this.rejectedByDrivers,
|
||||
this.scheduleDateTime,
|
||||
this.duration,
|
||||
this.roundTrip,
|
||||
this.paymentStatus,
|
||||
this.discount,
|
||||
this.destinationLocationName,
|
||||
this.authorID,
|
||||
this.createdAt,
|
||||
this.destinationLocation,
|
||||
this.adminCommissionType,
|
||||
this.sourceLocationName,
|
||||
this.rideType,
|
||||
this.taxSetting,
|
||||
this.triggerDelevery,
|
||||
this.id,
|
||||
this.adminCommission,
|
||||
this.couponCode,
|
||||
this.couponId,
|
||||
this.scheduleReturnDateTime,
|
||||
this.sectionId,
|
||||
this.tipAmount,
|
||||
this.distance,
|
||||
this.vehicleId,
|
||||
this.paymentMethod,
|
||||
this.vehicleType,
|
||||
this.otpCode,
|
||||
this.sourceLocation,
|
||||
this.author,
|
||||
this.subTotal,
|
||||
this.driver,
|
||||
this.driverId,
|
||||
});
|
||||
|
||||
CabOrderModel.fromJson(Map<String, dynamic> json) {
|
||||
status = json['status'];
|
||||
rejectedByDrivers = json['rejectedByDrivers'] ?? [];
|
||||
couponId = json['couponId'];
|
||||
scheduleDateTime = json['scheduleDateTime'];
|
||||
duration = json['duration'];
|
||||
roundTrip = json['roundTrip'];
|
||||
paymentStatus = json['paymentStatus'];
|
||||
discount = json['discount'] == null ?"0.0": json['discount'].toString();
|
||||
destinationLocationName = json['destinationLocationName'];
|
||||
authorID = json['authorID'];
|
||||
createdAt = json['createdAt'];
|
||||
destinationLocation = json['destinationLocation'] != null ? DestinationLocation.fromJson(json['destinationLocation']) : null;
|
||||
adminCommissionType = json['adminCommissionType'];
|
||||
sourceLocationName = json['sourceLocationName'];
|
||||
rideType = json['rideType'];
|
||||
if (json['taxSetting'] != null) {
|
||||
taxSetting = <TaxModel>[];
|
||||
json['taxSetting'].forEach((v) {
|
||||
taxSetting!.add(TaxModel.fromJson(v));
|
||||
});
|
||||
}
|
||||
triggerDelevery = json['trigger_delevery'];
|
||||
id = json['id'];
|
||||
adminCommission = json['adminCommission'];
|
||||
couponCode = json['couponCode'];
|
||||
scheduleReturnDateTime = json['scheduleReturnDateTime'];
|
||||
sectionId = json['sectionId'];
|
||||
tipAmount = json['tip_amount'];
|
||||
distance = json['distance'];
|
||||
vehicleId = json['vehicleId'];
|
||||
paymentMethod = json['paymentMethod'];
|
||||
vehicleType = json['vehicleType'] != null ? VehicleType.fromJson(json['vehicleType']) : null;
|
||||
otpCode = json['otpCode'];
|
||||
sourceLocation = json['sourceLocation'] != null ? DestinationLocation.fromJson(json['sourceLocation']) : null;
|
||||
author = json['author'] != null ? UserModel.fromJson(json['author']) : null;
|
||||
subTotal = json['subTotal'];
|
||||
driver = json['driver'] != null ? UserModel.fromJson(json['driver']) : null;
|
||||
driverId = json['driverId'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['status'] = status;
|
||||
// if (rejectedByDrivers != null) {
|
||||
// data['rejectedByDrivers'] = rejectedByDrivers!.map((v) => v.toJson()).toList();
|
||||
// }
|
||||
if (rejectedByDrivers != null) {
|
||||
data['rejectedByDrivers'] = rejectedByDrivers;
|
||||
}
|
||||
data['couponId'] = couponId;
|
||||
data['scheduleDateTime'] = scheduleDateTime;
|
||||
data['duration'] = duration;
|
||||
data['roundTrip'] = roundTrip;
|
||||
data['paymentStatus'] = paymentStatus;
|
||||
data['discount'] = discount;
|
||||
data['destinationLocationName'] = destinationLocationName;
|
||||
data['authorID'] = authorID;
|
||||
data['createdAt'] = createdAt;
|
||||
if (destinationLocation != null) {
|
||||
data['destinationLocation'] = destinationLocation!.toJson();
|
||||
}
|
||||
data['adminCommissionType'] = adminCommissionType;
|
||||
data['sourceLocationName'] = sourceLocationName;
|
||||
data['rideType'] = rideType;
|
||||
if (taxSetting != null) {
|
||||
data['taxSetting'] = taxSetting!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
data['trigger_delevery'] = triggerDelevery!;
|
||||
data['id'] = id;
|
||||
data['adminCommission'] = adminCommission;
|
||||
data['couponCode'] = couponCode;
|
||||
data['scheduleReturnDateTime'] = scheduleReturnDateTime;
|
||||
data['sectionId'] = sectionId;
|
||||
data['tip_amount'] = tipAmount;
|
||||
data['distance'] = distance;
|
||||
data['vehicleId'] = vehicleId;
|
||||
data['paymentMethod'] = paymentMethod;
|
||||
data['driverId'] = driverId;
|
||||
if (driver != null) {
|
||||
data['driver'] = driver!.toJson();
|
||||
}
|
||||
|
||||
if (vehicleType != null) {
|
||||
data['vehicleType'] = vehicleType!.toJson();
|
||||
}
|
||||
data['otpCode'] = otpCode;
|
||||
if (sourceLocation != null) {
|
||||
data['sourceLocation'] = sourceLocation!.toJson();
|
||||
}
|
||||
if (author != null) {
|
||||
data['author'] = author!.toJson();
|
||||
}
|
||||
data['subTotal'] = subTotal;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class DestinationLocation {
|
||||
double? longitude;
|
||||
double? latitude;
|
||||
|
||||
DestinationLocation({this.longitude, this.latitude});
|
||||
|
||||
DestinationLocation.fromJson(Map<String, dynamic> json) {
|
||||
longitude = json['longitude'];
|
||||
latitude = json['latitude'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['longitude'] = longitude;
|
||||
data['latitude'] = latitude;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
99
lib/models/cart_product_model.dart
Normal file
99
lib/models/cart_product_model.dart
Normal file
@@ -0,0 +1,99 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class CartProductModel {
|
||||
String? id;
|
||||
String? categoryId;
|
||||
String? name;
|
||||
String? photo;
|
||||
String? price;
|
||||
String? discountPrice;
|
||||
String? vendorID;
|
||||
int? quantity;
|
||||
String? extrasPrice;
|
||||
List<dynamic>? extras;
|
||||
VariantInfo? variantInfo;
|
||||
|
||||
CartProductModel({
|
||||
this.id,
|
||||
this.categoryId,
|
||||
this.name,
|
||||
this.photo,
|
||||
this.price,
|
||||
this.discountPrice,
|
||||
this.vendorID,
|
||||
this.quantity,
|
||||
this.extrasPrice,
|
||||
this.variantInfo,
|
||||
this.extras,
|
||||
});
|
||||
|
||||
CartProductModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
categoryId = json['category_id'];
|
||||
name = json['name'];
|
||||
photo = json['photo'];
|
||||
price = json['price'] ?? "0.0";
|
||||
discountPrice = json['discountPrice'] ?? "0.0";
|
||||
vendorID = json['vendorID'];
|
||||
quantity = json['quantity'];
|
||||
extrasPrice = json['extras_price'];
|
||||
|
||||
extras = json['extras'] == "null" || json['extras'] == null
|
||||
? null
|
||||
: "String" == json['extras'].runtimeType.toString()
|
||||
? List<dynamic>.from(jsonDecode(json['extras']))
|
||||
: List<dynamic>.from(json['extras']);
|
||||
|
||||
variantInfo = json['variant_info'] == "null" || json['variant_info'] == null
|
||||
? null
|
||||
: "String" == json['variant_info'].runtimeType.toString()
|
||||
? VariantInfo.fromJson(jsonDecode(json['variant_info']))
|
||||
: VariantInfo.fromJson(json['variant_info']);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['category_id'] = categoryId;
|
||||
data['name'] = name;
|
||||
data['photo'] = photo;
|
||||
data['price'] = price;
|
||||
data['discountPrice'] = discountPrice;
|
||||
data['vendorID'] = vendorID;
|
||||
data['quantity'] = quantity;
|
||||
data['extras_price'] = extrasPrice;
|
||||
data['extras'] = extras;
|
||||
if (variantInfo != null) {
|
||||
data['variant_info'] = variantInfo?.toJson(); // Handle null value
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class VariantInfo {
|
||||
String? variantId;
|
||||
String? variantPrice;
|
||||
String? variantSku;
|
||||
String? variantImage;
|
||||
Map<String, dynamic>? variantOptions;
|
||||
|
||||
VariantInfo({this.variantId, this.variantPrice, this.variantSku, this.variantImage, this.variantOptions});
|
||||
|
||||
VariantInfo.fromJson(Map<String, dynamic> json) {
|
||||
variantId = json['variantId'] ?? '';
|
||||
variantPrice = json['variantPrice'] ?? '';
|
||||
variantSku = json['variantSku'] ?? '';
|
||||
variantImage = json['variant_image'] ?? '';
|
||||
variantOptions = json['variant_options'] ?? {};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['variantId'] = variantId;
|
||||
data['variantPrice'] = variantPrice;
|
||||
data['variantSku'] = variantSku;
|
||||
data['variant_image'] = variantImage;
|
||||
data['variant_options'] = variantOptions;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user