diff --git a/tranga-website/src/Components/Chapter.tsx b/tranga-website/src/Components/Chapter.tsx index d684833..3b7607b 100644 --- a/tranga-website/src/Components/Chapter.tsx +++ b/tranga-website/src/Components/Chapter.tsx @@ -1,9 +1,23 @@ -import {ReactElement, useContext, useState} from "react"; +import React, {ReactElement, useContext, useState} from "react"; import IChapter from "../api/types/IChapter.ts"; -import {Card, CardActions, CardContent, Chip, Link, Stack, Tooltip, Typography} from "@mui/joy"; +import {Box, Chip, Link, Stack, Typography} from "@mui/joy"; import {MangaFromId} from "./Manga.tsx"; import {ChapterContext} from "../api/Contexts/ChapterContext.tsx"; -import { Description } from "@mui/icons-material"; +import Drawer from "@mui/joy/Drawer"; +import ModalClose from "@mui/joy/ModalClose"; + +export function ChapterPopupFromId({chapterId, open, setOpen, children}: { chapterId: string | null, open: boolean, setOpen: React.Dispatch>, children?: ReactElement | ReactElement[] | undefined }) { + return ( + setOpen(false)}> + + { + chapterId !== null ? + {children} + : null + } + + ) +} export function ChapterFromId({chapterId, children} : { chapterId: string, children?: ReactElement | ReactElement[] | undefined }){ const chapterContext = useContext(ChapterContext); @@ -13,23 +27,7 @@ export function ChapterFromId({chapterId, children} : { chapterId: string, child return ( chapter === undefined ? - - - - - - - - - - - - {children} - - - - - + null : {children} ); @@ -37,25 +35,15 @@ export function ChapterFromId({chapterId, children} : { chapterId: string, child export function Chapter({chapter, children} : { chapter: IChapter, children?: ReactElement | ReactElement[] | undefined }){ return ( - - - - - - - {chapter.title} - Vol. {chapter.volumeNumber} - Ch. {chapter.chapterNumber} - - - - - - {children} - - - - - + + + + {chapter.title} + Volume {chapter.volumeNumber} + Chapter {chapter.chapterNumber} + Title {chapter.title} + + {children} + ); } \ No newline at end of file diff --git a/tranga-website/src/Components/Jobs.tsx b/tranga-website/src/Components/Jobs.tsx index c576bd1..4381f02 100644 --- a/tranga-website/src/Components/Jobs.tsx +++ b/tranga-website/src/Components/Jobs.tsx @@ -1,26 +1,24 @@ import { - Card, - CardContent, - Chip, + Button, DialogContent, DialogTitle, Drawer, Input, Option, Select, Stack, - Tooltip, + Table, Typography } from "@mui/joy"; -import {GetAllJobs} from "../api/Job.tsx"; +import {GetJobsInState, GetJobsOfTypeAndWithState, GetJobsWithType} from "../api/Job.tsx"; import * as React from "react"; import {useCallback, useContext, useEffect, useState} from "react"; import {ApiUriContext} from "../api/fetchApi.tsx"; import IJob, {JobState, JobType} from "../api/types/Jobs/IJob.ts"; -import IJobWithMangaId from "../api/types/Jobs/IJobWithMangaId.ts"; -import {MangaFromId} from "./Manga.tsx"; import ModalClose from "@mui/joy/ModalClose"; +import {MangaPopupFromId} from "./MangaPopup.tsx"; +import IJobWithMangaId from "../api/types/Jobs/IJobWithMangaId.ts"; +import {ChapterPopupFromId} from "./Chapter.tsx"; import IJobWithChapterId from "../api/types/Jobs/IJobWithChapterId.tsx"; -import {ChapterFromId} from "./Chapter.tsx"; export default function JobsDrawer({open, connected, setOpen} : {open: boolean, connected: boolean, setOpen:React.Dispatch>}) { const apiUri = useContext(ApiUriContext); @@ -36,35 +34,27 @@ export default function JobsDrawer({open, connected, setOpen} : {open: boolean, const updateDisplayJobs = useCallback(() => { if(!connected) return; - GetAllJobs(apiUri).then(setAllJobs); - }, [apiUri, connected]); - + if (filterState === null && filterType === null) + setAllJobs([]); + else if (filterState === null && filterType != null) + GetJobsWithType(apiUri, filterType as unknown as JobType).then(setAllJobs); + else if (filterState != null && filterType === null) + GetJobsInState(apiUri, filterState as unknown as JobState).then(setAllJobs); + else if (filterState != null && filterType != null) + GetJobsOfTypeAndWithState(apiUri, filterType as unknown as JobType, filterState as unknown as JobState).then(setAllJobs); + }, [connected, filterType, filterState]); + const timerRef = React.useRef>(undefined); - const updateTimer = useCallback(() => { - if(!connected){ - clearTimeout(timerRef.current); - return; - }else{ - if(timerRef.current === undefined) { - console.log("Added timer!"); - updateDisplayJobs(); - timerRef.current = setInterval(() => { - updateDisplayJobs(); - }, 2000); - } - } - }, [open, connected]); + useEffect(() => { + clearTimeout(timerRef.current); + updateDisplayJobs(); + timerRef.current = setInterval(updateDisplayJobs, 2000); + }, [filterState, filterType]); - const FilterJobs = (jobs? : IJob[] | undefined) : IJob[] => { - if(jobs === undefined) - return []; - let ret = jobs; - if(filterState != undefined) - ret = ret.filter(job => job.state == filterState); - if(filterType != undefined) - ret = ret.filter(job => job.jobType == filterType); - return ret.sort((a, b) => new Date(a.nextExecution).getDate() - new Date(b.nextExecution).getDate()); - } + useEffect(() => { + if (!open || !connected) + clearTimeout(timerRef.current); + }, [open, connected]); const handleChangeState = ( _: React.SyntheticEvent | null, @@ -73,6 +63,7 @@ export default function JobsDrawer({open, connected, setOpen} : {open: boolean, setFilterState(newValue); setPage(1); }; + const handleChangeType = ( _: React.SyntheticEvent | null, newValue: string | null, @@ -80,10 +71,20 @@ export default function JobsDrawer({open, connected, setOpen} : {open: boolean, setFilterType(newValue); setPage(1); }; - - useEffect(() => { - updateTimer(); - }, [open, connected]); + + const [mangaPopupOpen, setMangaPopupOpen] = React.useState(false); + const [selectedMangaId, setSelectedMangaId] = useState(null); + const OpenMangaPopupDrawer = (mangaId: string) => { + setSelectedMangaId(mangaId); + setMangaPopupOpen(true); + } + + const [chapterPopupOpen, setChapterPopupOpen] = React.useState(false); + const [selectedChapterId, setSelectedChapterId] = React.useState(null); + const OpenChapterPopupDrawer = (chapterId: string) => { + setSelectedChapterId(chapterId); + setChapterPopupOpen(true); + } return ( setOpen(false)}> @@ -105,47 +106,41 @@ export default function JobsDrawer({open, connected, setOpen} : {open: boolean, setPage(parseInt(e.target.value))} - slotProps={{input: { min: 1, max: Math.ceil(FilterJobs(allJobs).length / pageSize)}}} + slotProps={{input: { min: 1, max: Math.ceil(allJobs.length / pageSize)}}} startDecorator={Page} - endDecorator={/{Math.ceil(FilterJobs(allJobs).length / pageSize)}}/> + endDecorator={/{Math.ceil(allJobs.length / pageSize)}}/> - - {FilterJobs(allJobs).splice(pageSize*(page-1), pageSize).map(job => )} - + + + + + + + + + + + + {allJobs.slice((page-1)*pageSize, page*pageSize).map((job) => ( + + + + + + + + ))} + +
TypeStateLast ExecutionNextExecutionExtra
{job.jobType}{job.state}{new Date(job.lastExecution).toLocaleString()}{new Date(job.nextExecution).toLocaleString()}{ExtraContent(job, OpenMangaPopupDrawer, OpenChapterPopupDrawer)}
+ +
) } -function FormatJob({job} : {job: IJob}) { - - return ( - - - - {job.jobType} - - - - - - {new Date(job.lastExecution).toLocaleString()} - - - {new Date(job.nextExecution).toLocaleString()} - - {job.state} - - - - {ExtraContent(job)} - - - ); -} - -function ExtraContent(job: IJob){ +function ExtraContent(job: IJob, OpenMangaPopupDrawer: (mangaId: string) => void, OpenChapterPopupDrawer: (IJobWithChapterId: string) => void){ switch(job.jobType){ case JobType.DownloadAvailableChaptersJob: case JobType.DownloadMangaCoverJob: @@ -153,10 +148,10 @@ function ExtraContent(job: IJob){ case JobType.UpdateChaptersDownloadedJob: case JobType.UpdateCoverJob: case JobType.MoveMangaLibraryJob: - return ; + return case JobType.DownloadSingleChapterJob: case JobType.UpdateSingleChapterDownloadedJob: - return + return default: return null; } diff --git a/tranga-website/src/Components/MangaPopup.tsx b/tranga-website/src/Components/MangaPopup.tsx index 8a76e6f..ef31b77 100644 --- a/tranga-website/src/Components/MangaPopup.tsx +++ b/tranga-website/src/Components/MangaPopup.tsx @@ -1,6 +1,6 @@ import IManga from "../api/types/IManga.ts"; import {Badge, Box, Chip, CircularProgress, Drawer, Input, Link, Skeleton, Stack, Typography} from "@mui/joy"; -import {ReactElement, useCallback, useContext, useEffect, useRef, useState} from "react"; +import React, {ReactElement, useCallback, useContext, useEffect, useRef, useState} from "react"; import { GetLatestChapterAvailable, GetLatestChapterDownloaded, @@ -13,9 +13,58 @@ import {CardHeight} from "./Manga.tsx"; import IChapter from "../api/types/IChapter.ts"; import {MangaReleaseStatus, ReleaseStatusToPalette} from "../api/types/EnumMangaReleaseStatus.ts"; import {MangaConnectorContext} from "../api/Contexts/MangaConnectorContext.tsx"; +import {MangaContext} from "../api/Contexts/MangaContext.tsx"; +import ModalClose from "@mui/joy/ModalClose"; -export default function MangaPopup({manga, open, children} : {manga: IManga | null, open: boolean, children?: ReactElement | ReactElement[] | undefined}) { +export function MangaPopupFromId({mangaId, open, setOpen, children} : {mangaId: string | null, open: boolean, setOpen: React.Dispatch>, children?: ReactElement | ReactElement[] | undefined}) { + const mangaContext = useContext(MangaContext); + + const [manga, setManga] = useState(undefined); + + useEffect(() => { + if (!open || mangaId === null) + return; + mangaContext.GetManga(mangaId).then(setManga); + }, [open]); + + return ( + manga === undefined ? + setOpen(false)}> + + + { /* Cover and Description */ } + + + Manga Cover + + + + {mangaId?.split("").splice(0,mangaId.length/2).join(" ")} + + + {mangaId?.split("").filter(x => Number.isNaN(x)).map(_ => + + Wow + + )} + + + + + + { /* Actions */ } + + {children} + + + + : + {children} + ); +} + +export default function MangaPopup({manga, open, setOpen, children} : {manga: IManga | null, open: boolean, setOpen:React.Dispatch>, children?: ReactElement | ReactElement[] | undefined}) { const apiUri = useContext(ApiUriContext); @@ -24,6 +73,8 @@ export default function MangaPopup({manga, open, children} : {manga: IManga | nu const LoadMangaCover = useCallback(() => { if(CoverRef.current == null || manga == null) return; + if (!open) + return; const coverUrl = GetMangaCoverImageUrl(apiUri, manga.mangaId, CoverRef.current); if(CoverRef.current.src == coverUrl) return; @@ -32,7 +83,7 @@ export default function MangaPopup({manga, open, children} : {manga: IManga | nu getData(coverUrl).then(() => { if(CoverRef.current) CoverRef.current.src = coverUrl; }); - }, [manga, apiUri]) + }, [manga, apiUri, open]) useEffect(() => { if(!open) @@ -75,7 +126,8 @@ export default function MangaPopup({manga, open, children} : {manga: IManga | nu const mangaConnector = useContext(MangaConnectorContext).find(all => all.name == manga?.mangaConnectorName); return ( - + setOpen(false)}> + { /* Cover and Description */ }