import { useEffect, useState } from "react"; import { Link, useParams } from "react-router-dom"; import axiosInstance from "../api/axiosInstance"; import { useAuth } from "../context/authContext"; import type { SongDetail as SongDetailType } from "../utils/types"; const ROLE_LABELS: Record = { MAIN_VOCAL: "Main Vocal", FEATURED: "Featured", PRODUCER: "Producer", SONGWRITER: "Songwriter", COMPOSER: "Composer", MIXER: "Mixer", ENGINEER: "Engineer", }; const formatRole = (role: string): string => { return ROLE_LABELS[role] || role.replace(/_/g, " "); }; // convert a regular youtube URL to an embeddable URL const toEmbedUrl = (url: string): string => { try { const parsed = new URL(url); // youtube.com/watch?v=ID if ( (parsed.hostname === "www.youtube.com" || parsed.hostname === "youtube.com") && parsed.searchParams.has("v") ) { return `https://www.youtube.com/embed/${parsed.searchParams.get("v")}`; } // youtu.be/ID if (parsed.hostname === "youtu.be") { return `https://www.youtube.com/embed${parsed.pathname}`; } // already an embed URL or other provider – return as-is return url; } catch { return url; } }; const renderStars = (grade: number) => { return (
{[1, 2, 3, 4, 5].map((star) => ( ))}
); }; const SongDetail = () => { const { id } = useParams<{ id: string }>(); const { user } = useAuth(); const [song, setSong] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchSong = async () => { try { setLoading(true); const response = await axiosInstance.get(`/songs/${id}/details`); setSong(response.data); } catch (err) { console.error("Error fetching song details:", err); setError("Failed to load song details."); } finally { setLoading(false); } }; if (id) fetchSong(); }, [id]); const toggleLike = async () => { if (!song) return; try { await axiosInstance.post(`/musical-entity/${song.id}/like`); setSong((prev) => prev ? { ...prev, isLikedByCurrentUser: !prev.isLikedByCurrentUser } : prev, ); } catch (err) { console.error("Error toggling like:", err); } }; if (loading) { return (

Loading song…

); } if (error || !song) { return (

{error ?? "Song not found"}

← Back to Home
); } const otherContributors = song.contributions.filter( (c) => c.artistName !== song.releasedBy, ); const avgRating = song.reviews.length > 0 ? ( song.reviews.reduce((sum, r) => sum + r.grade, 0) / song.reviews.length ).toFixed(1) : null; return (
{/* Back link */} Back to Home {/* Hero section */}
{/* Cover art */}
{song.title} { (e.target as HTMLImageElement).src = "/favicon.png"; }} />
{/* Song info */}
{song.genre} • Song

{song.title}

{/* Main artist */}

{song.releasedBy}

{/* Album */} {song.album && (

Album: {song.album}

)} {/* Rating summary */} {avgRating && (
{renderStars(Math.round(Number(avgRating)))} {avgRating} · {song.reviews.length}{" "} {song.reviews.length === 1 ? "review" : "reviews"}
)} {/* Action buttons */} {/* todo: add add to playlist button */}
{user && ( )}
{/* YouTube embed */} {song.link && (