860 lines
38 KiB
Dart
860 lines
38 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import '../../core/services/chit_group_service.dart';
|
||
import '../../core/utils/chit_calculator.dart';
|
||
import '../../core/utils/snackbar_util.dart';
|
||
import '../../shared/widgets/monthly_schedule_table.dart';
|
||
|
||
class CreateGroupDialog extends StatefulWidget {
|
||
const CreateGroupDialog({super.key});
|
||
|
||
@override
|
||
State<CreateGroupDialog> createState() => _CreateGroupDialogState();
|
||
}
|
||
|
||
class _CreateGroupDialogState extends State<CreateGroupDialog> {
|
||
final _formKey = GlobalKey<FormState>();
|
||
final _nameController = TextEditingController();
|
||
final _totalValueController = TextEditingController();
|
||
final _monthlyInstallmentController = TextEditingController();
|
||
final _durationMonthsController = TextEditingController();
|
||
final _maxMembersController = TextEditingController();
|
||
final _foremanCommissionController = TextEditingController();
|
||
final _foremanCommissionTypeController = TextEditingController();
|
||
final _maxDividendController = TextEditingController();
|
||
final _drawDateController = TextEditingController();
|
||
|
||
bool _isLoading = false;
|
||
String? _selectedDrawDate;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_drawDateController.text = '15'; // Default draw date
|
||
_foremanCommissionController.text = '250'; // Default commission
|
||
_foremanCommissionTypeController.text = 'fixed'; // Default commission type
|
||
_maxDividendController.text = '500'; // Default max dividend
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_nameController.dispose();
|
||
_totalValueController.dispose();
|
||
_monthlyInstallmentController.dispose();
|
||
_durationMonthsController.dispose();
|
||
_maxMembersController.dispose();
|
||
_foremanCommissionController.dispose();
|
||
_foremanCommissionTypeController.dispose();
|
||
_maxDividendController.dispose();
|
||
_drawDateController.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
void _calculateMonthlyInstallment() {
|
||
final totalValue = double.tryParse(_totalValueController.text);
|
||
final durationMonths = int.tryParse(_durationMonthsController.text);
|
||
final commissionType = _foremanCommissionTypeController.text;
|
||
|
||
if (totalValue != null && durationMonths != null) {
|
||
double commission;
|
||
if (commissionType == 'percentage') {
|
||
final rate = double.tryParse(_foremanCommissionController.text) ?? 5.0;
|
||
commission = (totalValue / durationMonths) * (rate / 100);
|
||
} else {
|
||
commission = double.tryParse(_foremanCommissionController.text) ?? 250.0;
|
||
}
|
||
// Generic formula: Monthly Installment = (Total Value ÷ Duration Months) + Commission
|
||
final subscriptionPerMonth = totalValue / durationMonths;
|
||
final monthlyInstallment = subscriptionPerMonth + commission;
|
||
_monthlyInstallmentController.text = monthlyInstallment.toStringAsFixed(0);
|
||
}
|
||
setState(() {}); // Rebuild to update schedule
|
||
}
|
||
|
||
void _calculateTotalValue() {
|
||
final monthlyInstallment = double.tryParse(_monthlyInstallmentController.text);
|
||
final durationMonths = int.tryParse(_durationMonthsController.text);
|
||
final commissionType = _foremanCommissionTypeController.text;
|
||
|
||
if (monthlyInstallment != null && durationMonths != null) {
|
||
double totalValue;
|
||
if (commissionType == 'percentage') {
|
||
// For percentage commission: total_value = monthly_installment * duration_months / (1 + rate/100)
|
||
final rate = double.tryParse(_foremanCommissionController.text) ?? 5.0;
|
||
totalValue = (monthlyInstallment * durationMonths) / (1 + rate/100);
|
||
} else {
|
||
// For fixed commission: total_value = (monthly_installment - commission) × duration_months
|
||
final commission = double.tryParse(_foremanCommissionController.text) ?? 250.0;
|
||
totalValue = (monthlyInstallment - commission) * durationMonths;
|
||
}
|
||
|
||
_totalValueController.text = totalValue.toStringAsFixed(0);
|
||
}
|
||
setState(() {}); // Rebuild to update schedule
|
||
}
|
||
|
||
// Calculate advantage structure using the generic formula
|
||
Map<String, dynamic> _calculateAdvantageStructure() {
|
||
final totalValue = double.tryParse(_totalValueController.text) ?? 0;
|
||
final durationMonths = int.tryParse(_durationMonthsController.text) ?? 0;
|
||
final commissionType = _foremanCommissionTypeController.text;
|
||
final commission = double.tryParse(_foremanCommissionController.text) ?? 250;
|
||
final maxDividend = double.tryParse(_maxDividendController.text) ?? (commission * 2);
|
||
|
||
if (totalValue <= 0 || durationMonths <= 0) {
|
||
return {};
|
||
}
|
||
|
||
// Use the generic calculator
|
||
final advantageStructure = ChitCalculator.calculateAdvantageStructure(
|
||
chitValue: totalValue,
|
||
months: durationMonths,
|
||
commissionPerMonth: commission,
|
||
maxDividend: maxDividend,
|
||
);
|
||
|
||
return {
|
||
'first_month': {
|
||
'payment': advantageStructure['first_month_winner']['installment_paid'],
|
||
'receipt': advantageStructure['first_month_winner']['bid_amount'],
|
||
'net_gain': advantageStructure['first_month_winner']['net_gain'],
|
||
'dividend_per_member': advantageStructure['first_month_winner']['dividend_others_get'],
|
||
},
|
||
'last_month': {
|
||
'payment': advantageStructure['last_month_winner']['total_paid'],
|
||
'receipt': advantageStructure['last_month_winner']['total_received'],
|
||
'net_gain': advantageStructure['last_month_winner']['net_gain_total'],
|
||
'dividend_per_member': advantageStructure['last_month_winner']['dividend_others_pay'] * -1,
|
||
},
|
||
'monthly_commission': advantageStructure['commission_per_month'],
|
||
'winner_payout': advantageStructure['first_month_winner']['bid_amount'],
|
||
'dividend_per_member_early': advantageStructure['first_month_winner']['dividend_others_get'],
|
||
'subscription_per_month': advantageStructure['subscription_per_month'],
|
||
'installment_per_month': advantageStructure['installment_per_month'],
|
||
};
|
||
}
|
||
|
||
Future<void> _createGroup() async {
|
||
if (!_formKey.currentState!.validate()) return;
|
||
|
||
setState(() => _isLoading = true);
|
||
|
||
try {
|
||
final groupData = {
|
||
'name': _nameController.text.trim(),
|
||
'total_value': double.parse(_totalValueController.text),
|
||
'monthly_installment': double.parse(_monthlyInstallmentController.text),
|
||
'duration_months': int.parse(_durationMonthsController.text),
|
||
'max_members': int.parse(_maxMembersController.text),
|
||
'foreman_commission_amount': double.parse(_foremanCommissionController.text),
|
||
'foreman_commission_type': _foremanCommissionTypeController.text,
|
||
if (_foremanCommissionTypeController.text == 'percentage')
|
||
'foreman_commission_rate': double.parse(_foremanCommissionController.text),
|
||
'draw_date': int.parse(_drawDateController.text),
|
||
};
|
||
|
||
final success = await ChitGroupService.to.createChitGroup(groupData);
|
||
|
||
if (success) {
|
||
Navigator.of(context).pop(); // Close dialog
|
||
SnackbarUtil.showSuccess(
|
||
'Chit group created successfully!',
|
||
title: 'Success',
|
||
);
|
||
}
|
||
} catch (e) {
|
||
SnackbarUtil.showError(
|
||
'Failed to create chit group. Please try again.',
|
||
title: 'Error',
|
||
);
|
||
} finally {
|
||
setState(() => _isLoading = false);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Dialog(
|
||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)),
|
||
child: Container(
|
||
width: MediaQuery.of(context).size.width > 600 ? 600.w : double.infinity,
|
||
constraints: BoxConstraints(
|
||
maxHeight: 0.85.sh,
|
||
maxWidth: MediaQuery.of(context).size.width * 0.95,
|
||
),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
// Header
|
||
Container(
|
||
padding: EdgeInsets.all(20.w),
|
||
decoration: BoxDecoration(
|
||
color: Colors.green.shade600,
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(16.r),
|
||
topRight: Radius.circular(16.r),
|
||
),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Icon(
|
||
Icons.group_add,
|
||
color: Colors.white,
|
||
size: 24.w,
|
||
),
|
||
SizedBox(width: 12.w),
|
||
Text(
|
||
'Create New Chitfund',
|
||
style: TextStyle(
|
||
color: Colors.white,
|
||
fontSize: 18.sp,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
const Spacer(),
|
||
IconButton(
|
||
onPressed: () => Navigator.of(context).pop(),
|
||
icon: const Icon(Icons.close, color: Colors.white),
|
||
padding: EdgeInsets.zero,
|
||
constraints: const BoxConstraints(),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
|
||
// Form Content
|
||
Flexible(
|
||
child: SingleChildScrollView(
|
||
padding: EdgeInsets.all(20.w),
|
||
child: Form(
|
||
key: _formKey,
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
// Basic Information Section
|
||
_buildSectionTitle('Basic Information'),
|
||
SizedBox(height: 16.h),
|
||
|
||
TextFormField(
|
||
controller: _nameController,
|
||
decoration: InputDecoration(
|
||
labelText: 'Chitfund Name',
|
||
hintText: 'Enter chitfund name',
|
||
prefixIcon: const Icon(Icons.group),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
validator: (value) {
|
||
if (value == null || value.trim().isEmpty) {
|
||
return 'Chitfund name is required';
|
||
}
|
||
if (value.trim().length < 3) {
|
||
return 'Chitfund name must be at least 3 characters';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
SizedBox(height: 16.h),
|
||
|
||
// Financial Details Section
|
||
_buildSectionTitle('Financial Details'),
|
||
SizedBox(height: 16.h),
|
||
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: TextFormField(
|
||
controller: _totalValueController,
|
||
decoration: InputDecoration(
|
||
labelText: 'Total Value (₹)',
|
||
hintText: 'e.g., 100000',
|
||
prefixIcon: const Icon(Icons.currency_rupee),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
keyboardType: TextInputType.number,
|
||
onChanged: (_) => _calculateMonthlyInstallment(),
|
||
validator: (value) {
|
||
if (value == null || value.isEmpty) {
|
||
return 'Total value is required';
|
||
}
|
||
final amount = double.tryParse(value);
|
||
if (amount == null || amount <= 0) {
|
||
return 'Please enter a valid amount';
|
||
}
|
||
if (amount < 1000) {
|
||
return 'Minimum amount is ₹1,000';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
),
|
||
SizedBox(width: 16.w),
|
||
Expanded(
|
||
child: TextFormField(
|
||
controller: _monthlyInstallmentController,
|
||
decoration: InputDecoration(
|
||
labelText: 'Monthly Installment (₹)',
|
||
hintText: 'e.g., 5000',
|
||
prefixIcon: const Icon(Icons.payment),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
keyboardType: TextInputType.number,
|
||
onChanged: (_) => _calculateTotalValue(),
|
||
validator: (value) {
|
||
if (value == null || value.isEmpty) {
|
||
return 'Monthly installment is required';
|
||
}
|
||
final amount = double.tryParse(value);
|
||
if (amount == null || amount <= 0) {
|
||
return 'Please enter a valid amount';
|
||
}
|
||
if (amount < 100) {
|
||
return 'Minimum installment is ₹100';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 16.h),
|
||
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: TextFormField(
|
||
controller: _durationMonthsController,
|
||
decoration: InputDecoration(
|
||
labelText: 'Duration (Months)',
|
||
hintText: 'e.g., 20',
|
||
prefixIcon: const Icon(Icons.calendar_today),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
keyboardType: TextInputType.number,
|
||
onChanged: (_) => _calculateMonthlyInstallment(),
|
||
validator: (value) {
|
||
if (value == null || value.isEmpty) {
|
||
return 'Duration is required';
|
||
}
|
||
final months = int.tryParse(value);
|
||
if (months == null || months < 6) {
|
||
return 'Minimum duration is 6 months';
|
||
}
|
||
if (months > 60) {
|
||
return 'Maximum duration is 60 months';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
),
|
||
SizedBox(width: 16.w),
|
||
Expanded(
|
||
child: TextFormField(
|
||
controller: _maxMembersController,
|
||
decoration: InputDecoration(
|
||
labelText: 'Maximum Members',
|
||
hintText: 'e.g., 20',
|
||
prefixIcon: const Icon(Icons.people),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
keyboardType: TextInputType.number,
|
||
validator: (value) {
|
||
if (value == null || value.isEmpty) {
|
||
return 'Maximum members is required';
|
||
}
|
||
final members = int.tryParse(value);
|
||
if (members == null || members < 2) {
|
||
return 'Minimum 2 members required';
|
||
}
|
||
if (members > 100) {
|
||
return 'Maximum 100 members allowed';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 16.h),
|
||
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: TextFormField(
|
||
controller: _foremanCommissionController,
|
||
decoration: InputDecoration(
|
||
labelText: _foremanCommissionTypeController.text == 'percentage'
|
||
? 'Foreman Commission Rate (%)'
|
||
: 'Foreman Commission (₹)',
|
||
hintText: _foremanCommissionTypeController.text == 'percentage'
|
||
? 'e.g., 5'
|
||
: 'e.g., 250',
|
||
prefixIcon: Icon(
|
||
_foremanCommissionTypeController.text == 'percentage'
|
||
? Icons.percent
|
||
: Icons.currency_rupee,
|
||
),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
keyboardType: TextInputType.number,
|
||
onChanged: (_) => _calculateMonthlyInstallment(),
|
||
validator: (value) {
|
||
if (value == null || value.isEmpty) {
|
||
return _foremanCommissionTypeController.text == 'percentage'
|
||
? 'Commission rate is required'
|
||
: 'Commission is required';
|
||
}
|
||
final commission = double.tryParse(value);
|
||
if (commission == null || commission < 0) {
|
||
return 'Please enter a valid value';
|
||
}
|
||
if (_foremanCommissionTypeController.text == 'percentage' && commission > 100) {
|
||
return 'Commission rate cannot exceed 100%';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
),
|
||
SizedBox(width: 16.w),
|
||
Expanded(
|
||
child: DropdownButtonFormField<String>(
|
||
value: _foremanCommissionTypeController.text,
|
||
decoration: InputDecoration(
|
||
labelText: 'Commission Type',
|
||
prefixIcon: const Icon(Icons.settings),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
items: const [
|
||
DropdownMenuItem(value: 'fixed', child: Text('Fixed Amount')),
|
||
DropdownMenuItem(value: 'percentage', child: Text('Percentage')),
|
||
],
|
||
onChanged: (value) {
|
||
if (value != null) {
|
||
_foremanCommissionTypeController.text = value;
|
||
// Update the commission field value based on type
|
||
if (value == 'percentage') {
|
||
_foremanCommissionController.text = '5'; // Default 5%
|
||
} else {
|
||
_foremanCommissionController.text = '250'; // Default ₹250
|
||
}
|
||
_calculateMonthlyInstallment();
|
||
setState(() {}); // Trigger rebuild to update UI
|
||
}
|
||
},
|
||
),
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 16.h),
|
||
|
||
|
||
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: TextFormField(
|
||
controller: _maxDividendController,
|
||
decoration: InputDecoration(
|
||
labelText: 'Max Dividend (₹)',
|
||
hintText: 'e.g., 500',
|
||
prefixIcon: const Icon(Icons.trending_up),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
keyboardType: TextInputType.number,
|
||
validator: (value) {
|
||
if (value == null || value.isEmpty) {
|
||
return 'Max dividend is required';
|
||
}
|
||
final maxDividend = double.tryParse(value);
|
||
if (maxDividend == null || maxDividend < 0) {
|
||
return 'Please enter a valid amount';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
),
|
||
SizedBox(width: 16.w),
|
||
Expanded(child: Container()), // Empty space for alignment
|
||
],
|
||
),
|
||
SizedBox(height: 16.h),
|
||
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: TextFormField(
|
||
controller: _drawDateController,
|
||
decoration: InputDecoration(
|
||
labelText: 'Draw Date (Day of Month)',
|
||
hintText: 'e.g., 15',
|
||
prefixIcon: const Icon(Icons.casino),
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
keyboardType: TextInputType.number,
|
||
validator: (value) {
|
||
if (value == null || value.isEmpty) {
|
||
return 'Draw date is required';
|
||
}
|
||
final day = int.tryParse(value);
|
||
if (day == null || day < 1 || day > 31) {
|
||
return 'Please enter a valid day (1-31)';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
),
|
||
SizedBox(width: 16.w),
|
||
Expanded(child: Container()), // Empty space for alignment
|
||
],
|
||
),
|
||
SizedBox(height: 24.h),
|
||
|
||
// Summary Section
|
||
_buildSectionTitle('Summary'),
|
||
SizedBox(height: 16.h),
|
||
|
||
Container(
|
||
padding: EdgeInsets.all(16.w),
|
||
decoration: BoxDecoration(
|
||
color: Colors.grey.shade50,
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
border: Border.all(color: Colors.grey.shade300),
|
||
),
|
||
child: Column(
|
||
children: [
|
||
_buildSummaryRow('Chitfund Name', _nameController.text.isEmpty ? 'Not set' : _nameController.text),
|
||
_buildSummaryRow('Total Value', _totalValueController.text.isEmpty ? 'Not set' : '₹${_totalValueController.text}'),
|
||
_buildSummaryRow('Monthly Installment', _monthlyInstallmentController.text.isEmpty ? 'Not set' : '₹${_monthlyInstallmentController.text}'),
|
||
_buildSummaryRow('Duration', _durationMonthsController.text.isEmpty ? 'Not set' : '${_durationMonthsController.text} months'),
|
||
_buildSummaryRow('Max Members', _maxMembersController.text.isEmpty ? 'Not set' : _maxMembersController.text),
|
||
_buildSummaryRow('Commission', _foremanCommissionController.text.isEmpty ? 'Not set' : '₹${_foremanCommissionController.text}'),
|
||
_buildSummaryRow('Max Dividend', _maxDividendController.text.isEmpty ? 'Not set' : '₹${_maxDividendController.text}'),
|
||
_buildSummaryRow('Draw Date', _drawDateController.text.isEmpty ? 'Not set' : '${_drawDateController.text}th of each month'),
|
||
],
|
||
),
|
||
),
|
||
SizedBox(height: 24.h),
|
||
|
||
// Advantage Structure Section
|
||
_buildSectionTitle('Advantage Structure'),
|
||
SizedBox(height: 16.h),
|
||
|
||
_buildAdvantageStructureCard(),
|
||
SizedBox(height: 24.h),
|
||
|
||
// Monthly Schedule Section
|
||
_buildSectionTitle('Month-wise Payment Schedule'),
|
||
SizedBox(height: 16.h),
|
||
|
||
ExpandableMonthlySchedule(
|
||
totalValue: double.tryParse(_totalValueController.text) ?? 0,
|
||
durationMonths: int.tryParse(_durationMonthsController.text) ?? 0,
|
||
monthlyInstallment: double.tryParse(_monthlyInstallmentController.text) ?? 0,
|
||
commission: double.tryParse(_foremanCommissionController.text) ?? 0,
|
||
maxDividend: double.tryParse(_maxDividendController.text) ?? 0,
|
||
),
|
||
SizedBox(height: 24.h),
|
||
|
||
// Action Buttons
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: OutlinedButton(
|
||
onPressed: () => Navigator.of(context).pop(),
|
||
style: OutlinedButton.styleFrom(
|
||
padding: EdgeInsets.symmetric(vertical: 16.h),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
child: Text(
|
||
'Cancel',
|
||
style: TextStyle(fontSize: 16.sp),
|
||
),
|
||
),
|
||
),
|
||
SizedBox(width: 16.w),
|
||
Expanded(
|
||
child: ElevatedButton(
|
||
onPressed: _isLoading ? null : _createGroup,
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.green.shade600,
|
||
foregroundColor: Colors.white,
|
||
padding: EdgeInsets.symmetric(vertical: 16.h),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
),
|
||
child: _isLoading
|
||
? SizedBox(
|
||
height: 20.h,
|
||
width: 20.w,
|
||
child: const CircularProgressIndicator(
|
||
strokeWidth: 2,
|
||
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||
),
|
||
)
|
||
: Text(
|
||
'Create Chitfund',
|
||
style: TextStyle(fontSize: 16.sp),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildSectionTitle(String title) {
|
||
return Text(
|
||
title,
|
||
style: TextStyle(
|
||
fontSize: 16.sp,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.grey.shade800,
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildSummaryRow(String label, String value) {
|
||
return Padding(
|
||
padding: EdgeInsets.symmetric(vertical: 4.h),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
Text(
|
||
label,
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Colors.grey.shade600,
|
||
),
|
||
),
|
||
Text(
|
||
value,
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
fontWeight: FontWeight.w500,
|
||
color: Colors.grey.shade800,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildAdvantageStructureCard() {
|
||
final advantageData = _calculateAdvantageStructure();
|
||
|
||
if (advantageData.isEmpty) {
|
||
return Container(
|
||
padding: EdgeInsets.all(16.w),
|
||
decoration: BoxDecoration(
|
||
color: Colors.orange.shade50,
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
border: Border.all(color: Colors.orange.shade200),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Icon(Icons.info_outline, color: Colors.orange.shade600, size: 20.w),
|
||
SizedBox(width: 8.w),
|
||
Expanded(
|
||
child: Text(
|
||
'Fill in the group details above to see the advantage structure',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Colors.orange.shade700,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
return Container(
|
||
padding: EdgeInsets.all(16.w),
|
||
decoration: BoxDecoration(
|
||
color: Colors.blue.shade50,
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
border: Border.all(color: Colors.blue.shade200),
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Icon(Icons.trending_up, color: Colors.blue.shade600, size: 20.w),
|
||
SizedBox(width: 8.w),
|
||
Text(
|
||
'Chit Fund Advantage Structure',
|
||
style: TextStyle(
|
||
fontSize: 16.sp,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.blue.shade800,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 16.h),
|
||
|
||
// First Month Winner
|
||
Container(
|
||
padding: EdgeInsets.all(12.w),
|
||
decoration: BoxDecoration(
|
||
color: Colors.green.shade50,
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
border: Border.all(color: Colors.green.shade200),
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Icon(Icons.rocket_launch, color: Colors.green.shade600, size: 16.w),
|
||
SizedBox(width: 8.w),
|
||
Text(
|
||
'First Month Winner (Early Advantage)',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.green.shade700,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 8.h),
|
||
_buildAdvantageRow('Monthly Payment', '₹${advantageData['first_month']['payment'].toStringAsFixed(0)}'),
|
||
_buildAdvantageRow('Bid Amount', '₹${advantageData['first_month']['receipt'].toStringAsFixed(0)}'),
|
||
_buildAdvantageRow('Net Gain', '₹${advantageData['first_month']['net_gain'].toStringAsFixed(0)}', isHighlight: true),
|
||
_buildAdvantageRow('Others Get Dividend', '₹${advantageData['first_month']['dividend_per_member'].toStringAsFixed(0)}', isHighlight: false),
|
||
],
|
||
),
|
||
),
|
||
SizedBox(height: 12.h),
|
||
|
||
// Last Month Winner
|
||
Container(
|
||
padding: EdgeInsets.all(12.w),
|
||
decoration: BoxDecoration(
|
||
color: Colors.purple.shade50,
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
border: Border.all(color: Colors.purple.shade200),
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Icon(Icons.schedule, color: Colors.purple.shade600, size: 16.w),
|
||
SizedBox(width: 8.w),
|
||
Text(
|
||
'Last Month Winner (Late Advantage)',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.purple.shade700,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 8.h),
|
||
_buildAdvantageRow('Total Paid', '₹${advantageData['last_month']['payment'].toStringAsFixed(0)}'),
|
||
_buildAdvantageRow('Total Received', '₹${advantageData['last_month']['receipt'].toStringAsFixed(0)}'),
|
||
_buildAdvantageRow('Net Gain', '₹${advantageData['last_month']['net_gain'].toStringAsFixed(0)}', isHighlight: true),
|
||
_buildAdvantageRow('Others Pay Extra', '₹${(advantageData['last_month']['dividend_per_member'] * -1).toStringAsFixed(0)}', isHighlight: false),
|
||
],
|
||
),
|
||
),
|
||
SizedBox(height: 12.h),
|
||
|
||
// Commission Info
|
||
Container(
|
||
padding: EdgeInsets.all(12.w),
|
||
decoration: BoxDecoration(
|
||
color: Colors.orange.shade50,
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
border: Border.all(color: Colors.orange.shade200),
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Icon(Icons.percent, color: Colors.orange.shade600, size: 16.w),
|
||
SizedBox(width: 8.w),
|
||
Text(
|
||
'Fixed Monthly Commission: ₹${advantageData['monthly_commission'].toStringAsFixed(0)}',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.orange.shade700,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 8.h),
|
||
_buildAdvantageRow('Subscription/Month', '₹${advantageData['subscription_per_month'].toStringAsFixed(0)}'),
|
||
_buildAdvantageRow('Installment/Month', '₹${advantageData['installment_per_month'].toStringAsFixed(0)}'),
|
||
_buildAdvantageRow('Winner Payout', '₹${advantageData['winner_payout'].toStringAsFixed(0)}'),
|
||
_buildAdvantageRow('Early Month Dividend', '₹${advantageData['dividend_per_member_early'].toStringAsFixed(0)} per member'),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildAdvantageRow(String label, String value, {bool isHighlight = false}) {
|
||
return Padding(
|
||
padding: EdgeInsets.symmetric(vertical: 2.h),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
Text(
|
||
label,
|
||
style: TextStyle(
|
||
fontSize: 13.sp,
|
||
color: Colors.grey.shade600,
|
||
),
|
||
),
|
||
Text(
|
||
value,
|
||
style: TextStyle(
|
||
fontSize: 13.sp,
|
||
fontWeight: isHighlight ? FontWeight.w600 : FontWeight.w500,
|
||
color: isHighlight ? Colors.green.shade700 : Colors.grey.shade800,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|