Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
All services: admin-v2, studio-v2, website, ai-compliance-sdk, consent-service, klausur-service, voice-service, and infrastructure. Large PDFs and compiled binaries excluded via .gitignore.
293 lines
9.6 KiB
TypeScript
293 lines
9.6 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
|
|
interface Plan {
|
|
id: string
|
|
name: string
|
|
description: string
|
|
price: number
|
|
currency: string
|
|
interval: string
|
|
features: {
|
|
tasks: string
|
|
taskDescription: string
|
|
included: string[]
|
|
highlighted?: boolean
|
|
}
|
|
popular?: boolean
|
|
}
|
|
|
|
const plans: Plan[] = [
|
|
{
|
|
id: 'basic',
|
|
name: 'Basic',
|
|
description: 'Perfekt fuer den Einstieg',
|
|
price: 9.90,
|
|
currency: 'EUR',
|
|
interval: 'Monat',
|
|
features: {
|
|
tasks: '30 Aufgaben',
|
|
taskDescription: 'pro Monat',
|
|
included: [
|
|
'KI-gestuetzte Korrektur',
|
|
'Basis-Dokumentvorlagen',
|
|
'E-Mail Support',
|
|
],
|
|
},
|
|
},
|
|
{
|
|
id: 'standard',
|
|
name: 'Standard',
|
|
description: 'Fuer regelmaessige Nutzer',
|
|
price: 19.90,
|
|
currency: 'EUR',
|
|
interval: 'Monat',
|
|
popular: true,
|
|
features: {
|
|
tasks: '100 Aufgaben',
|
|
taskDescription: 'pro Monat',
|
|
included: [
|
|
'Alles aus Basic',
|
|
'Eigene Vorlagen erstellen',
|
|
'Batch-Verarbeitung',
|
|
'Bis zu 3 Teammitglieder',
|
|
'Prioritaets-Support',
|
|
],
|
|
highlighted: true,
|
|
},
|
|
},
|
|
{
|
|
id: 'premium',
|
|
name: 'Premium',
|
|
description: 'Sorglos-Tarif fuer Vielnutzer',
|
|
price: 39.90,
|
|
currency: 'EUR',
|
|
interval: 'Monat',
|
|
features: {
|
|
tasks: 'Unbegrenzt',
|
|
taskDescription: 'Fair Use',
|
|
included: [
|
|
'Alles aus Standard',
|
|
'Unbegrenzte Aufgaben (Fair Use)',
|
|
'Bis zu 10 Teammitglieder',
|
|
'Admin-Panel & Audit-Log',
|
|
'API-Zugang',
|
|
'Eigenes Branding',
|
|
'Dedizierter Support',
|
|
],
|
|
},
|
|
},
|
|
]
|
|
|
|
export default function PricingSection() {
|
|
const [selectedPlan, setSelectedPlan] = useState<string | null>(null)
|
|
const [isLoading, setIsLoading] = useState(false)
|
|
const [email, setEmail] = useState('')
|
|
const [showEmailForm, setShowEmailForm] = useState(false)
|
|
|
|
const handleSelectPlan = (planId: string) => {
|
|
setSelectedPlan(planId)
|
|
setShowEmailForm(true)
|
|
}
|
|
|
|
const handleStartTrial = async (e: React.FormEvent) => {
|
|
e.preventDefault()
|
|
if (!selectedPlan || !email) return
|
|
|
|
setIsLoading(true)
|
|
|
|
try {
|
|
// Call billing service to create checkout session
|
|
const response = await fetch(`${process.env.NEXT_PUBLIC_BILLING_API_URL}/api/v1/billing/trial/start`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
plan_id: selectedPlan,
|
|
email: email,
|
|
}),
|
|
})
|
|
|
|
const data = await response.json()
|
|
|
|
if (data.checkout_url) {
|
|
// Redirect to Stripe Checkout
|
|
window.location.href = data.checkout_url
|
|
} else {
|
|
alert('Fehler beim Starten des Trials. Bitte versuchen Sie es erneut.')
|
|
}
|
|
} catch (error) {
|
|
console.error('Error starting trial:', error)
|
|
alert('Verbindungsfehler. Bitte versuchen Sie es erneut.')
|
|
} finally {
|
|
setIsLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<section id="pricing" className="py-16 px-4 sm:px-6 lg:px-8">
|
|
<div className="max-w-7xl mx-auto">
|
|
{/* Section Header */}
|
|
<div className="text-center mb-12">
|
|
<h2 className="text-3xl sm:text-4xl font-bold text-slate-900">
|
|
Waehlen Sie Ihren Plan
|
|
</h2>
|
|
<p className="mt-4 text-lg text-slate-600">
|
|
7 Tage kostenlos testen. Jederzeit kuendbar.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Pricing Cards */}
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto">
|
|
{plans.map((plan) => (
|
|
<div
|
|
key={plan.id}
|
|
className={`relative bg-white rounded-2xl p-8 card-hover ${
|
|
plan.popular
|
|
? 'border-2 border-primary-500 shadow-xl'
|
|
: 'border border-slate-200 shadow-lg'
|
|
}`}
|
|
>
|
|
{/* Popular Badge */}
|
|
{plan.popular && (
|
|
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
|
<span className="bg-primary-500 text-white text-sm font-medium px-4 py-1 rounded-full">
|
|
Beliebteste Wahl
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
{/* Plan Header */}
|
|
<div className="text-center">
|
|
<h3 className="text-xl font-semibold text-slate-900">{plan.name}</h3>
|
|
<p className="mt-1 text-slate-500 text-sm">{plan.description}</p>
|
|
</div>
|
|
|
|
{/* Price */}
|
|
<div className="mt-6 text-center">
|
|
<span className="text-4xl font-bold text-slate-900">
|
|
{plan.price.toFixed(2).replace('.', ',')}
|
|
</span>
|
|
<span className="text-slate-500 ml-1">EUR/{plan.interval}</span>
|
|
</div>
|
|
|
|
{/* Tasks Highlight */}
|
|
<div className="mt-6 bg-slate-50 rounded-xl p-4 text-center">
|
|
<div className="text-2xl font-bold text-primary-600">{plan.features.tasks}</div>
|
|
<div className="text-sm text-slate-500">{plan.features.taskDescription}</div>
|
|
</div>
|
|
|
|
{/* Features List */}
|
|
<ul className="mt-6 space-y-3">
|
|
{plan.features.included.map((feature, index) => (
|
|
<li key={index} className="flex items-start">
|
|
<svg
|
|
className="w-5 h-5 text-primary-500 mr-3 mt-0.5 flex-shrink-0"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M5 13l4 4L19 7"
|
|
/>
|
|
</svg>
|
|
<span className="text-slate-600 text-sm">{feature}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
{/* CTA Button */}
|
|
<button
|
|
onClick={() => handleSelectPlan(plan.id)}
|
|
className={`mt-8 w-full py-3 px-4 rounded-xl font-medium transition-all btn-press ${
|
|
plan.popular
|
|
? 'bg-primary-600 text-white hover:bg-primary-700'
|
|
: 'bg-slate-100 text-slate-900 hover:bg-slate-200'
|
|
}`}
|
|
>
|
|
7 Tage kostenlos testen
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Carryover Info */}
|
|
<div className="mt-12 text-center">
|
|
<p className="text-slate-500 text-sm">
|
|
Ungenutzte Aufgaben sammeln sich bis zu 5 Monate an.
|
|
<br />
|
|
Keine versteckten Kosten. Kreditkarte fuer Trial erforderlich.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Email Form Modal */}
|
|
{showEmailForm && (
|
|
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
|
<div className="bg-white rounded-2xl p-8 max-w-md w-full shadow-2xl">
|
|
<h3 className="text-2xl font-bold text-slate-900 text-center">
|
|
Trial starten
|
|
</h3>
|
|
<p className="mt-2 text-slate-600 text-center">
|
|
{plans.find((p) => p.id === selectedPlan)?.name} - 7 Tage kostenlos
|
|
</p>
|
|
|
|
<form onSubmit={handleStartTrial} className="mt-6">
|
|
<label className="block">
|
|
<span className="text-sm font-medium text-slate-700">E-Mail-Adresse</span>
|
|
<input
|
|
type="email"
|
|
required
|
|
value={email}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
placeholder="ihre@email.de"
|
|
className="mt-1 block w-full px-4 py-3 rounded-xl border border-slate-300 focus:border-primary-500 focus:ring-2 focus:ring-primary-500/20 transition-all"
|
|
/>
|
|
</label>
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={isLoading}
|
|
className="mt-6 w-full bg-primary-600 text-white py-3 px-4 rounded-xl font-medium hover:bg-primary-700 transition-all btn-press disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
{isLoading ? (
|
|
<span className="flex items-center justify-center">
|
|
<svg className="animate-spin -ml-1 mr-2 h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
|
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
|
|
</svg>
|
|
Wird geladen...
|
|
</span>
|
|
) : (
|
|
'Weiter zu Stripe'
|
|
)}
|
|
</button>
|
|
</form>
|
|
|
|
<button
|
|
onClick={() => {
|
|
setShowEmailForm(false)
|
|
setSelectedPlan(null)
|
|
}}
|
|
className="mt-4 w-full text-slate-500 hover:text-slate-700 text-sm"
|
|
>
|
|
Abbrechen
|
|
</button>
|
|
|
|
<p className="mt-6 text-xs text-slate-400 text-center">
|
|
Mit dem Fortfahren akzeptieren Sie unsere{' '}
|
|
<a href="/agb" className="underline">AGB</a> und{' '}
|
|
<a href="/datenschutz" className="underline">Datenschutzerklaerung</a>.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|