neptune-web-wallet/src/views/Auth/components/SeedPhraseDisplayComponent.vue
2025-11-11 09:54:04 +07:00

304 lines
8.5 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { computed } from 'vue'
import { useNeptuneStore } from '@/stores/neptuneStore'
import { message } from 'ant-design-vue'
interface Props {
backButton?: boolean
nextButton?: boolean
backButtonText?: string
nextButtonText?: string
}
const props = withDefaults(defineProps<Props>(), {
backButton: true,
nextButton: true,
backButtonText: 'BACK',
nextButtonText: 'NEXT',
})
const emit = defineEmits<{
next: []
back: []
}>()
const neptuneStore = useNeptuneStore()
const seedWords = computed(() => neptuneStore.getSeedPhrase || [])
const handleNext = () => {
if (!seedWords.value || seedWords.value.length === 0) {
message.error('❌ Cannot proceed without seed phrase')
return
}
emit('next')
}
const handleBack = () => {
emit('back')
}
const handleCopySeed = async () => {
if (!seedWords.value || seedWords.value.length === 0) {
message.error('No seed phrase to copy')
return
}
try {
const seedPhrase = seedWords.value.join(' ')
await navigator.clipboard.writeText(seedPhrase)
message.success('Seed phrase copied to clipboard!')
} catch (err) {
message.error('Failed to copy seed phrase')
}
}
</script>
<template>
<div class="recovery-container">
<div class="recovery-card">
<div class="recovery-header">
<h1 class="recovery-title">Recovery Seed</h1>
</div>
<div class="recovery-content">
<div class="instruction-text">
<p>
Make sure no one is looking, as anyone with your seed phrase can access your
wallet and funds. Write it down and keep it safe.
</p>
</div>
<div v-if="seedWords.length > 0" class="seed-words-container">
<div class="seed-words-grid">
<div v-for="(word, index) in seedWords" :key="index" class="seed-word-item">
<span class="word-number">{{ index + 1 }}</span>
<span class="word-text">{{ word }}</span>
</div>
</div>
<button class="copy-seed-btn" @click="handleCopySeed" type="button">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
></path>
</svg>
Copy Seed Phrase
</button>
</div>
<div v-else class="no-seed-warning">
<p> No seed phrase found. Please go back and generate a wallet first.</p>
</div>
<div class="recovery-actions">
<ButtonCommon
v-if="props.backButton"
type="default"
size="large"
@click="handleBack"
>
{{ backButtonText }}
</ButtonCommon>
<ButtonCommon
v-if="props.nextButton"
type="primary"
size="large"
@click="handleNext"
:disabled="!seedWords || seedWords.length === 0"
>
{{ nextButtonText }}
</ButtonCommon>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.recovery-container {
display: flex;
align-items: center;
justify-content: center;
background: var(--bg-light);
}
.recovery-card {
max-width: 500px;
padding: var(--spacing-xl);
width: 100%;
border: 2px solid var(--primary-color);
border-radius: var(--radius-md);
}
.recovery-header {
text-align: center;
margin-bottom: var(--spacing-2xl);
padding-bottom: var(--spacing-xl);
border-bottom: 1px solid var(--border-color);
.recovery-title {
font-size: var(--font-2xl);
font-weight: var(--font-bold);
color: var(--text-primary);
margin: 0;
}
}
.recovery-content {
.instruction-text {
margin-bottom: var(--spacing-2xl);
p {
font-size: var(--font-sm);
color: var(--text-secondary);
line-height: var(--leading-normal);
margin-bottom: var(--spacing-md);
&:last-child {
margin-bottom: 0;
}
}
}
.seed-words-container {
margin-bottom: var(--spacing-2xl);
padding: var(--spacing-lg);
background: var(--bg-hover);
border-radius: var(--radius-md);
border: 1px solid var(--border-light);
.seed-words-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--spacing-md);
margin-bottom: var(--spacing-md);
.seed-word-item {
display: flex;
align-items: center;
gap: var(--spacing-sm);
padding: var(--spacing-sm);
background: var(--bg-white);
border-radius: var(--radius-sm);
border: 1px solid var(--border-light);
.word-number {
font-size: var(--font-xs);
font-weight: var(--font-bold);
color: var(--text-muted);
min-width: 20px;
}
.word-text {
font-size: var(--font-sm);
font-weight: var(--font-medium);
color: var(--text-primary);
}
}
}
.copy-seed-btn {
display: flex;
align-items: center;
gap: var(--spacing-sm);
width: 100%;
padding: var(--spacing-sm) var(--spacing-md);
background: var(--primary-color);
color: var(--text-light);
border: none;
border-radius: var(--radius-sm);
font-size: var(--font-sm);
font-weight: var(--font-medium);
cursor: pointer;
transition: all 0.2s ease;
justify-content: center;
svg {
flex-shrink: 0;
}
&:hover {
background: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 127, 207, 0.3);
}
&:active {
transform: translateY(0);
}
}
}
.cool-fact {
margin-bottom: var(--spacing-2xl);
text-align: center;
p {
font-size: var(--font-xs);
color: var(--text-muted);
font-style: italic;
margin: 0;
}
}
.recovery-actions {
display: flex;
justify-content: space-between;
gap: var(--spacing-md);
}
.no-seed-warning {
padding: var(--spacing-xl);
background: var(--error-light);
border: 2px solid var(--error-color);
border-radius: var(--radius-md);
text-align: center;
margin-bottom: var(--spacing-2xl);
p {
font-size: var(--font-md);
color: var(--error-color);
font-weight: var(--font-bold);
margin: 0;
}
}
}
@include screen(mobile) {
.recovery-container {
padding: var(--spacing-md);
}
.recovery-card {
max-width: 100%;
}
.recovery-content {
.seed-words-container {
.seed-words-grid {
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-sm);
.seed-word-item {
padding: var(--spacing-xs);
.word-number {
min-width: 16px;
}
}
}
}
}
}
</style>