Enhance authentication flow with improved error handling and logging in requireAuthHook. Refine HLS stream initialization and metadata fetching in AudioPlayer to handle station changes gracefully. Improve toast notifications and autocomplete behavior in LyricSearch. Simplify RandomMsg logic and remove unused imports. Add track and album count display in MediaRequestForm and enhance artist selection. Introduce dark mode styles for tables and dialogs in RequestManagement.css. Adjust imports and ensure proper usage of requireAuthHook in index.astro and requests.astro.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useRef, Suspense, lazy } from "react";
|
||||
import React, { useState, useEffect, useRef, Suspense, lazy, useMemo } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import { Button } from "@mui/joy";
|
||||
import { Accordion, AccordionTab } from "primereact/accordion";
|
||||
@@ -62,7 +62,7 @@ export default function MediaRequestForm() {
|
||||
searchArtists.lastCall = Date.now();
|
||||
|
||||
const res = await authFetch(
|
||||
`${API_URL}/trip/get_artists_by_name?artist=${encodeURIComponent(query)}`
|
||||
`${API_URL}/trip/get_artists_by_name?artist=${encodeURIComponent(query)}&group=true`
|
||||
);
|
||||
if (!res.ok) throw new Error("API error");
|
||||
const data = await res.json();
|
||||
@@ -82,9 +82,89 @@ export default function MediaRequestForm() {
|
||||
? text
|
||||
: text.slice(0, maxLen - 3) + '...';
|
||||
|
||||
const selectArtist = (artist) => {
|
||||
// artist may be a grouped item or an alternate object
|
||||
const value = artist.artist || artist.name || "";
|
||||
setSelectedArtist(artist);
|
||||
setArtistInput(value);
|
||||
setArtistSuggestions([]);
|
||||
|
||||
// Hide autocomplete panel and blur input to prevent leftover white box.
|
||||
// Use a small timeout so PrimeReact internal handlers can finish first.
|
||||
try {
|
||||
const ac = autoCompleteRef.current;
|
||||
// Give PrimeReact a tick to finish its events, then call hide().
|
||||
setTimeout(() => {
|
||||
try {
|
||||
if (ac && typeof ac.hide === "function") {
|
||||
ac.hide();
|
||||
}
|
||||
|
||||
// If panel still exists, hide it via style (safer than removing the node)
|
||||
setTimeout(() => {
|
||||
const panel = document.querySelector('.p-autocomplete-panel');
|
||||
if (panel) {
|
||||
panel.style.display = 'none';
|
||||
panel.style.opacity = '0';
|
||||
panel.style.visibility = 'hidden';
|
||||
panel.style.pointerEvents = 'none';
|
||||
}
|
||||
}, 10);
|
||||
|
||||
// blur the input element if present
|
||||
const inputEl = ac?.getInput ? ac.getInput() : document.querySelector('.p-autocomplete-input');
|
||||
if (inputEl && typeof inputEl.blur === 'function') inputEl.blur();
|
||||
} catch (innerErr) {
|
||||
console.debug('selectArtist: overlay hide fallback failed', innerErr);
|
||||
}
|
||||
}, 0);
|
||||
} catch (err) {
|
||||
console.debug('selectArtist: unable to schedule overlay hide', err);
|
||||
}
|
||||
};
|
||||
|
||||
const totalAlbums = albums.length;
|
||||
const totalTracks = useMemo(() =>
|
||||
Object.values(tracksByAlbum).reduce((sum, arr) => (Array.isArray(arr) ? sum + arr.length : sum), 0),
|
||||
[tracksByAlbum]
|
||||
);
|
||||
|
||||
const artistItemTemplate = (artist) => {
|
||||
if (!artist) return null;
|
||||
return <div>{truncate(artist.artist, 58)}</div>;
|
||||
|
||||
const alts = artist.alternatives || artist.alternates || [];
|
||||
|
||||
return (
|
||||
<div className="py-1">
|
||||
<div className="font-medium flex items-baseline gap-2">
|
||||
<span>{truncate(artist.artist || artist.name, 58)}</span>
|
||||
<span className="text-xs text-neutral-400">ID: {artist.id}</span>
|
||||
</div>
|
||||
{alts.length > 0 && (
|
||||
<div className="text-xs text-neutral-500 mt-1">
|
||||
<div className="flex flex-wrap gap-2 items-center">
|
||||
<span className="mr-1">Alternates:</span>
|
||||
{alts.map((alt, idx) => (
|
||||
<span key={alt.id || idx} className="inline-flex items-center max-w-[200px] truncate">
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
selectArtist({ ...alt, artist: alt.artist || alt.name });
|
||||
}}
|
||||
className="ml-1 mr-1 underline hover:text-blue-600 bg-transparent border-none p-0 cursor-pointer"
|
||||
>
|
||||
{truncate(alt.artist || alt.name, 26)}
|
||||
</button>
|
||||
<span className="text-xs text-neutral-400">ID: {alt.id}</span>
|
||||
{idx < alts.length - 1 ? <span className="mx-1">,</span> : null}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -553,19 +633,25 @@ export default function MediaRequestForm() {
|
||||
|
||||
{type === "artist" && albums.length > 0 && (
|
||||
<>
|
||||
<div className="flex justify-end mb-2">
|
||||
<a
|
||||
href="#"
|
||||
role="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault(); // prevent page jump
|
||||
handleToggleAllAlbums();
|
||||
}}
|
||||
className="text-sm text-blue-600 hover:underline cursor-pointer"
|
||||
>
|
||||
Check / Uncheck All Albums
|
||||
</a>
|
||||
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<div className="text-sm text-neutral-600 dark:text-neutral-400">
|
||||
<strong className="mr-2">Albums:</strong> {totalAlbums}
|
||||
<span className="mx-3">|</span>
|
||||
<strong className="mr-2">Tracks:</strong> {totalTracks}
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
href="#"
|
||||
role="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault(); // prevent page jump
|
||||
handleToggleAllAlbums();
|
||||
}}
|
||||
className="text-sm text-blue-600 hover:underline cursor-pointer"
|
||||
>
|
||||
Check / Uncheck All Albums
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<Accordion
|
||||
multiple
|
||||
@@ -588,7 +674,7 @@ export default function MediaRequestForm() {
|
||||
<AccordionTab
|
||||
key={id}
|
||||
header={
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-2 w-full">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={allChecked}
|
||||
@@ -605,6 +691,13 @@ export default function MediaRequestForm() {
|
||||
{loadingAlbumId === id && <Spinner />}
|
||||
</span>
|
||||
<small className="ml-2 text-neutral-500 dark:text-neutral-400">({release_date})</small>
|
||||
<span className="ml-auto text-xs text-neutral-500">
|
||||
{typeof tracksByAlbum[id] === 'undefined' ? (
|
||||
loadingAlbumId === id ? 'Loading...' : '...'
|
||||
) : (
|
||||
`${allTracks.length} track${allTracks.length !== 1 ? 's' : ''}`
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user