Ignore:
Timestamp:
02/10/26 21:58:39 (5 months ago)
Author:
Filip Gavrilovski <filipgavrilovski28@…>
Branches:
main
Children:
92db381
Parents:
0808ef2
Message:

refactor artist, collection, listener components to have similar style as other components; refactor some dto-s

File:
1 edited

Legend:

Unmodified
Added
Removed
  • frontend/src/components/search/SongResult.tsx

    r0808ef2 r1579b4f  
    1 import { useNavigate } from "react-router-dom";
    2 import { usePlayer } from "../../context/playerContext";
     1import axiosInstance from "../../api/axiosInstance";
    32import type { Song } from "../../utils/types";
     3import SongItem from "../SongItem";
    44
    55interface SongResultProps {
    66        song: Song;
     7        /** Propagate like state change upward if needed */
     8        onLikeToggled?: (songId: number, isLiked: boolean) => void;
    79}
    810
    9 const toEmbedUrl = (url: string): string => {
    10         try {
    11                 const parsed = new URL(url);
    12                 if (
    13                         (parsed.hostname === "www.youtube.com" ||
    14                                 parsed.hostname === "youtube.com") &&
    15                         parsed.searchParams.has("v")
    16                 ) {
    17                         return `https://www.youtube.com/embed/${parsed.searchParams.get("v")}`;
     11const SongResult = ({ song, onLikeToggled }: SongResultProps) => {
     12        const handleLike = async (songId: number) => {
     13                try {
     14                        const response = await axiosInstance.post(
     15                                `/musical-entity/${songId}/like`,
     16                        );
     17                        onLikeToggled?.(songId, response.data.isLiked);
     18                } catch (err) {
     19                        console.error("Error toggling like:", err);
    1820                }
    19                 if (parsed.hostname === "youtu.be") {
    20                         return `https://www.youtube.com/embed${parsed.pathname}`;
    21                 }
    22                 return url;
    23         } catch {
    24                 return url;
    25         }
    26 };
     21        };
    2722
    28 const SongResult = ({ song }: SongResultProps) => {
    29         const navigate = useNavigate();
    30         const { play, currentSong } = usePlayer();
    31 
    32         return (
    33                 <div
    34                         onClick={() => navigate(`/songs/${song.id}`)}
    35                         className="flex items-center gap-4 p-3 rounded-lg hover:bg-white/5 cursor-pointer transition-colors group"
    36                 >
    37                         <img
    38                                 src={song.cover || "/favicon.png"}
    39                                 alt={song.title}
    40                                 className="w-12 h-12 rounded object-cover"
    41                                 onError={(e) => {
    42                                         (e.target as HTMLImageElement).src = "/favicon.png";
    43                                 }}
    44                         />
    45                         <div className="flex-1 min-w-0">
    46                                 <p className="text-white font-medium truncate">{song.title}</p>
    47                                 <p className="text-sm text-gray-400 truncate">
    48                                         Song • {song.releasedBy}
    49                                 </p>
    50                         </div>
    51                         <span className="text-xs text-gray-500 uppercase tracking-wider mr-2">
    52                                 {song.genre}
    53                         </span>
    54                         {song.link && (
    55                                 <button
    56                                         onClick={(e) => {
    57                                                 e.stopPropagation();
    58                                                 play({
    59                                                         id: song.id,
    60                                                         title: song.title,
    61                                                         artist: song.releasedBy,
    62                                                         cover: song.cover,
    63                                                         embedUrl: toEmbedUrl(song.link!),
    64                                                 });
    65                                         }}
    66                                         className={`p-2 rounded-full transition-all opacity-0 group-hover:opacity-100 ${
    67                                                 currentSong?.id === song.id
    68                                                         ? "bg-white text-[#1db954]"
    69                                                         : "bg-[#1db954] text-black hover:scale-110"
    70                                         }`}
    71                                         aria-label={currentSong?.id === song.id ? "Now playing" : "Play song"}
    72                                 >
    73                                         {currentSong?.id === song.id ? (
    74                                                 <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
    75                                                         <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
    76                                                 </svg>
    77                                         ) : (
    78                                                 <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
    79                                                         <path d="M8 5v14l11-7z" />
    80                                                 </svg>
    81                                         )}
    82                                 </button>
    83                         )}
    84                 </div>
    85         );
     23        return <SongItem song={song} label="Song" onLikeToggle={handleLike} />;
    8624};
    8725
Note: See TracChangeset for help on using the changeset viewer.