import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:supplier_new/common/settings.dart'; import 'package:supplier_new/financials/add_transactions.dart'; import 'package:supplier_new/financials/building_transactions_details.dart'; import 'package:supplier_new/financials/create_credit_accounts.dart'; class FinancialMainScreen extends StatefulWidget { const FinancialMainScreen({super.key}); @override State createState() => _FinancialMainScreenState(); } Color _amountColor(Map txn) { if ((txn["status"] ?? "").toString().toLowerCase() == "failed") { return const Color(0xFF9F9F9F); // gray } final amt = (txn["amount"] ?? "").toString().trim(); if (amt.startsWith('+')) return const Color(0xFF0A9E04); // green if (amt.startsWith('-')) return const Color(0xFFE2483D); // red return const Color(0xFF2D2E30); // default/dark text } class _FinancialMainScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; /// ✅ API transactions bool isLoadingTransactions = true; List> transactions = []; bool isLoadingCreditAccounts = true; List> creditAccounts = []; double receivableBalance = 0; double advanceBalance = 0; int activeAccounts = 0; int overdueAccounts = 0; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); _tabController.addListener(() { setState(() {}); // rebuilds FAB visibility when tab changes }); fetchTransactions(); fetchCreditAccounts(); } Future fetchCreditAccounts() async { try { final response = await AppSettings.getAdvanceTransactionsBySupplier(); final decoded = jsonDecode(response); final List list = decoded["data"] ?? []; double receivable = 0; double advance = 0; int active = 0; int overdue = 0; // ✅ ADD THIS LIST final List customerIds = []; final accounts = list.map>((e) { final status = (e["status"] ?? "").toString().toLowerCase(); // ✅ COLLECT customerId (IMPORTANT) if (e["customerId"] != null) { customerIds.add(e["customerId"].toString()); } // ✅ PARSE advance_amount SAFELY final double balanceValue = double.tryParse(e["advance_amount"].toString()) ?? 0; // 🔥 MAIN LOGIC CHANGE (ONLY THIS) if (balanceValue > 0) { advance += balanceValue; } else if (balanceValue < 0) { receivable += balanceValue.abs(); } // existing counters (unchanged) if (status == "completed") active++; if (status == "overdue") overdue++; return { "name": e["customerName"] ?? "Unknown", "id": e["customerId"] ?? "***", "status": status, "orders": "${e["orderCount"] ?? 0} orders", "transactionId": e["transactionId"] ?? "", "balance": "₹$balanceValue", "credit": "₹${e["exceed_limit"] ?? 0}", "lastPayment": "₹${e["lastPaymentAmount"] ?? 0} | ${e["lastPaymentDate"] ?? ""}", }; }).toList(); // 🔥 STORE GLOBALLY FOR CREATE CREDIT SCREEN AppSettings.existingCreditCustomerIds = customerIds; setState(() { creditAccounts = accounts; receivableBalance = receivable; advanceBalance = advance; activeAccounts = active; overdueAccounts = overdue; isLoadingCreditAccounts = false; }); } catch (e) { debugPrint("⚠️ Credit accounts error: $e"); setState(() => isLoadingCreditAccounts = false); } } @override void dispose() { _tabController.dispose(); super.dispose(); } /// ✅ FETCH TRANSACTIONS API (based on your response) Future fetchTransactions() async { try { // ⚠️ Use your real method name here final response = await AppSettings.getSupplierTransactions(); final decoded = jsonDecode(response); final List data = decoded["data"] ?? []; transactions = data.map>((e) { final orderStatus = (e["orderStatus"] ?? "").toString().toLowerCase(); final price = (e["price"] ?? "0").toString(); // completed = credit (+) // others = debit (-) final amount = (orderStatus == "completed") ? "+ ₹$price" : "- ₹$price"; // cancelled = failed UI final status = (orderStatus == "cancelled") ? "failed" : "success"; return { "name": (e["buildingName"] ?? e["customerName"] ?? "Unknown").toString(), "date": (e["dateOfOrder"] ?? "").toString(), "amount": amount, "status": status, "raw": e, // keep full item if you want details page }; }).toList(); setState(() => isLoadingTransactions = false); } catch (e) { setState(() => isLoadingTransactions = false); } } Widget fab() { final index = _tabController.index; if (index == 0) { return SizedBox( width: 52, height: 52, child: FloatingActionButton( shape: const CircleBorder(), backgroundColor: Colors.black, onPressed: _onFabPressed, child: Image.asset( "images/plus.png", width: 20, height: 20, color: Colors.white, ), ), ); } else { return Container(); } } void _onFabPressed() { final index = _tabController.index; if (index == 0) { Navigator.push( context, MaterialPageRoute( builder: (_) => AddTransactionScreen(), ), ); } } Widget Transactions() { if (isLoadingTransactions) { return const Center(child: CircularProgressIndicator()); } return Container( color: const Color(0XFFFFFFFF), child: Column( children: [ // Filters row SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: Row( children: [ _buildFilterChip("Status"), _buildFilterChip("Payment Method"), _buildFilterChip("Date"), _buildFilterChip("Amount"), ], ), ), Expanded( child: transactions.isEmpty?Center( child: Text( 'No Data Available', style: fontTextStyle(16,Color(0XFF000000),FontWeight.w700), ), ): ListView.builder( padding: EdgeInsets.zero, itemCount: transactions.length, itemBuilder: (context, index) { final txn = transactions[index]; return ListTile( dense: true, minVerticalPadding: 0, visualDensity: const VisualDensity(vertical: 0, horizontal: 0), contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 0), horizontalTitleGap: 8, minLeadingWidth: 40, leading: Image.asset('images/avatar.png', width: 30, height: 30), title: Text( txn["name"].toString(), style: fontTextStyle(14, const Color(0xFF2D2E30), FontWeight.w500) .copyWith(height: 1.1), maxLines: 1, overflow: TextOverflow.ellipsis, ), subtitle: Text( txn["date"].toString(), style: fontTextStyle(12, const Color(0xFF939495), FontWeight.w400) .copyWith(height: 1.0), maxLines: 1, overflow: TextOverflow.ellipsis, ), trailing: Column( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( txn["amount"].toString(), style: fontTextStyle(12, _amountColor(txn), FontWeight.w600), ), if ((txn["status"] ?? "").toString().toLowerCase() == "failed") Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.error, color: Color(0xFF9F9F9F), size: 14), const SizedBox(width: 4), Text( "Failed", style: fontTextStyle(10, const Color(0xFF9F9F9F), FontWeight.w400), ), ], ), ], ), ); }, ), ) ], ), ); } Widget CreditAccounts() { if (isLoadingCreditAccounts) { return const Center(child: CircularProgressIndicator()); } return SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ /// Create Account Button (UNCHANGED) Align( alignment: Alignment.centerRight, child: OutlinedButton( style: OutlinedButton.styleFrom( foregroundColor: Colors.white, backgroundColor: Colors.black, ), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (_) => CreateCreditAccountScreen()), ); }, child: Row( mainAxisSize: MainAxisSize.min, children: [ Image.asset('images/plus.png', height: 20), const SizedBox(width: 6), const Text("Create Account"), ], ), ), ), const SizedBox(height: 12), /// Account Summary Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), ), child: Row( children: [ const Expanded(child: Text("Account Summary")), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( creditAccounts.length.toString(), style: fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500), ), Text( "$activeAccounts active, $overdueAccounts overdue", style: fontTextStyle(10, const Color(0xFF646566), FontWeight.w400), ), ], ), ], ), ), const SizedBox(height: 12), /// Balances Row( children: [ _balanceBox( title: "Receivable Balance", amount: receivableBalance, color: Colors.red, ), const SizedBox(width: 12), _balanceBox( title: "Advance Balance", amount: advanceBalance, color: Colors.green, ), ], ), const SizedBox(height: 20), /// Accounts List creditAccounts.isEmpty ? const Center(child: Text("No Credit Accounts")) : Column( children: creditAccounts.map((acc) { return _accountTile( name: acc["name"] ?? "", id: acc["id"] ?? "", status: acc["status"] ?? "", transactionId: acc["transactionId"] ?? "", // ✅ FIX orders: acc["orders"] ?? "", balance: acc["balance"] ?? "₹0", credit: acc["credit"] ?? "₹0", lastPayment: acc["lastPayment"] ?? "", balanceColor: (acc["balanceValue"] ?? 0) < 0 ? Colors.red : Colors.green, creditColor: Colors.red, ); }).toList(), ), ], ), ), ); } Widget _balanceBox({ required String title, required double amount, required Color color, }) { return Expanded( child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: Colors.white, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title), const SizedBox(height: 4), Text("₹${amount.toStringAsFixed(0)}", style: TextStyle(color: color, fontSize: 16)), ], ), ), ); } Widget _accountTile({ required String name, required String status, required String id, required String orders, required String balance, required String credit, required String lastPayment, required Color balanceColor, required Color creditColor, required String transactionId, }) { return GestureDetector( onTap: () { if (status == "paid_by_customer") return; Navigator.push( context, MaterialPageRoute( builder: (_) => BuildingTransactionsDetails( supplierId: AppSettings.supplierId, // ✅ from logged-in supplier customerId: id, // ✅ this account's customer ), ), ); }, child: Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text(id, style: fontTextStyle(14, const Color(0xFF2D2E30), FontWeight.w500)), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: status == "completed" ? Colors.green.withOpacity(0.1) : Colors.red.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( status == "completed" ? "active" : status == "paid_by_customer" ? "pending" : status, style: TextStyle( color: status == "completed" ? Colors.green : status == "paid_by_customer" ? Colors.orange : Colors.redAccent, fontSize: 12, fontWeight: FontWeight.w500, ), ), ) ], ), const SizedBox(height: 4), Text(orders, style: const TextStyle(color: Colors.grey, fontSize: 12)), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("Available Balance", style: TextStyle(fontSize: 12, color: Colors.black54)), const SizedBox(height: 4), Text(balance, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: balanceColor)), ], ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("Available Credit", style: TextStyle(fontSize: 12, color: Colors.black54)), const SizedBox(height: 4), Text(credit, style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: creditColor)), ], ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("Last Payment", style: TextStyle(fontSize: 12, color: Colors.black54)), const SizedBox(height: 4), Text(lastPayment, style: fontTextStyle(12, const Color(0XFFF1F1F1), FontWeight.w500)), ], ), ], ), // 👇 ADD THIS AT THE END OF children[] if (status == "paid_by_customer") ...[ const SizedBox(height: 8), Align( alignment: Alignment.centerRight, child: TextButton( onPressed: () async { final ok = await AppSettings.confirmAdvanceReceived( transactionId, // AWS transactionId "accept", ); if (ok) { AppSettings.longSuccessToast("Advance accepted"); fetchCreditAccounts(); // refresh list } else { AppSettings.longFailedToast("Failed to accept"); } }, child: const Text("Accept"), ), ), ], ], ), ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Color(0XFFFFFFFF), appBar: AppBar( elevation: 0, backgroundColor: Colors.white, bottom: PreferredSize( preferredSize: const Size.fromHeight(0.0), child: Container( height: 38, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: AnimatedBuilder( animation: _tabController, builder: (context, _) { return TabBar( controller: _tabController, indicatorColor: Colors.transparent, dividerColor: Colors.transparent, isScrollable: false, overlayColor: MaterialStateProperty.all(Colors.transparent), tabs: List.generate(2, (index) { final labels = ['Transactions', 'Credit Accounts']; final isSelected = _tabController.index == index; return Container( decoration: BoxDecoration( color: isSelected ? const Color(0XFFF1F1F1) : Colors.transparent, borderRadius: BorderRadius.circular(27), ), alignment: Alignment.center, child: Text( labels[index], style: fontTextStyle(12, const Color(0XFF000000), FontWeight.w600), ), ); }), ); }, ), ), ), ), body: TabBarView( controller: _tabController, children: [ Transactions(), CreditAccounts(), ], ), floatingActionButton: _tabController.index == 0 ? fab() : null, ); } Widget _buildFilterChip(String text) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: FilterChip( label: Row( mainAxisSize: MainAxisSize.min, children: [ Text( text, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: Colors.black, ), ), const SizedBox(width: 4), const Icon(Icons.keyboard_arrow_down, size: 18, color: Colors.black), ], ), backgroundColor: Colors.white, selectedColor: const Color(0XFFF1F1F1), side: const BorderSide(color: Color(0XFF444444)), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), onSelected: (val) {}, ), ); } }