From aaa3477d5ed9934f6346dee5638c774bbbac39b7 Mon Sep 17 00:00:00 2001 From: Dorian Date: Fri, 17 Jul 2026 03:07:30 +0100 Subject: [PATCH] feat(ui): Networking Profits becomes a dashboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dashboard tab (default): stat tiles per earning source, 7-day earnings LineChart (one line per source, daily buckets — earnings are sparse events so finer buckets would draw noise), active-session count and revenue-by-service bars from streaming.list-sessions. Configure tab keeps the old settings screen with the intro copy boxed in a card, plus a new TollGate WiFi entry (price per minute via openwrt.provision- tollgate, with a set-up-gateway hint when no router is paired). Demo mocks gain profit history entries and streaming sessions. Co-Authored-By: Claude Fable 5 --- neode-ui/mock-backend.js | 38 +- .../web5/Web5NetworkingProfitsSettings.vue | 484 +++++++++++++++--- 2 files changed, 455 insertions(+), 67 deletions(-) diff --git a/neode-ui/mock-backend.js b/neode-ui/mock-backend.js index 36b476c0..9cb03527 100755 --- a/neode-ui/mock-backend.js +++ b/neode-ui/mock-backend.js @@ -2382,6 +2382,23 @@ app.post('/rpc/v1', (req, res) => { case 'streaming.list-services': { return res.json({ result: { services: mockState.streamingServices || [] } }) } + case 'streaming.list-sessions': { + const mkTime = (minsAgo) => new Date(Date.now() - minsAgo * 60_000).toISOString() + return res.json({ result: { + sessions: [ + { id: 'sess-demo-1', peer_id: 'npub1walker…k3u9', service_id: 'content-download', metric: 'bytes', allotment: 524_288_000, used: 231_211_008, paid_sats: 500, created_at: mkTime(134), last_topup_at: mkTime(22), expires_at: '', active: true }, + { id: 'sess-demo-2', peer_id: 'npub1sailor…m2xq', service_id: 'nostr-relay', metric: 'milliseconds', allotment: 10_800_000, used: 4_920_000, paid_sats: 30, created_at: mkTime(82), last_topup_at: mkTime(82), expires_at: mkTime(-98), active: true }, + { id: 'sess-demo-3', peer_id: 'npub1nomad…t7rd', service_id: 'content-download', metric: 'bytes', allotment: 104_857_600, used: 88_080_384, paid_sats: 100, created_at: mkTime(9), last_topup_at: mkTime(9), expires_at: '', active: true }, + ], + total_active: 3, + total_revenue_sats: 770_000, + revenue_by_service: { + 'content-download': 512_400, + 'nostr-relay': 201_600, + 'api-access': 56_000, + }, + } }) + } case 'streaming.configure-service': { const p = params || {} const list = mockState.streamingServices || [] @@ -3566,13 +3583,32 @@ app.post('/rpc/v1', (req, res) => { } case 'wallet.networking-profits': { + // Deterministic-but-varied week of profit events for the dashboard + // chart (source/timestamp/sats mirror wallet::profits::ProfitEntry). + const profitSources = ['streaming_revenue', 'content_sale', 'routing_fee'] + const profitNotes = ['Paid streaming session', 'Ecash content sale', 'Lightning routing fees'] + const recent = [] + const nowMs = Date.now() + for (let i = 0; i < 42; i++) { + const daysAgo = (i * 3) % 7 + const hour = (i * 5) % 24 + recent.push({ + source: profitSources[i % 3], + amount_sats: 800 + ((i * 7919) % 14000), + timestamp: new Date(nowMs - daysAgo * 86_400_000 - hour * 3_600_000).toISOString(), + description: profitNotes[i % 3], + }) + } + recent.sort((a, b) => b.timestamp.localeCompare(a.timestamp)) return res.json({ result: { total_sats: 5_231_978, content_sales_sats: 3_180_000, routing_fees_sats: 1_281_978, - relay_sats: 770_000, + streaming_revenue_sats: 770_000, + recent, // legacy aliases kept for older UI builds + relay_sats: 770_000, total_earned_sats: 5_231_978, total_forwarded_sats: 1_281_978, forward_count: 1284, diff --git a/neode-ui/src/views/web5/Web5NetworkingProfitsSettings.vue b/neode-ui/src/views/web5/Web5NetworkingProfitsSettings.vue index e2dff309..6976cf37 100644 --- a/neode-ui/src/views/web5/Web5NetworkingProfitsSettings.vue +++ b/neode-ui/src/views/web5/Web5NetworkingProfitsSettings.vue @@ -1,9 +1,11 @@