230 lines
5.9 KiB
Vue
Raw Normal View History

2025-11-05 04:14:37 +07:00
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { Modal } from 'ant-design-vue'
import { useNeptuneStore } from '@/stores/neptuneStore'
import { useNeptuneWallet } from '@/composables/useNeptuneWallet'
import { message } from 'ant-design-vue'
import { ButtonCommon, CardBaseScrollable } from '@/components'
import SeedPhraseDisplayComponent from '@/views/Auth/components/SeedPhraseDisplayComponent.vue'
import WalletBalanceAndAddress from './WalletBalanceAndAddress.vue'
const neptuneStore = useNeptuneStore()
const { getBalance, saveKeystoreAs } = useNeptuneWallet()
const availableBalance = ref(0)
const pendingBalance = ref(0)
const loading = ref(false)
const error = ref<string | null>(null)
const showSeedModal = ref(false)
const getModalContainer = (): HTMLElement => {
const homeContainer = document.querySelector('.home-container') as HTMLElement
return homeContainer || document.body
}
const receiveAddress = computed(() => neptuneStore.getWallet?.address || '')
const walletStatus = computed(() => {
if (loading.value) return 'Loading...'
if (error.value) return 'Error'
if (neptuneStore.getWallet?.address) return 'Online'
return 'Offline'
})
const windowWidth = ref(window.innerWidth)
const modalWidth = computed(() => {
if (windowWidth.value <= 767) {
return '90%'
}
return '60%'
})
const handleResize = () => {
windowWidth.value = window.innerWidth
}
const handleClickSendButton = () => {
// TODO: Implement send transaction functionality
}
const handleBackupFile = async () => {
try {
const seed = neptuneStore.getSeedPhraseString
const password = neptuneStore.getPassword
if (!seed || !password) {
message.error('Missing seed or password')
return
}
await saveKeystoreAs(seed, password)
message.success('Keystore saved successfully')
} catch (err) {
if (err instanceof Error && err.message.includes('User canceled')) return
message.error('Failed to save keystore')
}
}
const handleBackupSeed = () => {
showSeedModal.value = true
}
const handleCloseModal = () => {
showSeedModal.value = false
}
const handleModalNext = () => {
handleCloseModal()
}
const loadWalletData = async () => {
const receiveAddress = neptuneStore.getWallet?.address || ''
if (!receiveAddress) return
loading.value = true
error.value = null
try {
const result = await getBalance()
availableBalance.value = +result.confirmedAvailable || 0
pendingBalance.value = +result.unconfirmedAvailable || 0
} catch (error) {
message.error('Failed to load wallet data')
} finally {
loading.value = false
}
}
onMounted(() => {
loadWalletData()
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
</script>
<template>
<CardBaseScrollable class="wallet-info-container">
<div class="wallet-content">
<WalletBalanceAndAddress
:is-loading-data="loading"
:available-balance="availableBalance"
:pending-balance="pendingBalance"
/>
<!-- Action Buttons -->
<div v-if="receiveAddress" class="action-buttons">
<ButtonCommon
type="primary"
size="large"
block
@click="handleClickSendButton"
class="btn-send"
>
SEND
</ButtonCommon>
<ButtonCommon type="primary" size="large" block @click="handleBackupFile">
Backup File
</ButtonCommon>
<ButtonCommon type="primary" size="large" block @click="handleBackupSeed">
Backup Seed
</ButtonCommon>
</div>
<!-- Wallet Status -->
<div v-if="receiveAddress" class="wallet-status">
<span
>Wallet Status: <strong>{{ walletStatus }}</strong></span
>
</div>
</div>
</CardBaseScrollable>
<Modal
v-model:open="showSeedModal"
title="Backup Seed Phrase"
:footer="null"
:width="modalWidth"
:mask-closable="false"
:keyboard="false"
:get-container="getModalContainer"
@cancel="handleCloseModal"
>
<div class="seed-modal-content">
<SeedPhraseDisplayComponent
:back-button="false"
:next-button-text="'DONE'"
@next="handleModalNext"
/>
</div>
</Modal>
</template>
<style lang="scss" scoped>
.wallet-info-container {
height: 100%;
}
.wallet-content {
background: inherit;
height: 100%;
}
.action-buttons {
@include center_flex;
gap: var(--spacing-md);
margin-bottom: var(--spacing-lg);
flex-shrink: 0;
:deep(.btn-send) {
letter-spacing: var(--tracking-wide);
}
}
.wallet-status {
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
padding: 1rem;
background: var(--bg-light);
border-radius: var(--radius-md);
font-size: var(--font-base);
color: var(--text-secondary);
margin-top: auto;
flex-shrink: 0;
strong {
color: var(--text-primary);
font-weight: var(--font-semibold);
}
}
.seed-modal-content {
:deep(.recovery-container) {
padding: 0;
min-height: auto;
background: transparent;
}
:deep(.recovery-card) {
border: none;
box-shadow: none;
padding: 0;
}
}
// Modal responsive width
:deep(.ant-modal) {
@media (max-width: 767px) {
width: 90% !important;
max-width: 90% !important;
}
@media (min-width: 768px) {
width: 60% !important;
max-width: 60% !important;
}
}
</style>