fix(machine): hide cancel after bills inserted, kiosk-only UI cleanup

- Hide header cancel button after bills are in cash box
- Add spinning hourglass to displayingQR waiting indicator
- Hide keyboard-dependent UI in Electron kiosk mode:
  QR mode selector, manual payment options, copy buttons
  These remain available in browser (web-ui) mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Patrick Mulligan 2026-02-25 19:26:06 -05:00
commit 642f0c5951
2 changed files with 32 additions and 9 deletions

View file

@ -13,6 +13,19 @@ import QRCode from '@/components/QRCode.vue'
const router = useRouter() const router = useRouter()
const atmStore = useAtmStore() const atmStore = useAtmStore()
const isElectron = typeof window !== 'undefined' && window.electronAPI !== undefined
// Whether the header cancel button should be visible
// Hide after bills are inserted — state machine routes to confirmAbandon instead
const showCancelButton = computed(() => {
const state = atmStore.nestedState
const hasBills = (atmStore.context?.billsInserted.length ?? 0) > 0
// Always show in insertingBills (before bills) and error (without bills)
if (state === 'insertingBills' || state === 'fetchingRate') return true
if (state === 'error' && !hasBills) return true
// Hide when bills are in the cash box
return false
})
// CLINK Debit: customer's npub/pubkey // CLINK Debit: customer's npub/pubkey
const pubkeyInput = ref('') const pubkeyInput = ref('')
@ -190,7 +203,10 @@ const isProcessing = computed(() => atmStore.isPayingInvoice || atmStore.isReque
<div class="flex min-h-0 flex-1 flex-col"> <div class="flex min-h-0 flex-1 flex-col">
<!-- Header --> <!-- Header -->
<header class="flex items-center bg-black/30 px-4 pb-3 pt-12 sm:px-8 sm:py-4"> <header class="flex items-center bg-black/30 px-4 pb-3 pt-12 sm:px-8 sm:py-4">
<Button variant="ghost" class="text-muted-foreground" @click="cancel">← Cancel</Button> <Button v-if="showCancelButton" variant="ghost" class="text-muted-foreground" @click="cancel">
← Cancel
</Button>
<div v-else class="w-20"></div>
<h2 class="flex-1 text-center text-lg font-semibold sm:text-xl">Buy Bitcoin</h2> <h2 class="flex-1 text-center text-lg font-semibold sm:text-xl">Buy Bitcoin</h2>
<div class="w-20"></div> <div class="w-20"></div>
</header> </header>
@ -312,8 +328,8 @@ const isProcessing = computed(() => atmStore.isPayingInvoice || atmStore.isReque
</p> </p>
</div> </div>
<!-- Scan with selector --> <!-- Scan with selector (web-ui only — kiosk users just scan) -->
<div class="text-center"> <div v-if="!isElectron" class="text-center">
<p class="text-xs text-muted-foreground mb-2">Scan with</p> <p class="text-xs text-muted-foreground mb-2">Scan with</p>
<div class="flex flex-wrap gap-2 justify-center"> <div class="flex flex-wrap gap-2 justify-center">
<Button <Button
@ -373,8 +389,14 @@ const isProcessing = computed(() => atmStore.isPayingInvoice || atmStore.isReque
</div> </div>
</div> </div>
<!-- Mode label + truncated URI --> <!-- Waiting for payment indicator -->
<div class="text-center space-y-1"> <div v-if="currentQrValue" class="flex items-center justify-center gap-2">
<span class="animate-hourglass text-lg">⏳</span>
<p class="text-sm text-muted-foreground">Waiting for payment...</p>
</div>
<!-- Mode label + truncated URI (web-ui only) -->
<div v-if="!isElectron" class="text-center space-y-1">
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wide"> <p class="text-xs font-medium text-muted-foreground uppercase tracking-wide">
{{ {{
qrMode === 'unified' qrMode === 'unified'
@ -395,8 +417,8 @@ const isProcessing = computed(() => atmStore.isPayingInvoice || atmStore.isReque
</div> </div>
</div> </div>
<!-- Alternative: Manual Options (collapsed) --> <!-- Alternative: Manual Options (web-ui only, no keyboard on kiosk) -->
<details class="rounded-lg bg-white/5 p-3"> <details v-if="!isElectron" class="rounded-lg bg-white/5 p-3">
<summary class="cursor-pointer text-sm text-muted-foreground"> <summary class="cursor-pointer text-sm text-muted-foreground">
Alternative: Manual payment options Alternative: Manual payment options
</summary> </summary>

View file

@ -12,6 +12,7 @@ import QRCode from '@/components/QRCode.vue'
const router = useRouter() const router = useRouter()
const atmStore = useAtmStore() const atmStore = useAtmStore()
const isElectron = typeof window !== 'undefined' && window.electronAPI !== undefined
// Copy invoice functionality // Copy invoice functionality
const copyButtonText = ref('Copy Invoice') const copyButtonText = ref('Copy Invoice')
@ -254,8 +255,8 @@ function formatFiat(cents: number): string {
<p class="text-center text-muted-foreground">Waiting for payment...</p> <p class="text-center text-muted-foreground">Waiting for payment...</p>
</div> </div>
<!-- Invoice info with copy button --> <!-- Invoice info with copy button (web-ui only) -->
<div v-if="context?.invoice" class="rounded-lg bg-white/5 p-3"> <div v-if="context?.invoice && !isElectron" class="rounded-lg bg-white/5 p-3">
<p class="mb-2 truncate text-center font-mono text-xs text-muted-foreground"> <p class="mb-2 truncate text-center font-mono text-xs text-muted-foreground">
{{ context.invoice.slice(0, 50) }}... {{ context.invoice.slice(0, 50) }}...
</p> </p>