"use client"; import { useState, useEffect, useCallback, useMemo } from "react"; import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, FormField, FormInput, FormSelect, Icon } from "@/app/components/ui"; import { KomgaSyncResponse, KomgaSyncReportSummary, UserDto } from "@/lib/api"; import { useTranslation } from "@/lib/i18n/context"; export function KomgaSyncCard({ users }: { users: UserDto[] }) { const { t, locale } = useTranslation(); const [komgaUrl, setKomgaUrl] = useState(""); const [komgaUsername, setKomgaUsername] = useState(""); const [komgaPassword, setKomgaPassword] = useState(""); const [komgaUserId, setKomgaUserId] = useState(users[0]?.id ?? ""); const [isSyncing, setIsSyncing] = useState(false); const [syncResult, setSyncResult] = useState(null); const [syncError, setSyncError] = useState(null); const [showUnmatched, setShowUnmatched] = useState(false); const [showMatchedBooks, setShowMatchedBooks] = useState(false); const [reports, setReports] = useState([]); const [selectedReport, setSelectedReport] = useState(null); const [showReportUnmatched, setShowReportUnmatched] = useState(false); const [showReportMatchedBooks, setShowReportMatchedBooks] = useState(false); const syncNewlyMarkedSet = useMemo( () => new Set(syncResult?.newly_marked_books ?? []), [syncResult?.newly_marked_books], ); const reportNewlyMarkedSet = useMemo( () => new Set(selectedReport?.newly_marked_books ?? []), [selectedReport?.newly_marked_books], ); const fetchReports = useCallback(async () => { try { const resp = await fetch("/api/komga/reports"); if (resp.ok) setReports(await resp.json()); } catch { /* ignore */ } }, []); useEffect(() => { fetchReports(); fetch("/api/settings/komga").then(r => r.ok ? r.json() : null).then(data => { if (data) { if (data.url) setKomgaUrl(data.url); if (data.username) setKomgaUsername(data.username); if (data.user_id) setKomgaUserId(data.user_id); } }).catch(() => {}); }, [fetchReports]); async function handleViewReport(id: string) { setSelectedReport(null); setShowReportUnmatched(false); setShowReportMatchedBooks(false); try { const resp = await fetch(`/api/komga/reports/${id}`); if (resp.ok) setSelectedReport(await resp.json()); } catch { /* ignore */ } } async function handleKomgaSync() { setIsSyncing(true); setSyncResult(null); setSyncError(null); setShowUnmatched(false); setShowMatchedBooks(false); try { const response = await fetch("/api/komga/sync", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: komgaUrl, username: komgaUsername, password: komgaPassword, user_id: komgaUserId }), }); const data = await response.json(); if (!response.ok) { setSyncError(data.error || "Sync failed"); } else { setSyncResult(data); fetchReports(); fetch("/api/settings/komga", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ value: { url: komgaUrl, username: komgaUsername, user_id: komgaUserId } }), }).catch(() => {}); } } catch { setSyncError("Failed to connect to sync endpoint"); } finally { setIsSyncing(false); } } return ( {t("settings.komgaSync")} {t("settings.komgaDesc")}
setKomgaUrl(e.target.value)} />
setKomgaUsername(e.target.value)} /> setKomgaPassword(e.target.value)} />
{users.length > 0 && (
setKomgaUserId(e.target.value)}> {users.map((u) => ( ))}
)} {syncError &&
{syncError}
} {syncResult && (

{t("settings.komgaRead")}

{syncResult.total_komga_read}

{t("settings.matched")}

{syncResult.matched}

{t("settings.alreadyRead")}

{syncResult.already_read}

{t("settings.newlyMarked")}

{syncResult.newly_marked}

{syncResult.matched_books.length > 0 && (
{showMatchedBooks && (
{syncResult.matched_books.map((title, i) => (

{syncNewlyMarkedSet.has(title) && } {title}

))}
)}
)} {syncResult.unmatched.length > 0 && (
{showUnmatched && (
{syncResult.unmatched.map((title, i) => (

{title}

))}
)}
)}
)} {reports.length > 0 && (

{t("settings.syncHistory")}

{reports.map((r) => ( ))}
{selectedReport && (

{t("settings.komgaRead")}

{selectedReport.total_komga_read}

{t("settings.matched")}

{selectedReport.matched}

{t("settings.alreadyRead")}

{selectedReport.already_read}

{t("settings.newlyMarked")}

{selectedReport.newly_marked}

{selectedReport.matched_books && selectedReport.matched_books.length > 0 && (
{showReportMatchedBooks && (
{selectedReport.matched_books.map((title, i) => (

{reportNewlyMarkedSet.has(title) && } {title}

))}
)}
)} {selectedReport.unmatched.length > 0 && (
{showReportUnmatched && (
{selectedReport.unmatched.map((title, i) => (

{title}

))}
)}
)}
)}
)}
); }