437 lines
11 KiB
Vue
437 lines
11 KiB
Vue
<script setup lang="ts">
|
|
import { ref, defineEmits, onMounted } from 'vue'
|
|
import { ButtonCommon } from '@/components'
|
|
import { useSeedStore } from '@/stores'
|
|
|
|
const emit = defineEmits<{
|
|
next: []
|
|
back: []
|
|
}>()
|
|
|
|
const seedStore = useSeedStore()
|
|
|
|
const seedWords = ref<string[]>([])
|
|
const currentQuestionIndex = ref(0)
|
|
const selectedAnswer = ref('')
|
|
const isCorrect = ref(false)
|
|
const showResult = ref(false)
|
|
|
|
const generateQuiz = (): {
|
|
position: number
|
|
correctWord: string
|
|
options: string[]
|
|
} | null => {
|
|
if (seedWords.value.length === 0) return null
|
|
|
|
const randomPosition = Math.floor(Math.random() * 12) + 1
|
|
currentQuestionIndex.value = randomPosition - 1
|
|
|
|
const correctWord = seedWords.value[randomPosition - 1]
|
|
const options = [correctWord]
|
|
|
|
const BIP39_WORDS = [
|
|
'abandon',
|
|
'ability',
|
|
'able',
|
|
'about',
|
|
'above',
|
|
'absent',
|
|
'absorb',
|
|
'abstract',
|
|
'absurd',
|
|
'abuse',
|
|
'access',
|
|
'accident',
|
|
'account',
|
|
'accuse',
|
|
'achieve',
|
|
'acid',
|
|
'acoustic',
|
|
'acquire',
|
|
'across',
|
|
'act',
|
|
'action',
|
|
'actor',
|
|
'actress',
|
|
'actual',
|
|
'adapt',
|
|
'add',
|
|
'addict',
|
|
'address',
|
|
'adjust',
|
|
'admit',
|
|
'adult',
|
|
'advance',
|
|
'advice',
|
|
'aerobic',
|
|
'affair',
|
|
'afford',
|
|
'afraid',
|
|
'again',
|
|
'age',
|
|
'agent',
|
|
'agree',
|
|
'ahead',
|
|
'aim',
|
|
'air',
|
|
'airport',
|
|
'aisle',
|
|
'alarm',
|
|
'album',
|
|
'alcohol',
|
|
'alert',
|
|
'alien',
|
|
'all',
|
|
'alley',
|
|
'allow',
|
|
'almost',
|
|
'alone',
|
|
'alpha',
|
|
'already',
|
|
'also',
|
|
'alter',
|
|
'always',
|
|
'amateur',
|
|
'amazing',
|
|
'among',
|
|
'amount',
|
|
'amused',
|
|
'analyst',
|
|
'anchor',
|
|
'ancient',
|
|
'anger',
|
|
'angle',
|
|
'angry',
|
|
'animal',
|
|
'ankle',
|
|
'announce',
|
|
'annual',
|
|
'another',
|
|
'answer',
|
|
'antenna',
|
|
'antique',
|
|
'anxiety',
|
|
'any',
|
|
'apart',
|
|
'apology',
|
|
'appear',
|
|
'apple',
|
|
'approve',
|
|
'april',
|
|
'arch',
|
|
'arctic',
|
|
'area',
|
|
'arena',
|
|
'argue',
|
|
'arm',
|
|
'armed',
|
|
'armor',
|
|
'army',
|
|
'around',
|
|
'arrange',
|
|
'arrest',
|
|
]
|
|
|
|
while (options.length < 4) {
|
|
const randomWord = BIP39_WORDS[Math.floor(Math.random() * BIP39_WORDS.length)]
|
|
if (!options.includes(randomWord)) {
|
|
options.push(randomWord)
|
|
}
|
|
}
|
|
|
|
options.sort(() => Math.random() - 0.5)
|
|
|
|
return {
|
|
position: randomPosition,
|
|
correctWord,
|
|
options,
|
|
}
|
|
}
|
|
|
|
const quizData = ref<{
|
|
position: number
|
|
correctWord: string
|
|
options: string[]
|
|
} | null>(null)
|
|
|
|
const handleAnswerSelect = (answer: string) => {
|
|
selectedAnswer.value = answer
|
|
isCorrect.value = answer === quizData.value?.correctWord
|
|
showResult.value = true
|
|
}
|
|
|
|
const handleNext = () => {
|
|
if (isCorrect.value) {
|
|
emit('next')
|
|
} else {
|
|
showResult.value = false
|
|
selectedAnswer.value = ''
|
|
const newQuiz = generateQuiz()
|
|
if (newQuiz) {
|
|
quizData.value = newQuiz
|
|
}
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
const words = seedStore.getSeedWords()
|
|
if (words.length > 0) {
|
|
seedWords.value = words
|
|
const newQuiz = generateQuiz()
|
|
if (newQuiz) {
|
|
quizData.value = newQuiz
|
|
}
|
|
} else {
|
|
const sampleWords = [
|
|
'abandon',
|
|
'ability',
|
|
'able',
|
|
'about',
|
|
'above',
|
|
'absent',
|
|
'absorb',
|
|
'abstract',
|
|
'absurd',
|
|
'abuse',
|
|
'access',
|
|
'accident',
|
|
]
|
|
seedWords.value = sampleWords
|
|
const newQuiz = generateQuiz()
|
|
if (newQuiz) {
|
|
quizData.value = newQuiz
|
|
}
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="confirm-container">
|
|
<div class="confirm-card">
|
|
<div class="confirm-header">
|
|
<h1 class="confirm-title">Recovery Seed</h1>
|
|
</div>
|
|
|
|
<div class="confirm-content">
|
|
<div class="progress-indicators">
|
|
<div class="progress-circle"></div>
|
|
<div class="progress-circle active"></div>
|
|
<div class="progress-circle"></div>
|
|
</div>
|
|
|
|
<div class="instruction-text">
|
|
<p>
|
|
Make sure you wrote the phrase down correctly by answering this quick
|
|
checkup.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="quiz-section">
|
|
<h2 class="quiz-question">What is the {{ quizData?.position }}th word?</h2>
|
|
|
|
<div class="answer-options">
|
|
<button
|
|
v-for="(option, index) in quizData?.options"
|
|
:key="index"
|
|
class="answer-button"
|
|
:class="{
|
|
selected: selectedAnswer === option,
|
|
correct: showResult && option === quizData?.correctWord,
|
|
incorrect:
|
|
showResult &&
|
|
selectedAnswer === option &&
|
|
option !== quizData?.correctWord,
|
|
}"
|
|
@click="handleAnswerSelect(option)"
|
|
:disabled="showResult"
|
|
>
|
|
{{ option }}
|
|
</button>
|
|
</div>
|
|
|
|
<div v-if="showResult" class="result-message">
|
|
<p v-if="isCorrect" class="success-message">✓ Correct! You can proceed.</p>
|
|
<p v-else class="error-message">✗ Incorrect. Please try again.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="confirm-actions">
|
|
<ButtonCommon
|
|
v-if="showResult && isCorrect"
|
|
type="primary"
|
|
size="large"
|
|
@click="handleNext"
|
|
>
|
|
CONTINUE
|
|
</ButtonCommon>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.confirm-container {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: var(--spacing-xl);
|
|
background: var(--bg-light);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.confirm-card {
|
|
@include card-base;
|
|
max-width: 500px;
|
|
width: 100%;
|
|
border: 2px solid var(--primary-color);
|
|
}
|
|
|
|
.confirm-header {
|
|
text-align: center;
|
|
margin-bottom: var(--spacing-2xl);
|
|
padding-bottom: var(--spacing-xl);
|
|
border-bottom: 1px solid var(--border-color);
|
|
|
|
.confirm-title {
|
|
font-size: var(--font-2xl);
|
|
font-weight: var(--font-bold);
|
|
color: var(--text-primary);
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
.confirm-content {
|
|
.progress-indicators {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: var(--spacing-sm);
|
|
margin-bottom: var(--spacing-2xl);
|
|
|
|
.progress-circle {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 50%;
|
|
background: var(--border-light);
|
|
transition: background-color 0.3s ease;
|
|
|
|
&.active {
|
|
background: var(--primary-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
.instruction-text {
|
|
text-align: center;
|
|
margin-bottom: var(--spacing-2xl);
|
|
|
|
p {
|
|
font-size: var(--font-sm);
|
|
color: var(--text-secondary);
|
|
line-height: var(--leading-normal);
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
.quiz-section {
|
|
margin-bottom: var(--spacing-2xl);
|
|
|
|
.quiz-question {
|
|
font-size: var(--font-lg);
|
|
font-weight: var(--font-bold);
|
|
color: var(--text-primary);
|
|
text-align: center;
|
|
margin-bottom: var(--spacing-xl);
|
|
}
|
|
|
|
.answer-options {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: var(--spacing-md);
|
|
margin-bottom: var(--spacing-lg);
|
|
|
|
.answer-button {
|
|
padding: var(--spacing-md);
|
|
border: 2px solid var(--border-light);
|
|
background: var(--bg-white);
|
|
border-radius: var(--radius-md);
|
|
font-size: var(--font-sm);
|
|
font-weight: var(--font-medium);
|
|
color: var(--text-primary);
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
|
|
&:hover:not(:disabled) {
|
|
border-color: var(--primary-color);
|
|
background: var(--primary-light);
|
|
}
|
|
|
|
&.selected {
|
|
border-color: var(--primary-color);
|
|
background: var(--primary-light);
|
|
}
|
|
|
|
&.correct {
|
|
border-color: var(--success-color);
|
|
background: var(--success-light);
|
|
color: var(--success-color);
|
|
}
|
|
|
|
&.incorrect {
|
|
border-color: var(--error-color);
|
|
background: var(--error-light);
|
|
color: var(--error-color);
|
|
}
|
|
|
|
&:disabled {
|
|
cursor: not-allowed;
|
|
opacity: 0.7;
|
|
}
|
|
}
|
|
}
|
|
|
|
.result-message {
|
|
text-align: center;
|
|
|
|
.success-message {
|
|
color: var(--success-color);
|
|
font-weight: var(--font-medium);
|
|
margin: 0;
|
|
}
|
|
|
|
.error-message {
|
|
color: var(--error-color);
|
|
font-weight: var(--font-medium);
|
|
margin: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.confirm-actions {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: var(--spacing-md);
|
|
}
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
.confirm-container {
|
|
padding: var(--spacing-md);
|
|
}
|
|
|
|
.confirm-card {
|
|
max-width: 100%;
|
|
}
|
|
|
|
.quiz-section {
|
|
.answer-options {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
|
|
.confirm-actions {
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
</style>
|