.refine check availibility
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import type { ReactNode } from "react";
|
||||
import type { TrackAvailability } from "@/types/api";
|
||||
import { openExternal } from "@/lib/utils";
|
||||
import { AmazonAvailabilityIcon, QobuzAvailabilityIcon, TidalAvailabilityIcon } from "./PlatformIcons";
|
||||
|
||||
interface AvailabilityLinkEntry {
|
||||
id: string;
|
||||
found: boolean;
|
||||
url?: string;
|
||||
icon: ReactNode;
|
||||
}
|
||||
|
||||
function getAvailabilityLinkEntries(availability: TrackAvailability): AvailabilityLinkEntry[] {
|
||||
const tidalUrl = availability.tidal_url?.trim() || "";
|
||||
const qobuzUrl = availability.qobuz_url?.trim() || "";
|
||||
const amazonUrl = availability.amazon_url?.trim() || "";
|
||||
|
||||
return [
|
||||
{
|
||||
id: "tidal",
|
||||
found: tidalUrl !== "",
|
||||
url: tidalUrl,
|
||||
icon: <TidalAvailabilityIcon className={`w-4 h-4 shrink-0 ${tidalUrl ? "text-green-500" : "text-red-500"}`}/>,
|
||||
},
|
||||
{
|
||||
id: "qobuz",
|
||||
found: qobuzUrl !== "",
|
||||
url: qobuzUrl,
|
||||
icon: <QobuzAvailabilityIcon className={`w-4 h-4 shrink-0 ${qobuzUrl ? "text-green-500" : "text-red-500"}`}/>,
|
||||
},
|
||||
{
|
||||
id: "amazon",
|
||||
found: amazonUrl !== "",
|
||||
url: amazonUrl,
|
||||
icon: <AmazonAvailabilityIcon className={`w-4 h-4 shrink-0 ${amazonUrl ? "text-green-500" : "text-red-500"}`}/>,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function hasAvailabilityLinks(availability?: TrackAvailability): boolean {
|
||||
if (!availability) {
|
||||
return false;
|
||||
}
|
||||
return getAvailabilityLinkEntries(availability).some((entry) => entry.found);
|
||||
}
|
||||
|
||||
export function AvailabilityLinks({ availability }: {
|
||||
availability?: TrackAvailability;
|
||||
}) {
|
||||
if (!availability) {
|
||||
return <p>Check Availability</p>;
|
||||
}
|
||||
|
||||
const entries = getAvailabilityLinkEntries(availability);
|
||||
return (
|
||||
<div className="flex flex-col gap-1.5 w-[260px] max-w-[260px] pointer-events-auto">
|
||||
{entries.map((entry) => entry.found ? (
|
||||
<button
|
||||
key={entry.id}
|
||||
type="button"
|
||||
onClick={() => entry.url && openExternal(entry.url)}
|
||||
className="flex items-center gap-2 text-left text-xs hover:underline min-w-0 cursor-pointer"
|
||||
title={entry.url}
|
||||
>
|
||||
{entry.icon}
|
||||
<span className="truncate whitespace-nowrap leading-5 min-w-0">
|
||||
{entry.url}
|
||||
</span>
|
||||
</button>
|
||||
) : (
|
||||
<div
|
||||
key={entry.id}
|
||||
className="flex items-center gap-2 text-left text-xs min-w-0"
|
||||
>
|
||||
{entry.icon}
|
||||
<span className="truncate whitespace-nowrap leading-5 min-w-0 text-red-500">
|
||||
Not Found
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import { Download, FolderOpen, CheckCircle, XCircle, FileText, FileCheck, Globe,
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip";
|
||||
import type { TrackMetadata, TrackAvailability } from "@/types/api";
|
||||
import { TidalAvailabilityIcon, QobuzAvailabilityIcon, AmazonAvailabilityIcon } from "./PlatformIcons";
|
||||
import { usePreview } from "@/hooks/usePreview";
|
||||
import { AvailabilityLinks, hasAvailabilityLinks } from "./AvailabilityLinks";
|
||||
interface TrackInfoProps {
|
||||
track: TrackMetadata & {
|
||||
album_name: string;
|
||||
@@ -135,15 +135,11 @@ export function TrackInfo({ track, isDownloading, downloadingTrack, isDownloaded
|
||||
{track.spotify_id && onCheckAvailability && (<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button onClick={() => onCheckAvailability(track.spotify_id!)} variant="outline" size="icon" disabled={checkingAvailability}>
|
||||
{checkingAvailability ? (<Spinner />) : availability ? (<CheckCircle className="h-4 w-4 text-green-500"/>) : (<Globe className="h-4 w-4"/>)}
|
||||
{checkingAvailability ? (<Spinner />) : availability ? (hasAvailabilityLinks(availability) ? (<CheckCircle className="h-4 w-4 text-green-500"/>) : (<XCircle className="h-4 w-4 text-red-500"/>)) : (<Globe className="h-4 w-4"/>)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{availability ? (<div className="flex items-center gap-2">
|
||||
<TidalAvailabilityIcon className={`w-4 h-4 ${availability.tidal ? "text-green-500" : "text-red-500"}`}/>
|
||||
<QobuzAvailabilityIcon className={`w-4 h-4 ${availability.qobuz ? "text-green-500" : "text-red-500"}`}/>
|
||||
<AmazonAvailabilityIcon className={`w-4 h-4 ${availability.amazon ? "text-green-500" : "text-red-500"}`}/>
|
||||
</div>) : (<p>Check Availability</p>)}
|
||||
<TooltipContent className="pointer-events-auto">
|
||||
<AvailabilityLinks availability={availability}/>
|
||||
</TooltipContent>
|
||||
</Tooltip>)}
|
||||
{isDownloaded && (<Tooltip>
|
||||
|
||||
@@ -5,8 +5,8 @@ import { Spinner } from "@/components/ui/spinner";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip";
|
||||
import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination";
|
||||
import type { TrackMetadata, TrackAvailability } from "@/types/api";
|
||||
import { TidalAvailabilityIcon, QobuzAvailabilityIcon, AmazonAvailabilityIcon } from "./PlatformIcons";
|
||||
import { usePreview } from "@/hooks/usePreview";
|
||||
import { AvailabilityLinks, hasAvailabilityLinks } from "./AvailabilityLinks";
|
||||
interface TrackListProps {
|
||||
tracks: TrackMetadata[];
|
||||
searchQuery: string;
|
||||
@@ -172,6 +172,22 @@ export function TrackList({ tracks, searchQuery, sortBy, selectedTracks, downloa
|
||||
return plays;
|
||||
return num.toLocaleString();
|
||||
};
|
||||
const getAvailabilityButtonIcon = (spotifyId?: string) => {
|
||||
if (!spotifyId) {
|
||||
return <Globe className="h-4 w-4"/>;
|
||||
}
|
||||
if (checkingAvailabilityTrack === spotifyId) {
|
||||
return <Spinner />;
|
||||
}
|
||||
const availability = availabilityMap?.get(spotifyId);
|
||||
if (!availability) {
|
||||
return <Globe className="h-4 w-4"/>;
|
||||
}
|
||||
if (hasAvailabilityLinks(availability)) {
|
||||
return <CheckCircle className="h-4 w-4 text-green-500"/>;
|
||||
}
|
||||
return <XCircle className="h-4 w-4 text-red-500"/>;
|
||||
};
|
||||
return (<div className="space-y-4">
|
||||
<div className="rounded-md border">
|
||||
<div className="overflow-x-auto">
|
||||
@@ -323,15 +339,11 @@ export function TrackList({ tracks, searchQuery, sortBy, selectedTracks, downloa
|
||||
{track.spotify_id && onCheckAvailability && (<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button onClick={() => onCheckAvailability(track.spotify_id!)} size="icon" variant="outline" disabled={checkingAvailabilityTrack === track.spotify_id}>
|
||||
{checkingAvailabilityTrack === track.spotify_id ? (<Spinner />) : availabilityMap?.has(track.spotify_id) ? (<CheckCircle className="h-4 w-4 text-green-500"/>) : (<Globe className="h-4 w-4"/>)}
|
||||
{getAvailabilityButtonIcon(track.spotify_id)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{availabilityMap?.has(track.spotify_id) ? (<div className="flex items-center gap-2">
|
||||
<TidalAvailabilityIcon className={`w-4 h-4 ${availabilityMap.get(track.spotify_id)?.tidal ? "text-green-500" : "text-red-500"}`}/>
|
||||
<QobuzAvailabilityIcon className={`w-4 h-4 ${availabilityMap.get(track.spotify_id)?.qobuz ? "text-green-500" : "text-red-500"}`}/>
|
||||
<AmazonAvailabilityIcon className={`w-4 h-4 ${availabilityMap.get(track.spotify_id)?.amazon ? "text-green-500" : "text-red-500"}`}/>
|
||||
</div>) : (<p>Check Availability</p>)}
|
||||
<TooltipContent className="pointer-events-auto">
|
||||
<AvailabilityLinks availability={track.spotify_id ? availabilityMap?.get(track.spotify_id) : undefined}/>
|
||||
</TooltipContent>
|
||||
</Tooltip>)}
|
||||
</div>
|
||||
|
||||
@@ -13,9 +13,6 @@ export function useAvailability() {
|
||||
setError("No Spotify ID provided");
|
||||
return null;
|
||||
}
|
||||
if (availabilityMap.has(spotifyId)) {
|
||||
return availabilityMap.get(spotifyId)!;
|
||||
}
|
||||
setChecking(true);
|
||||
setCheckingTrackId(spotifyId);
|
||||
setError(null);
|
||||
@@ -41,7 +38,7 @@ export function useAvailability() {
|
||||
setChecking(false);
|
||||
setCheckingTrackId(null);
|
||||
}
|
||||
}, [availabilityMap]);
|
||||
}, []);
|
||||
const getAvailability = useCallback((spotifyId: string) => {
|
||||
return availabilityMap.get(spotifyId);
|
||||
}, [availabilityMap]);
|
||||
|
||||
Reference in New Issue
Block a user