feat(ui): peer requests confirm via modal with optional message

Request-to-Peer (Federation Discover modal + Web5 Node Visibility list)
no longer fires instantly: a BaseModal confirm shows the target, an
optional 280-char message (handshake.connect already carried it), and
Send/Cancel with the standard orange CTA.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-07-14 09:28:21 -04:00
co-authored by Claude Fable 5
parent 9471d3727f
commit e113a2560e
3 changed files with 114 additions and 10 deletions
@@ -100,12 +100,21 @@
</div>
</div>
</Transition>
<PeerRequestModal
:show="requestTarget !== null"
:target-label="requestTarget?.label ?? ''"
:sending="sendingTo !== null && sendingTo === requestTarget?.target"
@send="confirmRequest"
@cancel="requestTarget = null"
/>
</Teleport>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { rpcClient, type PendingPeerRequest } from '@/api/rpc-client'
import PeerRequestModal from '@/components/federation/PeerRequestModal.vue'
interface DiscoverableNode {
nostr_pubkey: string
@@ -156,22 +165,33 @@ async function refresh() {
}
}
async function sendTo(node: DiscoverableNode) {
await sendInternal(node.nostr_pubkey)
// Request confirmation modal: peer requests always offer an optional
// message before anything is sent (Request/Cancel).
const requestTarget = ref<{ target: string; label: string; clearManual: boolean } | null>(null)
function sendTo(node: DiscoverableNode) {
requestTarget.value = { target: node.nostr_pubkey, label: shortNpub(node.nostr_npub), clearManual: false }
}
async function sendDirect() {
function sendDirect() {
const v = manualNpub.value.trim()
if (!v) return
await sendInternal(v)
manualNpub.value = ''
requestTarget.value = { target: v, label: v.length > 21 ? `${v.slice(0, 12)}${v.slice(-6)}` : v, clearManual: true }
}
async function sendInternal(target: string) {
async function confirmRequest(message: string | undefined) {
const req = requestTarget.value
if (!req) return
await sendInternal(req.target, message)
if (req.clearManual) manualNpub.value = ''
requestTarget.value = null
}
async function sendInternal(target: string, message?: string) {
sendingTo.value = target
error.value = ''
try {
await rpcClient.handshakeConnect(target)
await rpcClient.handshakeConnect(target, message)
emit('sent')
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Send failed'