diff --git a/Backend/index.js b/Backend/index.js index 9ea2f35..420f261 100644 --- a/Backend/index.js +++ b/Backend/index.js @@ -92,6 +92,28 @@ app.get('/api/transactions', async (req, res) => { res.status(500).json({ error: err.message }); } }); +// Get 5 most recent transactions +app.get('/api/transactions/recent', async (req, res) => { + try { + const transactions = await Transaction.find({}) + .sort({ date: -1 }) + .limit(5); // 👈 limit to 5 + + res.status(200).json({ + success: true, + data: transactions.map(tx => ({ + id: tx._id, + description: tx.description, + amount: tx.amount, + category: tx.category, + date: tx.date, + })), + }); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + // Start server app.listen(3000, () => { diff --git a/Frontend/monarch/lib/add.dart b/Frontend/monarch/lib/add.dart index f0f13cc..49b1791 100644 --- a/Frontend/monarch/lib/add.dart +++ b/Frontend/monarch/lib/add.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; -import 'package:monarch/static.dart'; +import 'package:monarch/statistics.dart'; class AddExpenseScreen extends StatefulWidget { const AddExpenseScreen({super.key}); diff --git a/Frontend/monarch/lib/colors.dart b/Frontend/monarch/lib/colors.dart new file mode 100644 index 0000000..ac81239 --- /dev/null +++ b/Frontend/monarch/lib/colors.dart @@ -0,0 +1,8 @@ + import 'dart:ui'; + +final Color backgroundColor = const Color(0xFFF8F9FA); // Light cream/white + final Color primaryColor = const Color(0xFF2D3436); // Deep charcoal + final Color accentColor = const Color(0xFF00B894); // Emerald green + final Color cardColor = const Color(0xFFFFFFFF); // Pure white + final Color textSecondary = const Color(0xFF636E72); // Muted gray + final Color surfaceColor = const Color(0xFFF1F2F6); // Light surface diff --git a/Frontend/monarch/lib/fetch_service.dart b/Frontend/monarch/lib/fetch_service.dart new file mode 100644 index 0000000..5c901bc --- /dev/null +++ b/Frontend/monarch/lib/fetch_service.dart @@ -0,0 +1,18 @@ +// ignore_for_file: avoid_print + +import 'package:http/http.dart' as http; +import 'dart:convert'; + +Future>> fetchRecentTransactions() async { + final response = await http.get( + Uri.parse('http://192.168.1.9:3000/api/transactions/recent'), + ); + + if (response.statusCode == 200) { + final List data = jsonDecode(response.body)['data']; + return List>.from(data); + } else { + print('Failed to load recent transactions'); + return []; + } +} diff --git a/Frontend/monarch/lib/hero_card.dart b/Frontend/monarch/lib/hero_card.dart new file mode 100644 index 0000000..ca1d402 --- /dev/null +++ b/Frontend/monarch/lib/hero_card.dart @@ -0,0 +1,129 @@ +// ignore_for_file: deprecated_member_use + +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:monarch/colors.dart'; + final double totalBalance = 5847.32; + final double monthlyIncome = 8500.00; + final double monthlyExpenses = 2652.68; + + +class BalanceCardPage extends StatelessWidget { + const BalanceCardPage({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [accentColor, accentColor.withOpacity(0.8)], + ), + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: accentColor.withOpacity(0.3), + blurRadius: 20, + offset: const Offset(0, 8), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Total Balance', + style: GoogleFonts.inter( + color: Colors.white.withOpacity(0.9), + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + Icon( + Icons.visibility_outlined, + color: Colors.white.withOpacity(0.9), + size: 20, + ), + ], + ), + const SizedBox(height: 8), + Text( + '\$${totalBalance.toStringAsFixed(2)}', + style: GoogleFonts.inter( + color: Colors.white, + fontSize: 36, + fontWeight: FontWeight.w700, + letterSpacing: -1, + ), + ), + const SizedBox(height: 20), + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Income', + style: GoogleFonts.inter( + color: Colors.white.withOpacity(0.8), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + ), + const SizedBox(height: 4), + Text( + '\$${monthlyIncome.toStringAsFixed(0)}', + style: GoogleFonts.inter( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + Container( + width: 1, + height: 40, + color: Colors.white.withOpacity(0.3), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Expenses', + style: GoogleFonts.inter( + color: Colors.white.withOpacity(0.8), + fontSize: 14, + fontWeight: FontWeight.w400, + ), + ), + const SizedBox(height: 4), + Text( + '\$${monthlyExpenses.toStringAsFixed(0)}', + style: GoogleFonts.inter( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/Frontend/monarch/lib/home_animations.dart b/Frontend/monarch/lib/home_animations.dart new file mode 100644 index 0000000..a41ee91 --- /dev/null +++ b/Frontend/monarch/lib/home_animations.dart @@ -0,0 +1,80 @@ + +// ignore_for_file: library_private_types_in_public_api + +import 'package:flutter/material.dart'; + +class AnimationControllerPage extends StatefulWidget { + final Function(Animation) onAnimationCreated; + final Function(Animation) onFadeAnimationCreated; + + const AnimationControllerPage({super.key, required this.onAnimationCreated, required this.onFadeAnimationCreated, required Center child}); + + @override + _AnimationControllerPageState createState() => _AnimationControllerPageState(); +} + +class _AnimationControllerPageState extends State with TickerProviderStateMixin { + late AnimationController _fadeController; + late AnimationController _slideController; + late Animation _fadeAnimation; + late Animation _slideAnimation; + + @override + void initState() { + super.initState(); + _fadeController = AnimationController( + duration: const Duration(milliseconds: 1200), + vsync: this, + ); + + _slideController = AnimationController( + duration: const Duration(milliseconds: 800), + vsync: this, + ); + + _fadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation(parent: _fadeController, curve: Curves.easeOut)); + + _slideAnimation = Tween( + begin: const Offset(0, 0.3), + end: Offset.zero, + ).animate( + CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic), + ); + + // Start animations + _fadeController.forward(); + _slideController.forward(); + + widget.onAnimationCreated(_slideAnimation); + widget.onFadeAnimationCreated(_fadeAnimation); + } + + @override + void dispose() { + _fadeController.dispose(); + _slideController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: FadeTransition( + opacity: _fadeAnimation, + child: SlideTransition( + position: _slideAnimation, + child: Container( + width: 200, + height: 200, + color: Colors.blue, + ), + ), + ), + ), + ); + } +} diff --git a/Frontend/monarch/lib/homepage.dart b/Frontend/monarch/lib/homepage.dart index 5958aa8..cf6aa37 100644 --- a/Frontend/monarch/lib/homepage.dart +++ b/Frontend/monarch/lib/homepage.dart @@ -1,13 +1,14 @@ // ignore_for_file: deprecated_member_use, unused_local_variable, use_super_parameters, avoid_print -import 'dart:convert'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:http/http.dart' as http; -import 'package:monarch/add.dart'; +import 'package:monarch/colors.dart'; +import 'package:monarch/fetch_service.dart'; +import 'package:monarch/hero_card.dart'; import 'package:monarch/navbar.dart'; +import 'package:monarch/quick_actions.dart'; +import 'package:monarch/transcations_recent.dart'; //import 'package:monarch/static.dart'; class FinTrackHomePage extends StatefulWidget { @@ -20,15 +21,9 @@ class FinTrackHomePage extends StatefulWidget { class _FinTrackHomePageState extends State with TickerProviderStateMixin { // Modern color palette - final Color backgroundColor = const Color(0xFFF8F9FA); // Light cream/white - final Color primaryColor = const Color(0xFF2D3436); // Deep charcoal - final Color accentColor = const Color(0xFF00B894); // Emerald green - final Color cardColor = const Color(0xFFFFFFFF); // Pure white - final Color textSecondary = const Color(0xFF636E72); // Muted gray - final Color surfaceColor = const Color(0xFFF1F2F6); // Light surface // List to hold recent transactions - List> recentTransactions = []; + late AnimationController _fadeController; late AnimationController _slideController; @@ -36,33 +31,14 @@ class _FinTrackHomePageState extends State late Animation _slideAnimation; // Sample data for dashboard - final double totalBalance = 5847.32; - final double monthlyIncome = 8500.00; - final double monthlyExpenses = 2652.68; - - - - Future fetchRecentTransactions() async { - final response = await http.get( - Uri.parse('http://192.168.1.9:3000/api/transactions/recent'), - ); - - if (response.statusCode == 200) { - final List data = jsonDecode(response.body)['data']; - - setState(() { - recentTransactions = List>.from(data); - }); - } else { - print('Failed to load recent transactions'); - } -} - @override void initState() { super.initState(); -fetchRecentTransactions(); + fetchRecentTransactions().then((transactions) { + // Do something with the transactions + }); + _fadeController = AnimationController( duration: const Duration(milliseconds: 1200), vsync: this, @@ -97,327 +73,6 @@ fetchRecentTransactions(); super.dispose(); } - Widget _buildBalanceCard() { - return Container( - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [accentColor, accentColor.withOpacity(0.8)], - ), - borderRadius: BorderRadius.circular(24), - boxShadow: [ - BoxShadow( - color: accentColor.withOpacity(0.3), - blurRadius: 20, - offset: const Offset(0, 8), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Total Balance', - style: GoogleFonts.inter( - color: Colors.white.withOpacity(0.9), - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - Icon( - Icons.visibility_outlined, - color: Colors.white.withOpacity(0.9), - size: 20, - ), - ], - ), - const SizedBox(height: 8), - Text( - '\$${totalBalance.toStringAsFixed(2)}', - style: GoogleFonts.inter( - color: Colors.white, - fontSize: 36, - fontWeight: FontWeight.w700, - letterSpacing: -1, - ), - ), - const SizedBox(height: 20), - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Income', - style: GoogleFonts.inter( - color: Colors.white.withOpacity(0.8), - fontSize: 14, - fontWeight: FontWeight.w400, - ), - ), - const SizedBox(height: 4), - Text( - '\$${monthlyIncome.toStringAsFixed(0)}', - style: GoogleFonts.inter( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - Container( - width: 1, - height: 40, - color: Colors.white.withOpacity(0.3), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Expenses', - style: GoogleFonts.inter( - color: Colors.white.withOpacity(0.8), - fontSize: 14, - fontWeight: FontWeight.w400, - ), - ), - const SizedBox(height: 4), - Text( - '\$${monthlyExpenses.toStringAsFixed(0)}', - style: GoogleFonts.inter( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildQuickActions() { - return Row( - children: [ - Expanded( - child: GestureDetector( - onTap: () { - HapticFeedback.heavyImpact(); - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => const AddExpenseScreen(), - ), - ); - }, - child: Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: cardColor, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: primaryColor.withOpacity(0.08), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: accentColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Icon(Icons.add, color: accentColor, size: 24), - ), - const SizedBox(height: 12), - Text( - 'Add Expense', - style: GoogleFonts.inter( - color: primaryColor, - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ), - const SizedBox(width: 16), - Expanded( - child: GestureDetector( - onTap: () { - HapticFeedback.lightImpact(); - // Navigate to Statistics - }, - child: Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: cardColor, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: primaryColor.withOpacity(0.08), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: Colors.blue.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - Icons.bar_chart, - color: Colors.blue, - size: 24, - ), - ), - const SizedBox(height: 12), - Text( - 'Statistics', - style: GoogleFonts.inter( - color: primaryColor, - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ), - ], - ); - } - -Widget _buildRecentTransactions() { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: cardColor, - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: primaryColor.withOpacity(0.08), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Recent Transactions', - style: GoogleFonts.inter( - color: primaryColor, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - Text( - 'View All', - style: GoogleFonts.inter( - color: accentColor, - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - const SizedBox(height: 16), - ...recentTransactions.map( - (transaction) => Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: accentColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Icon( - Icons.shopping_bag, // You can customize based on category - color: accentColor, - size: 20, - ), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - transaction['description'] ?? '', - style: GoogleFonts.inter( - color: primaryColor, - fontSize: 15, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 2), - Text( - '${transaction['category']} • ${DateTime.parse(transaction['date']).toLocal().toString().split(' ')[0]}', - style: GoogleFonts.inter( - color: textSecondary, - fontSize: 13, - fontWeight: FontWeight.w400, - ), - ), - ], - ), - ), - Text( - '₹${transaction['amount'].toStringAsFixed(2)}', - style: GoogleFonts.inter( - color: transaction['amount'] >= 0 ? accentColor : Colors.red, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ], - ), - ); -} - - - int _selectedIndex = 0; @override @@ -465,24 +120,17 @@ Widget _buildRecentTransactions() { ), ], ), - - const SizedBox(height: 32), - - // Balance Card - _buildBalanceCard(), - + const SizedBox(height: 16), + const BalanceCardPage(), + const SizedBox(height: 24), + QuickActionsPage(), + const SizedBox(height: 24), + RecentTransactionsWidget( + recentTransactions: fetchRecentTransactions(), + ), const SizedBox(height: 24), - // Quick Actions - _buildQuickActions(), - const SizedBox(height: 32), - - // Recent Transactions - _buildRecentTransactions(), - - - const SizedBox(height: 20), ], ), ), diff --git a/Frontend/monarch/lib/main.dart b/Frontend/monarch/lib/main.dart index 001d8fa..6ba8b67 100644 --- a/Frontend/monarch/lib/main.dart +++ b/Frontend/monarch/lib/main.dart @@ -4,10 +4,10 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; -import 'package:monarch/budget.dart'; +import 'package:monarch/update_budget.dart'; import 'package:monarch/homepage.dart'; //import 'package:monarch/homepage.dart'; -import 'package:monarch/static.dart'; +import 'package:monarch/statistics.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); // This fixes the issue diff --git a/Frontend/monarch/lib/navbar.dart b/Frontend/monarch/lib/navbar.dart index ccca636..c16489f 100644 --- a/Frontend/monarch/lib/navbar.dart +++ b/Frontend/monarch/lib/navbar.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:monarch/add.dart'; import 'package:monarch/homepage.dart'; -import 'package:monarch/static.dart'; +import 'package:monarch/statistics.dart'; class CustomNavBar extends StatelessWidget { final int currentIndex; @@ -146,4 +146,4 @@ class NavItem { required this.index, required this.page, }); -} \ No newline at end of file +} diff --git a/Frontend/monarch/lib/quick_actions.dart b/Frontend/monarch/lib/quick_actions.dart new file mode 100644 index 0000000..b070ad6 --- /dev/null +++ b/Frontend/monarch/lib/quick_actions.dart @@ -0,0 +1,117 @@ +// ignore_for_file: deprecated_member_use + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:monarch/add.dart'; +import 'package:monarch/colors.dart'; + +class QuickActionsPage extends StatelessWidget { + const QuickActionsPage({super.key}); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: GestureDetector( + onTap: () { + HapticFeedback.heavyImpact(); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => const AddExpenseScreen(), + ), + ); + }, + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: cardColor, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: primaryColor.withOpacity(0.08), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: accentColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Icon(Icons.add, color: accentColor, size: 24), + ), + const SizedBox(height: 12), + Text( + 'Add Expense', + style: GoogleFonts.inter( + color: primaryColor, + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(width: 16), + Expanded( + child: GestureDetector( + onTap: () { + HapticFeedback.lightImpact(); + // Navigate to Statistics + }, + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: cardColor, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: primaryColor.withOpacity(0.08), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: Colors.blue.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: const Icon( + Icons.bar_chart, + color: Colors.blue, + size: 24, + ), + ), + const SizedBox(height: 12), + Text( + 'Statistics', + style: GoogleFonts.inter( + color: primaryColor, + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ), + ], + ); + } +} diff --git a/Frontend/monarch/lib/static.dart b/Frontend/monarch/lib/statistics.dart similarity index 99% rename from Frontend/monarch/lib/static.dart rename to Frontend/monarch/lib/statistics.dart index 22ce78e..72322dc 100644 --- a/Frontend/monarch/lib/static.dart +++ b/Frontend/monarch/lib/statistics.dart @@ -7,7 +7,7 @@ import 'package:fl_chart/fl_chart.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:monarch/add.dart'; -import 'package:monarch/budget.dart'; +import 'package:monarch/update_budget.dart'; import 'package:monarch/budget_manager.dart'; import 'package:monarch/homepage.dart'; import 'package:monarch/navbar.dart'; @@ -203,7 +203,7 @@ class StatisticsState extends State with TickerProviderStateMixin { onSelected: (String value) async { final updatedBudget = await Navigator.push( context, - MaterialPageRoute(builder: (context) => const BudgetScreen()), + MaterialPageRoute(builder: (context) => const UpdateBudget()), ); if (updatedBudget != null) { setState(() => budget = updatedBudget); diff --git a/Frontend/monarch/lib/transcations_recent.dart b/Frontend/monarch/lib/transcations_recent.dart new file mode 100644 index 0000000..33ac49d --- /dev/null +++ b/Frontend/monarch/lib/transcations_recent.dart @@ -0,0 +1,126 @@ +// ignore_for_file: deprecated_member_use + +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:monarch/colors.dart'; + +class RecentTransactionsWidget extends StatelessWidget { + final Future>> recentTransactions; + + const RecentTransactionsWidget({super.key, required this.recentTransactions}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: cardColor, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: primaryColor.withOpacity(0.08), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Recent Transactions', + style: GoogleFonts.inter( + color: primaryColor, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + Text( + 'View All', + style: GoogleFonts.inter( + color: accentColor, + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + const SizedBox(height: 16), + FutureBuilder>>( + future: recentTransactions, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + return const Text('No recent transactions.'); + } else { + return Column( + children: snapshot.data!.map( + (transaction) => Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Row( + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: accentColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Icon( + Icons.shopping_bag, // You can customize based on category + color: accentColor, + size: 20, + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + transaction['description'] ?? '', + style: GoogleFonts.inter( + color: primaryColor, + fontSize: 15, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 2), + Text( + '${transaction['category']} • ${DateTime.parse(transaction['date']).toLocal().toString().split(' ')[0]}', + style: GoogleFonts.inter( + color: textSecondary, + fontSize: 13, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + Text( + '₹${transaction['amount'].toStringAsFixed(2)}', + style: GoogleFonts.inter( + color: transaction['amount'] >= 0 ? accentColor : Colors.red, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ).toList(), + ); + } + }, + ), + ], + ), + ); + } +} diff --git a/Frontend/monarch/lib/budget.dart b/Frontend/monarch/lib/update_budget.dart similarity index 95% rename from Frontend/monarch/lib/budget.dart rename to Frontend/monarch/lib/update_budget.dart index 6689071..d9a161d 100644 --- a/Frontend/monarch/lib/budget.dart +++ b/Frontend/monarch/lib/update_budget.dart @@ -3,28 +3,22 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:monarch/static.dart'; +import 'package:monarch/colors.dart'; +import 'package:monarch/statistics.dart'; -class BudgetScreen extends StatefulWidget { - const BudgetScreen({super.key}); +class UpdateBudget extends StatefulWidget { + const UpdateBudget({super.key}); @override - State createState() => _BudgetScreenState(); + State createState() => _UpdateBudgetState(); } -class _BudgetScreenState extends State +class _UpdateBudgetState extends State with TickerProviderStateMixin { // Constants and Controllers static const _animationDuration = Duration(milliseconds: 600); static const _fadeDuration = Duration(milliseconds: 800); - // Color Scheme - final Color backgroundColor = const Color(0xFFF8F9FA); - final Color primaryColor = const Color(0xFF2D3436); - final Color accentColor = const Color(0xFF00B894); - final Color cardColor = const Color(0xFFFFFFFF); - final Color textSecondary = const Color(0xFF636E72); - final Color surfaceColor = const Color(0xFFF1F2F6); // Controllers and Focus Nodes final TextEditingController amountController = TextEditingController();