diff --git a/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx b/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx index 796c0207..9879559c 100644 --- a/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx +++ b/src/renderer/components/maps-mangement-components/local-maps-list-panel.component.tsx @@ -1,6 +1,6 @@ import { MapsManagerService } from "renderer/services/maps-manager.service" import { BSVersion } from "shared/bs-version.interface" -import { useCallback, useEffect, useRef, useState } from "react" +import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react" import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface" import { Subscription } from "rxjs" import { MapItem, ParsedMapDiff } from "./map-item.component" @@ -15,16 +15,26 @@ type Props = { search?: string, } -export function LocalMapsListPanel({version, className, filter, search} : Props) { +export const LocalMapsListPanel = forwardRef(({version, className, filter, search} : Props, forwardRef) => { const mapsManager = MapsManagerService.getInstance(); const mapsDownloader = MapsDownloaderService.getInstance(); - const ref = useRef() + const ref = useRef(null) const isVisible = useInView(ref, {once: true}); - const [maps, setMaps] = useState([] as BsmLocalMap[]); - const [selectedMaps, setSelectedMaps] = useState([] as string[]); + const [maps, setMaps] = useState([]); const [subs] = useState([]); + const [selectedMaps, setSelectedMaps] = useState([]); + + useImperativeHandle(forwardRef ,()=>({ + deleteMaps(){ + const mapsToDelete = selectedMaps.length === 0 ? maps : selectedMaps + mapsManager.deleteMaps(mapsToDelete).finally(loadMaps); + }, + exportMaps(){ + console.log("TODO EXPORT MAPS"); + } + }), [selectedMaps, maps]); useEffect(() => { @@ -46,11 +56,9 @@ export function LocalMapsListPanel({version, className, filter, search} : Props) subs.push(mapsManager.getMaps(version).subscribe(localMaps => setMaps(() => [...localMaps]))); } - const handleDelete = useCallback((hash: string) => { - const map = maps.find(map => map.hash === hash); - console.log(maps); + const handleDelete = useCallback((map: BsmLocalMap) => { mapsManager.deleteMaps([map], version).then(res => res && loadMaps()) - }, [maps]); + }, []); const extractMapDiffs = (map: BsmLocalMap): Map => { const res = new Map(); @@ -75,16 +83,16 @@ export function LocalMapsListPanel({version, className, filter, search} : Props) return res; } - const onMapSelected = useCallback((hash: string) => { - const hashs = [...selectedMaps]; - if(hashs.some(selectedHash => selectedHash === hash)){ - const i = hashs.findIndex(selectedHash => selectedHash === hash); - hashs.splice(i, 1); + const onMapSelected = useCallback((map: BsmLocalMap) => { + const maps = [...selectedMaps]; + if(maps.some(selectedMap => selectedMap.hash === map.hash)){ + const i = maps.findIndex(selectedMap => selectedMap.hash === map.hash); + maps.splice(i, 1); } else{ - hashs.push(hash); + maps.push(map); } - setSelectedMaps(() => hashs); + setSelectedMaps(() => maps); }, [selectedMaps]); const isMapFitFilter = (map: BsmLocalMap): boolean => { @@ -199,11 +207,11 @@ export function LocalMapsListPanel({version, className, filter, search} : Props) songAutor={map.rawInfo._songAuthorName} bpm={map.rawInfo._beatsPerMinute} duration={map.bsaverInfo?.metadata?.duration} - selected={selectedMaps.some(hash => hash === map.hash)} + selected={selectedMaps.some(_map => _map.hash === map.hash)} diffs={extractMapDiffs(map)} mapId={map.bsaverInfo?.id} qualified={null} ranked={map.bsaverInfo?.ranked} autorId={map.bsaverInfo?.uploader?.id} likes={map.bsaverInfo?.stats?.upvotes} createdAt={map.bsaverInfo?.createdAt} onDelete={handleDelete} onSelected={onMapSelected} - callBackParam={map.hash} + callBackParam={map} />; } @@ -214,4 +222,4 @@ export function LocalMapsListPanel({version, className, filter, search} : Props) ) -} +}) diff --git a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx index b98ce193..1e729a8b 100644 --- a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx +++ b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx @@ -1,8 +1,8 @@ -import { DetailedHTMLProps, useEffect, useState } from "react" +import { createRef, DetailedHTMLProps, useEffect, useRef, useState } from "react" import { BSVersion } from "shared/bs-version.interface" import { TabNavBar } from "../shared/tab-nav-bar.component" import { LocalMapsListPanel } from "./local-maps-list-panel.component" -import { BsmDropdownButton } from "../shared/bsm-dropdown-button.component" +import { BsmDropdownButton, DropDownItem } from "../shared/bsm-dropdown-button.component" import { FilterPanel } from "./filter-panel.component" import { MapFilter, MapTag } from "shared/models/maps/beat-saver.model" import { BsmButton } from "../shared/bsm-button.component" @@ -11,6 +11,8 @@ import { MapsManagerService } from "renderer/services/maps-manager.service" import { motion, Variants } from "framer-motion"; import ReactTooltip from 'react-tooltip'; import { MapsDownloaderService } from "renderer/services/maps-downloader.service" +import { BehaviorSubject } from "rxjs" +import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface" type Props = { version?: BSVersion @@ -20,6 +22,7 @@ export function MapsPlaylistsPanel({version}: Props) { const mapsService = MapsManagerService.getInstance(); const mapsDownloader = MapsDownloaderService.getInstance(); + const mapsManager = MapsManagerService.getInstance(); const [tabIndex, setTabIndex] = useState(0); const [mapFilter, setMapFilter] = useState({ @@ -29,8 +32,9 @@ export function MapsPlaylistsPanel({version}: Props) { const [mapSearch, setMapSearch] = useState(""); const [playlistSearch, setPlaylistSearch] = useState(""); const [mapsLinked, setMapsLinked] = useState(false); - const color = useThemeColor("first-color") + const color = useThemeColor("first-color"); + const mapsRef = useRef(); useEffect(() => { loadMapIsLinked(); @@ -90,6 +94,19 @@ export function MapsPlaylistsPanel({version}: Props) { ) } + const dropDownItems = ((): DropDownItem[] => { + if(tabIndex === 1){ + return [ + + ] + } + return [ + {icon:"export", text: "Exporter les maps", onClick: () => mapsRef.current.exportMaps?.()}, + {icon: "trash", text: "Supprimer les maps", onClick: () => mapsRef.current.deleteMaps?.()} + ] + + })() + return (
- +
b
diff --git a/src/renderer/components/modal/modal-types/delete-maps-modal.component.tsx b/src/renderer/components/modal/modal-types/delete-maps-modal.component.tsx index 601df8c3..09590db3 100644 --- a/src/renderer/components/modal/modal-types/delete-maps-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/delete-maps-modal.component.tsx @@ -16,6 +16,8 @@ export const DeleteMapsModal: ModalComponent

{t(titleText)}

diff --git a/src/renderer/components/shared/bsm-dropdown-button.component.tsx b/src/renderer/components/shared/bsm-dropdown-button.component.tsx index ac10e717..8942417b 100644 --- a/src/renderer/components/shared/bsm-dropdown-button.component.tsx +++ b/src/renderer/components/shared/bsm-dropdown-button.component.tsx @@ -11,7 +11,7 @@ export interface DropDownItem {text: string, icon?: BsmIconType, onClick?: () => type Props = { className?: string, items?: DropDownItem[], - align?: "left"|"right", + align?: "left"|"right"|"center", withBar?: boolean, icon?: BsmIconType, buttonClassName?: string, @@ -35,10 +35,16 @@ export function BsmDropdownButton({className, items, align, withBar = true, icon setExpanded(false); } + const alignClass = (() => { + if(align === "center"){ return "right-1/2 origin-top-right translate-x-[50%]" } + if(align === "left"){ return "left-0 origin-top-left"; } + return "right-0 origin-top-right"; + })() + return (
setExpanded(!expanded)} className={buttonClassName ?? defaultButtonClassName} icon={icon} active={expanded} onClickOutside={handleClickOutside} withBar={withBar} text={text}/> -
+
{ items?.map((i) => (
i.onClick?.()} className="flex w-full px-3 py-2 hover:backdrop-brightness-150"> {i.icon && }