Files
auditly/pages/SubscriptionSetup.tsx

210 lines
11 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import { useUserOrganizations } from '../contexts/UserOrganizationsContext';
const SubscriptionSetup: React.FC = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { user } = useAuth();
const { createCheckoutSession, getSubscriptionStatus } = useUserOrganizations();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [orgId, setOrgId] = useState<string | null>(null);
useEffect(() => {
const orgIdParam = searchParams.get('orgId');
const sessionId = searchParams.get('session_id');
const canceled = searchParams.get('canceled');
if (orgIdParam) {
setOrgId(orgIdParam);
}
if (sessionId) {
// Handle successful checkout
handleSuccessfulCheckout(sessionId);
} else if (canceled) {
setError('Subscription setup was canceled. You can try again or use the 14-day trial.');
}
}, [searchParams]);
const handleSuccessfulCheckout = async (sessionId: string) => {
if (!orgId) return;
try {
setLoading(true);
// Get updated subscription status
await getSubscriptionStatus(orgId);
// Redirect to onboarding to complete organization setup
setTimeout(() => {
navigate('/onboarding', { replace: true });
}, 2000);
} catch (error) {
console.error('Error handling successful checkout:', error);
setError('There was an issue verifying your subscription. Please contact support.');
} finally {
setLoading(false);
}
};
const handleStartSubscription = async () => {
if (!user || !orgId) return;
try {
setLoading(true);
setError(null);
const { sessionUrl } = await createCheckoutSession(orgId, user.email!);
// Redirect to Stripe Checkout
window.location.href = sessionUrl;
} catch (error) {
console.error('Failed to create checkout session:', error);
setError('Failed to start subscription setup. Please try again.');
} finally {
setLoading(false);
}
};
const handleSkipForNow = () => {
// Allow user to continue with trial - go to onboarding to complete setup
navigate('/onboarding', { replace: true });
};
if (searchParams.get('session_id')) {
return (
<div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<div className="text-center">
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">Subscription Active!</h2>
<p className="text-gray-600 mb-4">
Your subscription has been successfully set up. Redirecting to complete your organization setup...
</p>
{loading && (
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-600 mx-auto"></div>
)}
</div>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<div className="text-center">
<h2 className="text-3xl font-extrabold text-gray-900">Complete Your Setup</h2>
<p className="mt-2 text-sm text-gray-600">
Set up your subscription to unlock all features
</p>
</div>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<div className="space-y-6">
{error && (
<div className="bg-red-50 border border-red-200 rounded-md p-4">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm text-red-800">{error}</p>
</div>
</div>
</div>
)}
<div className="bg-blue-50 border border-blue-200 rounded-md p-4">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-blue-800">14-Day Free Trial</h3>
<p className="mt-2 text-sm text-blue-700">
Start with a free trial. No payment required until the trial ends.
</p>
</div>
</div>
</div>
<div className="border rounded-lg p-4">
<h3 className="text-lg font-medium text-gray-900 mb-4">Auditly Standard Plan</h3>
<div className="space-y-2 mb-4">
<div className="flex items-center">
<svg className="h-4 w-4 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className="text-sm text-gray-600">Up to 50 employees</span>
</div>
<div className="flex items-center">
<svg className="h-4 w-4 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className="text-sm text-gray-600">AI-powered employee reports</span>
</div>
<div className="flex items-center">
<svg className="h-4 w-4 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className="text-sm text-gray-600">Company analytics & insights</span>
</div>
<div className="flex items-center">
<svg className="h-4 w-4 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className="text-sm text-gray-600">AI chat assistant</span>
</div>
</div>
<div className="text-2xl font-bold text-gray-900 mb-1">$29<span className="text-sm font-normal text-gray-600">/month</span></div>
<p className="text-xs text-gray-500">Billed monthly, cancel anytime</p>
</div>
<div className="space-y-3">
<button
onClick={handleStartSubscription}
disabled={loading}
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? (
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
) : (
'Start Subscription'
)}
</button>
<button
onClick={handleSkipForNow}
className="w-full flex justify-center py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Continue with Trial
</button>
</div>
<p className="text-xs text-center text-gray-500">
Your trial will last 14 days. No payment required until the trial ends.
</p>
</div>
</div>
</div>
</div>
);
};
export default SubscriptionSetup;