import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:intl/intl.dart'; /// Enhanced monthly schedule with traditional chit fund calculations /// Shows varying lift amounts (early lifters get less, late lifters get more) class EnhancedMonthlyScheduleTable extends StatelessWidget { final double totalValue; // Fixed target value final int durationMonths; final double monthlyContribution; // Principal amount final double monthlyCommission; // Fee/Commission final bool showAdvantageExplanation; const EnhancedMonthlyScheduleTable({ super.key, required this.totalValue, required this.durationMonths, required this.monthlyContribution, required this.monthlyCommission, this.showAdvantageExplanation = false, }); @override Widget build(BuildContext context) { if (totalValue <= 0 || durationMonths <= 0) { return _buildEmptyState(); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Explanation card if (showAdvantageExplanation) ...[ _buildExplanationCard(), SizedBox(height: 16.h), ], // Schedule table Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(12.r), ), child: Column( children: [ // Table header _buildTableHeader(), // Month rows (scrollable) Container( constraints: BoxConstraints( maxHeight: 350.h, ), child: ListView.builder( shrinkWrap: true, padding: EdgeInsets.zero, itemCount: durationMonths, itemBuilder: (context, index) { return _buildMonthRow(index + 1); }, ), ), ], ), ), SizedBox(height: 16.h), // Summary _buildSummaryCard(), ], ); } Widget _buildTableHeader() { return Container( padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 12.w), decoration: BoxDecoration( color: Colors.green.shade600, borderRadius: BorderRadius.vertical(top: Radius.circular(12.r)), ), child: Row( children: [ SizedBox( width: 50.w, child: Text( 'Month', style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.bold, color: Colors.white, ), textAlign: TextAlign.center, ), ), Expanded( flex: 2, child: Text( 'Payment', style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.bold, color: Colors.white, ), textAlign: TextAlign.center, ), ), Expanded( flex: 3, child: Text( 'Lift Amount', style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.bold, color: Colors.white, ), textAlign: TextAlign.center, ), ), ], ), ); } Widget _buildMonthRow(int month) { final monthlyPayment = monthlyContribution + monthlyCommission; final liftAmount = _calculateLiftAmount(month); final monthDate = _getMonthDate(month); final isEarly = month <= (durationMonths * 0.3).ceil(); final isLast = month == durationMonths; final bgColor = isLast ? Colors.purple.shade50 : isEarly ? Colors.green.shade50 : Colors.white; return Container( decoration: BoxDecoration( color: bgColor, border: Border( bottom: BorderSide(color: Colors.grey.shade200), ), ), padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 12.w), child: Row( children: [ // Month SizedBox( width: 50.w, child: Column( children: [ Text( '$month', style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.bold, color: isLast ? Colors.purple.shade700 : isEarly ? Colors.green.shade700 : Colors.grey.shade800, ), ), Text( monthDate, style: TextStyle( fontSize: 9.sp, color: Colors.grey.shade600, ), ), ], ), ), // Payment Expanded( flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( '₹${monthlyPayment.toStringAsFixed(0)}', style: TextStyle( fontSize: 13.sp, fontWeight: FontWeight.w600, color: Colors.grey.shade800, ), ), Text( 'Fixed', style: TextStyle( fontSize: 10.sp, color: Colors.grey.shade600, ), ), ], ), ), // Lift Amount Expanded( flex: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Icon( Icons.emoji_events_rounded, size: 14.w, color: Colors.amber.shade700, ), SizedBox(width: 4.w), Text( '₹${liftAmount.toStringAsFixed(0)}', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.bold, color: Colors.green.shade700, ), ), ], ), SizedBox(height: 2.h), Text( '${_getLiftPercentage(month)}% of target', style: TextStyle( fontSize: 10.sp, color: isLast ? Colors.purple.shade700 : isEarly ? Colors.green.shade700 : Colors.grey.shade600, fontWeight: FontWeight.w500, ), ), ], ), ), ], ), ); } /// Calculate lift amount for a specific month /// Formula: Early months get less, late months get more /// Based on traditional chit fund bidding system double _calculateLiftAmount(int month) { // Starting percentage (first month lifter gets ~87.65% of target) const double startingPercentage = 0.8765; // Ending percentage (last month lifter gets ~99.35% of target) const double endingPercentage = 0.9935; // Calculate increment per month final double incrementPerMonth = (endingPercentage - startingPercentage) / (durationMonths - 1); // Calculate lift amount for this month final double percentage = startingPercentage + (incrementPerMonth * (month - 1)); final double liftAmount = totalValue * percentage; return liftAmount; } String _getLiftPercentage(int month) { final liftAmount = _calculateLiftAmount(month); final percentage = (liftAmount / totalValue) * 100; return percentage.toStringAsFixed(1); } String _getMonthDate(int monthNumber) { final now = DateTime.now(); final futureMonth = DateTime(now.year, now.month + monthNumber - 1); return DateFormat('MMM-yy').format(futureMonth); } Widget _buildExplanationCard() { return Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( gradient: LinearGradient( colors: [Colors.blue.shade50, Colors.blue.shade100], ), borderRadius: BorderRadius.circular(12.r), border: Border.all(color: Colors.blue.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.lightbulb_rounded, color: Colors.blue.shade700, size: 20.w), SizedBox(width: 8.w), Text( 'How Chit Fund Works', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.bold, color: Colors.blue.shade800, ), ), ], ), SizedBox(height: 12.h), _buildExplanationPoint( '🏆 Early Lifters', 'Get money quickly but receive less (around 88% of target)', Colors.green.shade700, ), SizedBox(height: 8.h), _buildExplanationPoint( '⏳ Late Lifters', 'Wait longer but receive more (around 99% of target)', Colors.purple.shade700, ), SizedBox(height: 8.h), _buildExplanationPoint( '💰 Everyone Pays', 'Fixed monthly payment of ₹${(monthlyContribution + monthlyCommission).toStringAsFixed(0)}', Colors.orange.shade700, ), ], ), ); } Widget _buildExplanationPoint(String title, String description, Color color) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 4.w, height: 40.h, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(2.r), ), ), SizedBox(width: 8.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: 13.sp, fontWeight: FontWeight.w600, color: color, ), ), Text( description, style: TextStyle( fontSize: 12.sp, color: Colors.grey.shade700, ), ), ], ), ), ], ); } Widget _buildSummaryCard() { final monthlyPayment = monthlyContribution + monthlyCommission; final totalPayments = monthlyPayment * durationMonths; final totalCommission = monthlyCommission * durationMonths; final firstMonthLift = _calculateLiftAmount(1); final lastMonthLift = _calculateLiftAmount(durationMonths); return Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( color: Colors.orange.shade50, borderRadius: BorderRadius.circular(12.r), border: Border.all(color: Colors.orange.shade200), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.summarize_rounded, color: Colors.orange.shade700, size: 18.w), SizedBox(width: 8.w), Text( 'Financial Summary', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.bold, color: Colors.orange.shade800, ), ), ], ), SizedBox(height: 12.h), _buildSummaryRow('Fixed Target Value', '₹${totalValue.toStringAsFixed(0)}'), _buildSummaryRow('Monthly Payment (Fixed)', '₹${monthlyPayment.toStringAsFixed(0)}'), _buildSummaryRow('Duration', '$durationMonths months'), Divider(height: 16.h, color: Colors.orange.shade300), _buildSummaryRow( 'First Month Lifter Gets', '₹${firstMonthLift.toStringAsFixed(0)} (${_getLiftPercentage(1)}%)', color: Colors.green.shade700, ), _buildSummaryRow( 'Last Month Lifter Gets', '₹${lastMonthLift.toStringAsFixed(0)} (${_getLiftPercentage(durationMonths)}%)', color: Colors.purple.shade700, ), Divider(height: 16.h, color: Colors.orange.shade300), _buildSummaryRow('Total per Member', '₹${totalPayments.toStringAsFixed(0)}'), _buildSummaryRow('Total Commission', '₹${totalCommission.toStringAsFixed(0)}'), ], ), ); } Widget _buildSummaryRow(String label, String value, {Color? color}) { return Padding( padding: EdgeInsets.symmetric(vertical: 4.h), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( label, style: TextStyle( fontSize: 12.sp, color: Colors.grey.shade700, ), ), ), Text( value, style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w600, color: color ?? Colors.grey.shade800, ), ), ], ), ); } Widget _buildEmptyState() { return Container( padding: EdgeInsets.all(20.w), decoration: BoxDecoration( color: Colors.orange.shade50, borderRadius: BorderRadius.circular(12.r), border: Border.all(color: Colors.orange.shade200), ), child: Row( children: [ Icon(Icons.info_outline, color: Colors.orange.shade600, size: 24.w), SizedBox(width: 12.w), Expanded( child: Text( 'Enter financial details to see the month-wise schedule', style: TextStyle( fontSize: 14.sp, color: Colors.orange.shade700, ), ), ), ], ), ); } } /// Compact version with Date | Target | Lift Amount | Payment | Fee | Total columns class DetailedMonthlyScheduleTable extends StatelessWidget { final double totalValue; final int durationMonths; final double monthlyContribution; final double monthlyCommission; const DetailedMonthlyScheduleTable({ super.key, required this.totalValue, required this.durationMonths, required this.monthlyContribution, required this.monthlyCommission, }); @override Widget build(BuildContext context) { if (totalValue <= 0 || durationMonths <= 0) { return const SizedBox.shrink(); } final monthlyPayment = monthlyContribution + monthlyCommission; return Card( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: SingleChildScrollView( child: DataTable( headingRowColor: MaterialStateProperty.all(Colors.green.shade50), columnSpacing: 20.w, dataRowMinHeight: 50.h, dataRowMaxHeight: 60.h, columns: [ DataColumn( label: Text( 'Month', style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.bold), ), ), DataColumn( label: Text( 'Date', style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.bold), ), ), DataColumn( label: Text( 'Target Value', style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.bold), ), numeric: true, ), DataColumn( label: Text( 'Lifter Gets', style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.bold), ), numeric: true, ), DataColumn( label: Text( 'Contribution', style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.bold), ), numeric: true, ), DataColumn( label: Text( 'Fee', style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.bold), ), numeric: true, ), DataColumn( label: Text( 'Total Payment', style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.bold), ), numeric: true, ), ], rows: List.generate(durationMonths, (index) { final month = index + 1; final liftAmount = _calculateLiftAmount(month); final monthDate = _getMonthDate(month); final isEarly = month <= (durationMonths * 0.3).ceil(); final isLast = month == durationMonths; return DataRow( color: MaterialStateProperty.all( isLast ? Colors.purple.shade50 : isEarly ? Colors.green.shade50 : null, ), cells: [ DataCell(Text( '$month', style: TextStyle(fontSize: 13.sp, fontWeight: FontWeight.w600), )), DataCell(Text( monthDate, style: TextStyle(fontSize: 12.sp), )), DataCell(Text( '₹${totalValue.toStringAsFixed(0)}', style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.w500), )), DataCell(Text( '₹${liftAmount.toStringAsFixed(0)}', style: TextStyle( fontSize: 13.sp, fontWeight: FontWeight.bold, color: Colors.green.shade700, ), )), DataCell(Text( '₹${monthlyContribution.toStringAsFixed(0)}', style: TextStyle(fontSize: 12.sp), )), DataCell(Text( '₹${monthlyCommission.toStringAsFixed(0)}', style: TextStyle(fontSize: 12.sp), )), DataCell(Text( '₹${monthlyPayment.toStringAsFixed(0)}', style: TextStyle(fontSize: 13.sp, fontWeight: FontWeight.w600), )), ], ); }), ), ), ), ); } double _calculateLiftAmount(int month) { const double startingPercentage = 0.8765; const double endingPercentage = 0.9935; final double incrementPerMonth = (endingPercentage - startingPercentage) / (durationMonths - 1); final double percentage = startingPercentage + (incrementPerMonth * (month - 1)); return totalValue * percentage; } String _getMonthDate(int monthNumber) { final now = DateTime.now(); final futureMonth = DateTime(now.year, now.month + monthNumber - 1); return DateFormat('MMM-yy').format(futureMonth); } }