import { useState, useEffect } from "react"; import { useTranslation } from 'react-i18next'; import { useStripe, useElements, PaymentElement, Elements } from '@stripe/react-stripe-js'; import { loadStripe } from '@stripe/stripe-js'; import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js"; import { Button } from "@/components/ui/button"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { useCheckoutWizard } from "../WizardContext"; interface PaymentStepProps { stripePublishableKey: string; paypalClientId: string; } // Komponente für Stripe-Zahlungen const StripePaymentForm: React.FC<{ onError: (error: string) => void; onSuccess: () => void; selectedPackage: any; t: any }> = ({ onError, onSuccess, selectedPackage, t }) => { const stripe = useStripe(); const elements = useElements(); const [isProcessing, setIsProcessing] = useState(false); const [error, setError] = useState(''); const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); if (!stripe || !elements) { onError(t('checkout.payment_step.stripe_not_loaded')); return; } setIsProcessing(true); setError(''); try { const { error: stripeError, paymentIntent } = await stripe.confirmPayment({ elements, confirmParams: { return_url: `${window.location.origin}/checkout/success`, }, redirect: 'if_required', }); if (stripeError) { console.error('Stripe Payment Error:', stripeError); let errorMessage = t('checkout.payment_step.payment_failed'); switch (stripeError.type) { case 'card_error': errorMessage += stripeError.message || t('checkout.payment_step.error_card'); break; case 'validation_error': errorMessage += t('checkout.payment_step.error_validation'); break; case 'api_connection_error': errorMessage += t('checkout.payment_step.error_connection'); break; case 'api_error': errorMessage += t('checkout.payment_step.error_server'); break; case 'authentication_error': errorMessage += t('checkout.payment_step.error_auth'); break; default: errorMessage += stripeError.message || t('checkout.payment_step.error_unknown'); } setError(errorMessage); onError(errorMessage); } else if (paymentIntent && paymentIntent.status === 'succeeded') { onSuccess(); } else if (paymentIntent) { onError(t('checkout.payment_step.unexpected_status', { status: paymentIntent.status })); } } catch (err) { console.error('Unexpected payment error:', err); onError(t('checkout.payment_step.error_unknown')); } finally { setIsProcessing(false); } }; return (
{error && ( {error} )}

{t('checkout.payment_step.secure_payment_desc')}

); }; // Komponente für PayPal-Zahlungen const PayPalPaymentForm: React.FC<{ onError: (error: string) => void; onSuccess: () => void; selectedPackage: any; t: any; authUser: any; paypalClientId: string }> = ({ onError, onSuccess, selectedPackage, t, authUser, paypalClientId }) => { const createOrder = async () => { try { const response = await fetch('/paypal/create-order', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '', }, body: JSON.stringify({ tenant_id: authUser?.tenant_id || authUser?.id, // Annahme: tenant_id verfügbar package_id: selectedPackage?.id, }), }); const data = await response.json(); if (response.ok && data.id) { return data.id; } else { onError(data.error || t('checkout.payment_step.paypal_order_error')); throw new Error('Failed to create order'); } } catch (err) { onError(t('checkout.payment_step.network_error')); throw err; } }; const onApprove = async (data: any) => { try { const response = await fetch('/paypal/capture-order', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '', }, body: JSON.stringify({ order_id: data.orderID, }), }); const result = await response.json(); if (response.ok && result.status === 'captured') { onSuccess(); } else { onError(result.error || t('checkout.payment_step.paypal_capture_error')); } } catch (err) { onError(t('checkout.payment_step.network_error')); } }; const onErrorHandler = (error: any) => { console.error('PayPal Error:', error); onError(t('checkout.payment_step.paypal_error')); }; const onCancel = () => { onError(t('checkout.payment_step.paypal_cancelled')); }; return (

{t('checkout.payment_step.secure_paypal_desc') || 'Bezahlen Sie sicher mit PayPal.'}

); }; // Wrapper-Komponente export const PaymentStep: React.FC = ({ stripePublishableKey, paypalClientId }) => { const { t } = useTranslation('marketing'); const { selectedPackage, authUser, nextStep, resetPaymentState } = useCheckoutWizard(); const [clientSecret, setClientSecret] = useState(''); const [paymentMethod, setPaymentMethod] = useState<'stripe' | 'paypal'>('stripe'); const [error, setError] = useState(''); const [isFree, setIsFree] = useState(false); useEffect(() => { const free = selectedPackage ? selectedPackage.price <= 0 : false; setIsFree(free); if (free) { resetPaymentState(); return; } if (paymentMethod === 'stripe' && authUser && selectedPackage) { const loadPaymentIntent = async () => { try { const response = await fetch('/stripe/create-payment-intent', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '', }, body: JSON.stringify({ package_id: selectedPackage.id, }), }); const data = await response.json(); if (response.ok && data.client_secret) { setClientSecret(data.client_secret); setError(''); } else { setError(data.error || t('checkout.payment_step.payment_intent_error')); } } catch (err) { setError(t('checkout.payment_step.network_error')); } }; loadPaymentIntent(); } else { setClientSecret(''); } }, [selectedPackage?.id, authUser, paymentMethod, isFree, t, resetPaymentState]); const handlePaymentError = (errorMsg: string) => { setError(errorMsg); }; const handlePaymentSuccess = () => { setTimeout(() => nextStep(), 1000); }; // Für kostenlose Pakete if (isFree) { return (
{t('checkout.payment_step.free_package_title')} {t('checkout.payment_step.free_package_desc')}
); } // Fehler anzeigen if (error && !clientSecret) { return (
{error}
); } const stripePromise = loadStripe(stripePublishableKey); return (
{/* Zahlungsmethode Auswahl */}
{error && ( {error} )} {paymentMethod === 'stripe' && ( )} {paymentMethod === 'paypal' && ( )} {!clientSecret && paymentMethod === 'stripe' && (

{t('checkout.payment_step.loading_payment')}

)}
); };