Initial commit: Full Crawl API implementation
Some checks failed
CI / Test (push) Has been cancelled
Deploy / Deploy to Staging (push) Has been cancelled
CI / Build & Push (push) Has been cancelled
Deploy / Deploy to Production (push) Has been cancelled

This commit is contained in:
2026-04-29 07:03:48 +00:00
commit 62994d4f3d
92 changed files with 6176 additions and 0 deletions

View 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>
)
}