142 lines
5.9 KiB
JavaScript
142 lines
5.9 KiB
JavaScript
import React from 'react'
|
||
import { usePage, Link } from '@inertiajs/react'
|
||
import StudioLayout from '../../Layouts/StudioLayout'
|
||
|
||
const kpiConfig = [
|
||
{ key: 'total_artworks', label: 'Total Artworks', icon: 'fa-images', color: 'text-blue-400', link: '/studio/artworks' },
|
||
{ key: 'views_30d', label: 'Views (30d)', icon: 'fa-eye', color: 'text-emerald-400', link: null },
|
||
{ key: 'favourites_30d', label: 'Favourites (30d)', icon: 'fa-heart', color: 'text-pink-400', link: null },
|
||
{ key: 'shares_30d', label: 'Shares (30d)', icon: 'fa-share-nodes', color: 'text-amber-400', link: null },
|
||
{ key: 'followers', label: 'Followers', icon: 'fa-user-group', color: 'text-purple-400', link: null },
|
||
]
|
||
|
||
function KpiCard({ config, value }) {
|
||
const content = (
|
||
<div className="bg-nova-900/60 border border-white/10 rounded-2xl p-5 hover:border-white/20 hover:shadow-lg hover:shadow-accent/5 transition-all duration-300 cursor-pointer group">
|
||
<div className="flex items-center gap-3 mb-3">
|
||
<div className={`w-10 h-10 rounded-xl bg-white/5 flex items-center justify-center ${config.color} group-hover:scale-110 transition-transform`}>
|
||
<i className={`fa-solid ${config.icon}`} />
|
||
</div>
|
||
<span className="text-xs font-medium text-slate-400 uppercase tracking-wider">{config.label}</span>
|
||
</div>
|
||
<p className="text-3xl font-bold text-white tabular-nums">
|
||
{typeof value === 'number' ? value.toLocaleString() : value}
|
||
</p>
|
||
</div>
|
||
)
|
||
|
||
if (config.link) {
|
||
return <Link href={config.link}>{content}</Link>
|
||
}
|
||
return content
|
||
}
|
||
|
||
function TopPerformerCard({ artwork }) {
|
||
return (
|
||
<div className="bg-nova-900/60 border border-white/10 rounded-2xl p-4 hover:border-white/20 hover:shadow-lg hover:shadow-accent/5 transition-all duration-300 group">
|
||
<div className="flex items-start gap-3">
|
||
{artwork.thumb_url && (
|
||
<img
|
||
src={artwork.thumb_url}
|
||
alt={artwork.title}
|
||
className="w-16 h-16 rounded-xl object-cover bg-nova-800 flex-shrink-0 group-hover:scale-105 transition-transform"
|
||
loading="lazy"
|
||
/>
|
||
)}
|
||
<div className="min-w-0 flex-1">
|
||
<h4 className="text-sm font-semibold text-white truncate" title={artwork.title}>
|
||
{artwork.title}
|
||
</h4>
|
||
<div className="flex flex-wrap items-center gap-3 mt-1.5">
|
||
<span className="text-xs text-slate-400">
|
||
❤️ {artwork.favourites?.toLocaleString()}
|
||
</span>
|
||
<span className="text-xs text-slate-400">
|
||
🔗 {artwork.shares?.toLocaleString()}
|
||
</span>
|
||
</div>
|
||
{artwork.heat_score > 5 && (
|
||
<span className="inline-flex items-center gap-1 mt-2 px-2 py-0.5 rounded-md text-[10px] font-medium bg-orange-500/20 text-orange-400 border border-orange-500/30">
|
||
<i className="fa-solid fa-fire" /> Rising
|
||
</span>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
function RecentComment({ comment }) {
|
||
return (
|
||
<div className="flex items-start gap-3 py-3 border-b border-white/5 last:border-0">
|
||
<div className="w-8 h-8 rounded-full bg-white/10 flex items-center justify-center text-xs text-slate-400 flex-shrink-0">
|
||
<i className="fa-solid fa-comment" />
|
||
</div>
|
||
<div className="min-w-0 flex-1">
|
||
<p className="text-sm text-white">
|
||
<span className="font-medium text-accent">{comment.author_name}</span>
|
||
{' '}on{' '}
|
||
<span className="text-slate-300">{comment.artwork_title}</span>
|
||
</p>
|
||
<p className="text-xs text-slate-500 mt-0.5 line-clamp-2">{comment.body}</p>
|
||
<p className="text-[10px] text-slate-600 mt-1">
|
||
{new Date(comment.created_at).toLocaleDateString()}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default function StudioDashboard() {
|
||
const { props } = usePage()
|
||
const { kpis, topPerformers, recentComments } = props
|
||
|
||
return (
|
||
<StudioLayout title="Studio Overview">
|
||
{/* KPI Cards */}
|
||
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-4 mb-8">
|
||
{kpiConfig.map((config) => (
|
||
<KpiCard key={config.key} config={config} value={kpis?.[config.key] ?? 0} />
|
||
))}
|
||
</div>
|
||
|
||
{/* Top Performers */}
|
||
<div className="mb-8">
|
||
<div className="flex items-center justify-between mb-4">
|
||
<h2 className="text-lg font-bold text-white">Your Top Performers</h2>
|
||
<span className="text-xs text-slate-500">Last 7 days</span>
|
||
</div>
|
||
{topPerformers?.length > 0 ? (
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{topPerformers.map((art) => (
|
||
<TopPerformerCard key={art.id} artwork={art} />
|
||
))}
|
||
</div>
|
||
) : (
|
||
<div className="bg-nova-900/40 border border-white/10 rounded-2xl p-8 text-center">
|
||
<p className="text-slate-500 text-sm">No artworks yet. Upload your first creation!</p>
|
||
<Link
|
||
href="/upload"
|
||
className="inline-flex items-center gap-2 mt-4 px-5 py-2.5 rounded-xl bg-accent hover:bg-accent/90 text-white text-sm font-semibold transition-all shadow-lg shadow-accent/25"
|
||
>
|
||
<i className="fa-solid fa-cloud-arrow-up" /> Upload
|
||
</Link>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Recent Comments */}
|
||
<div>
|
||
<h2 className="text-lg font-bold text-white mb-4">Recent Comments</h2>
|
||
<div className="bg-nova-900/40 border border-white/10 rounded-2xl p-4">
|
||
{recentComments?.length > 0 ? (
|
||
recentComments.map((c) => <RecentComment key={c.id} comment={c} />)
|
||
) : (
|
||
<p className="text-slate-500 text-sm text-center py-4">No comments yet</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</StudioLayout>
|
||
)
|
||
}
|