- Introduce a new config module to manage Nostr relays, admin pubkeys, and API settings. - Update components to utilize the centralized config instead of environment variables directly. - Refactor relevant files to improve maintainability and reduce reliance on environment variables.
163 lines
No EOL
4.7 KiB
Vue
163 lines
No EOL
4.7 KiB
Vue
<!-- eslint-disable vue/multi-word-component-names -->
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Input } from '@/components/ui/input'
|
|
import { Label } from '@/components/ui/label'
|
|
import QRCode from 'qrcode'
|
|
import { config } from '@/lib/config'
|
|
|
|
interface Props {
|
|
event: {
|
|
id: string
|
|
name: string
|
|
price_per_ticket: number
|
|
currency: string
|
|
}
|
|
isOpen: boolean
|
|
}
|
|
|
|
interface Emits {
|
|
(e: 'update:isOpen', value: boolean): void
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
const emit = defineEmits<Emits>()
|
|
|
|
const name = ref('')
|
|
const email = ref('')
|
|
const isLoading = ref(false)
|
|
const paymentHash = ref('')
|
|
const paymentRequest = ref('')
|
|
const qrCode = ref('')
|
|
const error = ref('')
|
|
|
|
async function generateQRCode(bolt11: string) {
|
|
try {
|
|
qrCode.value = await QRCode.toDataURL(`lightning:${bolt11}`)
|
|
} catch (err) {
|
|
console.error('Failed to generate QR code:', err)
|
|
}
|
|
}
|
|
|
|
async function handleSubmit() {
|
|
if (!name.value || !email.value) {
|
|
error.value = 'Please fill out all fields'
|
|
return
|
|
}
|
|
|
|
isLoading.value = true
|
|
error.value = ''
|
|
|
|
const apiUrl = `${config.api.baseUrl}/events/api/v1/tickets/${props.event.id}/${encodeURIComponent(name.value)}/${encodeURIComponent(email.value)}`
|
|
console.log('Calling API:', apiUrl)
|
|
|
|
try {
|
|
const response = await fetch(apiUrl, {
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'X-API-KEY': config.api.key
|
|
}
|
|
})
|
|
|
|
console.log('Response status:', response.status)
|
|
const responseText = await response.text()
|
|
console.log('Response body:', responseText)
|
|
|
|
if (!response.ok) {
|
|
let errorMessage = 'Failed to generate payment request'
|
|
try {
|
|
const errorData = JSON.parse(responseText)
|
|
errorMessage = errorData.detail || errorMessage
|
|
} catch (e) {
|
|
console.error('Failed to parse error response:', e)
|
|
}
|
|
throw new Error(errorMessage)
|
|
}
|
|
|
|
let data
|
|
try {
|
|
data = JSON.parse(responseText)
|
|
} catch (e) {
|
|
console.error('Failed to parse response as JSON:', e)
|
|
throw new Error('Invalid response format from server')
|
|
}
|
|
|
|
if (!data.payment_hash || !data.payment_request) {
|
|
console.error('Invalid response data:', data)
|
|
throw new Error('Invalid payment data received')
|
|
}
|
|
|
|
paymentHash.value = data.payment_hash
|
|
paymentRequest.value = data.payment_request
|
|
await generateQRCode(data.payment_request)
|
|
} catch (err) {
|
|
console.error('Error generating ticket:', err)
|
|
error.value = err instanceof Error ? err.message : 'An error occurred while processing your request'
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
function handleOpenLightningWallet() {
|
|
if (paymentRequest.value) {
|
|
window.location.href = `lightning:${paymentRequest.value}`
|
|
}
|
|
}
|
|
|
|
function handleClose() {
|
|
emit('update:isOpen', false)
|
|
// Reset form state
|
|
name.value = ''
|
|
email.value = ''
|
|
paymentHash.value = ''
|
|
paymentRequest.value = ''
|
|
qrCode.value = ''
|
|
error.value = ''
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Dialog :open="isOpen" @update:open="handleClose">
|
|
<DialogContent class="sm:max-w-[425px]">
|
|
<DialogHeader>
|
|
<DialogTitle>Purchase Ticket</DialogTitle>
|
|
<DialogDescription>
|
|
Purchase a ticket for {{ event.name }} for {{ event.price_per_ticket }} {{ event.currency }}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div v-if="!paymentHash" class="grid gap-4 py-4">
|
|
<div class="grid gap-2">
|
|
<Label for="name">Name</Label>
|
|
<Input id="name" v-model="name" placeholder="Enter your name" :disabled="isLoading" />
|
|
</div>
|
|
<div class="grid gap-2">
|
|
<Label for="email">Email</Label>
|
|
<Input id="email" v-model="email" type="email" placeholder="Enter your email" :disabled="isLoading" />
|
|
</div>
|
|
<div v-if="error" class="text-sm text-destructive">
|
|
{{ error }}
|
|
</div>
|
|
</div>
|
|
|
|
<div v-else class="py-4 flex flex-col items-center gap-4">
|
|
<img :src="qrCode" alt="Lightning payment QR code" class="w-64 h-64" />
|
|
<div class="text-center space-y-2">
|
|
<p class="text-sm text-muted-foreground">Scan with your Lightning wallet to pay</p>
|
|
<Button variant="outline" @click="handleOpenLightningWallet">
|
|
Open in Lightning Wallet
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="!paymentHash" class="flex justify-end">
|
|
<Button type="submit" :disabled="isLoading" @click="handleSubmit">
|
|
<span v-if="isLoading" class="animate-spin mr-2">⚡</span>
|
|
Continue to Payment
|
|
</Button>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</template> |