From dcf2b418ff7b381914d779ba24c4f2392cc30b6c Mon Sep 17 00:00:00 2001 From: "smx.pusha" <139338836+smxpusha@users.noreply.github.com> Date: Tue, 18 Aug 2026 09:20:43 +0200 Subject: [PATCH] ENH - redesign VaultX as premium exchange Rebuild the portfolio, market, activity, asset-detail, and profile surfaces with a denser premium hierarchy and richer data visualization. Remove manual refresh controls, retain server-authoritative financial flows, and add localized allocation copy plus regression coverage. --- frontend/src/stores/phone.ts | 4 + .../src/views/apps/CryptoApp.contract.test.ts | 9 + frontend/src/views/apps/CryptoApp.vue | 1145 ++++++++++++++++- sky_phone/config/locales/de.lua | 2 +- sky_phone/config/locales/en.lua | 2 +- 5 files changed, 1099 insertions(+), 63 deletions(-) diff --git a/frontend/src/stores/phone.ts b/frontend/src/stores/phone.ts index e1d67f1..671f3f6 100644 --- a/frontend/src/stores/phone.ts +++ b/frontend/src/stores/phone.ts @@ -449,6 +449,10 @@ const cryptoFallbackLocales = { portfolio: { total: 'Total portfolio', cash: 'Available cash', + invested: 'Invested assets', + allocation: 'Portfolio allocation', + inMarket: 'in markets', + assets: 'assets', holdings: 'Your assets', empty: 'No assets yet', emptyBody: 'Open Markets to request a protected quote.', diff --git a/frontend/src/views/apps/CryptoApp.contract.test.ts b/frontend/src/views/apps/CryptoApp.contract.test.ts index bb44bd3..b3b508e 100644 --- a/frontend/src/views/apps/CryptoApp.contract.test.ts +++ b/frontend/src/views/apps/CryptoApp.contract.test.ts @@ -47,6 +47,15 @@ describe('VaultX crypto app contracts', () => { expect(server).toContain('`price_alerts`') }) + it('uses the premium dashboard hierarchy without manual refresh controls', () => { + expect(source).toContain('class="portfolio-shell"') + expect(source).toContain('class="featured-market"') + expect(source).toContain('class="activity-ring"') + expect(source).toContain('class="profile-card"') + expect(source).not.toContain('RefreshCw') + expect(source).not.toContain(':aria-label="t(\'refresh\')"') + }) + it('keeps all consequential calculations and state transitions on the server', () => { expect(server).toContain( 'Bridge.Callbacks.Register("sky_phone:crypto:quote"', diff --git a/frontend/src/views/apps/CryptoApp.vue b/frontend/src/views/apps/CryptoApp.vue index 80bfb6c..a2d1556 100644 --- a/frontend/src/views/apps/CryptoApp.vue +++ b/frontend/src/views/apps/CryptoApp.vue @@ -2,7 +2,6 @@ import { ArrowDownLeft, ArrowLeft, - ArrowLeftRight, ArrowUpRight, BellRing, ChartCandlestick, @@ -14,7 +13,6 @@ import { History, LockKeyhole, LogOut, - RefreshCw, Settings2, ShieldCheck, Sparkles, @@ -89,6 +87,25 @@ const portfolioChange = computed(() => markets.value.length : 0, ) +const investedValue = computed(() => + Math.max( + 0, + Number(crypto.data?.portfolioValue ?? 0) - + Number(crypto.data?.cashBalance ?? 0), + ), +) +const cashShare = computed(() => { + const total = Number(crypto.data?.portfolioValue ?? 0) + return total > 0 + ? Math.min(100, (Number(crypto.data?.cashBalance ?? 0) / total) * 100) + : 0 +}) +const topMover = computed( + () => + [...markets.value].sort( + (first, second) => second.changePercent - first.changePercent, + )[0], +) const detailHolding = computed(() => holdings.value.find((item) => item.assetId === detail.value?.id), ) @@ -131,6 +148,10 @@ function points(values: number[], width = 320, height = 110) { function market(id?: string) { return markets.value.find((item) => item.id === id) } +function allocation(value: string) { + const total = Number(crypto.data?.portfolioValue ?? 0) + return total > 0 ? Math.min(100, (Number(value) / total) * 100) : 0 +} function errorText(code: string) { const value = t(`errors.${code}`) return value.startsWith('Apps.crypto.') ? t('errors.default') : value @@ -247,10 +268,6 @@ onMounted(() => void crypto.load()) > - void crypto.load())