diff --git a/Backend/index.js b/Backend/index.js index b170d96..67b767d 100644 --- a/Backend/index.js +++ b/Backend/index.js @@ -212,13 +212,18 @@ app.get('/api/transactions/recent', async (req, res) => { //VOICE app.post('/api/transactions/voice', async (req, res) => { try { - const { voiceInput } = req.body; + const { voiceInput, userId } = req.body; // ✅ take userId from body if (!voiceInput) { return res.status(400).json({ error: 'No voice input provided' }); } + if (!userId) { + return res.status(400).json({ error: 'Missing userId' }); // ✅ enforce userId like others + } + // Step 1: Use regex to extract amount const amountMatch = voiceInput.match(/(?:\₹|\$)?(\d+(?:\.\d{1,2})?)/); const amount = amountMatch ? parseFloat(amountMatch[1]) : null; + // Step 2: Extract description (rough logic: remove common verbs + amount) const cleaned = voiceInput .toLowerCase() @@ -226,19 +231,24 @@ app.post('/api/transactions/voice', async (req, res) => { .replace(/₹?\d+/, '') .trim(); const description = cleaned || 'misc'; - // Step 3: Predict category using your Flask API + + // Step 3: Predict category using Flask API const predictRes = await axios.post('http://192.168.1.9:5000/api/predict', { description, }); const category = predictRes.data?.category || 'Other'; + // Step 4: Save to DB const newTransaction = new Transaction({ + userId, // ✅ store userId description, amount, category, source: 'voice' }); + await newTransaction.save(); + res.status(200).json({ message: '✅ Voice transaction saved', data: newTransaction, diff --git a/Frontend/lib/login.dart b/Frontend/lib/login.dart index 09f22a1..c5ac37d 100644 --- a/Frontend/lib/login.dart +++ b/Frontend/lib/login.dart @@ -115,7 +115,7 @@ import 'package:flutter/material.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:http/http.dart' as http; -import 'package:monarch/emai_screen.dart'; +import 'package:monarch/main_pages/HomePage/Components/Voice/voice_dialog.dart'; //import 'package:monarch/email.dart'; import 'package:monarch/other_pages/enviroment.dart'; import 'dart:convert'; @@ -181,12 +181,13 @@ class _LoginScreenState extends State { Navigator.pushReplacement( context, MaterialPageRoute( + builder: (_) => VoiceTransactionDialog(), // builder: // (_) => EmailsScreen( // accessToken: accessToken, // userId: data['user']['_id'], // ), - builder: (_) => AutoSyncEmailsScreen(accessToken: accessToken,userId: data['user']['_id'],), + //builder: (_) => AutoSyncEmailsScreen(accessToken: accessToken,userId: data['user']['_id'],), ), ); } else { diff --git a/Frontend/lib/main.dart b/Frontend/lib/main.dart index d1142c4..958f312 100644 --- a/Frontend/lib/main.dart +++ b/Frontend/lib/main.dart @@ -25,7 +25,7 @@ class MyApp extends StatelessWidget { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(primarySwatch: Colors.blue), - home: const FinTrackHomePage(), + home: const LoginScreen(), // home: const SpeechInputPage(), ); diff --git a/Frontend/lib/main_pages/HomePage/e_dialog.dart b/Frontend/lib/main_pages/HomePage/Components/Email/e_dialog.dart similarity index 100% rename from Frontend/lib/main_pages/HomePage/e_dialog.dart rename to Frontend/lib/main_pages/HomePage/Components/Email/e_dialog.dart diff --git a/Frontend/lib/main_pages/HomePage/Components/Voice/t_dialog.dart b/Frontend/lib/main_pages/HomePage/Components/Email/t_dialog.dart similarity index 100% rename from Frontend/lib/main_pages/HomePage/Components/Voice/t_dialog.dart rename to Frontend/lib/main_pages/HomePage/Components/Email/t_dialog.dart diff --git a/Frontend/lib/main_pages/HomePage/greeting.dart b/Frontend/lib/main_pages/HomePage/Components/Home/greeting.dart similarity index 97% rename from Frontend/lib/main_pages/HomePage/greeting.dart rename to Frontend/lib/main_pages/HomePage/Components/Home/greeting.dart index b8712d2..8b73d40 100644 --- a/Frontend/lib/main_pages/HomePage/greeting.dart +++ b/Frontend/lib/main_pages/HomePage/Components/Home/greeting.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:monarch/main_pages/HomePage/transaction_button.dart'; +import 'package:monarch/main_pages/HomePage/Components/Home/transaction_button.dart'; import 'package:monarch/other_pages/colors.dart'; class GreetingHeader extends StatelessWidget { diff --git a/Frontend/lib/main_pages/HomePage/hero_card.dart b/Frontend/lib/main_pages/HomePage/Components/Home/hero_card.dart similarity index 100% rename from Frontend/lib/main_pages/HomePage/hero_card.dart rename to Frontend/lib/main_pages/HomePage/Components/Home/hero_card.dart diff --git a/Frontend/lib/main_pages/HomePage/navbar.dart b/Frontend/lib/main_pages/HomePage/Components/Home/navbar.dart similarity index 100% rename from Frontend/lib/main_pages/HomePage/navbar.dart rename to Frontend/lib/main_pages/HomePage/Components/Home/navbar.dart diff --git a/Frontend/lib/main_pages/HomePage/quick_actions.dart b/Frontend/lib/main_pages/HomePage/Components/Home/quick_actions.dart similarity index 100% rename from Frontend/lib/main_pages/HomePage/quick_actions.dart rename to Frontend/lib/main_pages/HomePage/Components/Home/quick_actions.dart diff --git a/Frontend/lib/main_pages/HomePage/transaction_button.dart b/Frontend/lib/main_pages/HomePage/Components/Home/transaction_button.dart similarity index 100% rename from Frontend/lib/main_pages/HomePage/transaction_button.dart rename to Frontend/lib/main_pages/HomePage/Components/Home/transaction_button.dart diff --git a/Frontend/lib/main_pages/HomePage/Components/Voice/confirm.dart b/Frontend/lib/main_pages/HomePage/Components/Voice/confirm.dart index 34f9c83..7ef322d 100644 --- a/Frontend/lib/main_pages/HomePage/Components/Voice/confirm.dart +++ b/Frontend/lib/main_pages/HomePage/Components/Voice/confirm.dart @@ -4,8 +4,10 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; +import 'package:monarch/other_pages/reponsive.dart'; import 'package:monarch/other_pages/colors.dart'; import 'package:monarch/other_pages/enviroment.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class ConfirmTransactionPage extends StatelessWidget { final Map data; @@ -13,16 +15,27 @@ class ConfirmTransactionPage extends StatelessWidget { const ConfirmTransactionPage({super.key, required this.data}); Future _saveTransaction(BuildContext context) async { - const String saveUrl = '${Environment.baseUrl}/api/transaction/add'; + const String saveUrl = + '${Environment.baseUrl}/api/transaction/add'; // ✅ make sure this matches backend try { + final prefs = await SharedPreferences.getInstance(); + final userId = prefs.getString('userId'); + + if (userId == null) { + throw Exception('User ID not found. Please log in again.'); + } + final response = await http.post( Uri.parse(saveUrl), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ - 'description': data['description'], - 'amount': data['amount'], - 'category': data['category'], + 'userId': userId, + 'description': data['description'] ?? '', + 'amount': + double.tryParse(data['amount'].toString()) ?? + 0.0, // ✅ force number + 'category': data['category'] ?? 'Uncategorized', 'date': data['date'] ?? DateTime.now().toIso8601String(), }), ); @@ -38,7 +51,8 @@ class ConfirmTransactionPage extends StatelessWidget { ); Navigator.popUntil(context, (route) => route.isFirst); } else { - throw Exception('Save failed with status: ${response.statusCode}'); + // 👇 Log backend response + throw Exception('Save failed: ${response.statusCode} ${response.body}'); } } catch (e) { _showCustomSnackBar( @@ -53,35 +67,56 @@ class ConfirmTransactionPage extends StatelessWidget { } void _showCustomSnackBar({ - required BuildContext context, required String message, required IconData icon, required Color backgroundColor, required Color iconColor, - required Duration duration, + Duration duration = const Duration(seconds: 3), + required BuildContext context, }) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Row( - children: [ - Icon(icon, color: iconColor), - const SizedBox(width: 12), - Expanded( - child: Text( - message, - style: GoogleFonts.inter( - color: Colors.white, - fontWeight: FontWeight.w500, + content: Container( + padding: EdgeInsets.symmetric(vertical: context.responsiveHeight(4)), + child: Row( + children: [ + Container( + padding: EdgeInsets.all(context.responsiveWidth(8)), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.2), + borderRadius: BorderRadius.circular( + context.responsiveWidth(8), + ), + ), + child: Icon( + icon, + color: iconColor, + size: context.responsiveText(20), ), ), - ), - ], + SizedBox(width: context.responsiveWidth(12)), + Expanded( + child: Text( + message, + style: GoogleFonts.inter( + fontWeight: FontWeight.w500, + color: Colors.white, + fontSize: context.responsiveText(14), + height: 1.4, + ), + ), + ), + ], + ), ), backgroundColor: backgroundColor, - duration: duration, behavior: SnackBarBehavior.floating, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - margin: const EdgeInsets.all(16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(context.responsiveWidth(12)), + ), + margin: EdgeInsets.all(context.responsiveWidth(16)), + duration: duration, + elevation: 8, ), ); } diff --git a/Frontend/lib/main_pages/HomePage/Components/Voice/voice_dialog.dart b/Frontend/lib/main_pages/HomePage/Components/Voice/voice_dialog.dart index ceaa975..e1a6bd4 100644 --- a/Frontend/lib/main_pages/HomePage/Components/Voice/voice_dialog.dart +++ b/Frontend/lib/main_pages/HomePage/Components/Voice/voice_dialog.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:monarch/speech.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:speech_to_text/speech_to_text.dart' as stt; import 'package:monarch/other_pages/colors.dart'; import 'package:monarch/other_pages/enviroment.dart'; @@ -103,10 +104,17 @@ class _VoiceTransactionDialogState extends State Future _sendToBackend() async { try { + final prefs = await SharedPreferences.getInstance(); + final userId = prefs.getString('userId'); + + if (userId == null) { + throw Exception('User ID not found. Please log in again.'); + } + final response = await http.post( Uri.parse('${Environment.baseUrl}/api/transactions/voice'), headers: {'Content-Type': 'application/json'}, - body: jsonEncode({'voiceInput': _spokenText}), + body: jsonEncode({'userId': userId, 'voiceInput': _spokenText}), ); if (response.statusCode == 200) { @@ -120,28 +128,13 @@ class _VoiceTransactionDialogState extends State builder: (context) => ConfirmTransactionPage(data: transactionData), ), ); - - _showCustomSnackBar( - message: 'Transaction processed successfully!', - icon: Icons.check_circle, - backgroundColor: const Color(0xFF4CAF50), - iconColor: Colors.white, - duration: const Duration(seconds: 2), - ); } else { - throw Exception('Failed to process transaction'); + throw Exception('Save failed with status: ${response.statusCode}'); } } catch (e) { - _showCustomSnackBar( - message: 'Error processing transaction: ${e.toString()}', - icon: Icons.error_outline, - backgroundColor: const Color(0xFFFF6B6B), - iconColor: Colors.white, - duration: const Duration(seconds: 4), - ); - setState(() { - _processing = false; - }); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Error: ${e.toString()}'))); } } diff --git a/Frontend/lib/main_pages/HomePage/homepage.dart b/Frontend/lib/main_pages/HomePage/homepage.dart index 4e92eb6..6d116f7 100644 --- a/Frontend/lib/main_pages/HomePage/homepage.dart +++ b/Frontend/lib/main_pages/HomePage/homepage.dart @@ -1,15 +1,15 @@ // ignore_for_file: deprecated_member_use import 'package:flutter/material.dart'; +import 'package:monarch/main_pages/HomePage/Components/Home/hero_card.dart'; import 'package:monarch/main_pages/HomePage/animated.dart'; -import 'package:monarch/main_pages/HomePage/greeting.dart'; -import 'package:monarch/main_pages/HomePage/navbar.dart'; -import 'package:monarch/main_pages/HomePage/Components/Voice/t_dialog.dart'; +import 'package:monarch/main_pages/HomePage/Components/Home/greeting.dart'; +import 'package:monarch/main_pages/HomePage/Components/Home/navbar.dart'; +import 'package:monarch/main_pages/HomePage/Components/Email/t_dialog.dart'; import 'package:monarch/main_pages/HomePage/Components/Voice/voice_dialog.dart'; import 'package:monarch/other_pages/colors.dart'; import 'package:monarch/support/fetch_service.dart'; -import 'package:monarch/main_pages/HomePage/hero_card.dart'; -import 'package:monarch/main_pages/HomePage/quick_actions.dart'; +import 'package:monarch/main_pages/HomePage/Components/Home/quick_actions.dart'; import 'package:monarch/support/transcations_recent.dart'; class FinTrackHomePage extends StatefulWidget { diff --git a/Frontend/lib/main_pages/Statistics/statistics.dart b/Frontend/lib/main_pages/Statistics/statistics.dart index fe47327..ff8ab21 100644 --- a/Frontend/lib/main_pages/Statistics/statistics.dart +++ b/Frontend/lib/main_pages/Statistics/statistics.dart @@ -7,12 +7,13 @@ import 'package:fl_chart/fl_chart.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; +import 'package:monarch/other_pages/colors.dart'; import 'package:monarch/support/add.dart'; import 'package:monarch/other_pages/enviroment.dart'; import 'package:monarch/main_pages/Statistics/Budget/update_budget.dart'; import 'package:monarch/main_pages/Statistics/Budget/budget_manager.dart'; import 'package:monarch/main_pages/HomePage/homepage.dart'; -import 'package:monarch/main_pages/HomePage/navbar.dart'; +import 'package:monarch/main_pages/HomePage/Components/Home/navbar.dart'; import 'package:shared_preferences/shared_preferences.dart'; class Transaction { @@ -62,12 +63,6 @@ class StatisticsState extends State with TickerProviderStateMixin { String selectedCategory = 'All'; Map totalAmountPerCategory = {}; // 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); // Responsive methods double responsiveWidth(double size) => diff --git a/Frontend/lib/other_pages/enviroment.dart b/Frontend/lib/other_pages/enviroment.dart index 9d0169f..b95f386 100644 --- a/Frontend/lib/other_pages/enviroment.dart +++ b/Frontend/lib/other_pages/enviroment.dart @@ -1,5 +1,5 @@ class Environment { - static const String baseUrl = 'http://192.168.1.9:3000'; + static const String baseUrl = 'http://10.231.7.150:3000'; static const String serverClientId = "278433619849-cg6f7gk5cc45rgu1ojrlkf794lm4udgn.apps.googleusercontent.com"; } diff --git a/Frontend/lib/other_pages/reponsive.dart b/Frontend/lib/other_pages/reponsive.dart new file mode 100644 index 0000000..a52a805 --- /dev/null +++ b/Frontend/lib/other_pages/reponsive.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; + +extension ResponsiveExtension on BuildContext { + double responsiveWidth(double size) { + return size * (MediaQuery.of(this).size.width / 375); + } + + double responsiveHeight(double size) { + return size * (MediaQuery.of(this).size.height / 812); + } + + double responsiveText(double size) { + final width = MediaQuery.of(this).size.width; + if (width < 350) return size * 0.9; + if (width > 600) return size * 1.2; + return size; + } +}