From 88767dc84439e7c1ec39a8abd6b8b35d7ebe08d6 Mon Sep 17 00:00:00 2001 From: "smx.pusha" <139338836+smxpusha@users.noreply.github.com> Date: Tue, 18 Aug 2026 11:01:36 +0200 Subject: [PATCH] ENH - refine VaultX trading flow Pin Buy and Sell actions to the crypto detail footer, rebuild the trade sheet around protected quote review, and invalidate stale quotes after side or quantity changes. Add localized trading labels without config or SQL migrations. --- frontend/src/stores/phone.ts | 9 + .../src/views/apps/CryptoApp.contract.test.ts | 10 +- frontend/src/views/apps/CryptoApp.vue | 398 +++++++++++++++--- sky_phone/config/locales/de.lua | 2 +- sky_phone/config/locales/en.lua | 2 +- 5 files changed, 366 insertions(+), 55 deletions(-) diff --git a/frontend/src/stores/phone.ts b/frontend/src/stores/phone.ts index 7768f4d..9f1ed49 100644 --- a/frontend/src/stores/phone.ts +++ b/frontend/src/stores/phone.ts @@ -493,10 +493,19 @@ const cryptoFallbackLocales = { liquidity: 'Exchange liquidity', }, trade: { + actions: 'Trade actions', buy: 'Buy', + buyBody: 'Add', sell: 'Sell', + sellBody: 'Reduce', quantity: 'Quantity', available: 'Available:', + estimated: 'Estimated value', + marketPrice: 'Market price', + protected: 'Protected server quote', + protectedBody: + 'VaultX validates price, liquidity, balance and limits before execution.', + review: 'Order review', price: 'Quote price', gross: 'Gross', fee: 'Exchange fee', diff --git a/frontend/src/views/apps/CryptoApp.contract.test.ts b/frontend/src/views/apps/CryptoApp.contract.test.ts index 8b7749b..646fd9a 100644 --- a/frontend/src/views/apps/CryptoApp.contract.test.ts +++ b/frontend/src/views/apps/CryptoApp.contract.test.ts @@ -53,6 +53,12 @@ describe('VaultX crypto app contracts', () => { it('includes advanced market detail and persistent profile controls', () => { expect(source).toContain('detail.sparkline') expect(source).toContain("t('marketDetail.statistics')") + expect(source).toContain('class="detail-trade-dock"') + expect(source).toContain('class="vault-view vault-detail-scroll"') + expect(source).toContain('class="trade-side-selector"') + expect(source).toContain('class="trade-entry-card"') + expect(source).toContain('class="trade-protection"') + expect(source).toContain('crypto.pendingQuote = null') expect(source).toContain(' { }) it('uses the compact Flare-style navigation and polished overlay transitions', () => { + const navbarTag = source.match(//)?.[0] ?? '' + expect(source).toContain('class="vault-navbar"') expect(source).toContain('class="vault-header-logo"') expect(source).toContain( @@ -98,7 +106,7 @@ describe('VaultX crypto app contracts', () => { expect(source).not.toContain('class="coin-detail-logo"') expect(source).not.toContain('.vault-header-brand > i') expect(source).toContain(':show-back="Boolean(detail)"') - expect(source).not.toMatch(/)/) + expect(navbarTag).not.toMatch(/\slarge(?:\s|=|>)/) expect(source).toContain('class="vault-view"') expect(source).toContain('@keyframes vault-view-in') expect(source).toContain('class="sheet-header"') diff --git a/frontend/src/views/apps/CryptoApp.vue b/frontend/src/views/apps/CryptoApp.vue index 7dedab7..9608352 100644 --- a/frontend/src/views/apps/CryptoApp.vue +++ b/frontend/src/views/apps/CryptoApp.vue @@ -211,6 +211,9 @@ const detailHolding = computed(() => const selectedHolding = computed(() => holdings.value.find((item) => item.assetId === selectedMarket.value?.id), ) +const estimatedTradeValue = computed( + () => Number(amount.value || 0) * Number(selectedMarket.value?.price || 0), +) function t(key: string) { return phone.t(`Apps.crypto.${key}`) @@ -280,6 +283,12 @@ function openTrade(next: CryptoMarket, nextSide: CryptoSide = 'buy') { crypto.pendingQuote = null sheet.value = 'trade' } +function selectTradeSide(next: CryptoSide) { + if (side.value === next) return + side.value = next + crypto.pendingQuote = null + formError.value = '' +} function openSettlement(next: 'deposit' | 'withdraw') { sheet.value = next amount.value = '' @@ -385,6 +394,12 @@ watch( }, { immediate: true }, ) +watch(amount, () => { + if (sheet.value === 'trade' && crypto.pendingQuote) { + crypto.pendingQuote = null + formError.value = '' + } +}) onMounted(() => void crypto.load()) @@ -520,7 +535,7 @@ onMounted(() => void crypto.load()) @@ -609,17 +624,6 @@ onMounted(() => void crypto.load()) >{{ compact(detail.treasuryAvailable) }} {{ detail.symbol }} -
- {{ - t('trade.buy') - }}{{ t('trade.sell') }} -
void crypto.load()) +
+ + + + {{ t('trade.buy') }} + {{ t('trade.buyBody') }} + + + + + + {{ t('trade.sell') }} + {{ t('trade.sellBody') }} + + +
+ void crypto.load()) -