import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { RefreshCw, XCircle } from "lucide-react"; import { Button, Dialog, DismissibleAlert, LoadingFrame, StatusBadge, type ApiSettings, } from "@govoplan/core-webui"; import { cancelCalendarMigration, getCalendarMigration, type CalendarMigrationBatch, } from "../../api/calendar"; import { dateTimeLabel, errorText } from "./calendarViewModel"; export function CalendarMigrationDialog({ settings, batchId, onClose, onChanged, }: { settings: ApiSettings; batchId: string; onClose: () => void; onChanged: () => void; }) { const [batch, setBatch] = useState(null); const [loading, setLoading] = useState(true); const [working, setWorking] = useState(false); const [error, setError] = useState(""); const [cancellationEvidence, setCancellationEvidence] = useState(""); const onChangedRef = useRef(onChanged); onChangedRef.current = onChanged; const load = useCallback(async () => { try { const next = await getCalendarMigration(settings, batchId); setBatch(next); setError(""); if (next.status === "completed" || next.status === "cancelled") { onChangedRef.current(); } } catch (err) { setError(errorText(err)); } finally { setLoading(false); } }, [batchId, settings.accessToken, settings.apiBaseUrl, settings.apiKey]); useEffect(() => { void load(); }, [load]); useEffect(() => { if (!batch || !["active", "blocked", "cancel_requested"].includes(batch.status)) { return undefined; } const timer = window.setInterval(() => void load(), 3000); return () => window.clearInterval(timer); }, [batch, load]); const progress = useMemo(() => { if (!batch?.total_resources) return 0; const completedSteps = batch.copied_resources + batch.deleted_source_resources; return Math.round((completedSteps / (batch.total_resources * 2)) * 100); }, [batch]); async function cancelMigration() { if (!batch?.can_cancel || cancellationEvidence.trim().length < 10) return; setWorking(true); setError(""); try { const next = await cancelCalendarMigration( settings, batch.id, cancellationEvidence.trim(), ); setBatch(next); setCancellationEvidence(""); onChanged(); } catch (err) { setError(errorText(err)); } finally { setWorking(false); } } return ( } > {loading && !batch ? (
) : (
{error && ( {error} )} {batch && ( <>
{phaseLabel(batch.phase)} Updated {dateTimeLabel(new Date(batch.updated_at))}
Events
{batch.total_events}
Copied
{batch.copied_resources} / {batch.total_resources}
Source deleted
{batch.deleted_source_resources} / {batch.total_resources}
Conflicts
{batch.conflict_count}
{typeof batch.authorization_evidence.note === "string" && (

Authorization evidence: {batch.authorization_evidence.note}

)} {batch.last_error &&

{batch.last_error}

}
    {batch.resources.map((resource) => (
  1. {resource.source_href}
    Copy: {statusLabel(resource.destination_operation_status || "pending")}; source: {statusLabel(resource.source_delete_operation_status || "pending")} {resource.last_error &&

    {resource.last_error}

    }
  2. ))}
{batch.can_cancel && (