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()) -