752 lines
No EOL
28 KiB
Vue
752 lines
No EOL
28 KiB
Vue
<template>
|
|
<div>
|
|
<!-- Page Header -->
|
|
<PageHeader
|
|
title="Join"
|
|
subtitle="Become a member of our cooperative community and start building the future of game development together"
|
|
theme="blue"
|
|
size="large"
|
|
/>
|
|
|
|
<!-- Membership Sign Up Form -->
|
|
<section class="py-20 bg-white dark:bg-gray-900">
|
|
<UContainer class="max-w-4xl">
|
|
<div class="text-center mb-12">
|
|
<h2 class="text-3xl font-bold text-blue-600 dark:text-blue-400 mb-4">
|
|
Membership Sign Up
|
|
</h2>
|
|
<p class="text-gray-600 dark:text-gray-300">
|
|
Choose your circle and contribution level to get started
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Step Indicators -->
|
|
<div class="flex justify-center mb-8">
|
|
<div class="flex items-center space-x-4">
|
|
<div class="flex items-center">
|
|
<div
|
|
:class="[
|
|
'w-10 h-10 rounded-full flex items-center justify-center font-semibold',
|
|
currentStep >= 1
|
|
? 'bg-blue-500 text-white'
|
|
: 'bg-gray-200 text-gray-500'
|
|
]"
|
|
>
|
|
1
|
|
</div>
|
|
<span class="ml-2 font-medium" :class="currentStep === 1 ? 'text-blue-600' : 'text-gray-500'">
|
|
Information
|
|
</span>
|
|
</div>
|
|
|
|
<div v-if="needsPayment" class="w-16 h-1 bg-gray-200">
|
|
<div
|
|
class="h-full bg-blue-500 transition-all"
|
|
:style="{ width: currentStep >= 2 ? '100%' : '0%' }"
|
|
/>
|
|
</div>
|
|
|
|
<div v-if="needsPayment" class="flex items-center">
|
|
<div
|
|
:class="[
|
|
'w-10 h-10 rounded-full flex items-center justify-center font-semibold',
|
|
currentStep >= 2
|
|
? 'bg-blue-500 text-white'
|
|
: 'bg-gray-200 text-gray-500'
|
|
]"
|
|
>
|
|
2
|
|
</div>
|
|
<span class="ml-2 font-medium" :class="currentStep === 2 ? 'text-blue-600' : 'text-gray-500'">
|
|
Payment
|
|
</span>
|
|
</div>
|
|
|
|
<div class="w-16 h-1 bg-gray-200">
|
|
<div
|
|
class="h-full bg-blue-500 transition-all"
|
|
:style="{ width: currentStep >= 3 ? '100%' : '0%' }"
|
|
/>
|
|
</div>
|
|
|
|
<div class="flex items-center">
|
|
<div
|
|
:class="[
|
|
'w-10 h-10 rounded-full flex items-center justify-center font-semibold',
|
|
currentStep >= 3
|
|
? 'bg-blue-500 text-white'
|
|
: 'bg-gray-200 text-gray-500'
|
|
]"
|
|
>
|
|
<span v-if="needsPayment">3</span>
|
|
<span v-else>2</span>
|
|
</div>
|
|
<span class="ml-2 font-medium" :class="currentStep === 3 ? 'text-blue-600' : 'text-gray-500'">
|
|
Confirmation
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Error Message -->
|
|
<div v-if="errorMessage" class="mb-6">
|
|
<UAlert color="red" :title="errorMessage" />
|
|
</div>
|
|
|
|
<!-- Step 1: Information -->
|
|
<div v-if="currentStep === 1" class="bg-white dark:bg-gray-800 rounded-2xl p-8 shadow-xl border border-blue-200 dark:border-blue-800">
|
|
<UForm :state="form" class="space-y-8" @submit="handleSubmit">
|
|
<!-- Personal Information -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<UFormField label="Full Name" name="name" required>
|
|
<UInput
|
|
v-model="form.name"
|
|
placeholder="Enter your full name"
|
|
size="xl"
|
|
class="w-full"
|
|
/>
|
|
</UFormField>
|
|
|
|
<UFormField label="Email Address" name="email" required>
|
|
<UInput
|
|
v-model="form.email"
|
|
type="email"
|
|
size="xl"
|
|
class="w-full"
|
|
placeholder="Enter your email address"
|
|
/>
|
|
</UFormField>
|
|
</div>
|
|
|
|
<!-- Circle Selection -->
|
|
<div>
|
|
<h3 class="text-lg font-semibold mb-4">Choose Your Circle</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<label
|
|
v-for="option in circleOptions"
|
|
:key="option.value"
|
|
class="flex flex-col p-6 rounded-lg border-2 cursor-pointer transition-all hover:shadow-md"
|
|
:class="
|
|
form.circle === option.value
|
|
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
|
|
: 'border-gray-200 dark:border-gray-700 hover:border-blue-300'
|
|
"
|
|
>
|
|
<input
|
|
v-model="form.circle"
|
|
type="radio"
|
|
:value="option.value"
|
|
name="circle"
|
|
class="mb-3"
|
|
>
|
|
<div class="font-medium text-lg mb-2">{{ option.label }}</div>
|
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
{{ option.description }}
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Contribution Selection -->
|
|
<div>
|
|
<h3 class="text-lg font-semibold mb-4">Choose Your Monthly Contribution</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
<label
|
|
v-for="option in contributionOptions"
|
|
:key="option.value"
|
|
class="flex flex-col p-6 rounded-lg border-2 cursor-pointer transition-all hover:shadow-md"
|
|
:class="
|
|
form.contributionTier === option.value
|
|
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
|
|
: 'border-gray-200 dark:border-gray-700 hover:border-blue-300'
|
|
"
|
|
>
|
|
<input
|
|
v-model="form.contributionTier"
|
|
type="radio"
|
|
:value="option.value"
|
|
name="contributionTier"
|
|
class="mb-3"
|
|
>
|
|
<div class="font-medium text-lg mb-2">{{ option.label }}</div>
|
|
<ul class="text-sm text-gray-600 dark:text-gray-400 space-y-1">
|
|
<li v-for="feature in option.features.slice(0, 2)" :key="feature">
|
|
• {{ feature }}
|
|
</li>
|
|
</ul>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<div class="flex justify-center pt-6">
|
|
<UButton
|
|
type="submit"
|
|
:loading="isSubmitting"
|
|
:disabled="!isFormValid"
|
|
size="xl"
|
|
class="px-12"
|
|
>
|
|
{{ needsPayment ? 'Continue to Payment' : 'Complete Registration' }}
|
|
</UButton>
|
|
</div>
|
|
</UForm>
|
|
</div>
|
|
|
|
<!-- Step 2: Payment -->
|
|
<div v-if="currentStep === 2" class="bg-white dark:bg-gray-800 rounded-2xl p-8 shadow-xl border border-blue-200 dark:border-blue-800">
|
|
<div class="mb-6">
|
|
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">
|
|
Payment Information
|
|
</h3>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
You're signing up for the {{ selectedTier.label }} plan
|
|
</p>
|
|
<p class="text-lg font-semibold text-blue-600 dark:text-blue-400 mt-2">
|
|
${{ selectedTier.amount }} CAD / month
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Payment Instructions -->
|
|
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6 mb-6">
|
|
<p class="text-gray-700 dark:text-gray-300">
|
|
Click "Complete Payment" below to open the secure payment modal and verify your payment method.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="flex justify-between pt-6">
|
|
<UButton
|
|
variant="outline"
|
|
size="lg"
|
|
@click="goBack"
|
|
:disabled="isSubmitting"
|
|
>
|
|
Back
|
|
</UButton>
|
|
<UButton
|
|
size="lg"
|
|
:loading="isSubmitting"
|
|
@click="processPayment"
|
|
>
|
|
Complete Payment
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 3: Confirmation -->
|
|
<div v-if="currentStep === 3" class="bg-white dark:bg-gray-800 rounded-2xl p-8 shadow-xl border border-blue-200 dark:border-blue-800">
|
|
<div class="text-center">
|
|
<div class="w-20 h-20 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-6">
|
|
<svg class="w-10 h-10 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
</svg>
|
|
</div>
|
|
|
|
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
|
|
Welcome to Ghost Guild!
|
|
</h3>
|
|
|
|
<div v-if="successMessage" class="mb-6">
|
|
<UAlert color="green" :title="successMessage" />
|
|
</div>
|
|
|
|
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6 mb-6 text-left">
|
|
<h4 class="font-semibold mb-3">Membership Details:</h4>
|
|
<dl class="space-y-2">
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-600 dark:text-gray-400">Name:</dt>
|
|
<dd class="font-medium">{{ form.name }}</dd>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-600 dark:text-gray-400">Email:</dt>
|
|
<dd class="font-medium">{{ form.email }}</dd>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-600 dark:text-gray-400">Circle:</dt>
|
|
<dd class="font-medium capitalize">{{ form.circle }}</dd>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-600 dark:text-gray-400">Contribution:</dt>
|
|
<dd class="font-medium">{{ selectedTier.label }}</dd>
|
|
</div>
|
|
<div v-if="customerCode" class="flex justify-between">
|
|
<dt class="text-gray-600 dark:text-gray-400">Member ID:</dt>
|
|
<dd class="font-medium">{{ customerCode }}</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400 mb-4">
|
|
We've sent a confirmation email to {{ form.email }} with your membership details.
|
|
</p>
|
|
|
|
<div class="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 mb-8">
|
|
<p class="text-blue-800 dark:text-blue-200 text-center">
|
|
You will be automatically redirected to your dashboard in a few seconds...
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
|
<UButton
|
|
to="/member/dashboard"
|
|
size="lg"
|
|
class="px-8"
|
|
>
|
|
Go to Dashboard Now
|
|
</UButton>
|
|
<UButton
|
|
variant="outline"
|
|
size="lg"
|
|
@click="resetForm"
|
|
>
|
|
Register Another Member
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</UContainer>
|
|
</section>
|
|
|
|
<!-- Membership Benefits -->
|
|
<section class="py-20 bg-gray-50 dark:bg-gray-800">
|
|
<UContainer>
|
|
<div class="text-center mb-12">
|
|
<h2 class="text-3xl font-bold text-blue-600 dark:text-blue-400 mb-4">
|
|
Membership Benefits
|
|
</h2>
|
|
<p class="text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Join our community and unlock these amazing benefits.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
<div class="bg-white dark:bg-gray-900 rounded-xl p-8 shadow-lg">
|
|
<div class="w-12 h-12 bg-blue-100 dark:bg-blue-900/30 rounded-lg flex items-center justify-center mb-6">
|
|
<div class="w-6 h-6 bg-blue-500 rounded" />
|
|
</div>
|
|
<h3 class="text-xl font-semibold mb-4 text-gray-900 dark:text-white">
|
|
Community Access
|
|
</h3>
|
|
<div class="space-y-2 mb-4">
|
|
<div class="h-1 bg-blue-500 rounded-full w-full" />
|
|
<div class="h-1 bg-blue-300 rounded-full w-3/4" />
|
|
<div class="h-1 bg-blue-200 rounded-full w-1/2" />
|
|
</div>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Access to forums and resources.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-gray-900 rounded-xl p-8 shadow-lg">
|
|
<div class="w-12 h-12 bg-emerald-100 dark:bg-emerald-900/30 rounded-lg flex items-center justify-center mb-6">
|
|
<div class="w-6 h-6 bg-emerald-500" style="clip-path: polygon(50% 0%, 0% 100%, 100% 100%)" />
|
|
</div>
|
|
<h3 class="text-xl font-semibold mb-4 text-gray-900 dark:text-white">
|
|
Learning Resources
|
|
</h3>
|
|
<div class="space-y-2 mb-4">
|
|
<div class="h-1 bg-emerald-500 rounded-full w-full" />
|
|
<div class="h-1 bg-emerald-300 rounded-full w-2/3" />
|
|
<div class="h-1 bg-emerald-200 rounded-full w-3/4" />
|
|
</div>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Educational content and workshops.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-gray-900 rounded-xl p-8 shadow-lg md:col-span-2 lg:col-span-1">
|
|
<div class="w-12 h-12 bg-purple-100 dark:bg-purple-900/30 rounded-lg flex items-center justify-center mb-6">
|
|
<div class="w-6 h-6 bg-purple-500 rounded-full" />
|
|
</div>
|
|
<h3 class="text-xl font-semibold mb-4 text-gray-900 dark:text-white">
|
|
Network & Support
|
|
</h3>
|
|
<div class="space-y-2 mb-4">
|
|
<div class="h-1 bg-purple-500 rounded-full w-5/6" />
|
|
<div class="h-1 bg-purple-300 rounded-full w-full" />
|
|
<div class="h-1 bg-purple-200 rounded-full w-2/3" />
|
|
</div>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Connect with like-minded professionals.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</UContainer>
|
|
</section>
|
|
|
|
<!-- How to Join -->
|
|
<section class="py-20 bg-white dark:bg-gray-900">
|
|
<UContainer>
|
|
<div class="text-center mb-16">
|
|
<h2 class="text-3xl font-bold text-blue-600 dark:text-blue-400 mb-4">
|
|
How to Join
|
|
</h2>
|
|
<p class="text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Follow these simple steps to become a member.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="max-w-4xl mx-auto">
|
|
<div class="space-y-12">
|
|
<div class="flex flex-col md:flex-row items-center gap-8">
|
|
<div class="flex-shrink-0">
|
|
<div class="w-16 h-16 bg-blue-500 rounded-full flex items-center justify-center text-white font-bold text-xl">
|
|
1
|
|
</div>
|
|
</div>
|
|
<div class="flex-1 text-center md:text-left">
|
|
<div class="space-y-3 mb-4">
|
|
<div class="h-2 bg-blue-500 rounded-full max-w-md mx-auto md:mx-0" />
|
|
<div class="h-2 bg-blue-300 rounded-full max-w-sm mx-auto md:mx-0" />
|
|
<div class="h-2 bg-blue-200 rounded-full max-w-xs mx-auto md:mx-0" />
|
|
</div>
|
|
<h3 class="text-xl font-semibold mb-2 text-gray-900 dark:text-white">
|
|
Choose Your Circle
|
|
</h3>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Select the circle that matches your interests.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col md:flex-row items-center gap-8">
|
|
<div class="flex-shrink-0">
|
|
<div class="w-16 h-16 bg-blue-500 rounded-full flex items-center justify-center text-white font-bold text-xl">
|
|
2
|
|
</div>
|
|
</div>
|
|
<div class="flex-1 text-center md:text-left">
|
|
<div class="space-y-3 mb-4">
|
|
<div class="h-2 bg-blue-500 rounded-full max-w-lg mx-auto md:mx-0" />
|
|
<div class="h-2 bg-blue-300 rounded-full max-w-md mx-auto md:mx-0" />
|
|
<div class="h-2 bg-blue-200 rounded-full max-w-sm mx-auto md:mx-0" />
|
|
</div>
|
|
<h3 class="text-xl font-semibold mb-2 text-gray-900 dark:text-white">
|
|
Set Your Contribution
|
|
</h3>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Choose a contribution level based on your means.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col md:flex-row items-center gap-8">
|
|
<div class="flex-shrink-0">
|
|
<div class="w-16 h-16 bg-blue-500 rounded-full flex items-center justify-center text-white font-bold text-xl">
|
|
3
|
|
</div>
|
|
</div>
|
|
<div class="flex-1 text-center md:text-left">
|
|
<div class="space-y-3 mb-4">
|
|
<div class="h-2 bg-blue-500 rounded-full max-w-sm mx-auto md:mx-0" />
|
|
<div class="h-2 bg-blue-300 rounded-full max-w-lg mx-auto md:mx-0" />
|
|
<div class="h-2 bg-blue-200 rounded-full max-w-md mx-auto md:mx-0" />
|
|
</div>
|
|
<h3 class="text-xl font-semibold mb-2 text-gray-900 dark:text-white">
|
|
Complete Registration
|
|
</h3>
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Finalize your membership and start participating.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</UContainer>
|
|
</section>
|
|
|
|
<!-- Ready to Join CTA -->
|
|
<section class="py-20 bg-blue-50 dark:bg-blue-900/20">
|
|
<UContainer>
|
|
<div class="text-center max-w-3xl mx-auto">
|
|
<h2 class="text-3xl font-bold text-blue-600 dark:text-blue-400 mb-8">
|
|
Ready to Join?
|
|
</h2>
|
|
|
|
<div class="flex flex-col md:flex-row items-center justify-center gap-8 mb-8">
|
|
<div class="bg-white dark:bg-gray-800 rounded-2xl p-8 shadow-lg border border-blue-200 dark:border-blue-800 flex-1 max-w-md">
|
|
<div class="text-2xl font-bold text-blue-600 dark:text-blue-400 mb-2">
|
|
Start Today
|
|
</div>
|
|
<p class="text-gray-600 dark:text-gray-300 mb-4">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
</p>
|
|
<div class="space-y-2">
|
|
<div class="h-1 bg-blue-500 rounded-full" />
|
|
<div class="h-1 bg-blue-300 rounded-full w-3/4" />
|
|
<div class="h-1 bg-blue-200 rounded-full w-1/2" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col items-center gap-4">
|
|
<UButton
|
|
to="#membership-form"
|
|
size="xl"
|
|
color="primary"
|
|
class="px-8 py-4"
|
|
>
|
|
Join Now
|
|
</UButton>
|
|
<div class="h-2 bg-blue-500 rounded-full w-32" />
|
|
</div>
|
|
</div>
|
|
|
|
<p class="text-gray-600 dark:text-gray-300">
|
|
Questions? Contact us at <a href="mailto:hello@ghostguild.org" class="text-blue-600 dark:text-blue-400 hover:underline">hello@ghostguild.org</a>
|
|
</p>
|
|
</div>
|
|
</UContainer>
|
|
</section>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { reactive, ref, computed, onMounted, onUnmounted } from 'vue'
|
|
import { getCircleOptions } from '~/config/circles'
|
|
import { getContributionOptions, requiresPayment, getContributionTierByValue } from '~/config/contributions'
|
|
|
|
// Form state
|
|
const form = reactive({
|
|
email: '',
|
|
name: '',
|
|
circle: 'community',
|
|
contributionTier: '15',
|
|
billingAddress: {
|
|
street: '',
|
|
city: '',
|
|
province: '',
|
|
postalCode: '',
|
|
country: 'CA'
|
|
}
|
|
})
|
|
|
|
// UI state
|
|
const isSubmitting = ref(false)
|
|
const currentStep = ref(1) // 1: Info, 2: Billing (paid only), 3: Payment, 4: Confirmation
|
|
const errorMessage = ref('')
|
|
const successMessage = ref('')
|
|
|
|
// Helcim state
|
|
const customerId = ref(null)
|
|
const customerCode = ref(null)
|
|
const subscriptionData = ref(null)
|
|
const paymentToken = ref(null)
|
|
|
|
// Circle options from central config
|
|
const circleOptions = getCircleOptions()
|
|
|
|
// Contribution options from central config
|
|
const contributionOptions = getContributionOptions()
|
|
|
|
// Initialize composables
|
|
const { initializeHelcimPay, verifyPayment, cleanup: cleanupHelcimPay } = useHelcimPay()
|
|
const { checkMemberStatus } = useAuth()
|
|
|
|
// Form validation
|
|
const isFormValid = computed(() => {
|
|
return form.name && form.email && form.circle && form.contributionTier
|
|
})
|
|
|
|
// Check if payment is required
|
|
const needsPayment = computed(() => {
|
|
return requiresPayment(form.contributionTier)
|
|
})
|
|
|
|
|
|
// Get selected tier info
|
|
const selectedTier = computed(() => {
|
|
return getContributionTierByValue(form.contributionTier)
|
|
})
|
|
|
|
// Step 1: Create customer
|
|
const handleSubmit = async () => {
|
|
if (isSubmitting.value || !isFormValid.value) return
|
|
|
|
isSubmitting.value = true
|
|
errorMessage.value = ''
|
|
|
|
try {
|
|
// Create customer in Helcim
|
|
const response = await $fetch('/api/helcim/customer', {
|
|
method: 'POST',
|
|
body: {
|
|
name: form.name,
|
|
email: form.email,
|
|
circle: form.circle,
|
|
contributionTier: form.contributionTier,
|
|
billingAddress: form.billingAddress
|
|
}
|
|
})
|
|
|
|
if (response.success) {
|
|
console.log('Customer response:', response)
|
|
customerId.value = response.customerId
|
|
customerCode.value = response.customerCode
|
|
|
|
// Token is now set as httpOnly cookie by the server
|
|
// No need to manually set cookie on client side
|
|
|
|
// Move to next step
|
|
if (needsPayment.value) {
|
|
currentStep.value = 2
|
|
// Debug log
|
|
console.log('Customer ID:', customerId.value, 'Customer Code:', customerCode.value)
|
|
// Initialize HelcimPay.js session for card verification
|
|
await initializeHelcimPay(customerId.value, customerCode.value, 0)
|
|
} else {
|
|
// For free tier, create subscription directly
|
|
await createSubscription()
|
|
// Check member status to ensure user is properly authenticated
|
|
await checkMemberStatus()
|
|
|
|
// Automatically redirect to dashboard after a short delay
|
|
setTimeout(() => {
|
|
navigateTo('/member/dashboard')
|
|
}, 3000) // 3 second delay to show success message
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error creating customer:', error)
|
|
errorMessage.value = error.data?.message || 'Failed to create account. Please try again.'
|
|
} finally {
|
|
isSubmitting.value = false
|
|
}
|
|
}
|
|
|
|
// Step 2: Process payment
|
|
const processPayment = async () => {
|
|
if (isSubmitting.value) return
|
|
|
|
console.log('Starting payment process...')
|
|
isSubmitting.value = true
|
|
errorMessage.value = ''
|
|
|
|
try {
|
|
console.log('Calling verifyPayment()...')
|
|
// Verify payment through HelcimPay.js
|
|
const paymentResult = await verifyPayment()
|
|
console.log('Payment result from HelcimPay:', paymentResult)
|
|
|
|
if (paymentResult.success) {
|
|
paymentToken.value = paymentResult.cardToken
|
|
console.log('Payment successful, cardToken:', paymentResult.cardToken)
|
|
|
|
console.log('Calling verify-payment endpoint...')
|
|
// Verify payment on server
|
|
const verifyResult = await $fetch('/api/helcim/verify-payment', {
|
|
method: 'POST',
|
|
body: {
|
|
cardToken: paymentResult.cardToken,
|
|
customerId: customerId.value
|
|
}
|
|
})
|
|
console.log('Payment verification result:', verifyResult)
|
|
|
|
console.log('Calling createSubscription...')
|
|
// Create subscription (don't let subscription errors prevent form progression)
|
|
const subscriptionResult = await createSubscription(paymentResult.cardToken)
|
|
|
|
if (!subscriptionResult || !subscriptionResult.success) {
|
|
console.warn('Subscription creation failed but payment succeeded:', subscriptionResult?.error)
|
|
// Still progress to success page since payment worked
|
|
currentStep.value = 3
|
|
successMessage.value = 'Payment successful! Subscription setup may need manual completion.'
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Payment process error:', error)
|
|
console.error('Error details:', {
|
|
message: error.message,
|
|
statusCode: error.statusCode,
|
|
statusMessage: error.statusMessage,
|
|
data: error.data
|
|
})
|
|
errorMessage.value = error.message || 'Payment verification failed. Please try again.'
|
|
} finally {
|
|
isSubmitting.value = false
|
|
}
|
|
}
|
|
|
|
// Create subscription
|
|
const createSubscription = async (cardToken = null) => {
|
|
try {
|
|
console.log('Creating subscription with:', {
|
|
customerId: customerId.value,
|
|
contributionTier: form.contributionTier,
|
|
cardToken: cardToken ? 'present' : 'null'
|
|
})
|
|
|
|
const response = await $fetch('/api/helcim/subscription', {
|
|
method: 'POST',
|
|
body: {
|
|
customerId: customerId.value,
|
|
customerCode: customerCode.value,
|
|
contributionTier: form.contributionTier,
|
|
cardToken: cardToken
|
|
}
|
|
})
|
|
|
|
console.log('Subscription creation response:', response)
|
|
|
|
if (response.success) {
|
|
subscriptionData.value = response.subscription
|
|
console.log('Moving to step 3 - success!')
|
|
currentStep.value = 3
|
|
successMessage.value = 'Your membership has been activated successfully!'
|
|
|
|
// Check member status to ensure user is properly authenticated
|
|
await checkMemberStatus()
|
|
|
|
// Automatically redirect to dashboard after a short delay
|
|
setTimeout(() => {
|
|
navigateTo('/member/dashboard')
|
|
}, 3000) // 3 second delay to show success message
|
|
} else {
|
|
throw new Error('Subscription creation failed - response not successful')
|
|
}
|
|
} catch (error) {
|
|
console.error('Subscription creation error:', error)
|
|
console.error('Error details:', {
|
|
message: error.message,
|
|
statusCode: error.statusCode,
|
|
statusMessage: error.statusMessage,
|
|
data: error.data
|
|
})
|
|
console.error('Subscription creation completely failed, but payment was successful')
|
|
// Don't throw error - let the calling function handle progression
|
|
return {
|
|
success: false,
|
|
error: error.data?.message || error.message || 'Failed to create subscription'
|
|
}
|
|
}
|
|
}
|
|
|
|
// Go back to previous step
|
|
const goBack = () => {
|
|
if (currentStep.value > 1) {
|
|
currentStep.value--
|
|
errorMessage.value = ''
|
|
}
|
|
}
|
|
|
|
// Reset form
|
|
const resetForm = () => {
|
|
currentStep.value = 1
|
|
customerId.value = null
|
|
customerCode.value = null
|
|
subscriptionData.value = null
|
|
paymentToken.value = null
|
|
errorMessage.value = ''
|
|
successMessage.value = ''
|
|
form.email = ''
|
|
form.name = ''
|
|
form.circle = 'community'
|
|
form.contributionTier = '15'
|
|
}
|
|
|
|
// Cleanup on unmount
|
|
onUnmounted(() => {
|
|
cleanupHelcimPay()
|
|
})
|
|
</script> |