60 lines
1.8 KiB
JavaScript
60 lines
1.8 KiB
JavaScript
import { userService } from './userService.js'
|
|
|
|
let _stripe = null
|
|
|
|
async function getStripe() {
|
|
if (_stripe) return _stripe
|
|
const config = useRuntimeConfig()
|
|
const key = config.public.stripePublishableKey
|
|
if (!key) throw new Error('Stripe publishable key not configured')
|
|
const { loadStripe } = await import('@stripe/stripe-js')
|
|
_stripe = await loadStripe(key)
|
|
return _stripe
|
|
}
|
|
|
|
export const paymentService = {
|
|
/**
|
|
* Create a Stripe PaymentIntent via the backend and return the client_secret.
|
|
* pack: 'starter' | 'studio' | 'agency'
|
|
*/
|
|
async createPaymentIntent(pack) {
|
|
const config = useRuntimeConfig()
|
|
const token = userService.getToken()
|
|
const res = await fetch(`${config.public.apiBase}/api/payments/create-intent`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
},
|
|
body: JSON.stringify({ pack }),
|
|
})
|
|
if (!res.ok) {
|
|
const err = await res.json()
|
|
throw new Error(err.message || 'Failed to create payment intent')
|
|
}
|
|
return res.json()
|
|
},
|
|
|
|
/**
|
|
* Mount Stripe Elements into the given DOM element and confirm payment.
|
|
* Returns a promise that resolves when the payment is confirmed.
|
|
*/
|
|
async mountAndConfirm(mountElement, clientSecret) {
|
|
const stripe = await getStripe()
|
|
const elements = stripe.elements({ clientSecret })
|
|
const paymentElement = elements.create('payment')
|
|
paymentElement.mount(mountElement)
|
|
|
|
return {
|
|
elements,
|
|
confirm: async (returnUrl) => {
|
|
const { error } = await stripe.confirmPayment({
|
|
elements,
|
|
confirmParams: { return_url: returnUrl },
|
|
})
|
|
if (error) throw new Error(error.message)
|
|
},
|
|
}
|
|
},
|
|
}
|