SaaS platform for roofing contractors to manage leads, quotes, and jobs
/**
* Billing Client Component
*
* Client-side component for billing interactions.
* Handles plan upgrades and payment processing.
*/
'use client';
import { useState } from 'react';
import { Button } from '@/components/ui/Button';
import { Card } from '@/components/ui/Card';
import { SubscriptionTier } from '@/lib/pricing/types';
import { TIER_PRICING } from '@/lib/pricing/tier-config';
interface BillingClientProps {
currentTier: SubscriptionTier;
availableUpgrades: SubscriptionTier[];
organizationId: string;
}
export function BillingClient({
currentTier,
availableUpgrades,
organizationId,
}: BillingClientProps) {
const [isUpgrading, setIsUpgrading] = useState(false);
const [selectedTier, setSelectedTier] = useState<SubscriptionTier | null>(null);
const handleUpgrade = async (tier: SubscriptionTier) => {
setIsUpgrading(true);
setSelectedTier(tier);
try {
const response = await fetch('/api/pricing/tiers/upgrade', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
organizationId,
targetTier: tier,
billingCycle: 'monthly',
}),
});
const result = await response.json();
if (!result.success) {
throw new Error(result.error);
}
// Reload page to reflect new tier
window.location.reload();
} catch (error) {
console.error('Upgrade failed:', error);
alert('Upgrade failed. Please try again.');
} finally {
setIsUpgrading(false);
setSelectedTier(null);
}
};
const tierLabels: Record<SubscriptionTier, string> = {
SOLO: 'Solo Roofer',
CREW_LEADER: 'Crew Leader',
ENTERPRISE: 'Enterprise',
};
return (
<div className="space-y-4">
{availableUpgrades.map((tier) => {
const pricing = TIER_PRICING[tier];
const isProcessing = isUpgrading && selectedTier === tier;
return (
<div
// ... (truncated)Step 21 of 30 — paused