project-standalo-sonic-cloud/app/label/dashboard/page.tsx

210 lines
6.3 KiB
TypeScript

'use client'
import { useState, useEffect } from 'react'
import { LabelStats } from '@/components/LabelStats'
import { ArtistRoster } from '@/components/ArtistRoster'
import { InvitationCard } from '@/components/InvitationCard'
import { InviteArtistModal } from '@/components/InviteArtistModal'
export default function LabelDashboardPage() {
const [label, setLabel] = useState<any>(null)
const [stats, setStats] = useState<any>(null)
const [invitations, setInvitations] = useState<any[]>([])
const [loading, setLoading] = useState(true)
const [isInviteModalOpen, setIsInviteModalOpen] = useState(false)
useEffect(() => {
fetchDashboardData()
}, [])
const fetchDashboardData = async () => {
try {
// Check authentication
const userRes = await fetch('/api/users/me')
if (!userRes.ok) {
window.location.href = '/login'
return
}
const userData = await userRes.json()
// Fetch user's label
const labelRes = await fetch(`/api/users/${userData.user.id}/label`)
if (!labelRes.ok) {
window.location.href = '/label/create'
return
}
const labelData = await labelRes.json()
setLabel(labelData.label)
// Fetch stats
const statsRes = await fetch(`/api/labels/${labelData.label.id}/stats`)
if (statsRes.ok) {
const statsData = await statsRes.json()
setStats(statsData.stats)
}
// Fetch invitations
const invitationsRes = await fetch(`/api/labels/${labelData.label.id}/invitations`)
if (invitationsRes.ok) {
const invitationsData = await invitationsRes.json()
setInvitations(invitationsData.invitations || [])
}
} catch (error) {
console.error('Failed to fetch dashboard data:', error)
} finally {
setLoading(false)
}
}
const handleRemoveArtist = async (artistId: string) => {
if (!confirm('Are you sure you want to remove this artist from your label?')) {
return
}
try {
const res = await fetch(`/api/labels/${label.id}/artists/${artistId}`, {
method: 'DELETE'
})
if (res.ok) {
fetchDashboardData()
} else {
alert('Failed to remove artist')
}
} catch (error) {
console.error('Failed to remove artist:', error)
alert('Network error')
}
}
const handleCancelInvitation = async (invitationId: string) => {
try {
const res = await fetch(`/api/invitations/${invitationId}`, {
method: 'DELETE'
})
if (res.ok) {
setInvitations(invitations.filter(inv => inv.id !== invitationId))
} else {
alert('Failed to cancel invitation')
}
} catch (error) {
console.error('Failed to cancel invitation:', error)
alert('Network error')
}
}
if (loading) {
return (
<main className="min-h-screen bg-zinc-950 flex items-center justify-center">
<p className="text-zinc-400">Loading dashboard...</p>
</main>
)
}
if (!label) {
return (
<main className="min-h-screen bg-zinc-950 flex items-center justify-center">
<div className="text-center">
<p className="text-xl text-zinc-400 mb-4">You don't have a label yet</p>
<a
href="/label/create"
className="px-6 py-3 bg-purple-600 hover:bg-purple-700 text-white font-semibold rounded-lg inline-block"
>
Create Label
</a>
</div>
</main>
)
}
return (
<main className="min-h-screen bg-zinc-950">
<div className="max-w-7xl mx-auto px-4 py-8">
{/* Header */}
<div className="mb-8 flex items-center justify-between">
<div>
<h1 className="text-4xl font-bold text-white mb-2">{label.name}</h1>
<p className="text-xl text-zinc-400">Label Dashboard</p>
</div>
<div className="flex gap-3">
<a
href="/label/settings"
className="px-6 py-3 bg-zinc-800 hover:bg-zinc-700 text-white font-medium rounded-lg transition"
>
Settings
</a>
<button
onClick={() => setIsInviteModalOpen(true)}
className="px-6 py-3 bg-purple-600 hover:bg-purple-700 text-white font-medium rounded-lg transition"
>
Invite Artist
</button>
</div>
</div>
{/* Stats */}
{stats && (
<section className="mb-12">
<LabelStats stats={stats} />
</section>
)}
{/* Artist Roster */}
<section className="mb-12">
<div className="flex items-center justify-between mb-6">
<h2 className="text-2xl font-bold text-white">Your Artists</h2>
<button
onClick={() => setIsInviteModalOpen(true)}
className="text-purple-400 hover:text-purple-300 font-medium"
>
+ Invite Artist
</button>
</div>
<ArtistRoster
artists={label.artists || []}
isOwner={true}
emptyMessage="No artists signed yet. Start inviting artists to join your label!"
onRemoveArtist={handleRemoveArtist}
onArtistClick={(artistId) => {
window.location.href = `/artist/${artistId}`
}}
/>
</section>
{/* Pending Invitations */}
{invitations.length > 0 && (
<section>
<h2 className="text-2xl font-bold text-white mb-6">
Pending Invitations ({invitations.filter(inv => inv.status === 'PENDING').length})
</h2>
<div className="space-y-4">
{invitations
.filter(inv => inv.status === 'PENDING')
.map((invitation) => (
<InvitationCard
key={invitation.id}
invitation={invitation}
viewType="label"
onCancel={handleCancelInvitation}
/>
))}
</div>
</section>
)}
</div>
{/* Invite Modal */}
<InviteArtistModal
isOpen={isInviteModalOpen}
labelId={label.id}
onClose={() => setIsInviteModalOpen(false)}
onInviteSent={() => {
setIsInviteModalOpen(false)
fetchDashboardData()
}}
/>
</main>
)
}