feat(machine): confirm-abandon warning, retry on error, hourglass animation
- Add confirmAbandon state UI: warns user cash can't be returned, offers "Show QR Code Again" or "Abandon (lose cash)" - Error state shows "Try Again" button when bills are inserted - Replace Skeleton loading placeholders with hourglass emoji - Add animate-hourglass: 45-degree step rotation (Tailwind v4 @utility) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
625af457d1
commit
165ad59704
2 changed files with 69 additions and 2 deletions
|
|
@ -491,3 +491,38 @@
|
||||||
@utility animate-float {
|
@utility animate-float {
|
||||||
animation: float 3s ease-in-out infinite;
|
animation: float 3s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hourglass 45-degree step rotation */
|
||||||
|
@keyframes hourglass {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
12.5% {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
37.5% {
|
||||||
|
transform: rotate(135deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
62.5% {
|
||||||
|
transform: rotate(225deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
87.5% {
|
||||||
|
transform: rotate(315deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility animate-hourglass {
|
||||||
|
animation: hourglass 4s steps(8) infinite;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,7 @@ const isProcessing = computed(() => atmStore.isPayingInvoice || atmStore.isReque
|
||||||
class="w-full max-w-80 border-0 bg-white/5"
|
class="w-full max-w-80 border-0 bg-white/5"
|
||||||
>
|
>
|
||||||
<CardContent class="flex flex-col items-center gap-4 p-8">
|
<CardContent class="flex flex-col items-center gap-4 p-8">
|
||||||
<Skeleton class="h-10 w-10 rounded-full" />
|
<span class="animate-hourglass text-5xl">⏳</span>
|
||||||
<p class="text-muted-foreground">Preparing payment code...</p>
|
<p class="text-muted-foreground">Preparing payment code...</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -485,7 +485,7 @@ const isProcessing = computed(() => atmStore.isPayingInvoice || atmStore.isReque
|
||||||
class="w-full max-w-80 border-0 bg-white/5"
|
class="w-full max-w-80 border-0 bg-white/5"
|
||||||
>
|
>
|
||||||
<CardContent class="flex flex-col items-center gap-4 p-8">
|
<CardContent class="flex flex-col items-center gap-4 p-8">
|
||||||
<Skeleton class="h-10 w-10 rounded-full" />
|
<span class="animate-hourglass text-5xl">⏳</span>
|
||||||
<p class="text-muted-foreground">Sending receipt...</p>
|
<p class="text-muted-foreground">Sending receipt...</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -506,12 +506,44 @@ const isProcessing = computed(() => atmStore.isPayingInvoice || atmStore.isReque
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<!-- Confirm Abandon Warning -->
|
||||||
|
<Card
|
||||||
|
v-else-if="nestedState === 'confirmAbandon'"
|
||||||
|
class="w-full max-w-80 border-0 bg-red-900/30"
|
||||||
|
>
|
||||||
|
<CardContent class="flex flex-col items-center gap-4 p-8 text-center">
|
||||||
|
<div class="text-6xl">⚠️</div>
|
||||||
|
<CardTitle class="text-red-400">Cash Already Accepted</CardTitle>
|
||||||
|
<p class="text-muted-foreground">
|
||||||
|
Your {{ atmStore.fiatSymbol
|
||||||
|
}}{{ context ? (context.fiatAmount / 100).toLocaleString() : '' }} has been accepted
|
||||||
|
and cannot be returned. Please scan the QR code to receive your Bitcoin.
|
||||||
|
</p>
|
||||||
|
<Button
|
||||||
|
class="w-full bg-gradient-to-r from-green-500 to-emerald-400 text-black"
|
||||||
|
@click="atmStore.send({ type: 'RETRY' })"
|
||||||
|
>
|
||||||
|
Show QR Code Again
|
||||||
|
</Button>
|
||||||
|
<Button variant="ghost" class="w-full text-red-400" @click="cancel">
|
||||||
|
Abandon (lose cash)
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<!-- Error -->
|
<!-- Error -->
|
||||||
<Card v-else-if="nestedState === 'error'" class="w-full max-w-80 border-0 bg-red-900/30">
|
<Card v-else-if="nestedState === 'error'" class="w-full max-w-80 border-0 bg-red-900/30">
|
||||||
<CardContent class="flex flex-col items-center gap-4 p-8 text-center">
|
<CardContent class="flex flex-col items-center gap-4 p-8 text-center">
|
||||||
<div class="text-6xl">⚠️</div>
|
<div class="text-6xl">⚠️</div>
|
||||||
<CardTitle class="text-red-400">Error</CardTitle>
|
<CardTitle class="text-red-400">Error</CardTitle>
|
||||||
<p class="text-muted-foreground">{{ context?.error || 'An error occurred' }}</p>
|
<p class="text-muted-foreground">{{ context?.error || 'An error occurred' }}</p>
|
||||||
|
<Button
|
||||||
|
v-if="context && context.billsInserted.length > 0"
|
||||||
|
class="w-full bg-gradient-to-r from-green-500 to-emerald-400 text-black"
|
||||||
|
@click="atmStore.send({ type: 'RETRY' })"
|
||||||
|
>
|
||||||
|
Try Again
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
class="bg-gradient-to-r from-orange-500 to-yellow-400 text-black"
|
class="bg-gradient-to-r from-orange-500 to-yellow-400 text-black"
|
||||||
@click="cancel"
|
@click="cancel"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue