wwww_3node_tenstorrent/src/components/BecomeMember.jsx
2025-07-25 09:29:49 +02:00

527 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from 'react'
import { Button } from '@/components/ui/button.jsx'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card.jsx'
import { Input } from '@/components/ui/input.jsx'
import { Label } from '@/components/ui/label.jsx'
import { Textarea } from '@/components/ui/textarea.jsx'
import { Checkbox } from '@/components/ui/checkbox.jsx'
import { Badge } from '@/components/ui/badge.jsx'
import { Globe, Mail, User, MessageSquare, CheckCircle, AlertCircle, DollarSign } from 'lucide-react'
import { Link } from 'react-router-dom'
import { loadStripe } from '@stripe/stripe-js'
// Make sure to call `loadStripe` outside of a components render to avoid
// recreating the Stripe object on every render.
// This is your publishable key.
const stripePromise = loadStripe('pk_test_TYooMQauvdEDq5XKxTMn5jxK') // Replace with your actual publishable key
function DirectBuy() {
const [currentStep, setCurrentStep] = useState(1)
const [formData, setFormData] = useState({
name: '',
email: '',
country: '',
uniqueNamePart1: '',
uniqueNamePart2: '',
experience: '',
whyInterested: '',
tipsForInfo: '',
newsletter: false,
terms: false
})
const [isSubmitting, setIsSubmitting] = useState(false)
const [submitStatus, setSubmitStatus] = useState(null) // 'success', 'error', or null
const [uniqueNameError, setUniqueNameError] = useState('')
const [uniqueNameValid, setUniqueNameValid] = useState(false)
const handleInputChange = (e) => {
const { id, value, type, checked } = e.target
setFormData(prev => ({
...prev,
[id]: type === 'checkbox' ? checked : value
}))
}
const validateUniqueNamePart = (part) => {
const regex = /^[a-z]{6,}$/
return regex.test(part)
}
const validateStep1 = () => {
const { name, email, uniqueNamePart1, uniqueNamePart2 } = formData
if (!name || !email) {
setSubmitStatus('error')
setUniqueNameValid(false) // Set to false if other required fields are missing
return false
}
let isValid = true
if (!validateUniqueNamePart(uniqueNamePart1)) {
setUniqueNameError('First part must be at least 6 lowercase letters.')
isValid = false
} else if (!validateUniqueNamePart(uniqueNamePart2)) {
setUniqueNameError('Second part must be at least 6 lowercase letters.')
isValid = false
} else {
setUniqueNameError('')
}
setUniqueNameValid(isValid)
if (!isValid) {
setSubmitStatus('error')
return false
}
setSubmitStatus(null)
return true
}
const validateStep2 = () => {
const { terms } = formData
if (!terms) {
setSubmitStatus('error')
return false
}
setSubmitStatus(null)
return true
}
const handleNext = () => {
setSubmitStatus(null) // Clear previous status
if (currentStep === 1 && !validateStep1()) {
return
}
if (currentStep === 2 && !validateStep2()) {
return
}
setCurrentStep(prev => prev + 1)
}
const handlePrev = () => {
setSubmitStatus(null) // Clear previous status
setCurrentStep(prev => prev - 1)
}
const handleBuy = async (e) => {
e.preventDefault()
setIsSubmitting(true)
setSubmitStatus(null)
try {
// Create a Checkout Session on your backend
// Replace with your actual API endpoint
const response = await fetch('https://your-backend.com/create-checkout-session', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: formData.name,
email: formData.email,
country: formData.country,
uniqueName: `${formData.uniqueNamePart1}.${formData.uniqueNamePart2}`,
experience: formData.experience,
whyInterested: formData.whyInterested,
tipsForInfo: formData.tipsForInfo,
newsletter: formData.newsletter,
priceId: 'price_12345', // Replace with your actual Stripe Price ID for $20/month
}),
})
if (!response.ok) {
throw new Error('Failed to create Stripe Checkout Session')
}
const { sessionId } = await response.json()
const stripe = await stripePromise
const { error } = await stripe.redirectToCheckout({
sessionId,
})
if (error) {
console.error('Stripe checkout error:', error)
setSubmitStatus('error')
}
} catch (error) {
console.error('Purchase error:', error)
setSubmitStatus('error')
} finally {
setIsSubmitting(false)
}
}
const renderStepContent = () => {
switch (currentStep) {
case 1:
return (
<>
<CardHeader className="text-center">
<CardTitle className="text-2xl">Step 1: Personal Information</CardTitle>
<CardDescription>
Tell us about yourself and choose your unique identifier.
</CardDescription>
</CardHeader>
<CardContent>
{submitStatus === 'error' && (
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg flex items-center gap-3">
<AlertCircle className="h-5 w-5 text-red-600" />
<div>
<h4 className="font-semibold text-red-800">Validation Error</h4>
<p className="text-red-700">Please fill in all required fields and correct any errors.</p>
</div>
</div>
)}
<div className="space-y-6">
{/* Personal Information */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-slate-900 flex items-center gap-2">
<User className="h-5 w-5" />
Your Details
</h3>
<div className="grid md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="name">Full Name *</Label>
<Input
id="name"
type="text"
value={formData.name}
onChange={handleInputChange}
placeholder="Your full name"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="email">Email Address *</Label>
<Input
id="email"
type="email"
value={formData.email}
onChange={handleInputChange}
placeholder="your@email.com"
required
/>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="country">Country/Region</Label>
<Input
id="country"
type="text"
value={formData.country}
onChange={handleInputChange}
placeholder="Your country or region"
/>
</div>
</div>
{/* Unique Name */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-slate-900 flex items-center gap-2">
<Globe className="h-5 w-5" />
Choose Your Unique Name
</h3>
<p className="text-sm text-slate-600">This will be your unique identifier (e.g., firstpart.secondpart). Each part must be 7 lowercase letters.</p>
<div className="grid md:grid-cols-2 gap-4 items-end">
<div className="space-y-2">
<Label htmlFor="uniqueNamePart1">First Part *</Label>
<Input
id="uniqueNamePart1"
type="text"
value={formData.uniqueNamePart1}
onChange={(e) => {
setFormData(prev => ({ ...prev, uniqueNamePart1: e.target.value.toLowerCase() }))
setUniqueNameError('')
}}
placeholder="at least 6 lowercase letters"
required
className={uniqueNameError && formData.uniqueNamePart1 ? 'border-red-500' : uniqueNameValid && formData.uniqueNamePart1 ? 'border-green-500' : ''}
/>
</div>
<div className="space-y-2">
<Label htmlFor="uniqueNamePart2">Second Part *</Label>
<Input
id="uniqueNamePart2"
type="text"
value={formData.uniqueNamePart2}
onChange={(e) => {
setFormData(prev => ({ ...prev, uniqueNamePart2: e.target.value.toLowerCase() }))
setUniqueNameError('')
}}
placeholder="at least 6 lowercase letters"
required
className={uniqueNameError && formData.uniqueNamePart2 ? 'border-red-500' : uniqueNameValid && formData.uniqueNamePart2 ? 'border-green-500' : ''}
/>
</div>
</div>
{uniqueNameError && <p className="text-red-500 text-sm">{uniqueNameError}</p>}
</div>
<Button type="button" onClick={handleNext} className="w-full bg-blue-600 hover:bg-blue-700 text-lg py-3">
Next: About You & Preferences
</Button>
</div>
</CardContent>
</>
)
case 2:
return (
<>
<CardHeader className="text-center">
<CardTitle className="text-2xl">Step 2: About You & Preferences</CardTitle>
<CardDescription>
Share more about your interests and communication preferences.
</CardDescription>
</CardHeader>
<CardContent>
{submitStatus === 'error' && (
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg flex items-center gap-3">
<AlertCircle className="h-5 w-5 text-red-600" />
<div>
<h4 className="font-semibold text-red-800">Validation Error</h4>
<p className="text-red-700">Please fill in all required fields and agree to the terms.</p>
</div>
</div>
)}
<div className="space-y-6">
{/* Tell Us About Yourself (Optional) */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-slate-900 flex items-center gap-2">
<MessageSquare className="h-5 w-5" />
Tell Us About Yourself (Optional)
</h3>
<div className="space-y-2">
<Label htmlFor="experience">Relevant Experience</Label>
<Textarea
id="experience"
value={formData.experience}
onChange={handleInputChange}
placeholder="Tell us about your background in technology, governance, cooperatives, or related fields..."
rows={4}
/>
</div>
<div className="space-y-2">
<Label htmlFor="whyInterested">Why are you interested in this service? *</Label>
<Textarea
id="whyInterested"
value={formData.whyInterested}
onChange={handleInputChange}
placeholder="What motivates you to join ThreeFold Galaxy Coop? What do you hope to contribute or gain?"
rows={4}
/>
</div>
<div className="space-y-2">
<Label htmlFor="tipsForInfo">Any tips to make info more smooth? (Optional)</Label>
<Textarea
id="tipsForInfo"
value={formData.tipsForInfo}
onChange={handleInputChange}
placeholder="Share any suggestions for improving our information delivery or onboarding process."
rows={4}
/>
</div>
</div>
{/* Preferences */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-slate-900 flex items-center gap-2">
<Mail className="h-5 w-5" />
Communication Preferences
</h3>
<div className="flex items-center space-x-2">
<Checkbox
id="newsletter"
checked={formData.newsletter}
onCheckedChange={(checked) => setFormData(prev => ({ ...prev, newsletter: checked }))}
/>
<Label htmlFor="newsletter" className="text-sm">
I'd like to receive updates about ThreeFold Galaxy Coop's development and launch
</Label>
</div>
</div>
{/* Terms */}
<div className="space-y-4">
<div className="flex items-start space-x-2">
<Checkbox
id="terms"
checked={formData.terms}
onCheckedChange={(checked) => setFormData(prev => ({ ...prev, terms: checked }))}
required
/>
<Label htmlFor="terms" className="text-sm">
I agree to the <Link to="/terms" className="text-blue-600 hover:underline">Terms of Service</Link> and <Link to="/privacy" className="text-blue-600 hover:underline">Privacy Policy</Link> for my ThreeFold Galaxy Coop membership. *
</Label>
</div>
</div>
<div className="flex justify-between gap-4">
<Button type="button" onClick={handlePrev} className="w-1/2 bg-gray-300 hover:bg-gray-400 text-gray-800 text-lg py-3">
Previous
</Button>
<Button type="button" onClick={handleNext} className="w-1/2 bg-blue-600 hover:bg-blue-700 text-lg py-3">
Next: Payment
</Button>
</div>
</div>
</CardContent>
</>
)
case 3:
return (
<>
<CardHeader className="text-center">
<CardTitle className="text-2xl">Step 3: Payment</CardTitle>
<CardDescription>
Secure your $20 USD/month membership via Stripe.
</CardDescription>
</CardHeader>
<CardContent>
{submitStatus === 'success' && (
<div className="mb-6 p-4 bg-green-50 border border-green-200 rounded-lg flex items-center gap-3">
<CheckCircle className="h-5 w-5 text-green-600" />
<div>
<h4 className="font-semibold text-green-800">Purchase Initiated!</h4>
<p className="text-green-700">Redirecting to secure Stripe checkout...</p>
</div>
</div>
)}
{submitStatus === 'error' && (
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg flex items-center gap-3">
<AlertCircle className="h-5 w-5 text-red-600" />
<div>
<h4 className="font-semibold text-red-800">Purchase Failed</h4>
<p className="text-red-700">There was an error processing your purchase. Please try again or contact support.</p>
</div>
</div>
)}
<div className="space-y-6">
<p className="text-md text-slate-700 text-center">
You are about to purchase a membership to ThreeFold Galaxy Coop for <span className="font-bold">$20 USD per month</span>.
</p>
<p className="text-sm text-slate-600 text-center">
Click "Proceed to Payment" to be redirected to Stripe's secure checkout page.
</p>
<div className="flex justify-between gap-4">
<Button type="button" onClick={handlePrev} className="w-1/2 bg-gray-300 hover:bg-gray-400 text-gray-800 text-lg py-3">
Previous
</Button>
<Button
type="submit"
onClick={handleBuy}
className="w-1/2 bg-green-600 hover:bg-green-700 text-lg py-3"
disabled={isSubmitting}
>
{isSubmitting ? 'Processing...' : 'Proceed to Payment'}
</Button>
</div>
</div>
</CardContent>
</>
)
default:
return null
}
}
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50">
{/* The `Navigation` component is now rendered in `App.jsx` remove it from here */}
{/* Hero Section */}
<section className="py-24 pb-16 px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto text-center space-y-8">
<Badge className="bg-blue-100 text-blue-800 hover:bg-blue-200">Direct Purchase</Badge>
<h1 className="text-4xl md:text-6xl font-bold text-slate-900 leading-tight">
Become A <span className="text-blue-600">Member</span>
</h1>
<p className="text-xl text-slate-600 leading-relaxed max-w-3xl mx-auto">
Join ThreeFold Galaxy Coop's sovereign digital freezone for $20 USD per month.
</p>
</div>
</section>
{/* Purchase Form */}
<section className="pb-16 px-4 sm:px-6 lg:px-8">
<div className="max-w-2xl mx-auto">
<Card className="shadow-xl">
{renderStepContent()}
</Card>
</div>
</section>
{/* What Happens Next */}
<section className="py-16 px-4 sm:px-6 lg:px-8 bg-white">
<div className="max-w-4xl mx-auto">
<div className="text-center space-y-8 mb-12">
<h2 className="text-3xl md:text-4xl font-bold text-slate-900">What Happens Next?</h2>
</div>
<div className="grid md:grid-cols-3 gap-8">
<Card className="text-center">
<CardHeader>
<div className="w-12 h-12 bg-blue-600 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-white font-bold">1</span>
</div>
<CardTitle className="text-blue-600">Confirm Your Membership</CardTitle>
</CardHeader>
<CardContent>
Complete your secure Stripe checkout to confirm your ThreeFold Galaxy Coop membership.
</CardContent>
</Card>
<Card className="text-center">
<CardHeader>
<div className="w-12 h-12 bg-green-600 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-white font-bold">2</span>
</div>
<CardTitle className="text-green-600">Access Your Benefits</CardTitle>
</CardHeader>
<CardContent>
Gain immediate access to member-exclusive content, tools, and community forums.
</CardContent>
</Card>
<Card className="text-center">
<CardHeader>
<div className="w-12 h-12 bg-purple-600 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-white font-bold">3</span>
</div>
<CardTitle className="text-purple-600">Engage & Govern</CardTitle>
</CardHeader>
<CardContent>
Participate in cooperative governance, shape the future, and contribute to the digital freezone.
</CardContent>
</Card>
</div>
</div>
</section>
{/* Footer */}
<footer className="py-8 px-4 sm:px-6 lg:px-8 bg-slate-900 text-white">
<div className="max-w-6xl mx-auto text-center">
<div className="flex items-center justify-center space-x-2 mb-4">
<Globe className="h-6 w-6 text-blue-400" />
<span className="text-xl font-bold">ThreeFold Galaxy Coop</span>
</div>
<p className="text-slate-400">Building the new internet, together in our sovereign digital freezone.</p>
<p className="text-sm text-slate-500 mt-4">© 2025 ThreeFold Galaxy Coop. A cooperative for digital freedom.</p>
</div>
</footer>
</div>
)
}
export default DirectBuy