109 lines
3.8 KiB
TypeScript
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't have an account?{' '}
|
|
<Link href="/register" className="text-purple-400 hover:text-purple-300">
|
|
Sign up free
|
|
</Link>
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|