Files
botfights/frontend/src/components/WalletConnect.vue
T
DorianandClaude Opus 4.6 95b53e271f feat: wallet UI — WalletConnect component + ranked fight flow in pages
Add WalletConnect.vue with NWC/LN Address connection states. Add "FIGHT
FOR SATS" button to JoinBoutPage with entry fee payment flow. Show ranked
pot and winner payout in FightPage. Add sats stats and wallet section to
BotProfilePage. Extend BotData interface with satsWon/satsWagered/hasWallet.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 01:31:51 +00:00

148 lines
5.2 KiB
Vue

<script setup lang="ts">
import { ref, watch } from 'vue'
import { useWallet } from '../composables/useWallet'
const { isWalletConnected, walletMethod, paymentStatus, disconnectWallet, connectNWC, connectLightningAddress } = useWallet()
const isExpanded = ref(false)
const nwcInput = ref('')
const lnAddressInput = ref('')
const connectError = ref('')
const isConnecting = ref(false)
async function handleConnectNWC() {
if (!nwcInput.value.trim()) return
isConnecting.value = true
connectError.value = ''
try {
await connectNWC(nwcInput.value.trim())
isExpanded.value = false
nwcInput.value = ''
} catch (err) {
connectError.value = err instanceof Error ? err.message : 'Connection failed'
}
isConnecting.value = false
}
async function handleConnectLnAddress() {
if (!lnAddressInput.value.trim()) return
isConnecting.value = true
connectError.value = ''
try {
await connectLightningAddress(lnAddressInput.value.trim())
isExpanded.value = false
lnAddressInput.value = ''
} catch (err) {
connectError.value = err instanceof Error ? err.message : 'Connection failed'
}
isConnecting.value = false
}
async function handleDisconnect() {
await disconnectWallet()
}
</script>
<template>
<!-- Paying state -->
<div v-if="paymentStatus === 'paying' || paymentStatus === 'invoiced'" class="text-center py-3">
<div class="flex items-center justify-center gap-2">
<span class="w-4 h-4 border-2 border-neon-cyan/30 border-t-neon-cyan rounded-full animate-spin" />
<span class="font-display font-bold text-xs tracking-wider text-neon-cyan">PAYING 21 SATS...</span>
</div>
</div>
<!-- Confirmed flash -->
<div v-else-if="paymentStatus === 'confirmed'" class="text-center py-3">
<span class="font-display font-bold text-xs tracking-wider text-green-400 animate-pulse">LOCKED IN</span>
</div>
<!-- Connected state -->
<div v-else-if="isWalletConnected" class="flex items-center justify-center gap-2 py-2">
<span class="text-neon-cyan"></span>
<span class="font-display font-bold text-[10px] tracking-wider text-neon-cyan">WALLET READY</span>
<button
class="font-mono text-[9px] text-text-muted hover:text-ko transition-colors ml-2 underline"
@click="handleDisconnect"
>
disconnect
</button>
</div>
<!-- Not connected -->
<div v-else class="space-y-2">
<button
v-if="!isExpanded"
class="w-full py-2 border border-neon-cyan/30 text-neon-cyan
font-display font-bold text-[10px] tracking-wider
hover:bg-neon-cyan/10 transition-all"
@click="isExpanded = true"
>
CONNECT WALLET
</button>
<div v-else class="border border-border p-3 space-y-3">
<p class="font-display font-bold text-[10px] tracking-wider text-text-secondary text-center">CONNECT WALLET</p>
<!-- NWC input -->
<div>
<label class="font-mono text-[9px] text-text-muted block mb-1">NWC CONNECTION STRING</label>
<input
v-model="nwcInput"
type="text"
placeholder="nostr+walletconnect://..."
class="w-full bg-surface border border-border px-2 py-1.5 font-mono text-[10px] text-text-primary
focus:border-neon-cyan/50 focus:outline-none"
/>
<button
class="w-full mt-1 py-1.5 bg-neon-cyan/10 border border-neon-cyan/30 text-neon-cyan
font-display font-bold text-[9px] tracking-wider
hover:bg-neon-cyan/20 transition-all disabled:opacity-50"
:disabled="!nwcInput.trim() || isConnecting"
@click="handleConnectNWC"
>
{{ isConnecting ? 'CONNECTING...' : 'CONNECT NWC' }}
</button>
</div>
<div class="flex items-center gap-2">
<div class="flex-1 border-t border-border" />
<span class="font-mono text-[8px] text-text-muted">OR</span>
<div class="flex-1 border-t border-border" />
</div>
<!-- Lightning Address input -->
<div>
<label class="font-mono text-[9px] text-text-muted block mb-1">LIGHTNING ADDRESS (payouts only)</label>
<input
v-model="lnAddressInput"
type="text"
placeholder="you@getalby.com"
class="w-full bg-surface border border-border px-2 py-1.5 font-mono text-[10px] text-text-primary
focus:border-neon-cyan/50 focus:outline-none"
/>
<button
class="w-full mt-1 py-1.5 bg-neon-purple/10 border border-neon-purple/30 text-neon-purple
font-display font-bold text-[9px] tracking-wider
hover:bg-neon-purple/20 transition-all disabled:opacity-50"
:disabled="!lnAddressInput.trim() || isConnecting"
@click="handleConnectLnAddress"
>
{{ isConnecting ? 'CONNECTING...' : 'SET ADDRESS' }}
</button>
</div>
<div v-if="connectError" class="text-center">
<p class="font-mono text-[9px] text-ko">{{ connectError }}</p>
</div>
<button
class="w-full py-1 font-mono text-[9px] text-text-muted hover:text-text-secondary transition-colors"
@click="isExpanded = false"
>
cancel
</button>
</div>
</div>
</template>