import { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { apiFetch } from '../lib/api'; interface Playlist { id: string; title: string; description: string | null; visibility: 'private' | 'shared' | 'public'; } interface Invitation { shareId: string; playlistId: string; playlistTitle: string; permission: 'view' | 'edit'; } interface PlaylistsResponse { success: boolean; data: { owned: Playlist[]; shared: (Playlist & { permission: 'view' | 'edit' })[]; invitations?: Invitation[]; }; } export default function PlaylistsPage() { const [owned, setOwned] = useState([]); const [shared, setShared] = useState<(Playlist & { permission: 'view' | 'edit' })[]>([]); const [invitations, setInvitations] = useState([]); const [loading, setLoading] = useState(true); const [fetchError, setFetchError] = useState(null); const [createTitle, setCreateTitle] = useState(''); const [creating, setCreating] = useState(false); const [createError, setCreateError] = useState(null); const [inviteError, setInviteError] = useState(null); const [respondingId, setRespondingId] = useState(null); useEffect(() => { apiFetch('/playlists') .then((res) => { setOwned(res.data.owned); setShared(res.data.shared); setInvitations(res.data.invitations ?? []); }) .catch(() => setFetchError('Impossible de charger les playlists.')) .finally(() => setLoading(false)); }, []); async function handleCreate(e: React.FormEvent) { e.preventDefault(); if (!createTitle.trim() || creating) return; setCreating(true); setCreateError(null); try { const res = await apiFetch<{ success: boolean; data: { playlist: Playlist } }>( '/playlists', { method: 'POST', body: JSON.stringify({ title: createTitle.trim() }) } ); setOwned((prev) => [res.data.playlist, ...prev]); setCreateTitle(''); } catch { setCreateError('Impossible de créer la playlist.'); } setCreating(false); } async function respondInvitation(inv: Invitation, status: 'accepted' | 'revoked') { if (respondingId) return; setRespondingId(inv.shareId); setInviteError(null); try { await apiFetch(`/playlists/${inv.playlistId}/share/${inv.shareId}`, { method: 'PATCH', body: JSON.stringify({ status }), }); setInvitations((prev) => prev.filter((i) => i.shareId !== inv.shareId)); if (status === 'accepted') { const res = await apiFetch('/playlists'); setOwned(res.data.owned); setShared(res.data.shared); setInvitations(res.data.invitations ?? []); } } catch { setInviteError("Impossible de répondre à l'invitation."); } setRespondingId(null); } if (loading) { return (
{[...Array(3)].map((_, i) => (
))}
); } if (fetchError) { return

{fetchError}

; } return (

Mes playlists

{/* Créer */}
setCreateTitle(e.target.value)} placeholder="Nouvelle playlist…" className="flex-1 rounded border border-od-border bg-od-surface px-3 py-2 text-sm text-od-text placeholder-od-muted outline-none focus:border-od-accent" />
{createError &&

{createError}

}
{/* Invitations reçues */} {invitations.length > 0 && (

Invitations

{inviteError &&

{inviteError}

} {invitations.map((inv) => (
{inv.playlistTitle} {inv.permission}
))}
)} {/* Mes playlists */} {owned.length > 0 && (

Créées

{owned.map((p) => )}
)} {/* Partagées */} {shared.length > 0 && (

Partagées avec moi

{shared.map((p) => )}
)} {owned.length === 0 && shared.length === 0 && invitations.length === 0 && (

Aucune playlist pour l'instant.

)}
); } function PlaylistRow({ playlist, badge }: { playlist: Playlist; badge?: string }) { return ( {playlist.title}
{badge && ( {badge} )} {playlist.visibility === 'private' ? '⊠' : playlist.visibility === 'shared' ? '⊡' : '⊞'}
); }