import { useQueryClient } from "@tanstack/react-query"; import { ArrowLeft, Bell, BellOff, BookOpen, Calendar, ChevronDown, Database, Heart, Star, } from "lucide-react"; import { useCallback, useState } from "react"; import { useNavigate, useParams } from "react-router"; import { toast } from "sonner"; import { useSetFavorite, useSetUnfavorite, } from "@/api/generated/favorite-mangas/favorite-mangas.ts"; import { useFetchMangaChapters, useFollowManga, useGetManga, useUnfollowManga, } from "@/api/generated/manga/manga.ts"; import { useFetchAllChapters } from "@/api/generated/manga-chapter/manga-chapter.ts"; import { ThemeToggle } from "@/components/ThemeToggle.tsx"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible.tsx"; import { useAuth } from "@/contexts/AuthContext.tsx"; import { MangaChapter } from "@/features/manga/MangaChapter.tsx"; import { formatToTwoDigitsDateRange } from "@/utils/dateFormatter.ts"; const Manga = () => { const { isAuthenticated } = useAuth(); const navigate = useNavigate(); const params = useParams(); const mangaId = Number(params.mangaId); const queryClient = useQueryClient(); const { data: mangaData, queryKey } = useGetManga(mangaId); const { mutate, isPending: fetchPending } = useFetchMangaChapters({ mutation: { onSuccess: () => queryClient.invalidateQueries({ queryKey }), }, }); const { mutate: fetchAllMutate, isPending: fetchAllPending } = useFetchAllChapters({ mutation: { onSuccess: () => toast.success("Chapter import queued successfully."), }, }); const isPending = fetchPending || fetchAllPending; const [openProviders, setOpenProviders] = useState>(new Set()); const { mutate: mutateFavorite, isPending: isPendingFavorite } = useSetFavorite({ mutation: { onSuccess: () => queryClient.invalidateQueries({ queryKey }), }, }); const { mutate: mutateUnfavorite, isPending: isPendingUnfavorite } = useSetUnfavorite({ mutation: { onSuccess: () => queryClient.invalidateQueries({ queryKey }), }, }); const isPendingFavoriteChange = isPendingFavorite || isPendingUnfavorite; const handleFavoriteClick = useCallback( (isFavorite: boolean) => { isFavorite ? mutateUnfavorite({ id: mangaData?.data?.id ?? -1 }) : mutateFavorite({ id: mangaData?.data?.id ?? -1 }); }, [mutateUnfavorite, mutateFavorite, mangaData?.data?.id], ); const { mutate: mutateFollow, isPending: isPendingFollow } = useFollowManga({ mutation: { onSuccess: () => { queryClient.invalidateQueries({ queryKey }); toast.success( "We will notify you when new content if available for this manga.", ); }, }, }); const { mutate: mutateUnfollow, isPending: isPendingUnfollow } = useUnfollowManga({ mutation: { onSuccess: () => { queryClient.invalidateQueries({ queryKey }); toast.success( "You will no longer received notifications for this manga.", ); }, }, }); const isPendingFollowChange = isPendingFollow || isPendingUnfollow; const handleFollowClick = useCallback( (isFollowing: boolean) => { isFollowing ? mutateUnfollow({ mangaId: mangaData?.data?.id ?? -1 }) : mutateFollow({ mangaId: mangaData?.data?.id ?? -1 }); }, [mangaData?.data?.id, mutateUnfollow, mutateFollow], ); if (!mangaData) { return (

Manga not found

); } const toggleProvider = (providerId: number) => { setOpenProviders((prev) => { const next = new Set(prev); if (next.has(providerId)) { next.delete(providerId); } else { next.add(providerId); } return next; }); }; return (
{/* Header */}

MangaMochi

{/* Content */}
{/* Manga Info Section */}
{/* Cover */}
{mangaData.data?.title
{/* Details */}

{mangaData.data?.title}

{mangaData.data?.status} {isAuthenticated && ( <> )}

{mangaData.data?.authors.join(", ")}

{mangaData.data?.alternativeTitles && mangaData.data?.alternativeTitles.length > 0 && (

Alternative Titles

{mangaData.data?.alternativeTitles.map((title, index) => ( {title} ))}
)}

{mangaData.data?.synopsis}

Rating

{mangaData.data?.score && mangaData.data?.score > 0 ? mangaData.data?.score : "-"}

Chapters

{mangaData.data?.chapterCount && mangaData.data?.chapterCount > 0 ? mangaData.data?.chapterCount : "-"}

{mangaData?.data?.publishedFrom && (

Published

{formatToTwoDigitsDateRange( mangaData.data.publishedFrom, mangaData?.data?.publishedTo, )}

)}

Providers

{mangaData.data?.providerCount}

{mangaData.data?.genres.map((genre) => ( {genre} ))}

Chapters by Provider

{mangaData.data?.providers.map((provider) => ( toggleProvider(provider.id)} >

{provider.providerName}

{provider.chaptersDownloaded} downloaded •{" "} {provider.chaptersAvailable} available

{provider.supportsChapterFetch && (
)}
))}
); }; export default Manga;