Initial commit: Full Crawl API implementation
This commit is contained in:
92
frontend/app/billing/page.tsx
Normal file
92
frontend/app/billing/page.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
const plans = [
|
||||
{ name: 'Free', price: '$0', credits: '30 / month', features: ['9 endpoints', '1 concurrent', 'Community support'] },
|
||||
{ name: 'Hobby', price: '$9', credits: '1,000 / month', features: ['9 endpoints', '3 concurrent', 'Email support', 'Webhooks'] },
|
||||
{ name: 'Starter', price: '$19', credits: '3,000 / month', features: ['9 endpoints', '5 concurrent', 'Priority support', 'Webhooks', 'AI extraction'] },
|
||||
{ name: 'Pro', price: '$49', credits: '10,000 / month', features: ['All endpoints', '10 concurrent', 'Priority support', 'Webhooks', 'AI extraction', 'Proxy rotation'] },
|
||||
{ name: 'Startup', price: '$99', credits: '25,000 / month', features: ['All endpoints', '20 concurrent', 'Dedicated support', 'Custom integrations', 'SLA'] },
|
||||
]
|
||||
|
||||
export default function Billing() {
|
||||
const [token, setToken] = useState('')
|
||||
const [credits, setCredits] = useState<number | null>(null)
|
||||
const [usage, setUsage] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const t = localStorage.getItem('crawlapi_token')
|
||||
if (t) {
|
||||
setToken(t)
|
||||
fetchUser(t)
|
||||
}
|
||||
}, [])
|
||||
|
||||
async function fetchUser(t: string) {
|
||||
try {
|
||||
const res = await fetch('http://localhost:3000/api/auth/api-keys', {
|
||||
headers: { 'x-auth-token': t }
|
||||
})
|
||||
// Just a mock - in production this would call a /me endpoint
|
||||
setCredits(30)
|
||||
setUsage(12)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<main style={{ maxWidth: 1200, margin: '0 auto', padding: '40px 20px' }}>
|
||||
<nav style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 40 }}>
|
||||
<Link href="/" style={{ fontSize: 24, fontWeight: 700, color: '#fff', textDecoration: 'none' }}>Crawl API</Link>
|
||||
<Link href="/" style={{ color: '#888', textDecoration: 'none' }}>← Back</Link>
|
||||
</nav>
|
||||
|
||||
<h1 style={{ fontSize: 36, marginBottom: 8 }}>Billing</h1>
|
||||
<p style={{ color: '#888', marginBottom: 40 }}>Manage your subscription and usage.</p>
|
||||
|
||||
{token && credits !== null && (
|
||||
<div style={{ background: '#111', borderRadius: 12, padding: 24, marginBottom: 40 }}>
|
||||
<h3 style={{ marginTop: 0 }}>Current Usage</h3>
|
||||
<div style={{ display: 'flex', gap: 40, marginTop: 16 }}>
|
||||
<div>
|
||||
<div style={{ fontSize: 32, fontWeight: 700 }}>{credits - usage}</div>
|
||||
<div style={{ color: '#888', fontSize: 14 }}>Credits remaining</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: 32, fontWeight: 700 }}>{usage}</div>
|
||||
<div style={{ color: '#888', fontSize: 14 }}>Used this month</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: 32, fontWeight: 700 }}>{credits}</div>
|
||||
<div style={{ color: '#888', fontSize: 14 }}>Total credits</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ marginTop: 16, background: '#1a1a1a', borderRadius: 8, height: 8, overflow: 'hidden' }}>
|
||||
<div style={{ width: `${(usage / credits) * 100}%`, background: '#4ade80', height: '100%' }} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 16 }}>
|
||||
{plans.map(plan => (
|
||||
<div key={plan.name} style={{ background: '#111', borderRadius: 12, padding: 24, border: plan.name === 'Hobby' ? '1px solid #4ade80' : '1px solid transparent' }}>
|
||||
<div style={{ fontSize: 14, color: '#888', marginBottom: 8 }}>{plan.name}</div>
|
||||
<div style={{ fontSize: 36, fontWeight: 700, marginBottom: 8 }}>{plan.price}<span style={{ fontSize: 14, color: '#888' }}>/mo</span></div>
|
||||
<div style={{ fontSize: 14, marginBottom: 16, color: '#4ade80' }}>{plan.credits}</div>
|
||||
<ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
|
||||
{plan.features.map((f, i) => (
|
||||
<li key={i} style={{ padding: '4px 0', fontSize: 14, color: '#aaa' }}>✓ {f}</li>
|
||||
))}
|
||||
</ul>
|
||||
<button style={{ width: '100%', marginTop: 16, padding: '10px', background: plan.name === 'Hobby' ? '#4ade80' : '#fff', color: '#000', borderRadius: 6, border: 'none', fontWeight: 600, cursor: 'pointer' }}>
|
||||
{plan.name === 'Free' ? 'Current Plan' : 'Upgrade'}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user