Files
rabby/ui/app.js
T
2026-07-08 23:41:07 -05:00

130 lines
5.1 KiB
JavaScript

const fallbackDashboard = {
active_account: {
name: 'Main Wallet',
address: '0x1111111111111111111111111111111111111111',
source: 'SeedPhrase'
},
chains: [
{ id: 1, name: 'Ethereum' },
{ id: 8453, name: 'Base' }
],
balances: [
{ chain_id: 1, symbol: 'ETH', amount: 1.24, usd_value: 4200 },
{ chain_id: 8453, symbol: 'USDC', amount: 1280, usd_value: 1280 }
],
approvals: [
{ chain_id: 1, asset_symbol: 'USDC', spender: '0x2222222222222222222222222222222222222222', allowance: 'unlimited', risk: 'High' }
],
activities: [
{ label: 'Swap ETH → USDC', status: 'Confirmed', chain_id: 1 }
],
settings: {
theme: 'System',
language: 'en',
currency: 'USD',
auto_lock_minutes: 15,
prefer_rabby_over_metamask: true
}
};
const fallbackFeatures = [
['Create/unlock wallet', 'Password, lock/unlock, encrypted local state', 'Modeled'],
['Import/create accounts', 'Seed phrase, private key, JSON, watch-only', 'Modeled'],
['Multi-chain networks', 'Built-in, custom RPC, testnet, offline chain flags', 'Modeled'],
['Portfolio dashboard', 'Balances, NFTs, DeFi positions, activity', 'UiPrototype'],
['Dapp provider and permissions', 'Origin/account/chain permissions', 'Modeled'],
['Signing and security previews', 'Typed data/message/transaction previews and risk', 'Modeled'],
['Settings and customization', 'Theme, language, currency, auto-lock, default wallet mode', 'UiPrototype']
];
function money(value) {
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value || 0);
}
function shortAddress(address) {
if (!address || address.length < 12) return address || '';
return `${address.slice(0, 6)}${address.slice(-4)}`;
}
function statusLabel(value) {
if (typeof value === 'string') return value;
if (value && typeof value === 'object') return Object.keys(value)[0] || 'Modeled';
return 'Modeled';
}
async function invokeOrFallback(command, fallback) {
try {
const tauri = window.__TAURI__?.core;
if (!tauri) return fallback;
return await tauri.invoke(command);
} catch (_) {
return fallback;
}
}
function renderDashboard(dashboard) {
const total = dashboard.balances.reduce((sum, token) => sum + token.usd_value, 0);
const highRisk = dashboard.approvals.filter((approval) => ['High', 'Critical'].includes(statusLabel(approval.risk))).length;
document.getElementById('account-address').textContent = shortAddress(dashboard.active_account.address);
document.getElementById('portfolio-total').textContent = money(total);
document.getElementById('hero-total').textContent = money(total);
document.getElementById('chain-count').textContent = dashboard.chains.length;
document.getElementById('risk-count').textContent = highRisk;
document.getElementById('approval-risk').textContent = highRisk;
document.getElementById('token-list').innerHTML = dashboard.balances.map((token) => `
<div class="asset-row">
<div class="coin-mark">${token.symbol.slice(0, 1)}</div>
<div><strong>${token.symbol}</strong><span>Chain ${token.chain_id}</span></div>
<div class="asset-value"><strong>${money(token.usd_value)}</strong><span>${token.amount}</span></div>
</div>
`).join('');
document.getElementById('approval-list').innerHTML = dashboard.approvals.map((approval) => `
<div class="approval-row">
<div><strong>${approval.asset_symbol} allowance</strong><span>${shortAddress(approval.spender)}</span></div>
<span class="risk ${statusLabel(approval.risk).toLowerCase()}">${statusLabel(approval.risk)}</span>
</div>
`).join('');
document.getElementById('activity-list').innerHTML = dashboard.activities.map((activity) => `
<div class="activity-row"><span>↗</span><div><strong>${activity.label}</strong><small>${statusLabel(activity.status)} · Chain ${activity.chain_id}</small></div></div>
`).join('');
const settings = dashboard.settings;
document.getElementById('settings-summary').innerHTML = [
['Theme', statusLabel(settings.theme)],
['Language', settings.language],
['Currency', settings.currency],
['Auto-lock', `${settings.auto_lock_minutes} min`],
['Default wallet', settings.prefer_rabby_over_metamask ? 'Rabby' : 'Browser default']
].map(([label, value]) => `<div><span>${label}</span><strong>${value}</strong></div>`).join('');
}
function renderFeatures(features) {
document.getElementById('wallet-features').innerHTML = features.map((feature) => {
const title = Array.isArray(feature) ? feature[0] : feature.feature;
const acceptance = Array.isArray(feature) ? feature[1] : feature.acceptance;
const status = Array.isArray(feature) ? feature[2] : statusLabel(feature.status);
return `
<article class="feature-card">
<span class="feature-status">${status}</span>
<strong>${title}</strong>
<p>${acceptance}</p>
</article>
`;
}).join('');
}
async function boot() {
const [dashboard, features] = await Promise.all([
invokeOrFallback('wallet_dashboard', fallbackDashboard),
invokeOrFallback('wallet_mvp_summary', fallbackFeatures)
]);
renderDashboard(dashboard);
renderFeatures(features);
}
boot();