import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:bookatanker/common/settings.dart'; import 'package:bookatanker/supplier/my_orders_model.dart'; import 'cancel_order.dart'; class MyOrders extends StatefulWidget { final String? navigationFrom; const MyOrders({this.navigationFrom, Key? key}) : super(key: key); @override State createState() => _MyOrdersState(); } class _MyOrdersState extends State with TickerProviderStateMixin { bool isOrdersDataLoading = false; List ordersList = []; List upcomingOrders = []; List previousOrders = []; bool isPlansLoading = false; List plansList = []; List activePlans = []; List pendingPlans = []; late TabController _controller; String tabMessage = "Welcome to Tab 1"; @override void initState() { super.initState(); _controller = TabController(vsync: this, length: 2); // Listen for tab changes _controller.addListener(() { setState(() { tabMessage = _controller.index == 0 ? "Welcome to Tab 1" : "Welcome to Tab 2"; }); }); getOrdersData(); getPlansData(); } Future getPlansData() async { setState(() => isPlansLoading = true); try { final response = await AppSettings.getCustomerPlans(); final decoded = jsonDecode(response); if (decoded == null || decoded['data'] == null) { setState(() { plansList = []; isPlansLoading = false; }); return; } final List data = decoded['data']; setState(() { plansList = data; activePlans = data.where((p) => p['status'] == "processed" || p['status'] == "accepted" || p['status'] == "payment_completed").toList(); pendingPlans = data.where((p) => p['status'] == "pending").toList(); isPlansLoading = false; }); } catch (e) { print("Plans error $e"); setState(() => isPlansLoading = false); } } Future getOrdersData() async { setState(() => isOrdersDataLoading = true); try { final response = await AppSettings.getAllOrders(); final decoded = jsonDecode(response); print("🔹 Full API Response: $decoded"); if (decoded == null || decoded['data'] == null) { print("⚠️ No data key found in API response"); setState(() { isOrdersDataLoading = false; ordersList = []; }); return; } final List data = decoded['data']; if (data.isEmpty) { print("⚠️ Empty data array"); setState(() { isOrdersDataLoading = false; ordersList = []; }); return; } final parsedOrders = data.map((model) => MyOrdersModel.fromJson(model)).toList(); print("✅ Total orders fetched: ${parsedOrders.length}"); setState(() { ordersList = parsedOrders; upcomingOrders = parsedOrders.where((order) { final status = order.orderStatus.toLowerCase(); return status == "pending" || status == "advance_paid" || status == "assigned" || status == "deliveryboy_assigned"; }).toList(); previousOrders = parsedOrders.where((order) { final status = order.orderStatus.toLowerCase(); return status == "completed" || status == "cancelled"; }).toList(); isOrdersDataLoading = false; }); print("📦 Upcoming: ${upcomingOrders.length}, Previous: ${previousOrders.length}"); } catch (e) { print("❌ Error in getOrdersData: $e"); setState(() => isOrdersDataLoading = false); } } String capitalizeFirst(String input) { if (input.isEmpty) return input; return input[0].toUpperCase() + input.substring(1); } Widget buildUpcomingOrdersCard(MyOrdersModel order) { return Card( color: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(10.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Supplier name & status Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Visibility( visible: order.supplierName.isNotEmpty, child: Text( order.supplierName, style: fontTextStyle(16, const Color(0xFF2D2E30), FontWeight.w600), ), ), _statusChip(order.orderStatus, const Color(0xFFFDF3D3), const Color(0xFFF5CD47), 'images/out_for_delivery.png'), ], ), const SizedBox(height: 6), // Type + Capacity Row( children: [ Text("${order.capacity} L - ${order.typeofwater}", style: fontTextStyle(12, const Color(0xFF71ABFD), FontWeight.w500)), const SizedBox(width: 6), Image.asset('images/arrow-right.png', width: 16, height: 16, color: const Color(0xFF71ABFD)), ], ), const SizedBox(height: 4), // Address + Payment Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text(order.displayAddress, style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w400))), _paymentChip(order.paymentStatus), ], ), const SizedBox(height: 4), // Expected Delivery Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("Expected delivery: ${order.expectedDateOfDelivery}", style: fontTextStyle(10, const Color(0xFF939495), FontWeight.w500)), if (order.price.isNotEmpty) Text("₹ ${order.price}", style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w400)), ], ), const Divider(height: 20), // Buttons Row( mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( onTap: ()async{ final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => CancelOrderPage( order: order, status: order.orderStatus, ), ), ); if (result == true) { getOrdersData(); } }, /* onTap: () => Navigator.push( context, MaterialPageRoute(builder: (_) => CancelOrderPage(order:order,status: order.orderStatus,))),*/ child: Text("CANCEL ORDER", style: fontTextStyle(12, const Color(0xFFE2483D), FontWeight.w600))), const SizedBox(width: 30), GestureDetector( onTap: () {}, child: Text("TRACK ORDER", style: fontTextStyle(12, const Color(0xFF1D7AFC), FontWeight.w600))), ], ), ], ), ), ); } Widget buildPreviousOrdersCard(MyOrdersModel order) { final isDelivered = order.orderStatus == 'completed'; return Card( color: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(10.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (order.supplierName.isNotEmpty) Text(order.supplierName, style: fontTextStyle(16, const Color(0xFF2D2E30), FontWeight.w600)), _statusChip( order.orderStatus, isDelivered ? const Color(0xFFC4E8C3) : const Color(0xFFF8D3D0), isDelivered ? const Color(0xFF098603) : const Color(0xFFE2483D), isDelivered ? 'images/rite.png' : 'images/cancel.png', ), ], ), const SizedBox(height: 4), Text(order.typeofwater, style: fontTextStyle(12, const Color(0xFF71ABFD), FontWeight.w500)), const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text(order.displayAddress, style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w400))), _paymentChip(order.paymentStatus), ], ), const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(order.displayDeliveredDate, style: fontTextStyle(10, const Color(0xFF939495), FontWeight.w500)), if (order.price.isNotEmpty) Text("₹ ${order.price}", style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w400)), ], ), if (isDelivered) ...[ const Divider(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( onTap: () {}, child: Text("REPEAT ORDER", style: fontTextStyle(12, const Color(0xFF4692FD), FontWeight.w600)), ), const SizedBox(width: 30), GestureDetector( onTap: () {}, child: Text("RATE ORDER", style: fontTextStyle(12, const Color(0xFF646566), FontWeight.w600)), ), ], ), ] ], ), ), ); } Widget _statusChip(String text, Color bg, Color txt, String img) { return Container( padding: const EdgeInsets.fromLTRB(4, 2, 4, 2), decoration: BoxDecoration( color: bg, borderRadius: BorderRadius.circular(4), border: Border.all(color: bg)), child: Row( children: [ Image.asset(img, width: 12, height: 12), const SizedBox(width: 4), Text(capitalizeFirst(text), style: fontTextStyle(10, txt, FontWeight.w500)), ], ), ); } Widget _paymentChip(String status) { final isPaid = status.toLowerCase() == 'paid'; return Row( children: [ Image.asset(isPaid ? 'images/paid.png' : 'images/warning.png', width: 16, height: 16), const SizedBox(width: 4), Text(capitalizeFirst(status), style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w400)), ], ); } Widget renderUi() { if (ordersList.isEmpty) { return const Center( child: Text("No Data Available", style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500))); } return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (upcomingOrders.isNotEmpty) ...[ Text("UPCOMING ORDERS", style: fontTextStyle(12, const Color(0xFF646566), FontWeight.w400)), const SizedBox(height: 8), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: upcomingOrders.length, itemBuilder: (context, index) => buildUpcomingOrdersCard(upcomingOrders[index]), ), ], if (previousOrders.isNotEmpty) ...[ const SizedBox(height: 16), Text("PREVIOUS ORDERS", style: fontTextStyle(12, const Color(0xFF646566), FontWeight.w400)), const SizedBox(height: 8), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: previousOrders.length, itemBuilder: (context, index) => buildPreviousOrdersCard(previousOrders[index]), ), ], ], ), ); } Widget buildPlansCard(var plan) { return Card( color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "${plan['capacity']} L - ${plan['type_of_water']}", style: fontTextStyle( 14, const Color(0xFF2D2E30), FontWeight.w600), ), _statusChip( plan['status'], const Color(0xFFE3F2FD), const Color(0xFF1D7AFC), 'images/rite.png', ), ], ), const SizedBox(height: 6), Text( "Frequency : ${plan['frequency']}", style: fontTextStyle( 12, const Color(0xFF71ABFD), FontWeight.w500), ), const SizedBox(height: 4), Text( "Start : ${plan['start_date']}", style: fontTextStyle( 10, const Color(0xFF939495), FontWeight.w500), ), Text( "End : ${plan['end_date']}", style: fontTextStyle( 10, const Color(0xFF939495), FontWeight.w500), ), const Divider(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( onTap: () {}, child: Text( "VIEW PLAN", style: fontTextStyle( 12, const Color(0xFF1D7AFC), FontWeight.w600), ), ), const SizedBox(width: 30), GestureDetector( onTap: () {}, child: Text( "CANCEL PLAN", style: fontTextStyle( 12, const Color(0xFFE2483D), FontWeight.w600), ), ), ], ) ], ), ), ); } Widget renderPlansUi() { if (plansList.isEmpty) { return const Center( child: Text("No Plans Available"), ); } return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ /// ACTIVE PLANS if (activePlans.isNotEmpty) ...[ Text( "ACTIVE PLANS", style: fontTextStyle( 12, const Color(0xFF646566), FontWeight.w400, ), ), const SizedBox(height: 10), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: activePlans.length, itemBuilder: (context, index) { final plan = activePlans[index]; return Padding( padding: const EdgeInsets.only(bottom: 10), child: buildPlansCard(plan), ); }, ), ], /// SPACE const SizedBox(height: 20), /// PENDING PLANS if (pendingPlans.isNotEmpty) ...[ Text( "PENDING PLANS", style: fontTextStyle( 12, const Color(0xFF646566), FontWeight.w400, ), ), const SizedBox(height: 10), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: pendingPlans.length, itemBuilder: (context, index) { final plan = pendingPlans[index]; return Padding( padding: const EdgeInsets.only(bottom: 10), child: buildPlansCard(plan), ); }, ), ], const SizedBox(height: 20), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( backgroundColor: Colors.white, title: Text( 'Orders', style: fontTextStyle(14, Color(0XFF2A2A2A), FontWeight.w500), ), iconTheme: IconThemeData(color: Color(0XFF2A2A2A)), actions: [ Row( children: [ Padding( padding: EdgeInsets.fromLTRB(10, 10, 0, 10), child: IconButton( icon: Image( image: AssetImage('images/customercare_appbar.png')), onPressed: () {}, ), ), Padding( padding: EdgeInsets.fromLTRB(0, 10, 10, 10), child: IconButton( icon: Image.asset( 'images/notification_appbar.png', // Example URL image ), onPressed: () {}, ), ) ], ) ], bottom: PreferredSize( preferredSize: Size.fromHeight(50.0), child: Container( color: Colors.white, child: TabBar( controller: _controller, indicatorColor: Colors.transparent, tabs: [ // Tab 1 Builder( builder: (BuildContext context) { return Container( decoration: BoxDecoration( color: _controller.index == 0 ? Color(0XFFFE8F2FF) : Colors.white, // Selected tab color borderRadius: BorderRadius.circular(10), border: Border.all( color: _controller.index == 0 ? Color(0XFFFE8F2FF) : Colors.white, width: 2), ), child: Tab( child: Center( child: Text('Orders', style: fontTextStyle(12, Color(0XFF101214), FontWeight.w600))), ), ); }, ), // Tab 2 Builder( builder: (BuildContext context) { return Container( decoration: BoxDecoration( color: _controller.index == 1 ? Color(0XFFFE8F2FF) : Colors.white, // Selected tab color borderRadius: BorderRadius.circular(10), border: Border.all( color: _controller.index == 1 ? Color(0XFFFE8F2FF) : Colors.white, width: 2), ), child: Tab( child: Center( child: Text('Plans', style: fontTextStyle(12, Color(0XFF101214), FontWeight.w600))), ), ); }, ), ], )), ), ), body: Builder( builder: (BuildContext context) { return TabBarView( controller: _controller, children: [ isOrdersDataLoading ? const Center(child: CircularProgressIndicator()) : renderUi(), isPlansLoading ? const Center(child: CircularProgressIndicator()) : renderPlansUi(), ], ); }, ), ); } }