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([]); 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[]).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 ( setMemberships((prev) => [membership, ...prev])} /> ); }