"use client";
import { useMemo, useState } from "react";
import { Check, FileUp, MoreVertical, Plus, Search, UploadCloud, Wifi, WifiOff } from "lucide-react";
import LiquidGlass from "liquid-glass-react";
import { cn } from "@/lib/utils";
import { sourceFilters, type DashboardSource } from "@/components/dashboard/dashboardData";
import { PreviewBadge } from "@/components/dashboard/dashboardPrimitives";
import { MaterialTypeBadge } from "@/components/dashboard/SourceBlockedState";
import { getPublicDemoMode } from "@/lib/env";
import { hasLiveSession } from "@/lib/api/mode";
type SourcesPanelProps = {
className?: string;
selectedSourceId: string;
selectedSourceIds?: string[];
documents?: DashboardSource[];
onSourceOpen: (sourceId: string) => void;
onSourceToggle?: (sourceId: string) => void;
onUploadClick?: () => void;
};
export function SourcesPanel({
className,
selectedSourceId,
selectedSourceIds = [selectedSourceId],
documents = [],
onSourceOpen,
onSourceToggle,
onUploadClick,
}: SourcesPanelProps) {
const [activeFilter, setActiveFilter] = useState("All");
const [query, setQuery] = useState("");
const isLive = getPublicDemoMode() === "live" || hasLiveSession();
const liveBadge = isLive ? (
Connected to AI
) : (
Offline preview
);
const visibleSources = useMemo(
() =>
documents.filter((source) => {
const filterMatches =
activeFilter === "All" ||
source.type === activeFilter ||
(activeFilter === "Books" && source.type === "Book") ||
(activeFilter === "PYQs" && source.type === "PYQ") ||
(activeFilter === "Links" && source.type === "Link") ||
(activeFilter === "Images" && source.type === "Image");
const searchText = `${source.title} ${source.subtitle} ${source.type}`.toLowerCase();
return filterMatches && searchText.includes(query.trim().toLowerCase());
}),
[activeFilter, query, documents],
);
const pinnedSources = visibleSources.filter((source) => source.group === "Pinned");
const recentSources = visibleSources.filter((source) => source.group === "Recent");
const hasSources = visibleSources.length > 0;
const selectedCount = selectedSourceIds.length;
const sourceUsageLabel =
selectedCount > 1
? `Using ${selectedCount} sources`
: selectedCount === 1
? "Using 1 source"
: "Choose sources for DocDoe";
return (
Sources {liveBadge}
{sourceUsageLabel}
{hasSources ? (
{pinnedSources.length > 0 && (
)}
) : (
)}
);
}
function SourceGroup({
title,
sources,
selectedSourceId,
selectedSourceIds,
onSourceOpen,
onSourceToggle,
}: {
title: string;
sources: DashboardSource[];
selectedSourceId: string;
selectedSourceIds: string[];
onSourceOpen: (sourceId: string) => void;
onSourceToggle?: (sourceId: string) => void;
}) {
if (sources.length === 0) {
return null;
}
return (
{title}
{sources.map((source) => (
onSourceOpen(source.id)}
onToggle={() => onSourceToggle?.(source.id)}
/>
))}
);
}
function SourcePanelRow({
source,
isSelected,
isIncluded,
onOpen,
onToggle,
}: {
source: DashboardSource;
isSelected: boolean;
isIncluded: boolean;
onOpen: () => void;
onToggle: () => void;
}) {
const Icon = source.icon;
const statusLabel =
source.status === "processing" || source.status === "uploaded"
? "Preparing"
: source.status === "failed"
? "Could not read"
: "Ready";
return (
{isSelected ? On : null}
{statusLabel}
);
}