import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:google_maps_widget/google_maps_widget.dart'; import 'package:muaawana/views/client_view/rating/rating_screen.dart'; import 'package:muaawana/views/technicien_view/order/map_screen.dart'; import 'package:muaawana/widgets/custom_botton_widget.dart'; import '../../../config/app_constant.dart'; import '../../../config/lang_enum.dart'; import '../../../config/provider.dart'; import '../../../config/size.dart'; import '../../../config/style.dart'; import '../../../models/booking_service/Result.dart'; import '../../../models/order/order_response.dart'; import '../../../providers/language_provider.dart'; import '../../../providers/request_status_provider.dart'; import '../../../utils/date_time_utils.dart'; import '../../../utils/text_style.dart'; import '../../../utils/text_widget.dart'; import '../../../widgets/custom_app_bar.dart'; import '../../technicien_view/order/order_add_price_screen.dart'; import '../home/all_services/service_detail.dart'; class BookingDashboard extends StatelessWidget { final ViewListModel item; const BookingDashboard({super.key, required this.item}); @override Widget build(BuildContext context) { final langProvider = Provider.of(context); final bool isProduct = item.bookingType == BookingType.product; final bool showRating = item.status == "COMPLETED"; final hm = SizeConfig.heightMultiplier; final wm = SizeConfig.widthMultiplier; return Scaffold( backgroundColor: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkAppBackground : AppNewStyle.appBackground, body: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Custom App Bar CustomAppBar( title: '', titleColor: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), SizedBox(height: hm * 2), // Service/Product Name Header Padding( padding: EdgeInsets.symmetric(horizontal: wm * 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: item.name, style: tS( "Inter", 24, FontWeight.bold, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), SizedBox(height: hm), Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(20), border: Border.all( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.primaryButton, width: 1, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( isProduct ? Icons.shopping_bag_outlined : Icons.build_outlined, size: 16, color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.primaryButton, ), SizedBox(width: 6), Txt( text: "${langProvider.translate("Request Type:")} ${item.bookingType.name}", style: tS( "Inter", 12, FontWeight.w600, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.primaryButton, ), ), ], ), ), ], ), ), SizedBox(height: hm * 3), // Main Content Card isProduct ? ProductOrderDetail(id: item.bookingId) : ServiceOrderDetail(id: item.bookingId), SizedBox(height: hm * 4), // Rating Button if (showRating) Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: wm * 4), child: GestureDetector( onTap: () async { Navigator.push( context, MaterialPageRoute( builder: (context) => RatingScreen( bookingType: item.bookingType, id: item.bookingId, technicianId: item.technician?.id, ), ), ); }, child: Container( width: double.infinity, height: 56, decoration: BoxDecoration( color: AppStyle.buttonBlue, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: AppStyle.buttonBlue.withOpacity(0.3), spreadRadius: 2, blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.star_rate_rounded, color: AppStyle.white, size: 20, ), SizedBox(width: 8), Txt( text: langProvider.translate("Leave review"), style: tS( 'Inter', 16, FontWeight.w600, AppStyle.white, ), ), ], ), ), ), ), ), SizedBox(height: hm * 4), ], ), ), ); } } class ProductOrderDetail extends StatelessWidget { ProductOrderDetail({super.key, required this.id}); final int id; final hm = SizeConfig.heightMultiplier; final wm = SizeConfig.widthMultiplier; final tm = SizeConfig.textMultiplier; @override Widget build(BuildContext context) { final orderProvider = Provider.of(context); final langProvider = Provider.of(context); final orderProduct = orderProvider.productBookingList .firstWhere((element) => element.id == id); return Padding( padding: EdgeInsets.symmetric(horizontal: wm * 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Main Order Card Container( width: double.infinity, decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(16), border: langProvider.currentLangCode == Language.en ? Border( left: BorderSide( color: Consts.colorMap["LOW"]!, width: 4.0, ), ) : Border( right: BorderSide( color: Consts.colorMap["LOW"]!, width: 4.0, ), ), boxShadow: [ BoxShadow( color: Theme.of(context).brightness == Brightness.dark ? Colors.black.withOpacity(0.2) : Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Padding( padding: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: AppStyle.dividerGrey.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Txt( text: langProvider.currentLangCode == Language.en ? "Order ${orderProduct.id!}" : "طلب ${orderProduct.id!}", style: tS( "Inter", 11, FontWeight.w600, AppStyle.dividerGrey, ), ), ), SizedBox(height: 8), Txt( text: orderProduct.product!.name!, style: tS( "Inter", 18, FontWeight.bold, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( padding: EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: Consts.colorMap["LOW"]!.withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( height: 8, width: 8, decoration: BoxDecoration( shape: BoxShape.circle, color: Consts.colorMap["LOW"]!, ), ), SizedBox(width: 6), Txt( text: orderProduct.prioritys!, style: tS( "Inter", 12, FontWeight.w600, Consts.colorMap["LOW"]!, ), ), ], ), ), SizedBox(height: 8), Txt( text: formatTimestampToDate(orderProduct.timestamp!), style: tS("Inter", 11, FontWeight.w500, AppStyle.dividerGrey), ), ], ), ], ), SizedBox(height: 20), // Location Row GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => MapScreen( destination: LatLng( orderProduct.address!.position!.altitude!, orderProduct.address!.position!.longitude!, ), ), ), ); }, child: Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: SvgPicture.asset( Consts.markerIcon, height: 16, color: AppStyle.buttonBlue, ), ), SizedBox(width: 12), Expanded( child: Txt( text: orderProduct.address!.address!, style: tS( "Inter", 13, FontWeight.w500, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), overflow: TextOverflow.ellipsis, ), ), Icon( Icons.arrow_forward_ios, size: 14, color: AppStyle.buttonBlue, ), ], ), ), ), SizedBox(height: 16), // Date and Duration Row Row( children: [ Expanded( child: Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ SvgPicture.asset( Consts.calendarIcon, height: 16, color: AppStyle.buttonBlue, ), SizedBox(width: 8), Txt( text: formatTimestampToDate( orderProduct.date ?? DateTime.now().millisecondsSinceEpoch, ), style: tS("Inter", 12, FontWeight.w500, AppStyle.dividerGrey), ), ], ), ), ), SizedBox(width: 12), Expanded( child: Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ SvgPicture.asset( Consts.clockUnfilledIcon, height: 16, color: AppStyle.buttonBlue, ), SizedBox(width: 8), Txt( text: langProvider.currentLangCode == Language.en ? "${orderProduct.serviceduration ?? 30} min" : "${orderProduct.serviceduration ?? 30} دق", style: tS("Inter", 12, FontWeight.w500, AppStyle.dividerGrey), ), ], ), ), ), ], ), SizedBox(height: 16), // Product Description Container( width: double.infinity, padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: langProvider.translate("Product description"), style: tS( "Inter", 14, FontWeight.bold, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), SizedBox(height: 8), Txt( text: orderProduct.product!.description!, style: tS( "Inter", 13, FontWeight.normal, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground.withOpacity(0.8) : AppNewStyle.darkAppBackground.withOpacity(0.8), ), ), ], ), ), ], ), ), ), SizedBox(height: 20), // Payment Summary Card Container( width: double.infinity, padding: EdgeInsets.all(20), decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(16), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.2), width: 1, ), boxShadow: [ BoxShadow( color: Theme.of(context).brightness == Brightness.dark ? Colors.black.withOpacity(0.2) : Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Row( children: [ Container( padding: EdgeInsets.all(10), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Image.asset( Consts.cashPayment, height: 24, ), ), SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: langProvider.translate("Payment Method"), style: tS( "Inter", 12, FontWeight.w500, AppStyle.dividerGrey, ), ), Txt( text: langProvider.translate("Cash"), style: tS( "Inter", 16, FontWeight.w600, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Txt( text: langProvider.translate("Total"), style: tS( "Inter", 12, FontWeight.w500, AppStyle.dividerGrey, ), ), Txt( text: "${orderProduct.product!.price} OMR", style: tS( "Inter", 18, FontWeight.bold, AppStyle.buttonBlue, ), ), ], ), ], ), ), SizedBox(height: 20), // Status Card Container( width: double.infinity, padding: EdgeInsets.all(20), decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Theme.of(context).brightness == Brightness.dark ? Colors.black.withOpacity(0.2) : Colors.grey.withOpacity(0.1), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: langProvider.translate("Request State description"), style: tS( "Inter", 12, FontWeight.w500, AppStyle.dividerGrey, ), ), SizedBox(height: 4), Txt( text: orderProduct.requeststate!, style: tS( "Inter", 16, FontWeight.w600, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: Icon( Icons.info_outline, color: AppStyle.buttonBlue, size: 20, ), ), ], ), ), ], ), ); } } class ServiceOrderDetail extends StatefulWidget { final int id; const ServiceOrderDetail({super.key, required this.id}); @override State createState() => _ServiceOrderDetailState(); } class _ServiceOrderDetailState extends State { final hm = SizeConfig.heightMultiplier; final wm = SizeConfig.widthMultiplier; final tm = SizeConfig.textMultiplier; ServiceResult? serviceProduct; double? total; bool loaded = false; @override void initState() { loaded = false; Future.delayed(Duration.zero, () { serviceProduct = context .read() .serviceBookingList .firstWhere((element) => element.id == widget.id); setState(() { loaded = true; }); calculateTotal(); }); super.initState(); } calculateTotal() { double amount = 0.0; if (serviceProduct != null) { amount = amount + serviceProduct!.amount!; if (serviceProduct!.requestItems!.isNotEmpty) { for (var requestItem in serviceProduct!.requestItems!) { if (requestItem.price != null) { amount = amount + requestItem.price!; } } } } setState(() { total = amount; }); } @override Widget build(BuildContext context) { final langProvider = Provider.of(context); final orderProvider = Provider.of(context); return loaded ? Padding( padding: EdgeInsets.symmetric(horizontal: wm * 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Main Order Card Container( width: double.infinity, decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(16), border: langProvider.currentLangCode == Language.en ? Border( left: BorderSide( color: Consts.colorMap["LOW"]!, width: 4.0, ), ) : Border( right: BorderSide( color: Consts.colorMap["LOW"]!, width: 4.0, ), ), boxShadow: [ BoxShadow( color: Theme.of(context).brightness == Brightness.dark ? Colors.black.withOpacity(0.3) : Colors.grey.withOpacity(0.1), blurRadius: 12, offset: const Offset(0, 4), spreadRadius: 2, ), ], ), child: Padding( padding: EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: EdgeInsets.symmetric( horizontal: 10, vertical: 6), decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppStyle.dividerGrey.withOpacity(0.1), AppStyle.dividerGrey.withOpacity(0.05), ], ), borderRadius: BorderRadius.circular(8), border: Border.all( color: AppStyle.dividerGrey.withOpacity(0.2), width: 1, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.receipt_long, size: 14, color: AppStyle.dividerGrey, ), SizedBox(width: 4), Txt( text: langProvider.currentLangCode == Language.en ? "Order ${serviceProduct!.id!}" : "طلب ${serviceProduct!.id!}", style: tS( "Inter", 12, FontWeight.w700, AppStyle.dividerGrey, ), ), ], ), ), SizedBox(height: 12), Txt( text: serviceProduct!.service!.name!, style: tS( "Inter", 20, FontWeight.bold, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( padding: EdgeInsets.symmetric( horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Consts.colorMap["LOW"]!.withOpacity(0.1), borderRadius: BorderRadius.circular(20), border: Border.all( color: Consts.colorMap["LOW"]!.withOpacity(0.3), width: 1, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( height: 8, width: 8, decoration: BoxDecoration( shape: BoxShape.circle, color: Consts.colorMap["LOW"]!, ), ), SizedBox(width: 6), Txt( text: serviceProduct!.prioritys!, style: tS( "Inter", 12, FontWeight.w700, Consts.colorMap["LOW"]!, ), ), ], ), ), SizedBox(height: 8), Container( padding: EdgeInsets.symmetric( horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(6), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.schedule, size: 12, color: AppStyle.dividerGrey, ), SizedBox(width: 4), Txt( text: formatTimestampToDate( serviceProduct!.timestamp!), style: tS("Inter", 11, FontWeight.w500, AppStyle.dividerGrey), ), ], ), ), ], ), ], ), SizedBox(height: 24), // Location Row GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => MapScreen( destination: LatLng( serviceProduct!.address!.position!.altitude!, serviceProduct!.address!.position!.longitude!, ), ), ), ); }, child: Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.1), width: 1, ), ), child: Row( children: [ Container( padding: EdgeInsets.all(10), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: SvgPicture.asset( Consts.markerIcon, height: 18, color: AppStyle.buttonBlue, ), ), SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: langProvider.translate("Service Location"), style: tS( "Inter", 12, FontWeight.w500, AppStyle.dividerGrey, ), ), SizedBox(height: 4), Txt( text: serviceProduct!.address!.address!, style: tS( "Inter", 14, FontWeight.w600, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), overflow: TextOverflow.ellipsis, maxLines: 2, ), ], ), ), Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.arrow_forward_ios, size: 14, color: AppStyle.buttonBlue, ), ), ], ), ), ), SizedBox(height: 16), // Date and Duration Row Row( children: [ Expanded( child: Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.1), width: 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: EdgeInsets.all(6), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(6), ), child: SvgPicture.asset( Consts.calendarIcon, height: 14, color: AppStyle.buttonBlue, ), ), SizedBox(width: 8), Txt( text: langProvider.translate("Date"), style: tS("Inter", 11, FontWeight.w500, AppStyle.dividerGrey), ), ], ), SizedBox(height: 8), Txt( text: formatTimestampToDate( serviceProduct!.date ?? DateTime.now().millisecondsSinceEpoch, ), style: tS( "Inter", 13, FontWeight.w600, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), ), SizedBox(width: 12), Expanded( child: Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.1), width: 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: EdgeInsets.all(6), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(6), ), child: SvgPicture.asset( Consts.clockUnfilledIcon, height: 14, color: AppStyle.buttonBlue, ), ), SizedBox(width: 8), Txt( text: langProvider.translate("Duration"), style: tS("Inter", 11, FontWeight.w500, AppStyle.dividerGrey), ), ], ), SizedBox(height: 8), Txt( text: langProvider.currentLangCode == Language.en ? "${serviceProduct!.serviceduration ?? 30} min" : "${serviceProduct!.serviceduration ?? 30} دق", style: tS( "Inter", 13, FontWeight.w600, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), ), ], ), SizedBox(height: 16), // Service Description Container( width: double.infinity, padding: EdgeInsets.all(18), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.1), width: 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: EdgeInsets.all(6), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(6), ), child: Icon( Icons.description_outlined, size: 14, color: AppStyle.buttonBlue, ), ), SizedBox(width: 8), Txt( text: langProvider.translate("Service Description"), style: tS( "Inter", 14, FontWeight.bold, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), SizedBox(height: 12), Txt( text: serviceProduct!.description!, style: tS( "Inter", 13, FontWeight.normal, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground.withOpacity(0.8) : AppNewStyle.darkAppBackground.withOpacity(0.8), ), ), ], ), ), SizedBox(height: 16), // Base Price Container( width: double.infinity, padding: EdgeInsets.all(18), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.1), width: 1, ), ), child: Row( children: [ Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.price_check, size: 16, color: AppStyle.buttonBlue, ), ), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: langProvider.translate("Service base price:"), style: tS( "Inter", 12, FontWeight.w500, AppStyle.dividerGrey, ), ), SizedBox(height: 4), Txt( text: "${serviceProduct!.amount!} OMR", style: tS( "Inter", 16, FontWeight.bold, AppStyle.buttonBlue, ), ), ], ), ), ], ), ), ], ), ), ), SizedBox(height: 20), // Payment Summary Card GestureDetector( onTap: () { showDialog( context: context, barrierColor: Colors.black.withOpacity(0.5), builder: (context) { return PricePopUp(listItem: serviceProduct!.requestItems ?? []); }, ); }, child: Container( width: double.infinity, padding: EdgeInsets.all(20), decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(16), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.2), width: 1.5, ), boxShadow: [ BoxShadow( color: Theme.of(context).brightness == Brightness.dark ? Colors.black.withOpacity(0.3) : Colors.grey.withOpacity(0.1), blurRadius: 12, offset: const Offset(0, 4), spreadRadius: 2, ), ], ), child: Row( children: [ Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Image.asset( Consts.cashPayment, height: 28, ), ), SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: langProvider.translate("Payment Method"), style: tS( "Inter", 12, FontWeight.w500, AppStyle.dividerGrey, ), ), SizedBox(height: 4), Txt( text: langProvider.translate("Cash"), style: tS( "Inter", 16, FontWeight.w600, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Txt( text: langProvider.translate("Total"), style: tS( "Inter", 12, FontWeight.w500, AppStyle.dividerGrey, ), ), SizedBox(height: 4), Row( mainAxisSize: MainAxisSize.min, children: [ Txt( text: "$total OMR", style: tS( "Inter", 18, FontWeight.bold, AppStyle.buttonBlue, ), ), SizedBox(width: 8), Container( padding: EdgeInsets.all(4), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(6), ), child: Icon( Icons.receipt_long, size: 14, color: AppStyle.buttonBlue, ), ), ], ), ], ), ], ), ), ), SizedBox(height: 20), // Status Information Cards _buildStatusCard( context, langProvider, langProvider.translate("Request State"), serviceProduct?.requeststate?.capitalizeFirst ?? "", Icons.info_outline, AppStyle.buttonBlue, ), SizedBox(height: 12), _buildStatusCard( context, langProvider, langProvider.translate("Driver State"), serviceProduct?.driverState?.capitalizeFirst ?? "", Icons.local_shipping_outlined, Colors.orange, ), SizedBox(height: 12), _buildStatusCard( context, langProvider, langProvider.translate("Payment Status"), (serviceProduct?.paymentState ?? "No Payment") .toString() .capitalizeFirst ?? "No Payment", Icons.payment_outlined, Colors.green, ), SizedBox(height: 12), _buildStatusCard( context, langProvider, langProvider.translate("Payed amount"), "${serviceProduct!.receivedAmount?.toStringAsFixed(2) ?? 0} OMR", Icons.account_balance_wallet_outlined, Colors.purple, ), SizedBox(height: 20), // Action Buttons (Cancel/Update) if (serviceProduct?.requeststate != null && serviceProduct!.requeststate! == "SUBMITTED") Row( children: [ Expanded( child: GestureDetector( onTap: () async { final result = await orderProvider.cancelRequest(widget.id); if (result && mounted) { Navigator.of(context).pop(); orderProvider.fetchAllRequest('Products & Services'); } else { Get.showSnackbar( GetSnackBar( title: languageSingleton.translate("Error occurred"), message: languageSingleton.translate( 'Please try again. An error occurred'), duration: const Duration(seconds: 3), ), ); } }, child: Container( height: 48, decoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.red.withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.cancel_outlined, color: Colors.white, size: 18), SizedBox(width: 8), Text( languageSingleton.translate('Cancel'), style: TextStyle( color: Colors.white, fontSize: 15, fontWeight: FontWeight.w600, ), ), ], ), ), ), ), SizedBox(width: 15), Expanded( child: GestureDetector( onTap: () async { if (serviceProduct?.service?.id == null) return; final resultService = await orderProvider .getServiceById(serviceProduct!.service!.id!); if (resultService == null) return; if (mounted) { Navigator.push( context, MaterialPageRoute( builder: (context) => ServiceDetailsScreen( service: resultService, isModify: true, requestId: serviceProduct?.id!, ), ), ); } }, child: Container( height: 48, decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppStyle.mediumPriorityColor, AppStyle.mediumPriorityColor.withOpacity(0.8) ], ), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: AppStyle.mediumPriorityColor.withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.edit_outlined, color: Colors.white, size: 18), SizedBox(width: 8), Text( languageSingleton.translate('Update'), style: TextStyle( color: Colors.white, fontSize: 15, fontWeight: FontWeight.w600, ), ), ], ), ), ), ), ], ), ], ), ) : Center( child: Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( color: Theme.of(context).cardColor, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, offset: const Offset(0, 4), ), ], ), child: CircularProgressIndicator( strokeWidth: 3, valueColor: AlwaysStoppedAnimation(AppStyle.buttonBlue), ), ), ); } Widget _buildStatusCard( BuildContext context, LanguageProvider langProvider, String title, String value, IconData icon, Color iconColor, ) { return Container( width: double.infinity, padding: EdgeInsets.all(18), decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: iconColor.withOpacity(0.2), width: 1, ), boxShadow: [ BoxShadow( color: Theme.of(context).brightness == Brightness.dark ? Colors.black.withOpacity(0.2) : Colors.grey.withOpacity(0.08), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Row( children: [ Container( padding: EdgeInsets.all(10), decoration: BoxDecoration( color: iconColor.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: Icon( icon, size: 18, color: iconColor, ), ), SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Txt( text: title, style: tS( "Inter", 12, FontWeight.w500, AppStyle.dividerGrey, ), ), SizedBox(height: 4), Txt( text: value, style: tS( "Inter", 15, FontWeight.w600, Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), ], ), ); } } class PricePopUp extends StatelessWidget { const PricePopUp({super.key, required this.listItem}); final List listItem; @override Widget build(BuildContext context) { final hm = SizeConfig.heightMultiplier; final wm = SizeConfig.widthMultiplier; return Dialog( backgroundColor: Colors.transparent, insetPadding: EdgeInsets.symmetric(horizontal: wm * 6, vertical: hm * 10), child: Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(Theme.of(context).brightness == Brightness.dark ? 0.5 : 0.2), blurRadius: 30, offset: const Offset(0, 10), spreadRadius: 5, ), ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Header Container( padding: EdgeInsets.symmetric(horizontal: 24, vertical: 20), decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppStyle.buttonBlue, AppStyle.buttonBlue.withOpacity(0.8), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadiusDirectional.only( topStart: Radius.circular(20), topEnd: Radius.circular(20), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(10), ), child: Icon( Icons.receipt_long, color: Colors.white, size: 20, ), ), SizedBox(width: 12), Text( languageSingleton.translate("Price Breakdown"), style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), ], ), GestureDetector( onTap: () => Navigator.of(context).pop(), child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(10), ), child: Icon( Icons.close, color: Colors.white, size: 20, ), ), ), ], ), ), // Content Container( constraints: BoxConstraints(maxHeight: hm * 50), child: SingleChildScrollView( padding: EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row Container( padding: EdgeInsets.symmetric(vertical: 16, horizontal: 20), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.2), width: 1, ), ), child: Row( children: [ Expanded( flex: 3, child: Row( children: [ Container( padding: EdgeInsets.all(6), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.inventory_2_outlined, size: 16, color: AppStyle.buttonBlue, ), ), SizedBox(width: 12), Txt(text: "Item Name", style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), Container( width: 1, height: 20, color: AppStyle.dividerGrey.withOpacity(0.3), ), Expanded( flex: 2, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: EdgeInsets.all(6), decoration: BoxDecoration( color: Colors.green.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.attach_money, size: 16, color: Colors.green, ), ), SizedBox(width: 8), Text( languageSingleton.translate("Price"), style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), ), ], ), ), ], ), ), SizedBox(height: 16), // Items List if (listItem.isEmpty) Container( width: double.infinity, padding: EdgeInsets.all(40), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadius.circular(12), ), child: Column( children: [ Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon( Icons.inventory_2_outlined, size: 32, color: Colors.grey[400], ), ), SizedBox(height: 16), Text( languageSingleton.translate("No additional items"), style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Colors.grey[600], ), ), SizedBox(height: 8), Text( languageSingleton.translate("Only base service price applies"), style: TextStyle( fontSize: 14, color: Colors.grey[500], ), ), ], ), ) else ...listItem.asMap().entries.map((entry) { final index = entry.key; final item = entry.value; final isEven = index % 2 == 0; return Container( margin: EdgeInsets.only(bottom: 12), padding: EdgeInsets.all(16), decoration: BoxDecoration( color: isEven ? (Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor) : Theme.of(context).cardColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.1), width: 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity( Theme.of(context).brightness == Brightness.dark ? 0.2 : 0.05 ), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: ItemPriceTileModern( name: item.name!, price: item.price ?? 0.0, index: index + 1, ), ); }).toList(), SizedBox(height: 20), // Total Summary Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppStyle.buttonBlue.withOpacity(0.1), AppStyle.buttonBlue.withOpacity(0.05), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.3), width: 1.5, ), ), child:Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( // <-- Added child: Row( children: [ Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.2), borderRadius: BorderRadius.circular(10), ), child: Icon( Icons.calculate, color: AppStyle.buttonBlue, size: 18, ), ), SizedBox(width: 12), Flexible( // <-- Ensures text wraps/ellipses within available space child: Text( languageSingleton.translate("Additional Items Total"), style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), overflow: TextOverflow.ellipsis, maxLines: 1, ), ), ], ), ), Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: AppStyle.buttonBlue, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: AppStyle.buttonBlue.withOpacity(0.3), blurRadius: 8, offset: Offset(0, 2), ), ], ), child: Text( "${_calculateTotal()} OMR", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ], ) ), ], ), ), ), // Footer Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.darkProductOptionColor : AppNewStyle.productOptionColor, borderRadius: BorderRadiusDirectional.only( bottomStart: Radius.circular(20), bottomEnd: Radius.circular(20), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.info_outline, size: 16, color: AppStyle.dividerGrey, ), SizedBox(width: 8), Text( languageSingleton.translate("Prices are in Omani Rial (OMR)"), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: AppStyle.dividerGrey, ), ), ], ), ), ], ), ), ); } double _calculateTotal() { double total = 0.0; for (var item in listItem) { if (item.price != null) { total += item.price!; } } return total; } } class ItemPriceTileModern extends StatelessWidget { final String name; final double price; final int index; const ItemPriceTileModern({ Key? key, required this.name, required this.price, required this.index, }) : super(key: key); @override Widget build(BuildContext context) { return Row( children: [ // Index Badge Container( width: 28, height: 28, decoration: BoxDecoration( color: AppStyle.buttonBlue.withOpacity(0.1), borderRadius: BorderRadius.circular(14), border: Border.all( color: AppStyle.buttonBlue.withOpacity(0.3), width: 1, ), ), child: Center( child: Text( index.toString(), style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: AppStyle.buttonBlue, ), ), ), ), SizedBox(width: 16), // Item Name Expanded( flex: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( name, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Theme.of(context).brightness == Brightness.dark ? AppNewStyle.appBackground : AppNewStyle.darkAppBackground, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), SizedBox(height: 4), Container( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: Text( languageSingleton.translate("Additional Item"), style: TextStyle( fontSize: 10, fontWeight: FontWeight.w500, color: Colors.blue, ), ), ), ], ), ), SizedBox(width: 16), // Dotted Line Expanded( flex: 1, child: CustomPaint( painter: DottedLinePainter(), child: Container(height: 1), ), ), SizedBox(width: 16), // Price Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: price >= 0 ? Colors.green.withOpacity(0.1) : Colors.red.withOpacity(0.1), borderRadius: BorderRadius.circular(12), border: Border.all( color: price >= 0 ? Colors.green.withOpacity(0.3) : Colors.red.withOpacity(0.3), width: 1, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( price >= 0 ? Icons.add : Icons.remove, size: 14, color: price >= 0 ? Colors.green : Colors.red, ), SizedBox(width: 4), Text( "${price.abs()} OMR", style: TextStyle( fontSize: 13, fontWeight: FontWeight.bold, color: price >= 0 ? Colors.green : Colors.red, ), ), ], ), ), ], ); } } class DottedLinePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { var paint = Paint() ..color = Colors.grey.withOpacity(0.4) ..strokeWidth = 1; var max = size.width; var dashWidth = 3; var dashSpace = 3; double startX = 0; while (startX < max) { canvas.drawLine( Offset(startX, 0), Offset(startX + dashWidth, 0), paint, ); startX += dashWidth + dashSpace; } } @override bool shouldRepaint(CustomPainter oldDelegate) => false; }