import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:shimmer/shimmer.dart'; import '../../Controller/Dashboard/Dashboardcontroller.dart'; import '../../Controller/Dashboard/Tabs/Ordercontroller.dart'; import '../../Controller/products/product_controller.dart'; import '../../Globalwidgets/textwidget.dart'; import '../../Helper/Constants/AssetConstants.dart'; import '../../Helper/Constants/Colorconstants.dart'; import '../../Helper/Logger.dart'; import '../../widgets/product_bottom_sheet.dart'; import '../More/Notification/Notificationview.dart'; import '../Orders/orderDetails.dart'; class DashboardView extends StatelessWidget { DashboardView({super.key}); final DashboardController dashboardController = Get.put(DashboardController()); final CurrentOrderController currentOrderController = Get.put(CurrentOrderController()); final ProductController productController = Get.put(ProductController()); @override Widget build(BuildContext context) { SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: Colors.transparent, // or your color statusBarIconBrightness: Brightness.dark, // Android icons statusBarBrightness: Brightness.light, // iOS icons ), ); return DefaultTabController( length: 4, child: Builder( builder: (context) { final TabController tabController = DefaultTabController.of(context); // Listen to tab changes (tap or swipe) tabController.addListener(() { if (!tabController.indexIsChanging) { String status; switch (tabController.index) { case 0: status = 'created'; break; case 1: status = 'ongoing'; break; case 2: status = 'delivered'; break; case 3: status = 'cancelled'; break; default: status = 'created'; } // Only fetch if not already loaded currentOrderController.getOrder(status); if (!currentOrderController.hasLoaded(status)) { currentOrderController.getOrder(status); } } }); return GetBuilder( initState: (_) { logger.i('Init state triggered in View : '); WidgetsBinding.instance.addPostFrameCallback((_) { dashboardController.getDetails(); dashboardController.getTenantInfo(); currentOrderController.getOrder('created'); // Initial fetch for Placed tab }); }, builder: (dashboardCtrl) { return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, toolbarHeight: 70, elevation: 0, backgroundColor: ColorConstants.secondaryColor, actions: [ Padding( padding: EdgeInsets.only(right: 15), child: InkWell( onTap: () { Get.to(() => NotificationView()); }, child: Icon( Icons.notifications, color: ColorConstants.darkGreyColor, ), ), ), ], title: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ TextWidget( text: dashboardCtrl.tenantInfo?.tenantname ?? '', fontWeight: FontWeight.w700, fontSize: 20, ), SizedBox(height: 5), Row( children: [ Icon(Icons.location_on_outlined, color: ColorConstants.darkGreyColor, size: 15), TextWidget( text: dashboardCtrl.tenantInfo?.locationname ?? '', fontWeight: FontWeight.w500, fontSize: 14, ), ], ) ], ), bottom: TabBar( physics: NeverScrollableScrollPhysics(), tabs: [ Tab(text: 'Placed'), Tab(text: 'Ongoing'), Tab(text: 'Completed'), Tab(text: 'Cancelled'), ], labelColor: ColorConstants.primaryColor, unselectedLabelColor: ColorConstants.darkGreyColor?.withOpacity(0.5), indicatorColor: ColorConstants.primaryColor, labelStyle: TextStyle(fontWeight: FontWeight.w600, fontSize: 14), unselectedLabelStyle: TextStyle(fontWeight: FontWeight.w400, fontSize: 12), ), ), body: TabBarView( physics: const NeverScrollableScrollPhysics(), children: [ OrderTabView(orderStatus: 'created'), OrderTabView(orderStatus: 'ongoing'), OrderTabView(orderStatus: 'delivered'), OrderTabView(orderStatus: 'cancelled'), ], ), ); }, ); }, ), ); } } class OrderTabView extends StatelessWidget { final String orderStatus; final CurrentOrderController currentOrderController = Get.find(); OrderTabView({ super.key, required this.orderStatus, }); @override Widget build(BuildContext context) { return Obx(() { final orders = currentOrderController.getOrdersByStatus(orderStatus); final isLoading = currentOrderController.getLoadingByStatus(orderStatus).value; // Show shimmer only on first load if (isLoading && !currentOrderController.hasLoaded(orderStatus)) { return Center(child: ShimmerListView(height: 200)); } if (orders.isEmpty) { return emptyOrdersWidget(); } return ListView.builder( padding: const EdgeInsets.only(top: 10), itemCount: orders.length, itemBuilder: (context, index) { final order = orders[index]; return InkWell( onTap: () async { final orderId = order.orderheaderid ?? 0; final productController = Get.find(); await productController.getProductDetails(orderId); if (context.mounted) { Navigator.push( context, MaterialPageRoute( builder: (_) => OrderDetailsPage( orderDetails: order, productDetails: productController.productDetail, controller: currentOrderController, ), ), ); } }, child: OrderCard( orderStatus: order.orderstatus ?? '', orderId: order.orderid ?? '', orderDateTime: order.orderdate ?? '', customerName: order.deliverycustomer ?? '', phoneNumber: order.deliverycontactno ?? '', deliveryLocation: order.deliveryaddress ?? '', onInfoTap: () async { final orderId = order.orderheaderid ?? 1; final productController = Get.find(); await productController.getProductDetails(orderId); for (var product in productController.productDetail ?? []) { if (product.productimage != null) { precacheImage( CachedNetworkImageProvider(product.productimage ?? ''), context, ); } } if (context.mounted) { ProductBottomSheet.show(context, productController.productDetail ?? []); } }, ), ); }, ); }); } } /// Shimmer Card widget class ShimmerListView extends StatelessWidget { final double height; const ShimmerListView({super.key, required this.height}); @override Widget build(BuildContext context) { return ListView.builder( itemCount: 10, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: Shimmer.fromColors( baseColor: Colors.grey.shade300, highlightColor: Colors.grey.shade100, child: Container( height: height, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Container( width: 60, height: 60, margin: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.grey.shade400, borderRadius: BorderRadius.circular(8), ), ), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Container( height: 14, width: double.infinity, color: Colors.grey.shade400, ), const SizedBox(height: 10), Container( height: 12, width: 150, color: Colors.grey.shade400, ), ], ), ) ], ), ), ), ); }, ); } } showConfirmationBottomSheet( BuildContext context, { required VoidCallback onAccept, VoidCallback? onCancel, String title = "Confirmation", String message = "Are you sure you want to continue?", }) { showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), backgroundColor: Colors.white, builder: (context) { return Padding( padding: const EdgeInsets.fromLTRB(20, 20, 20, 30), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 12), Text( message, style: TextStyle(fontSize: 15, color: Colors.grey[700]), textAlign: TextAlign.center, ), const SizedBox(height: 24), Row( children: [ Expanded( child: OutlinedButton( onPressed: () { Navigator.pop(context); Future.microtask(() => onCancel?.call()); }, style: OutlinedButton.styleFrom( side: const BorderSide(color: Colors.grey), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: const Text('Cancel'), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton( onPressed: () { Navigator.pop(context); Future.microtask(() => onAccept()); }, style: ElevatedButton.styleFrom( backgroundColor: ColorConstants.primaryColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: const Text('Accept'), ), ), ], ), ], ), ); }, ); } class OrderCard extends StatelessWidget { final String orderId; final String orderDateTime; final String customerName; final String phoneNumber; final String orderStatus; final String deliveryLocation; final VoidCallback? onInfoTap; const OrderCard({ super.key, required this.orderId, required this.orderDateTime, required this.customerName, required this.phoneNumber, required this.orderStatus, required this.deliveryLocation, this.onInfoTap, }); @override Widget build(BuildContext context) { DateTime dateTime = DateTime.parse(orderDateTime); logger.i('orderDateTime : ${dateTime}'); final dataStr = dateTime.toLocal().toString().split(' ')[0]; final timeStr = DateFormat('h:mm a').format(dateTime); return Card( elevation: 0, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 5), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: const EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ const Icon(Icons.confirmation_number_outlined, color: Colors.deepPurple), const SizedBox(width: 6), TextWidget( text: 'Order ID: $orderId', fontWeight: FontWeight.w700, fontSize: 16, ), ], ), IconButton( icon: const Icon(Icons.info_outline_rounded, color: Colors.grey), onPressed: onInfoTap ?? () {}, ), ], ), const SizedBox(height: 5), Row( children: [ const Icon(Icons.calendar_today_outlined, size: 20, color: Colors.teal), const SizedBox(width: 6), TextWidget(text: '$dataStr • $timeStr'), Spacer(), Container( margin: const EdgeInsets.only(top: 4), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: _getStatusColor(orderStatus).withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: TextWidget( text: orderStatus, fontWeight: FontWeight.w600, fontSize: 13, color: _getStatusColor(orderStatus), ), ), ], ), const Divider(height: 24, thickness: 0.7), Row( children: [ const Icon(Icons.person_outline, color: Colors.indigo, size: 20,), const SizedBox(width: 6), Expanded( child: TextWidget( text: customerName, fontWeight: FontWeight.w500, ) ), ], ), const SizedBox(height: 8), Row( children: [ const Icon(Icons.phone_outlined, color: Colors.green, size: 20), const SizedBox(width: 6), TextWidget(text: phoneNumber), ], ), const SizedBox(height: 8), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Icon(Icons.location_on_outlined, color: Colors.redAccent, size: 20), const SizedBox(width: 6), Expanded( child: TextWidget( text: deliveryLocation, textHeight: 1.4, ), ), ], ), ], ), ), ); } } Color _getStatusColor(String status) { switch (status.toLowerCase()) { case 'created': return Colors.blueGrey; case 'assigned': return Colors.indigo; case 'accepted': return Colors.teal; case 'arrived': return Colors.blue; case 'picked': return Colors.deepPurple; case 'delivered': return Colors.green; case 'cancelled': return Colors.red; default: return Colors.grey; } } Widget emptyOrdersWidget() { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height:10), Image.asset( AssetConstants.noOrdersFound, height: 200, width: 200, fit: BoxFit.fill, ), TextWidget( text: 'No Orders Yet!', color: ColorConstants.blackColor, fontSize: 18, fontWeight: FontWeight.w700, maxLines: 2, textAlign: TextAlign.center, ), SizedBox(height: 10), TextWidget( text: 'Stay tuned, your next order will appear here soon!', color: ColorConstants.blackColor, fontSize: 14, fontWeight: FontWeight.normal, maxLines: 2, textAlign: TextAlign.center, ), ], ), ); }