project-standalo-sonic-cloud/components/SharedContentDisplay.tsx

109 lines
3.8 KiB
TypeScript

'use client';
import { useEffect } from 'react';
import Link from 'next/link';
import Image from 'next/image';
import type { ShareType, SongShareContent, PlaylistShareContent, AlbumShareContent } from '@/types/api-types';
interface SharedContentDisplayProps {
type: ShareType;
content: SongShareContent | PlaylistShareContent | AlbumShareContent;
token: string;
}
export function SharedContentDisplay({ type, content, token }: SharedContentDisplayProps) {
// Track click on mount
useEffect(() => {
fetch(`/api/share/${token}/click`, { method: 'POST' }).catch(() => {});
}, [token]);
const getCoverUrl = () => {
if (type === 'SONG') return (content as SongShareContent).coverArtUrl;
if (type === 'PLAYLIST') return (content as PlaylistShareContent).coverImageUrl;
return (content as AlbumShareContent).coverArtUrl;
};
const getTitle = () => {
if (type === 'SONG') return (content as SongShareContent).title;
if (type === 'PLAYLIST') return (content as PlaylistShareContent).name;
return (content as AlbumShareContent).title;
};
const getSubtitle = () => {
if (type === 'SONG') return (content as SongShareContent).artist.stage_name;
if (type === 'PLAYLIST') return `by ${(content as PlaylistShareContent).curator.name}`;
return (content as AlbumShareContent).artist.stage_name;
};
const getLink = () => {
if (type === 'SONG') return `/song/${content.id}`;
if (type === 'PLAYLIST') return `/playlist/${content.id}`;
return `/album/${content.id}`;
};
const typeLabel = type === 'SONG' ? 'Song' : type === 'PLAYLIST' ? 'Playlist' : 'Album';
const coverUrl = getCoverUrl();
return (
<div className="flex flex-col items-center text-center max-w-lg mx-auto">
{/* Cover Art */}
<div className="relative w-64 h-64 mb-6 rounded-xl overflow-hidden shadow-2xl">
{coverUrl ? (
<Image
src={coverUrl}
alt={getTitle()}
fill
className="object-cover"
/>
) : (
<div className="w-full h-full bg-zinc-800 flex items-center justify-center">
<svg className="w-16 h-16 text-zinc-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3" />
</svg>
</div>
)}
</div>
{/* Type Badge */}
<span className="inline-block px-3 py-1 bg-purple-600/20 text-purple-400 rounded-full text-xs font-medium mb-3">
{typeLabel}
</span>
{/* Title */}
<h1 className="text-2xl font-bold text-white mb-2">{getTitle()}</h1>
{/* Subtitle */}
<p className="text-zinc-400 mb-6">{getSubtitle()}</p>
{/* Song count for playlists/albums */}
{type !== 'SONG' && (
<p className="text-zinc-500 text-sm mb-6">
{type === 'PLAYLIST'
? `${(content as PlaylistShareContent).songCount} songs`
: `${(content as AlbumShareContent).songs?.length || 0} tracks`
}
</p>
)}
{/* CTA Button */}
<Link
href={getLink()}
className="inline-flex items-center gap-2 px-6 py-3 bg-purple-600 hover:bg-purple-700 text-white rounded-full font-medium transition-colors"
>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z"/>
</svg>
Listen on Sonic Cloud
</Link>
{/* Sign up CTA */}
<p className="text-zinc-500 text-sm mt-4">
Don&apos;t have an account?{' '}
<Link href="/register" className="text-purple-400 hover:text-purple-300">
Sign up free
</Link>
</p>
</div>
);
}