diff --git a/src/components/TRip/BreadcrumbNav.jsx b/src/components/TRip/BreadcrumbNav.jsx
index 4c76754..c843603 100644
--- a/src/components/TRip/BreadcrumbNav.jsx
+++ b/src/components/TRip/BreadcrumbNav.jsx
@@ -7,19 +7,24 @@ export default function BreadcrumbNav({ currentPage }) {
];
return (
-
+
+
+
+ Self Service
+
+
);
}
diff --git a/src/components/TRip/MediaRequestForm.jsx b/src/components/TRip/MediaRequestForm.jsx
index 4f36ed5..bc27670 100644
--- a/src/components/TRip/MediaRequestForm.jsx
+++ b/src/components/TRip/MediaRequestForm.jsx
@@ -123,6 +123,8 @@ export default function MediaRequestForm() {
metadataFetchToastId.current = toast.info("Retrieving metadata...",
{
autoClose: false,
+ progress: 0,
+ closeOnClick: false,
}
);
if (type === "artist") {
@@ -222,6 +224,42 @@ export default function MediaRequestForm() {
}
};
+ const allTracksLoaded = albums.every(({ id }) => Array.isArray(tracksByAlbum[id]) && tracksByAlbum[id].length > 0);
+
+ const handleToggleAllAlbums = () => {
+ const allSelected = albums.every(({ id }) => {
+ const allTracks = tracksByAlbum[id] || [];
+ return selectedTracks[id]?.length === allTracks.length && allTracks.length > 0;
+ });
+
+ const newSelection = {};
+ albums.forEach(({ id }) => {
+ const allTracks = tracksByAlbum[id] || [];
+ if (allSelected) {
+ // Uncheck all
+ newSelection[id] = [];
+ } else {
+ // Check all tracks in the album
+ newSelection[id] = allTracks.map(track => String(track.id));
+ }
+ });
+ setSelectedTracks(newSelection);
+ };
+
+ {
+ e.preventDefault();
+ if (!allTracksLoaded) return; // prevent clicking before data ready
+ handleToggleAllAlbums();
+ }}
+ className={`text-sm hover:underline cursor-pointer ${!allTracksLoaded ? "text-gray-400 dark:text-gray-500 pointer-events-none" : "text-blue-600"
+ }`}
+ >
+ Check / Uncheck All Albums
+
+
// Sequentially fetch tracks for albums not loaded yet
@@ -233,9 +271,14 @@ export default function MediaRequestForm() {
if (albumsToFetch.length === 0) return;
const fetchTracksSequentially = async () => {
- const minDelay = 600; // ms between API requests
+ const minDelay = 400; // ms between API requests
setIsFetching(true);
- for (const album of albumsToFetch) {
+
+ const totalAlbums = albumsToFetch.length;
+
+ for (let index = 0; index < totalAlbums; index++) {
+ const album = albumsToFetch[index];
+
if (isCancelled) break;
setLoadingAlbumId(album.id);
@@ -263,14 +306,24 @@ export default function MediaRequestForm() {
setTracksByAlbum((prev) => ({ ...prev, [album.id]: [] }));
setSelectedTracks((prev) => ({ ...prev, [album.id]: [] }));
}
+
+ // Update progress toast
+ toast.update(metadataFetchToastId.current, {
+ progress: (index + 1) / totalAlbums,
+ render: `Retrieving metadata... (${index + 1} / ${totalAlbums})`,
+ });
}
+
setLoadingAlbumId(null);
setIsFetching(false);
- try {
- toast.done(metadataFetchToastId.current);
- } catch (err) {
- console.log(err);
- };
+
+ // Finish the toast
+ toast.update(metadataFetchToastId.current, {
+ render: "Metadata retrieved!",
+ type: "success",
+ progress: 1,
+ autoClose: 1500,
+ });
};
fetchTracksSequentially();
@@ -281,6 +334,7 @@ export default function MediaRequestForm() {
}, [albums, type]);
+
// Toggle individual track checkbox
const toggleTrack = (albumId, trackId) => {
setSelectedTracks((prev) => {
@@ -337,21 +391,36 @@ export default function MediaRequestForm() {
}
setIsSubmitting(true);
try {
- // Example: simulate submission delay
- await new Promise((resolve) => setTimeout(resolve, 1500));
const allSelectedIds = Object.values(selectedTracks)
.filter(arr => Array.isArray(arr)) // skip null entries
.flat();
+
+ const response = await authFetch(`${API_URL}/trip/bulk_fetch`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ body: JSON.stringify({ track_ids: allSelectedIds }),
+ });
+
+ if (!response.ok) {
+ throw new Error(`Server error: ${response.status}`);
+ }
+
+ const data = await response.json();
toast.success(`Request submitted! (${allSelectedIds.length} tracks)`);
console.debug("Requested: ", selectedTracks);
console.debug("Flattened: ", allSelectedIds);
+ console.debug("Server response: ", data);
} catch (err) {
+ console.error(err);
toast.error("Failed to submit request.");
} finally {
setIsSubmitting(false);
}
};
+
return (