Skip to content

FIntech #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions Analitics.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//Main page for the analytics section

import React, { useState, useEffect } from "react";
import { BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from "recharts";
import { fetchGooglePayTransactions } from "./transaction"; // Adjust the import path as necessary
import './styles/analytics.css'; // Add this import

const AnalyticsChart = ({ userAccount }) => {
const [transactionData, setTransactionData] = useState([]);
const [year, setYear] = useState("2025");

useEffect(() => {
const loadTransactions = async () => {
const transactions = await fetchGooglePayTransactions(userAccount);
setTransactionData(transactions);
};
loadTransactions();
}, [userAccount]);

// Function to process transactions and get income & outcome per month
const getMonthlyData = () => {
const monthlyData = Array.from({ length: 12 }, (_, index) => ({
month: new Date(2025, index, 1).toLocaleString("en-US", { month: "short" }),
income: 0,
outcome: 0,
}));

transactionData.transactions?.forEach((txn) => {
const txnDate = new Date(txn.date);
if (txnDate.getFullYear().toString() === year) {
const monthIndex = txnDate.getMonth();
if (txn.receiver_account === userAccount) {
monthlyData[monthIndex].income += txn.amount_transferred; // Money received
}
if (txn.sender_account === userAccount) {
monthlyData[monthIndex].outcome += txn.amount_transferred; // Money spent
}
}
});

return monthlyData;
};

const monthlyData = getMonthlyData();

return (
<div className="chart-container">
<h3>Income vs Outcome</h3>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={monthlyData} margin={{ top: 20, right: 10, left: 20, bottom: 5 }}>
<XAxis dataKey="month" stroke="#fff" />
<YAxis stroke="#fff" />
<Tooltip
contentStyle={{
background: 'rgba(18, 18, 18, 0.95)',
border: '1px solid rgba(255, 255, 255, 0.1)',
borderRadius: '4px'
}}
/>
<Legend />
<Bar
dataKey="income"
fill="#774EBD"
name="Income"
barSize={15} // Make bars thinner
/>
<Bar
dataKey="outcome"
fill="#372457"
name="Outcome"
barSize={15} // Make bars thinner
/>
</BarChart>
</ResponsiveContainer>
</div>
);
};
export default AnalyticsChart;
74 changes: 74 additions & 0 deletions Analytics.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useState, useEffect } from "react";
import { BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from "recharts";
import { fetchGooglePayTransactions } from "../utils/product_trancation.jsx"; // Add .jsx extension

const AnalyticsChart = () => {
const [transactionData, setTransactionData] = useState([]);
const [year, setYear] = useState("2024");

useEffect(() => {
// Fetch transactions (Replace with real API call)
const loadTransactions = async () => {
const transactions = await fetchGooglePayTransactions();
setTransactionData(transactions);
};
loadTransactions();
}, []);

// Function to process transactions and get income & outcome per month
const getMonthlyData = () => {
const monthlyData = Array.from({ length: 12 }, (_, index) => ({
month: new Date(2024, index, 1).toLocaleString("en-US", { month: "short" }),
income: 0,
outcome: 0,
}));

transactionData.forEach((txn) => {
const txnDate = new Date(txn.date);
const txnYear = txnDate.getFullYear().toString();
if (txnYear === year) {
const monthIndex = txnDate.getMonth();
if (txn.type === "income") {
monthlyData[monthIndex].income += txn.amount;
} else if (txn.type === "outcome") {
monthlyData[monthIndex].outcome += txn.amount;
}
}
});

return monthlyData;
};

return (
<div className="analytics-container">
<h2>Analytics</h2>
<select
value={year}
onChange={(e) => setYear(e.target.value)}
className="year-select"
>
<option value="2024">2024</option>
<option value="2023">2023</option>
</select>

<ResponsiveContainer width="100%" height={300}>
<BarChart data={getMonthlyData()}>
<XAxis dataKey="month" stroke="rgba(255,255,255,0.7)" />
<YAxis stroke="rgba(255,255,255,0.7)" />
<Tooltip
contentStyle={{
background: '#1A1A1A',
border: '1px solid rgba(255,255,255,0.1)',
color: '#fff'
}}
/>
<Legend />
<Bar dataKey="income" fill="#774EBD" name="Income" />
<Bar dataKey="outcome" fill="#372457" name="Outcome" />
</BarChart>
</ResponsiveContainer>
</div>
);
};

export default AnalyticsChart;
49 changes: 49 additions & 0 deletions App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}

.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}

@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}

.card {
padding: 2em;
}

.read-the-docs {
color: #888;
}

@media screen and (max-width: 768px) {
#root {
max-width: 100%;
padding: 1rem;
}
}
175 changes: 175 additions & 0 deletions Dashboard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import React, { useState, useEffect, useRef } from 'react';
import { useNavigate, Route, Routes, Link } from 'react-router-dom';
import '../styles/dashboard.css';
import AnalyticsChart from './Analytics';
import TransactionHistory from './TransactionHistory';
import StockTrends from './StockTrends';
import SplitPayApp from './SplitPayApp'; // Import the SplitPayApp component

function Dashboard() {
const navigate = useNavigate();
const [showLogoutConfirm, setShowLogoutConfirm] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [chatMessages, setChatMessages] = useState([]);
const [inputMessage, setInputMessage] = useState('');
const messagesEndRef = useRef(null);

const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};

useEffect(() => {
scrollToBottom();
}, [chatMessages]);

useEffect(() => {
// Check authentication and set up dashboard
const isAuth = localStorage.getItem('isAuthenticated');
if (!isAuth) {
navigate('/');
return;
}
setIsLoading(false);
}, [navigate]);

const handleLogoutClick = () => {
setShowLogoutConfirm(true);
};

const handleLogoutConfirm = () => {
localStorage.removeItem('isAuthenticated');
localStorage.removeItem('currentUser');
navigate('/');
};

if (isLoading) {
return (
<div className="dashboard-container loading">
<div className="loading-spinner">Loading...</div>
</div>
);
}

async function handleSendMessage(e) {
e.preventDefault();
if (!inputMessage.trim()) return;

const message = inputMessage.trim();
setChatMessages(prev => [...prev, { type: 'user', content: message }]);
setInputMessage('');

try {
const response = await fetch('http://localhost:5174/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message })
});

if (!response.ok) {
const errorText = await response.text();
console.error('API Error Response:', errorText);
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();
console.log('Response data:', data); // Debug logging

if (data && data.response) {
setChatMessages(prev => [...prev, {
type: 'bot',
content: data.response
}]);
} else {
throw new Error('Invalid response format');
}
} catch (error) {
console.error('Chat Error:', error);
setChatMessages(prev => [...prev, {
type: 'bot',
content: 'FinBot: I apologize, but I am temporarily unable to process requests. Please try again shortly.'
}]);
}
}

return (
<div className="dashboard-container">
<header className="dashboard-header">
<div className="logo">Finura</div>
<nav className="dashboard-nav">
<Link to="/" className="active">Overview</Link>
<Link to="/transactions">Transactions</Link>
<Link to="/analytics">Analytics</Link>
<Link to="/settings">Settings</Link>
<Link to="/split-pay">Split Pay</Link> {/* Add Split Pay link */}
</nav>
<div className="logout-container">
<button className="logout-btn" onClick={handleLogoutClick} style={{ width: '30px', height: '15px' }}>Logout</button>
</div>
</header>
<div className="dashboard-main">
<Routes>
<Route path="/" element={
<div className="dashboard-content">
<div className="dashboard-left">
<div className="dashboard-card">
<h2>Financial Overview</h2>
<AnalyticsChart />
</div>
<div className="bottom-row">
<div className="bottom-row-item">
<TransactionHistory />
</div>
<div className="bottom-row-item">
<StockTrends />
</div>
</div>
</div>
</div>
} />
<Route path="/split-pay" element={<SplitPayApp />} /> {/* Add route for Split Pay */}
</Routes>
<div className="dashboard-right">
<div className="chatbot-container">
<div className="chatbot-header">
<h3>AI Financial Assistant</h3>
</div>
<div className="chatbot-messages">
{chatMessages.map((msg, index) => (
<div key={index} className={`message ${msg.type}`}>
{msg.type === 'user' ? `You: ${msg.content}` : msg.content}
</div>
))}
<div ref={messagesEndRef} />
</div>
<form className="chatbot-input" onSubmit={handleSendMessage}>
<input
type="text"
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
placeholder="Ask about your finances..."
/>
<button type="submit">Send</button>
</form>
</div>
</div>
</div>

{showLogoutConfirm && (
<div className="logout-confirm-overlay">
<div className="logout-confirm-modal">
<h3>Confirm Logout</h3>
<p>Are you sure you want to logout?</p>
<div className="logout-confirm-buttons">
<button onClick={handleLogoutConfirm}>Yes, Logout</button>
<button onClick={() => setShowLogoutConfirm(false)}>Cancel</button>
</div>
</div>
</div>
)}
</div>
);
}

export default Dashboard;
Loading