Fix admin dashboard build: remove date-fns, replace Card with native divs, fix Button props

Made-with: Cursor
This commit is contained in:
Usman Baig
2026-02-25 22:02:53 +01:00
parent 3fe20a4b1b
commit 30b450cdb6
3 changed files with 53 additions and 54 deletions

View File

@@ -3,8 +3,24 @@
import { useEffect, useState } from 'react'
import { useParams, useRouter } from 'next/navigation'
import { getAdminOrg, grantPlan, type AdminOrgDetail } from '@/lib/api/admin'
import { Card, CardHeader, CardTitle, CardContent, Button, LoadingOverlay, Select, toast } from '@ciphera-net/ui'
import { format, addMonths, addYears } from 'date-fns'
import { Button, LoadingOverlay, Select, toast } from '@ciphera-net/ui'
function formatDate(d: Date) {
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
}
function formatDateTime(d: Date) {
return d.toLocaleDateString('en-US', { dateStyle: 'long' }) + ' ' + d.toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric' })
}
function addMonths(d: Date, months: number) {
const out = new Date(d)
out.setMonth(out.getMonth() + months)
return out
}
function addYears(d: Date, years: number) {
const out = new Date(d)
out.setFullYear(out.getFullYear() + years)
return out
}
const PLAN_OPTIONS = [
{ value: 'free', label: 'Free' },
@@ -105,12 +121,9 @@ export default function AdminOrgDetailPage() {
<div className="grid gap-6 md:grid-cols-2">
{/* Current Status */}
<Card>
<CardHeader>
<CardTitle>Current Status</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-2 text-sm">
<div className="rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900 p-6 shadow-sm">
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white mb-4">Current Status</h3>
<div className="grid grid-cols-2 gap-2 text-sm">
<span className="text-neutral-500">Plan:</span>
<span className="font-medium">{org.plan_id}</span>
@@ -125,7 +138,7 @@ export default function AdminOrgDetailPage() {
<span className="text-neutral-500">Period End:</span>
<span className="font-medium">
{org.current_period_end ? format(new Date(org.current_period_end), 'PPP p') : '-'}
{org.current_period_end ? formatDateTime(new Date(org.current_period_end)) : '-'}
</span>
<span className="text-neutral-500">Stripe Cust:</span>
@@ -133,35 +146,27 @@ export default function AdminOrgDetailPage() {
<span className="text-neutral-500">Stripe Sub:</span>
<span className="font-mono text-xs">{org.stripe_subscription_id || '-'}</span>
</div>
</CardContent>
</Card>
</div>
</div>
{/* Sites */}
<Card>
<CardHeader>
<CardTitle>Sites ({org.sites.length})</CardTitle>
</CardHeader>
<CardContent>
<div className="rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900 p-6 shadow-sm">
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white mb-4">Sites ({org.sites.length})</h3>
<ul className="space-y-2 max-h-60 overflow-y-auto">
{org.sites.map((site) => (
<li key={site.id} className="flex justify-between items-center text-sm p-2 bg-neutral-50 dark:bg-neutral-900 rounded">
<span className="font-medium">{site.domain}</span>
<span className="text-neutral-500 text-xs">{format(new Date(site.created_at), 'MMM d, yyyy')}</span>
<span className="text-neutral-500 text-xs">{formatDate(new Date(site.created_at))}</span>
</li>
))}
{org.sites.length === 0 && <li className="text-neutral-500 text-sm">No sites found</li>}
</ul>
</CardContent>
</Card>
</ul>
</div>
</div>
{/* Grant Plan Form */}
<Card>
<CardHeader>
<CardTitle>Grant Plan (Manual Override)</CardTitle>
</CardHeader>
<CardContent>
<div className="rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900 p-6 shadow-sm">
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white mb-4">Grant Plan (Manual Override)</h3>
<form onSubmit={handleGrantPlan} className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
@@ -232,8 +237,7 @@ export default function AdminOrgDetailPage() {
</Button>
</div>
</form>
</CardContent>
</Card>
</div>
</div>
)
}

View File

@@ -3,8 +3,11 @@
import { useEffect, useState } from 'react'
import Link from 'next/link'
import { listAdminOrgs, type AdminOrgSummary } from '@/lib/api/admin'
import { Card, CardHeader, CardTitle, CardContent, Button, LoadingOverlay } from '@ciphera-net/ui'
import { format } from 'date-fns'
import { Button, LoadingOverlay } from '@ciphera-net/ui'
function formatDate(d: Date) {
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
}
export default function AdminOrgsPage() {
const [orgs, setOrgs] = useState<AdminOrgSummary[]>([])
@@ -26,12 +29,9 @@ export default function AdminOrgsPage() {
<h2 className="text-xl font-semibold text-neutral-900 dark:text-white">Organizations</h2>
</div>
<Card>
<CardHeader>
<CardTitle>All Organizations</CardTitle>
</CardHeader>
<CardContent>
<div className="overflow-x-auto">
<div className="rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900 p-6 shadow-sm">
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white mb-4">All Organizations</h3>
<div className="overflow-x-auto">
<table className="w-full text-left text-sm">
<thead className="border-b border-neutral-200 dark:border-neutral-800">
<tr>
@@ -70,20 +70,19 @@ export default function AdminOrgsPage() {
{new Intl.NumberFormat().format(org.pageview_limit)}
</td>
<td className="px-4 py-3 text-neutral-500 text-xs">
{format(new Date(org.updated_at), 'MMM d, yyyy')}
{formatDate(new Date(org.updated_at))}
</td>
<td className="px-4 py-3">
<Link href={`/admin/orgs/${org.organization_id}`}>
<Button variant="ghost" size="sm">Manage</Button>
<Button variant="ghost">Manage</Button>
</Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
)
}

View File

@@ -1,23 +1,19 @@
'use client'
import Link from 'next/link'
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@ciphera-net/ui'
export default function AdminDashboard() {
return (
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
<Link href="/admin/orgs" className="block transition-transform hover:scale-[1.02]">
<Card>
<CardHeader>
<CardTitle>Organizations</CardTitle>
<CardDescription>Manage organization plans and limits</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-neutral-500 dark:text-neutral-400">
View all organizations, check billing status, and manually grant plans.
</p>
</CardContent>
</Card>
<Link
href="/admin/orgs"
className="block transition-transform hover:scale-[1.02] rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900 p-6 shadow-sm"
>
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white">Organizations</h3>
<p className="text-sm text-neutral-500 dark:text-neutral-400 mt-1">Manage organization plans and limits</p>
<p className="text-sm text-neutral-500 dark:text-neutral-400 mt-4">
View all organizations, check billing status, and manually grant plans.
</p>
</Link>
</div>
)