fix(dnd): align drop flow with modal add; use same backend save and show success toast; improve payload parsing for drop targets
This commit is contained in:
parent
c7dd2e6d33
commit
8a9f51a0c6
@ -1,4 +1,4 @@
|
|||||||
import { Box, Button, Flex, Heading, Spinner, Text, useBreakpointValue, IconButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, VStack } from "@chakra-ui/react";
|
import { Box, Button, Flex, Heading, Spinner, Text, useBreakpointValue, IconButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, VStack, useToast } from "@chakra-ui/react";
|
||||||
import { ChevronLeftIcon, ChevronRightIcon, SettingsIcon, DownloadIcon } from "@chakra-ui/icons";
|
import { ChevronLeftIcon, ChevronRightIcon, SettingsIcon, DownloadIcon } from "@chakra-ui/icons";
|
||||||
import React, { useState, useRef, useEffect, useCallback } from "react";
|
import React, { useState, useRef, useEffect, useCallback } from "react";
|
||||||
import { useNavigate, useLocation, Routes, Route } from "react-router-dom";
|
import { useNavigate, useLocation, Routes, Route } from "react-router-dom";
|
||||||
@ -76,6 +76,7 @@ const RekordboxReader: React.FC = () => {
|
|||||||
const [isDatabaseInitialized, setIsDatabaseInitialized] = useState(false);
|
const [isDatabaseInitialized, setIsDatabaseInitialized] = useState(false);
|
||||||
const [isSwitchingPlaylist, setIsSwitchingPlaylist] = useState(false);
|
const [isSwitchingPlaylist, setIsSwitchingPlaylist] = useState(false);
|
||||||
const { currentSong, playSong, closePlayer } = useMusicPlayer();
|
const { currentSong, playSong, closePlayer } = useMusicPlayer();
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
// Memoized song selection handler to prevent unnecessary re-renders
|
// Memoized song selection handler to prevent unnecessary re-renders
|
||||||
const handleSongSelect = useCallback((song: Song) => {
|
const handleSongSelect = useCallback((song: Song) => {
|
||||||
@ -254,8 +255,10 @@ const RekordboxReader: React.FC = () => {
|
|||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
});
|
});
|
||||||
const savedPlaylists = await api.savePlaylists(updatedPlaylists);
|
await api.savePlaylists(updatedPlaylists);
|
||||||
setPlaylists(savedPlaylists);
|
// Always normalize state to structure for consistent counters
|
||||||
|
const structure = await api.getPlaylistStructure();
|
||||||
|
setPlaylists(structure);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle drop from song list into playlist (with duplicate check and user choice)
|
// Handle drop from song list into playlist (with duplicate check and user choice)
|
||||||
@ -286,11 +289,13 @@ const RekordboxReader: React.FC = () => {
|
|||||||
const finalIds = proceedMode === 'skip' ? songIds.filter(id => !existing.has(id)) : songIds;
|
const finalIds = proceedMode === 'skip' ? songIds.filter(id => !existing.has(id)) : songIds;
|
||||||
if (finalIds.length === 0) return;
|
if (finalIds.length === 0) return;
|
||||||
await handleAddSongsToPlaylist(finalIds, playlistName);
|
await handleAddSongsToPlaylist(finalIds, playlistName);
|
||||||
// If we were on that playlist, refresh counters by reloading structure
|
toast({
|
||||||
try {
|
title: 'Songs Added',
|
||||||
const updated = await api.getPlaylistStructure();
|
description: `${finalIds.length} song${finalIds.length === 1 ? '' : 's'} added to "${playlistName}"`,
|
||||||
setPlaylists(updated);
|
status: 'success',
|
||||||
} catch {}
|
duration: 3000,
|
||||||
|
isClosable: true,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveFromPlaylist = async (songIds: string[]) => {
|
const handleRemoveFromPlaylist = async (songIds: string[]) => {
|
||||||
|
|||||||
@ -153,8 +153,8 @@ const PlaylistItem: React.FC<PlaylistItemProps> = React.memo(({
|
|||||||
onDragLeave={() => setIsDragOver(false)}
|
onDragLeave={() => setIsDragOver(false)}
|
||||||
onDrop={(e) => {
|
onDrop={(e) => {
|
||||||
try {
|
try {
|
||||||
const data = e.dataTransfer.getData('application/json');
|
const json = e.dataTransfer.getData('application/json') || e.dataTransfer.getData('text/plain');
|
||||||
const parsed = JSON.parse(data);
|
const parsed = JSON.parse(json);
|
||||||
if (parsed?.type === 'songs' && Array.isArray(parsed.songIds) && onDropSongs) {
|
if (parsed?.type === 'songs' && Array.isArray(parsed.songIds) && onDropSongs) {
|
||||||
onDropSongs(node.name, parsed.songIds);
|
onDropSongs(node.name, parsed.songIds);
|
||||||
}
|
}
|
||||||
@ -233,8 +233,8 @@ const PlaylistItem: React.FC<PlaylistItemProps> = React.memo(({
|
|||||||
onDragLeave={() => setIsDragOver(false)}
|
onDragLeave={() => setIsDragOver(false)}
|
||||||
onDrop={(e) => {
|
onDrop={(e) => {
|
||||||
try {
|
try {
|
||||||
const data = e.dataTransfer.getData('application/json');
|
const json = e.dataTransfer.getData('application/json') || e.dataTransfer.getData('text/plain');
|
||||||
const parsed = JSON.parse(data);
|
const parsed = JSON.parse(json);
|
||||||
if (parsed?.type === 'songs' && Array.isArray(parsed.songIds) && onDropSongs) {
|
if (parsed?.type === 'songs' && Array.isArray(parsed.songIds) && onDropSongs) {
|
||||||
onDropSongs(node.name, parsed.songIds);
|
onDropSongs(node.name, parsed.songIds);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user