All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 50s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { t } from "@lingui/core/macro";
|
|
import { API_URL } from "../../config/api.ts";
|
|
import { useAuth } from "../../hooks/auth/useAuth.ts";
|
|
import type { PlaylistMembership } from "../../../shared/playlist.ts";
|
|
import type { Wire } from "../../../shared/api.ts";
|
|
import { deserializePlaylistMembership } from "../../utils/shared/deserialize.ts";
|
|
import { Modal } from "../shared/Modal.tsx";
|
|
import { PlaylistMembershipPanel } from "./PlaylistMembershipPanel.tsx";
|
|
|
|
interface AddToPlaylistModalProps {
|
|
dumpId: string;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export function AddToPlaylistModal(
|
|
{ dumpId, onClose }: AddToPlaylistModalProps,
|
|
) {
|
|
const { authFetch } = useAuth();
|
|
const [memberships, setMemberships] = useState<PlaylistMembership[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
authFetch(`${API_URL}/api/playlists/by-dump/${dumpId}/memberships`)
|
|
.then((r) => r.json())
|
|
.then((body) => {
|
|
if (body.success) {
|
|
setMemberships(
|
|
(body.data as Wire<PlaylistMembership>[]).map(
|
|
deserializePlaylistMembership,
|
|
),
|
|
);
|
|
}
|
|
})
|
|
.catch(() => {})
|
|
.finally(() => setLoading(false));
|
|
}, [dumpId, authFetch]);
|
|
|
|
const toggleMembership = async (membership: PlaylistMembership) => {
|
|
const { playlist, hasDump } = membership;
|
|
// The box only changes once the server agrees; a refusal or a dropped
|
|
// connection leaves it showing the truth.
|
|
try {
|
|
const res = await authFetch(
|
|
`${API_URL}/api/playlists/${playlist.id}/dumps/${dumpId}`,
|
|
{ method: hasDump ? "DELETE" : "POST" },
|
|
);
|
|
if (!res.ok) return;
|
|
} catch {
|
|
return;
|
|
}
|
|
setMemberships((prev) =>
|
|
prev.map((m) =>
|
|
m.playlist.id === playlist.id ? { ...m, hasDump: !hasDump } : m
|
|
)
|
|
);
|
|
};
|
|
|
|
return (
|
|
<Modal title={t`Add to playlist`} onClose={onClose}>
|
|
<PlaylistMembershipPanel
|
|
dumpId={dumpId}
|
|
memberships={memberships}
|
|
loading={loading}
|
|
onToggle={toggleMembership}
|
|
onPlaylistCreated={(membership) =>
|
|
setMemberships((prev) => [membership, ...prev])}
|
|
/>
|
|
</Modal>
|
|
);
|
|
}
|