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
266 lines
9.5 KiB
HTML
266 lines
9.5 KiB
HTML
<!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> |