LocalLibrary Select in Manga Search

This commit is contained in:
glax 2025-04-01 18:10:30 +02:00
parent 6b10aa8926
commit 44755675e5
2 changed files with 51 additions and 10 deletions

View File

@ -59,7 +59,7 @@ export function Manga({manga, children} : { manga: IManga | undefined, children?
position: "relative", position: "relative",
} }
const interactiveElements = ["button", "input", "textarea", "a"]; const interactiveElements = ["button", "input", "textarea", "a", "select", "option", "li"];
return ( return (
<Badge badgeContent={useManga.mangaConnectorId} color={ReleaseStatusToPalette(useManga.releaseStatus)} size={"lg"}> <Badge badgeContent={useManga.mangaConnectorId} color={ReleaseStatusToPalette(useManga.releaseStatus)} size={"lg"}>

View File

@ -1,15 +1,19 @@
import { import {
Avatar, Button, Chip, Avatar,
Button,
Chip,
CircularProgress,
Drawer, Drawer,
Input, Input,
ListItemDecorator, ListItemDecorator,
Option, Option,
Select, Select, SelectOption,
SelectOption, Skeleton,
Skeleton, Stack, Stack,
Step, Step,
StepIndicator, StepIndicator,
Stepper, Typography Stepper,
Typography
} from "@mui/joy"; } from "@mui/joy";
import ModalClose from "@mui/joy/ModalClose"; import ModalClose from "@mui/joy/ModalClose";
import IMangaConnector from "../api/types/IMangaConnector"; import IMangaConnector from "../api/types/IMangaConnector";
@ -22,6 +26,9 @@ import {Manga} from "./Manga.tsx";
import Add from "@mui/icons-material/Add"; import Add from "@mui/icons-material/Add";
import React from "react"; import React from "react";
import {CreateDownloadAvailableChaptersJob} from "../api/Job.tsx"; import {CreateDownloadAvailableChaptersJob} from "../api/Job.tsx";
import ILocalLibrary from "../api/types/ILocalLibrary.ts";
import {GetLibraries} from "../api/LocalLibrary.tsx";
import { LibraryBooks } from "@mui/icons-material";
export default function Search({open, setOpen}:{open:boolean, setOpen:React.Dispatch<React.SetStateAction<boolean>>}){ export default function Search({open, setOpen}:{open:boolean, setOpen:React.Dispatch<React.SetStateAction<boolean>>}){
@ -32,10 +39,10 @@ export default function Search({open, setOpen}:{open:boolean, setOpen:React.Disp
const [mangaConnectorsLoading, setMangaConnectorsLoading] = useState<boolean>(true); const [mangaConnectorsLoading, setMangaConnectorsLoading] = useState<boolean>(true);
const [selectedMangaConnector, setSelectedMangaConnector] = useState<IMangaConnector>(); const [selectedMangaConnector, setSelectedMangaConnector] = useState<IMangaConnector>();
useEffect(() => { const loadMangaConnectors = useCallback(() => {
setMangaConnectorsLoading(true); setMangaConnectorsLoading(true);
GetAllConnectors(apiUri).then(setMangaConnectors).finally(() => setMangaConnectorsLoading(false)); GetAllConnectors(apiUri).then(setMangaConnectors).finally(() => setMangaConnectorsLoading(false));
},[apiUri]) }, [apiUri]);
const [results, setResults] = useState<IManga[]>([]); const [results, setResults] = useState<IManga[]>([]);
const [resultsLoading, setResultsLoading] = useState<boolean>(false); const [resultsLoading, setResultsLoading] = useState<boolean>(false);
@ -48,6 +55,25 @@ export default function Search({open, setOpen}:{open:boolean, setOpen:React.Disp
SearchNameOnConnector(apiUri, mangaConnector.name, value).then(setResults).finally(() => setResultsLoading(false)); SearchNameOnConnector(apiUri, mangaConnector.name, value).then(setResults).finally(() => setResultsLoading(false));
},[apiUri]) },[apiUri])
const [localLibraries, setLocalLibraries] = useState<ILocalLibrary[]>();
const [localLibrariesLoading, setLocalLibrariesLoading] = useState<boolean>(true);
const [selectedLibraryId, setSelectedLibraryId] = useState<string>();
const loadLocalLibraries = useCallback(() => {
setLocalLibrariesLoading(true);
GetLibraries(apiUri).then(setLocalLibraries).finally(() => setLocalLibrariesLoading(false));
}, [apiUri]);
useEffect(() => {
loadMangaConnectors();
loadLocalLibraries();
},[apiUri]);
useEffect(() => {
loadMangaConnectors();
loadLocalLibraries();
}, []);
function renderValue(option: SelectOption<string> | null) { function renderValue(option: SelectOption<string> | null) {
if (!option) { if (!option) {
return null; return null;
@ -63,6 +89,7 @@ export default function Search({open, setOpen}:{open:boolean, setOpen:React.Disp
); );
} }
// @ts-ignore
return ( return (
<Drawer size={"lg"} anchor={"right"} open={open} onClose={() => { <Drawer size={"lg"} anchor={"right"} open={open} onClose={() => {
setStep(2); setStep(2);
@ -118,8 +145,22 @@ export default function Search({open, setOpen}:{open:boolean, setOpen:React.Disp
<Stack direction={"row"} spacing={1}> <Stack direction={"row"} spacing={1}>
{results.map((result) => {results.map((result) =>
<Manga key={result.mangaId} manga={result}> <Manga key={result.mangaId} manga={result}>
<Button onClick={() => { <Select
CreateDownloadAvailableChaptersJob(apiUri, result.mangaId, {localLibraryId: "",recurrenceTimeMs: 1000 * 60 * 60 * 3}) placeholder={"Select Library"}
defaultValue={""}
startDecorator={<LibraryBooks />}
onChange={(_e, newValue) => setSelectedLibraryId(newValue!)}>
{localLibrariesLoading ?
<Option value={""} disabled>Loading <CircularProgress color={"primary"} size={"sm"} /></Option>
:
(localLibraries??[]).map(library => {
return (
<Option value={library.localLibraryId}>{library.libraryName} ({library.basePath})</Option>
);
})}
</Select>
<Button disabled={localLibrariesLoading || selectedLibraryId === undefined} onClick={() => {
CreateDownloadAvailableChaptersJob(apiUri, result.mangaId, {localLibraryId: selectedLibraryId!,recurrenceTimeMs: 1000 * 60 * 60 * 3})
}} endDecorator={<Add />}>Watch</Button> }} endDecorator={<Add />}>Watch</Button>
</Manga>)} </Manga>)}
</Stack> </Stack>