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 React, { useState, useRef, useEffect, useCallback } from "react";
|
||||
import { useNavigate, useLocation, Routes, Route } from "react-router-dom";
|
||||
@ -76,6 +76,7 @@ const RekordboxReader: React.FC = () => {
|
||||
const [isDatabaseInitialized, setIsDatabaseInitialized] = useState(false);
|
||||
const [isSwitchingPlaylist, setIsSwitchingPlaylist] = useState(false);
|
||||
const { currentSong, playSong, closePlayer } = useMusicPlayer();
|
||||
const toast = useToast();
|
||||
|
||||
// Memoized song selection handler to prevent unnecessary re-renders
|
||||
const handleSongSelect = useCallback((song: Song) => {
|
||||
@ -254,8 +255,10 @@ const RekordboxReader: React.FC = () => {
|
||||
}
|
||||
return node;
|
||||
});
|
||||
const savedPlaylists = await api.savePlaylists(updatedPlaylists);
|
||||
setPlaylists(savedPlaylists);
|
||||
await api.savePlaylists(updatedPlaylists);
|
||||
// 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)
|
||||
@ -286,11 +289,13 @@ const RekordboxReader: React.FC = () => {
|
||||
const finalIds = proceedMode === 'skip' ? songIds.filter(id => !existing.has(id)) : songIds;
|
||||
if (finalIds.length === 0) return;
|
||||
await handleAddSongsToPlaylist(finalIds, playlistName);
|
||||
// If we were on that playlist, refresh counters by reloading structure
|
||||
try {
|
||||
const updated = await api.getPlaylistStructure();
|
||||
setPlaylists(updated);
|
||||
} catch {}
|
||||
toast({
|
||||
title: 'Songs Added',
|
||||
description: `${finalIds.length} song${finalIds.length === 1 ? '' : 's'} added to "${playlistName}"`,
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
isClosable: true,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoveFromPlaylist = async (songIds: string[]) => {
|
||||
|
||||
@ -153,8 +153,8 @@ const PlaylistItem: React.FC<PlaylistItemProps> = React.memo(({
|
||||
onDragLeave={() => setIsDragOver(false)}
|
||||
onDrop={(e) => {
|
||||
try {
|
||||
const data = e.dataTransfer.getData('application/json');
|
||||
const parsed = JSON.parse(data);
|
||||
const json = e.dataTransfer.getData('application/json') || e.dataTransfer.getData('text/plain');
|
||||
const parsed = JSON.parse(json);
|
||||
if (parsed?.type === 'songs' && Array.isArray(parsed.songIds) && onDropSongs) {
|
||||
onDropSongs(node.name, parsed.songIds);
|
||||
}
|
||||
@ -233,8 +233,8 @@ const PlaylistItem: React.FC<PlaylistItemProps> = React.memo(({
|
||||
onDragLeave={() => setIsDragOver(false)}
|
||||
onDrop={(e) => {
|
||||
try {
|
||||
const data = e.dataTransfer.getData('application/json');
|
||||
const parsed = JSON.parse(data);
|
||||
const json = e.dataTransfer.getData('application/json') || e.dataTransfer.getData('text/plain');
|
||||
const parsed = JSON.parse(json);
|
||||
if (parsed?.type === 'songs' && Array.isArray(parsed.songIds) && onDropSongs) {
|
||||
onDropSongs(node.name, parsed.songIds);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user