← back to IWasCute
src/app/dashboard/page.tsx
321 lines
'use client'
import { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import {
Camera,
DollarSign,
Clock,
CheckCircle2,
AlertCircle,
Eye,
TrendingUp,
Plus,
ChevronRight,
Shield,
ImageIcon,
} from 'lucide-react'
import Link from 'next/link'
import Navbar from '@/components/shared/Navbar'
const DEMO_STATS = [
{ label: 'Total Photos', value: '0', icon: Camera, color: 'var(--color-peach)' },
{ label: 'Cleared', value: '0', icon: CheckCircle2, color: 'var(--color-sage-dark)' },
{ label: 'Pending Review', value: '0', icon: Clock, color: 'var(--color-warm-gray)' },
{ label: 'Total Earnings', value: '$0.00', icon: DollarSign, color: 'var(--color-peach-dark)' },
]
const DEMO_UPLOADS: {
id: string
name: string
status: 'pending' | 'cleared' | 'rejected'
submittedAt: string
views: number
earnings: number
}[] = []
type Tab = 'overview' | 'photos' | 'earnings'
function StatCard({
label,
value,
icon: Icon,
color,
}: {
label: string
value: string
icon: typeof Camera
color: string
}) {
return (
<div
className="flex items-center gap-4 p-5 rounded-3xl"
style={{ background: 'rgba(255,255,255,0.6)', border: '1px solid var(--color-cream-dark)' }}
>
<div
className="w-12 h-12 rounded-2xl flex items-center justify-center shrink-0"
style={{ background: color, opacity: 0.9 }}
>
<Icon size={22} style={{ color: 'white' }} />
</div>
<div>
<p className="text-2xl font-black tracking-tight" style={{ color: 'var(--color-brown)' }}>
{value}
</p>
<p className="text-xs font-medium tracking-wide" style={{ color: 'var(--color-warm-gray)' }}>
{label}
</p>
</div>
</div>
)
}
function EmptyState() {
return (
<div className="flex flex-col items-center justify-center gap-6 py-20 text-center">
<div
className="w-20 h-20 rounded-3xl flex items-center justify-center"
style={{ background: 'var(--color-cream-dark)' }}
>
<ImageIcon size={36} style={{ color: 'var(--color-warm-gray)' }} />
</div>
<div className="max-w-sm">
<h3 className="text-xl font-bold tracking-tight" style={{ color: 'var(--color-brown)' }}>
No photos yet
</h3>
<p className="mt-2 text-sm leading-relaxed" style={{ color: 'var(--color-warm-gray)' }}>
Upload your first childhood photo to start building your portfolio and earning royalties.
</p>
</div>
<Link
href="/licensor"
className="flex items-center gap-2 px-8 py-3.5 rounded-3xl text-sm font-semibold tracking-wide transition-all hover:scale-105"
style={{ background: 'var(--color-peach)', color: 'var(--color-brown)' }}
>
<Plus size={16} />
Upload Photos
</Link>
</div>
)
}
function StatusBadge({ status }: { status: 'pending' | 'cleared' | 'rejected' }) {
const config = {
pending: { bg: 'rgba(255, 181, 167, 0.2)', color: 'var(--color-peach-dark)', label: 'Pending' },
cleared: { bg: 'rgba(181, 213, 197, 0.3)', color: 'var(--color-sage-dark)', label: 'Cleared' },
rejected: { bg: 'rgba(107, 112, 92, 0.15)', color: 'var(--color-warm-gray)', label: 'Rejected' },
}
const c = config[status]
return (
<span
className="inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-semibold"
style={{ background: c.bg, color: c.color }}
>
{status === 'pending' && <Clock size={10} />}
{status === 'cleared' && <CheckCircle2 size={10} />}
{status === 'rejected' && <AlertCircle size={10} />}
{c.label}
</span>
)
}
export default function DashboardPage() {
const [activeTab, setActiveTab] = useState<Tab>('overview')
const tabs: { id: Tab; label: string }[] = [
{ id: 'overview', label: 'Overview' },
{ id: 'photos', label: 'My Photos' },
{ id: 'earnings', label: 'Earnings' },
]
return (
<div className="min-h-screen" style={{ background: 'var(--color-cream)' }}>
<Navbar />
<div className="max-w-5xl mx-auto px-4 py-8 md:px-8 md:py-12">
{/* Header */}
<div className="flex items-center justify-between mb-8">
<div>
<h1 className="text-3xl font-black tracking-tighter" style={{ color: 'var(--color-brown)' }}>
Dashboard
</h1>
<p className="mt-1 text-sm" style={{ color: 'var(--color-warm-gray)' }}>
Manage your photos, track rights clearance, and monitor earnings.
</p>
</div>
<Link
href="/licensor"
className="flex items-center gap-2 px-6 py-3 rounded-3xl text-sm font-semibold tracking-wide transition-all hover:scale-105"
style={{ background: 'var(--color-peach)', color: 'var(--color-brown)' }}
>
<Plus size={14} />
<span className="hidden sm:inline">Upload Photos</span>
</Link>
</div>
{/* Stats grid */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-8">
{DEMO_STATS.map((stat) => (
<StatCard key={stat.label} {...stat} />
))}
</div>
{/* Tab bar */}
<div
className="flex gap-1 p-1 rounded-2xl mb-8"
style={{ background: 'var(--color-cream-dark)' }}
>
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className="relative flex-1 py-2.5 text-sm font-semibold rounded-xl transition-all"
style={{
color: activeTab === tab.id ? 'var(--color-brown)' : 'var(--color-warm-gray)',
}}
>
{activeTab === tab.id && (
<motion.div
layoutId="dashboard-tab"
className="absolute inset-0 rounded-xl"
style={{ background: 'white', boxShadow: '0 1px 3px rgba(0,0,0,0.08)' }}
transition={{ type: 'spring', stiffness: 380, damping: 30 }}
/>
)}
<span className="relative z-10">{tab.label}</span>
</button>
))}
</div>
{/* Tab content */}
<AnimatePresence mode="wait">
{activeTab === 'overview' && (
<div key="overview">
{DEMO_UPLOADS.length === 0 ? (
<EmptyState />
) : (
<div className="flex flex-col gap-4" />
)}
{/* How it works card */}
<div
className="mt-8 rounded-3xl p-8"
style={{ background: 'rgba(181, 213, 197, 0.15)', border: '1px solid var(--color-sage)' }}
>
<div className="flex items-center gap-3 mb-6">
<Shield size={20} style={{ color: 'var(--color-sage-dark)' }} />
<h3 className="text-base font-bold tracking-wide" style={{ color: 'var(--color-brown)' }}>
How Dual-Rights Clearance Works
</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[
{
step: '1',
title: 'Copyright Clearance',
desc: 'We verify the photographer or copyright owner has granted permission for your photo to be licensed.',
},
{
step: '2',
title: 'Likeness Release',
desc: 'Your signed model release confirms you are the person depicted and consent to licensing.',
},
{
step: '3',
title: 'Start Earning',
desc: 'Once both rights are cleared, your photo enters the marketplace. You earn royalties on every license.',
},
].map(({ step, title, desc }) => (
<div key={step} className="flex flex-col gap-2">
<div
className="w-8 h-8 rounded-full flex items-center justify-center text-xs font-black"
style={{ background: 'var(--color-sage)', color: 'white' }}
>
{step}
</div>
<h4 className="text-sm font-bold" style={{ color: 'var(--color-brown)' }}>
{title}
</h4>
<p className="text-xs leading-relaxed" style={{ color: 'var(--color-warm-gray)' }}>
{desc}
</p>
</div>
))}
</div>
</div>
</div>
)}
{activeTab === 'photos' && (
<div key="photos">
{DEMO_UPLOADS.length === 0 ? (
<EmptyState />
) : (
<div className="flex flex-col gap-3">
{DEMO_UPLOADS.map((upload) => (
<div
key={upload.id}
className="flex items-center gap-4 p-4 rounded-2xl transition-all hover:scale-[1.01]"
style={{
background: 'rgba(255,255,255,0.6)',
border: '1px solid var(--color-cream-dark)',
}}
>
<div
className="w-14 h-14 rounded-xl flex items-center justify-center shrink-0"
style={{ background: 'var(--color-cream-dark)' }}
>
<ImageIcon size={20} style={{ color: 'var(--color-warm-gray)' }} />
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-semibold truncate" style={{ color: 'var(--color-brown)' }}>
{upload.name}
</p>
<p className="text-xs" style={{ color: 'var(--color-warm-gray)' }}>
{upload.submittedAt}
</p>
</div>
<StatusBadge status={upload.status} />
<div className="flex items-center gap-3 text-xs" style={{ color: 'var(--color-warm-gray)' }}>
<span className="flex items-center gap-1">
<Eye size={12} /> {upload.views}
</span>
<span className="flex items-center gap-1">
<DollarSign size={12} /> ${upload.earnings.toFixed(2)}
</span>
</div>
<ChevronRight size={16} style={{ color: 'var(--color-warm-gray)' }} />
</div>
))}
</div>
)}
</div>
)}
{activeTab === 'earnings' && (
<div
key="earnings"
className="flex flex-col items-center gap-6 py-16 text-center"
>
<div
className="w-20 h-20 rounded-3xl flex items-center justify-center"
style={{ background: 'var(--color-cream-dark)' }}
>
<TrendingUp size={36} style={{ color: 'var(--color-warm-gray)' }} />
</div>
<div className="max-w-sm">
<h3 className="text-xl font-bold tracking-tight" style={{ color: 'var(--color-brown)' }}>
No earnings yet
</h3>
<p className="mt-2 text-sm leading-relaxed" style={{ color: 'var(--color-warm-gray)' }}>
Upload photos and get them cleared to start earning royalties from licenses.
</p>
</div>
</div>
)}
</AnimatePresence>
</div>
</div>
)
}