version 1
the reminder not showing content on the card at dashboard view and the quizes are hardcoded must move to the db make api's for it
This commit is contained in:
266
backend/index.html
Normal file
266
backend/index.html
Normal file
@@ -0,0 +1,266 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Plaid Data Dashboard</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.panel {
|
||||
background: #f5f5f5;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.data-section {
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
}
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
.account-card {
|
||||
background: white;
|
||||
padding: 15px;
|
||||
margin: 10px 0;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.transaction-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.positive { color: green; }
|
||||
.negative { color: red; }
|
||||
#logs {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Plaid Data Dashboard</h1>
|
||||
|
||||
<div class="panel">
|
||||
<h3>Step 1: Link Bank Account</h3>
|
||||
<button id="newTokenButton">Get New Link Token</button>
|
||||
<button id="linkButton">Connect Bank Account</button>
|
||||
</div>
|
||||
|
||||
<div class="data-section">
|
||||
<h3>Accounts Overview</h3>
|
||||
<button onclick="fetchAccounts()">Refresh Accounts</button>
|
||||
<div id="accountsData"></div>
|
||||
</div>
|
||||
|
||||
<div class="data-section">
|
||||
<h3>Transactions</h3>
|
||||
<button onclick="fetchTransactions()">Load Transactions</button>
|
||||
<div id="transactionsData"></div>
|
||||
</div>
|
||||
|
||||
<div class="data-section">
|
||||
<h3>Income Information</h3>
|
||||
<button onclick="fetchIncome()">Load Income Data</button>
|
||||
<div id="incomeData"></div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h3>Debug Logs</h3>
|
||||
<div id="logs"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let linkToken = null;
|
||||
let accessToken = null;
|
||||
let linkHandler = null;
|
||||
|
||||
function addLog(message, data = null) {
|
||||
const logDiv = document.createElement('div');
|
||||
logDiv.innerHTML = `<strong>${new Date().toLocaleTimeString()}</strong>: ${message}`;
|
||||
if (data) {
|
||||
logDiv.innerHTML += `<pre>${JSON.stringify(data, null, 2)}</pre>`;
|
||||
}
|
||||
const logs = document.getElementById('logs');
|
||||
logs.insertBefore(logDiv, logs.firstChild);
|
||||
}
|
||||
|
||||
async function getNewLinkToken() {
|
||||
try {
|
||||
addLog('Getting new link token...');
|
||||
const response = await fetch('http://localhost:3000/api/create_link_token', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ userId: 'test-user-' + Date.now() })
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.link_token) {
|
||||
linkToken = data.link_token;
|
||||
addLog('Got new link token', { link_token: data.link_token });
|
||||
initializePlaidLink();
|
||||
}
|
||||
} catch (err) {
|
||||
addLog('Error getting link token', { error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchAccounts() {
|
||||
if (!accessToken) {
|
||||
addLog('No access token available. Please connect your bank first.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/accounts', {
|
||||
headers: { 'plaid-access-token': accessToken }
|
||||
});
|
||||
const data = await response.json();
|
||||
displayAccounts(data.accounts);
|
||||
} catch (err) {
|
||||
addLog('Error fetching accounts', { error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchTransactions() {
|
||||
if (!accessToken) {
|
||||
addLog('No access token available. Please connect your bank first.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/transactions', {
|
||||
headers: { 'plaid-access-token': accessToken }
|
||||
});
|
||||
const data = await response.json();
|
||||
displayTransactions(data.transactions);
|
||||
} catch (err) {
|
||||
addLog('Error fetching transactions', { error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchIncome() {
|
||||
if (!accessToken) {
|
||||
addLog('No access token available. Please connect your bank first.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/income', {
|
||||
headers: { 'plaid-access-token': accessToken }
|
||||
});
|
||||
const data = await response.json();
|
||||
displayIncome(data);
|
||||
} catch (err) {
|
||||
addLog('Error fetching income', { error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
function displayAccounts(accounts) {
|
||||
const container = document.getElementById('accountsData');
|
||||
container.innerHTML = accounts.map(account => `
|
||||
<div class="account-card">
|
||||
<h4>${account.name} (${account.subtype})</h4>
|
||||
<p>Balance: $${account.balances.current.toFixed(2)}</p>
|
||||
<p>Available: $${account.balances.available ? account.balances.available.toFixed(2) : 'N/A'}</p>
|
||||
<p>Type: ${account.type}</p>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function displayTransactions(transactions) {
|
||||
const container = document.getElementById('transactionsData');
|
||||
if (!transactions || transactions.length === 0) {
|
||||
container.innerHTML = '<p>No transactions found</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="transaction-header">
|
||||
<p>Found ${transactions.length} transactions</p>
|
||||
</div>
|
||||
${transactions.map(trans => `
|
||||
<div class="transaction-item">
|
||||
<div class="transaction-info">
|
||||
<strong>${trans.date}</strong>
|
||||
<span>${trans.merchant_name || trans.name}</span>
|
||||
</div>
|
||||
<span class="${trans.amount >= 0 ? 'negative' : 'positive'}">
|
||||
${trans.amount >= 0 ? '-' : '+'}${Math.abs(trans.amount).toFixed(2)}
|
||||
</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
`;
|
||||
}
|
||||
|
||||
function displayIncome(incomeData) {
|
||||
const container = document.getElementById('incomeData');
|
||||
container.innerHTML = `
|
||||
<div class="panel">
|
||||
<h4>Income Summary</h4>
|
||||
<p>Latest Monthly Income: ${incomeData.latest_monthly_income || 'N/A'}</p>
|
||||
<p>Projected Monthly Income: ${incomeData.projected_monthly_income || 'N/A'}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function initializePlaidLink() {
|
||||
linkHandler = Plaid.create({
|
||||
token: linkToken,
|
||||
onSuccess: async (public_token, metadata) => {
|
||||
addLog('Link Success - Got public token', { metadata });
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/exchange_public_token', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ public_token })
|
||||
});
|
||||
const data = await response.json();
|
||||
if (response.ok) {
|
||||
accessToken = data.access_token;
|
||||
addLog('Exchange successful');
|
||||
// Automatically fetch accounts after successful connection
|
||||
fetchAccounts();
|
||||
}
|
||||
} catch (err) {
|
||||
addLog('Exchange error', { error: err.message });
|
||||
}
|
||||
},
|
||||
onExit: (err, metadata) => {
|
||||
if (err != null) {
|
||||
addLog('Link error', { error: err, metadata });
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize event listeners
|
||||
document.getElementById('newTokenButton').onclick = getNewLinkToken;
|
||||
document.getElementById('linkButton').onclick = () => {
|
||||
if (linkHandler) {
|
||||
linkHandler.open();
|
||||
} else {
|
||||
addLog('Please get a new link token first');
|
||||
}
|
||||
};
|
||||
|
||||
// Initial setup
|
||||
getNewLinkToken();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user