Done Category, Product Catalogue, Customer, Vendor, Purchase Invoice Module
This commit is contained in:
@@ -13,30 +13,30 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final walletsState = ref.watch(walletProvider);
|
||||
|
||||
|
||||
if (!walletsState.hasValue || walletsState.value == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
|
||||
final wallets = walletsState.value!;
|
||||
|
||||
|
||||
// Filter for payables that have a due date/amount
|
||||
final payables = wallets.where((w) => w.nature == 'PAYABLES').toList();
|
||||
|
||||
|
||||
if (payables.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
|
||||
final now = DateTime.now();
|
||||
|
||||
|
||||
// Calculate dues
|
||||
final List<Map<String, dynamic>> dues = [];
|
||||
|
||||
|
||||
for (var w in payables) {
|
||||
double dueAmount = 0;
|
||||
DateTime? dueDate;
|
||||
String dueLabel = 'Upcoming Due';
|
||||
|
||||
|
||||
if (w.subNature == 'CREDIT_CARD' || w.subNature == 'OD_LIMIT') {
|
||||
// Balance is negative if we owe money
|
||||
if (w.balance < 0) {
|
||||
@@ -45,11 +45,11 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
} else if (w.subNature == 'LOAN_EMI' || w.subNature == 'POLICY_PREMIUM') {
|
||||
dueAmount = w.fixedAmount ?? 0;
|
||||
}
|
||||
|
||||
|
||||
if (dueAmount > 0 && w.cycleDate != null) {
|
||||
int year = now.year;
|
||||
int month = now.month;
|
||||
|
||||
|
||||
// Find next due date based on cycle
|
||||
if (w.paymentCycle == 'MONTHLY' || w.paymentCycle == null) {
|
||||
if (now.day > w.cycleDate!) {
|
||||
@@ -63,18 +63,20 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
} else if (w.paymentCycle == 'YEARLY') {
|
||||
// Assume cycleDate is day of current month, this is simplistic
|
||||
if (now.day > w.cycleDate!) {
|
||||
year++;
|
||||
year++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Handle end of month issues (e.g. Feb 30th)
|
||||
int maxDays = DateTime(year, month + 1, 0).day;
|
||||
int day = w.cycleDate! > maxDays ? maxDays : w.cycleDate!;
|
||||
|
||||
|
||||
dueDate = DateTime(year, month, day);
|
||||
|
||||
int daysLeft = dueDate.difference(DateTime(now.year, now.month, now.day)).inDays;
|
||||
|
||||
|
||||
int daysLeft = dueDate
|
||||
.difference(DateTime(now.year, now.month, now.day))
|
||||
.inDays;
|
||||
|
||||
if (daysLeft == 0) {
|
||||
dueLabel = 'Due Today';
|
||||
} else if (daysLeft == 1) {
|
||||
@@ -82,7 +84,7 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
} else {
|
||||
dueLabel = 'Due in $daysLeft days';
|
||||
}
|
||||
|
||||
|
||||
dues.add({
|
||||
'wallet': w,
|
||||
'amount': dueAmount,
|
||||
@@ -92,25 +94,34 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (dues.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
|
||||
// Sort by nearest due date
|
||||
dues.sort((a, b) => (a['daysLeft'] as int).compareTo(b['daysLeft'] as int));
|
||||
|
||||
|
||||
// Only show top 3 dues
|
||||
final displayDues = dues.take(3).toList();
|
||||
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(LucideIcons.calendarClock, color: Color(0xFF6C63FF), size: 20),
|
||||
const Icon(
|
||||
LucideIcons.calendarClock,
|
||||
color: Color(0xFF6C63FF),
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text('Upcoming Dues', style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.bold)),
|
||||
Text(
|
||||
'Upcoming Dues',
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -120,18 +131,33 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
final dueDate = due['dueDate'] as DateTime;
|
||||
final label = due['label'] as String;
|
||||
final daysLeft = due['daysLeft'] as int;
|
||||
|
||||
|
||||
final isUrgent = daysLeft <= 3;
|
||||
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: isUrgent ? (isDark ? Colors.red.withOpacity(0.2) : Colors.red.shade50) : Theme.of(context).cardColor,
|
||||
color: isUrgent
|
||||
? (isDark ? Colors.red.withOpacity(0.2) : Colors.red.shade50)
|
||||
: Theme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: isUrgent ? (isDark ? Colors.red.withOpacity(0.5) : Colors.red.shade200) : Theme.of(context).dividerColor.withOpacity(isDark ? 0.1 : 0.2)),
|
||||
border: Border.all(
|
||||
color: isUrgent
|
||||
? (isDark
|
||||
? Colors.red.withOpacity(0.5)
|
||||
: Colors.red.shade200)
|
||||
: Theme.of(
|
||||
context,
|
||||
).dividerColor.withOpacity(isDark ? 0.1 : 0.2),
|
||||
),
|
||||
boxShadow: [
|
||||
if (!isUrgent) BoxShadow(color: Colors.black.withOpacity(isDark ? 0.2 : 0.02), blurRadius: 8, offset: const Offset(0, 2))
|
||||
if (!isUrgent)
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(isDark ? 0.2 : 0.02),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
@@ -139,13 +165,22 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: (isUrgent ? Colors.red : NatureColors.getColor('PAYABLES')).withOpacity(0.1),
|
||||
color:
|
||||
(isUrgent
|
||||
? Colors.red
|
||||
: NatureColors.getColor('PAYABLES'))
|
||||
.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
w.subNature == 'CREDIT_CARD' ? LucideIcons.creditCard :
|
||||
(w.subNature == 'LOAN_EMI' ? LucideIcons.home : LucideIcons.fileText),
|
||||
color: isUrgent ? Colors.red : NatureColors.getColor('PAYABLES'),
|
||||
w.subNature == 'CREDIT_CARD'
|
||||
? LucideIcons.creditCard
|
||||
: (w.subNature == 'LOAN_EMI'
|
||||
? LucideIcons.home
|
||||
: LucideIcons.fileText),
|
||||
color: isUrgent
|
||||
? Colors.red
|
||||
: NatureColors.getColor('PAYABLES'),
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
@@ -154,14 +189,25 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(w.name, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15, color: Theme.of(context).textTheme.bodyLarge?.color)),
|
||||
Text(
|
||||
w.name,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
color: Theme.of(context).textTheme.bodyLarge?.color,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'$label • ${DateFormat('MMM dd').format(dueDate)}',
|
||||
style: TextStyle(
|
||||
color: isUrgent ? Colors.red.shade700 : Colors.grey.shade600,
|
||||
color: isUrgent
|
||||
? Colors.red.shade700
|
||||
: Colors.grey.shade600,
|
||||
fontSize: 12,
|
||||
fontWeight: isUrgent ? FontWeight.bold : FontWeight.normal
|
||||
fontWeight: isUrgent
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -170,9 +216,11 @@ class UpcomingDuesWidget extends ConsumerWidget {
|
||||
Text(
|
||||
'Rs. ${amount.toStringAsFixed(0)}',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: isUrgent ? (isDark ? Colors.redAccent : Colors.red.shade700) : Theme.of(context).textTheme.bodyLarge?.color
|
||||
color: isUrgent
|
||||
? (isDark ? Colors.redAccent : Colors.red.shade700)
|
||||
: Theme.of(context).textTheme.bodyLarge?.color,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user