import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:supplier_new/common/settings.dart'; import 'package:supplier_new/plans/plan_details.dart'; import 'package:supplier_new/plans/plan_requests.dart'; import 'package:supplier_new/plans/search_plan_appbar.dart'; /// ===================== /// MODEL /// ===================== class PlansModel { final String id; final String status; final String apartment; final String liters; final String price; final String advance; final String deliveries; final String frequency; final String waterType; PlansModel({ required this.id, required this.status, required this.apartment, required this.liters, required this.price, required this.advance, required this.deliveries, required this.frequency, required this.waterType, }); factory PlansModel.fromJson(Map json) { final supplier = json["my_supplier"] ?? {}; final List dates = json["dates"] ?? []; return PlansModel( id: json["_id"], status: json["status"] == "processed" ? "Active" : "Pending", apartment: json["customerId"], liters: "${json["capacity"]} - ${json["type_of_water"]}", price: "₹${supplier["quoted_amount"] ?? "--"}", advance: "--", deliveries: "${dates.length} Deliveries", frequency: "${json["weekly_count"]}/week", waterType: json["type_of_water"] ?? "", ); } } /// ===================== /// SCREEN /// ===================== /// Future showAcceptConfirmDialog(BuildContext context) async { return await showDialog( context: context, barrierDismissible: false, builder: (ctx) { return AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), title: const Text("Confirm Acceptance"), content: const Text( "Are you sure you want to accept this recurring plan?", ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text("Cancel"), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0XFF8270DB), ), onPressed: () => Navigator.pop(ctx, true), child: const Text("Accept"), ), ], ); }, ) ?? false; } /// class AllPlans extends StatefulWidget { final String navigationFrom; const AllPlans({super.key, required this.navigationFrom}); @override State createState() => _AllPlansState(); } class _AllPlansState extends State { final TextEditingController searchController = TextEditingController(); bool isLoading = true; /// UI MODELS List plans = []; /// RAW API DATA (IMPORTANT) List> rawPlans = []; int activeCount = 0; int boreCount = 0; int drinkingCount = 0; @override void initState() { super.initState(); fetchPlans(); } /// ===================== /// FETCH API /// ===================== Future fetchPlans() async { try { final response = await AppSettings.getAcceptedRecurringBookings(); final decoded = jsonDecode(response); final List data = decoded["data"] ?? []; /// ✅ FILTER ONLY payment_completed rawPlans = List>.from( data.where((e) => ["processed", "payment_completed"] .contains((e["status"] ?? "").toString().toLowerCase())), ); plans = rawPlans.map((e) => PlansModel.fromJson(e)).toList(); /// COUNTS (NOW ONLY payment_completed DATA) activeCount = plans.length; boreCount = plans.where((p) => p.waterType.toLowerCase().contains("bore")).length; drinkingCount = plans .where((p) => p.waterType.toLowerCase().contains("drinking")) .length; setState(() => isLoading = false); } catch (e) { setState(() => isLoading = false); } } /// ===================== /// UI /// ===================== @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: widget.navigationFrom.toLowerCase() == 'dashboard' ? SearchPlanAppBar( controller: searchController, onBack: () => Navigator.pop(context), onHelp: () {}, ) : null, body: isLoading ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( child: Column( children: [ /// 🔹 TOP SECTION Container( decoration: const BoxDecoration( color: Color(0XFFF2F2F2), borderRadius: BorderRadius.only( bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24), ), ), padding: const EdgeInsets.all(24), child: Column( children: [ Text( activeCount.toString().padLeft(2, '0'), style: fontTextStyle( 64, const Color(0XFF2D2E30), FontWeight.w700), ), Text( "Active Plans", style: fontTextStyle( 24, const Color(0XFF2D2E30), FontWeight.w600), ), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ PlanCategoryCard( image: Image.asset('images/bore-water.png', height: 40, width: 40), value: boreCount.toString().padLeft(2, '0'), label: "Bore Water", ), PlanCategoryCard( image: Image.asset('images/drinking-water.png', height: 40, width: 40), value: drinkingCount.toString().padLeft(2, '0'), label: "Drinking Water", ), ], ), const SizedBox(height: 24), SizedBox( width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0XFF8270DB), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(32), ), padding: const EdgeInsets.all(16), ), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (_) => const PlanRequestsPage()), ); }, child: Text( "View Plan Requests", style: fontTextStyle( 16, Colors.white, FontWeight.w500), ), ), ), ], ), ), /// 🔹 PLAN LIST isLoading ? Center( child: CircularProgressIndicator()) : (plans.isEmpty ? Center( child: Padding( padding: const EdgeInsets.symmetric( vertical: 50), child: Text( 'No Data Available', style: fontTextStyle( 12, const Color(0XFF2D2E30), FontWeight.w500), ), ), ) : ListView.builder( padding: const EdgeInsets.all(12), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: plans.length, itemBuilder: (_, index) { return PlansCard( delivery: plans[index], planJson: rawPlans[index], // ✅ FIXED ); }, )), ], ), ), ); } } /// ===================== /// PLAN CARD /// ===================== class PlansCard extends StatelessWidget { final PlansModel delivery; final Map planJson; const PlansCard({ super.key, required this.delivery, required this.planJson, }); @override Widget build(BuildContext context) { bool isActive = delivery.status == "Active"; return GestureDetector( onTap: () { if (delivery.status != "Active") return; Navigator.push( context, MaterialPageRoute( builder: (_) => PlanDetails(plan: planJson), ), ); }, child: Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFFE5E5E5)), color: Colors.white, ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: isActive ? const Color(0xFFE9F9EE) : Colors.grey.shade200, borderRadius: BorderRadius.circular(6), ), child: Text( delivery.status, style: TextStyle( fontSize: 12, color: isActive ? const Color(0xFF3BB273) : Colors.grey, ), ), ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(delivery.apartment, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600)), Text(delivery.price, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w600)), ], ), const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(delivery.liters, style: const TextStyle( fontSize: 14, color: Color(0xFF7B5AF4))), Text(delivery.advance, style: const TextStyle(fontSize: 12)), ], ), Visibility( visible: delivery.status=='payment_completed', child: Row( children: [ GestureDetector( onTap: (){ }, child: ColorFiltered( colorFilter: ColorFilter.mode( Colors.transparent, BlendMode.multiply), child: Image .asset( 'images/wrong_button.png', width: 44, height: 44, ), ), ), SizedBox( width: MediaQuery.of(context) .size .width * .012, ), GestureDetector( onTap: () async { final confirmed = await showAcceptConfirmDialog(context); if (!confirmed) return; try { final res = await AppSettings.respondRecurringBooking( bookingId: planJson["_id"], supplierId: planJson["my_supplier"]["supplierId"], action: "accept", ); final List dates = res["data"]["dates"] ?? []; if (dates.isEmpty) return; /* Navigator.push( context, MaterialPageRoute( builder: (_) => PlanCalendarScreen(dates: dates), ), );*/ } catch (e) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Failed to accept plan")), ); } }, child: Image.asset( 'images/right_button.png', width: 44, height: 44, ), ), ], ),), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFFF8F6FF), borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(delivery.deliveries, style: const TextStyle(fontSize: 13)), Text(delivery.frequency, style: const TextStyle( fontSize: 13, color: Color(0xFF7B5AF4))), ], ), ), ]), ), ); } } /// ===================== /// CATEGORY CARD /// ===================== class PlanCategoryCard extends StatelessWidget { final Image image; final String value; final String label; const PlanCategoryCard({ super.key, required this.image, required this.value, required this.label, }); @override Widget build(BuildContext context) { return Column( children: [ SizedBox(width: 40, height: 40, child: image), const SizedBox(height: 8), Text(value, style: fontTextStyle(20, const Color(0XFF515253), FontWeight.w700)), Text(label, style: fontTextStyle(16, const Color(0XFF515253), FontWeight.w400)), ], ); } }