Implement multi-step registration process: Add step indicators, error handling, and payment processing for membership registration. Enhance form validation and user feedback with success and error messages. Refactor state management for improved clarity and maintainability.
This commit is contained in:
parent
a88aa62198
commit
2ca290d6e0
22 changed files with 1994 additions and 213 deletions
158
app/composables/useHelcimPay.js
Normal file
158
app/composables/useHelcimPay.js
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
// HelcimPay.js integration composable
|
||||
export const useHelcimPay = () => {
|
||||
let checkoutToken = null
|
||||
let secretToken = null
|
||||
|
||||
// Initialize HelcimPay.js session
|
||||
const initializeHelcimPay = async (customerId, customerCode, amount = 0) => {
|
||||
try {
|
||||
const response = await $fetch('/api/helcim/initialize-payment', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
customerId,
|
||||
customerCode,
|
||||
amount
|
||||
}
|
||||
})
|
||||
|
||||
if (response.success) {
|
||||
checkoutToken = response.checkoutToken
|
||||
secretToken = response.secretToken
|
||||
return true
|
||||
}
|
||||
|
||||
throw new Error('Failed to initialize payment session')
|
||||
} catch (error) {
|
||||
console.error('Payment initialization error:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Show payment modal
|
||||
const showPaymentModal = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!checkoutToken) {
|
||||
reject(new Error('Payment not initialized. Call initializeHelcimPay first.'))
|
||||
return
|
||||
}
|
||||
|
||||
// Load HelcimPay.js modal script
|
||||
if (!window.appendHelcimPayIframe) {
|
||||
console.log('HelcimPay script not loaded, loading now...')
|
||||
const script = document.createElement('script')
|
||||
script.src = 'https://secure.helcim.app/helcim-pay/services/start.js'
|
||||
script.async = true
|
||||
script.onload = () => {
|
||||
console.log('HelcimPay script loaded successfully!')
|
||||
console.log('Available functions:', Object.keys(window).filter(key => key.includes('Helcim') || key.includes('helcim')))
|
||||
console.log('appendHelcimPayIframe available:', typeof window.appendHelcimPayIframe)
|
||||
openModal(resolve, reject)
|
||||
}
|
||||
script.onerror = () => {
|
||||
reject(new Error('Failed to load HelcimPay.js'))
|
||||
}
|
||||
document.head.appendChild(script)
|
||||
} else {
|
||||
console.log('HelcimPay script already loaded, calling openModal')
|
||||
openModal(resolve, reject)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Open the payment modal
|
||||
const openModal = (resolve, reject) => {
|
||||
try {
|
||||
console.log('Trying to open modal with checkoutToken:', checkoutToken)
|
||||
|
||||
if (typeof window.appendHelcimPayIframe === 'function') {
|
||||
// Set up event listener for HelcimPay.js responses
|
||||
const helcimPayJsIdentifierKey = 'helcim-pay-js-' + checkoutToken
|
||||
|
||||
const handleHelcimPayEvent = (event) => {
|
||||
console.log('Received window message:', event.data)
|
||||
|
||||
if (event.data.eventName === helcimPayJsIdentifierKey) {
|
||||
console.log('HelcimPay event received:', event.data)
|
||||
|
||||
// Remove event listener to prevent multiple responses
|
||||
window.removeEventListener('message', handleHelcimPayEvent)
|
||||
|
||||
if (event.data.eventStatus === 'SUCCESS') {
|
||||
console.log('Payment success:', event.data.eventMessage)
|
||||
|
||||
// Parse the JSON string eventMessage
|
||||
let paymentData
|
||||
try {
|
||||
paymentData = JSON.parse(event.data.eventMessage)
|
||||
console.log('Parsed payment data:', paymentData)
|
||||
} catch (parseError) {
|
||||
console.error('Failed to parse eventMessage:', parseError)
|
||||
reject(new Error('Invalid payment response format'))
|
||||
return
|
||||
}
|
||||
|
||||
// Extract transaction details from nested data structure
|
||||
const transactionData = paymentData.data?.data || {}
|
||||
console.log('Transaction data:', transactionData)
|
||||
|
||||
resolve({
|
||||
success: true,
|
||||
transactionId: transactionData.transactionId,
|
||||
cardToken: transactionData.cardToken,
|
||||
cardLast4: transactionData.cardNumber ? transactionData.cardNumber.slice(-4) : undefined,
|
||||
cardType: transactionData.cardType || 'unknown'
|
||||
})
|
||||
} else if (event.data.eventStatus === 'ABORTED') {
|
||||
console.log('Payment aborted:', event.data.eventMessage)
|
||||
reject(new Error(event.data.eventMessage || 'Payment failed'))
|
||||
} else if (event.data.eventStatus === 'HIDE') {
|
||||
console.log('Modal closed without completion')
|
||||
reject(new Error('Payment cancelled by user'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add event listener
|
||||
window.addEventListener('message', handleHelcimPayEvent)
|
||||
|
||||
// Open the HelcimPay iframe modal
|
||||
console.log('Calling appendHelcimPayIframe with token:', checkoutToken)
|
||||
window.appendHelcimPayIframe(checkoutToken, true)
|
||||
console.log('appendHelcimPayIframe called, waiting for window messages...')
|
||||
|
||||
// Add timeout to clean up if no response
|
||||
setTimeout(() => {
|
||||
console.log('60 seconds passed, cleaning up event listener...')
|
||||
window.removeEventListener('message', handleHelcimPayEvent)
|
||||
reject(new Error('Payment timeout - no response received'))
|
||||
}, 60000)
|
||||
} else {
|
||||
reject(new Error('appendHelcimPayIframe function not available'))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error opening modal:', error)
|
||||
reject(error)
|
||||
}
|
||||
}
|
||||
|
||||
// Process payment verification
|
||||
const verifyPayment = async () => {
|
||||
try {
|
||||
return await showPaymentModal()
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup tokens
|
||||
const cleanup = () => {
|
||||
checkoutToken = null
|
||||
secretToken = null
|
||||
}
|
||||
|
||||
return {
|
||||
initializeHelcimPay,
|
||||
verifyPayment,
|
||||
cleanup
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue