idconvert/frontend/app/components/pricing/PurchaseModal.vue

82 lines
3.5 KiB
Vue

<script setup>
const ui = useUiStore()
const auth = useAuthStore()
const purchasing = ref(null)
const success = ref(false)
const packs = [
{ id: 'starter', name: 'Starter', price: '$19', credits: 5, perCredit: '$3.80', popular: false },
{ id: 'studio', name: 'Studio', price: '$59', credits: 20, perCredit: '$2.95', popular: true },
{ id: 'agency', name: 'Agency', price: '$149', credits: 60, perCredit: '$2.48', popular: false },
]
async function handlePurchase(packId) {
purchasing.value = packId
const { paymentService } = await import('../../../services/paymentService.js')
const result = await paymentService.completePurchase(packId)
auth.refreshBalance(result.new_balance)
purchasing.value = null
success.value = true
setTimeout(() => { ui.closePurchaseModal(); success.value = false }, 2000)
}
</script>
<template>
<Teleport to="body">
<div class="fixed inset-0 bg-black/40 flex items-center justify-center z-[100] p-4" @click.self="ui.closePurchaseModal()">
<div class="bg-white rounded-xl p-8 w-full max-w-2xl shadow-xl">
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-bold text-gray-900">Buy credits</h2>
<button @click="ui.closePurchaseModal()" class="text-gray-400 hover:text-gray-600 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- Success state -->
<div v-if="success" class="text-center py-10">
<div class="w-14 h-14 rounded-full bg-green-50 flex items-center justify-center mx-auto mb-4">
<svg class="w-7 h-7 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 13l4 4L19 7" />
</svg>
</div>
<p class="font-semibold text-gray-900 text-lg">Credits added!</p>
<p class="text-sm text-gray-500 mt-1">New balance: {{ auth.creditsBalance }} credits</p>
</div>
<!-- Pack cards -->
<div v-else>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div
v-for="pack in packs"
:key="pack.id"
:class="['relative border rounded-xl p-6 flex flex-col gap-3', pack.popular ? 'border-[#1a56db] border-2' : 'border-gray-200']"
>
<span v-if="pack.popular" class="absolute -top-3 right-4 bg-[#1a56db] text-white text-xs font-semibold px-3 py-0.5 rounded-full">
Popular
</span>
<h3 class="text-base font-bold text-gray-900">{{ pack.name }}</h3>
<div class="text-3xl font-bold text-gray-900">{{ pack.price }}</div>
<div class="text-sm text-gray-500">{{ pack.credits }} credits</div>
<div class="text-xs text-gray-400">{{ pack.perCredit }} each</div>
<BaseButton
variant="primary"
full-width
:loading="purchasing === pack.id"
@click="handlePurchase(pack.id)"
>
Get {{ pack.name }}
</BaseButton>
</div>
</div>
<p class="text-xs text-gray-400 text-center mt-4">Credits never expire. Use them at your own pace.</p>
</div>
</div>
</div>
</Teleport>
</template>