OHO-23(email testing)
This commit is contained in:
parent
50fc322bc7
commit
9c79d8a59d
16 changed files with 113 additions and 61 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<LoginScreen> {
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -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<String, dynamic> data;
|
||||
|
|
@ -13,16 +15,27 @@ class ConfirmTransactionPage extends StatelessWidget {
|
|||
const ConfirmTransactionPage({super.key, required this.data});
|
||||
|
||||
Future<void> _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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<VoiceTransactionDialog>
|
|||
|
||||
Future<void> _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<VoiceTransactionDialog>
|
|||
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()}')));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<Statistics> with TickerProviderStateMixin {
|
|||
String selectedCategory = 'All';
|
||||
Map<String, double> 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) =>
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
18
Frontend/lib/other_pages/reponsive.dart
Normal file
18
Frontend/lib/other_pages/reponsive.dart
Normal file
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue