import React, { useState, useEffect } from "react"; import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Box, Typography, Stack, CircularProgress, Alert, Chip, IconButton, TextField, Tooltip, Checkbox, } from "@mui/material"; import { Newspaper as NewspaperIcon, ShowChart as ShowChartIcon, School as SchoolIcon, Public as PublicIcon, Close as CloseIcon, OpenInNew as OpenInNewIcon, Refresh as RefreshIcon, CheckCircle as CheckCircleIcon, Lightbulb as LightbulbIcon, Search as SearchIcon, Language as LanguageIcon, } from "@mui/icons-material"; interface CategoryTopic { title: string; url: string; snippet: string; score: number; favicon?: string; } type CategoryType = "news" | "finance" | "research-paper" | "personal-site"; interface CategoryResearchModalProps { open: boolean; onClose: () => void; category: CategoryType; keyword?: string; websiteUrl?: string; loading?: boolean; topics?: CategoryTopic[]; error?: string | null; onSelectTopic: (topic: string) => void; onRedoSearch?: (keyword: string, websiteUrl?: string) => void; onConfirmSelection?: (selectedTopics: string[]) => void; isCached?: boolean; } const CATEGORY_CONFIG: Record = { "news": { label: "News", icon: , color: "#4F46E5", bgLight: "#EEF2FF" }, "finance": { label: "Finance", icon: , color: "#059669", bgLight: "#ECFDF5" }, "research-paper": { label: "Research Papers", icon: , color: "#7C3AED", bgLight: "#F3E8FF" }, "personal-site": { label: "Personal Website", icon: , color: "#D97706", bgLight: "#FEF3C7" }, }; const BEST_PRACTICES: Record = { "news": [ "Use specific, focused keywords for better results", "Include relevant industry or niche terms", "Add location or timeframe for localized news", "Avoid very general terms like 'news' or 'updates'", ], "finance": [ "Use specific, focused keywords for better results", "Include asset class (stocks, crypto, forex, bonds)", "Add timeframe (q1 2024, last month, etc.)", "Include market or sector names for targeted results", ], "research-paper": [ "Use academic keywords and terminology", "Include specific topics or research areas", "Add field of study (AI, medicine, climate, etc.)", "Works best with technical or scientific topics", ], "personal-site": [ "Enter the website URL in the input field below", "The search will find content within that domain", "Use specific page or topic keywords for best results", "Leave keyword empty to get all pages from the site", ], }; export const CategoryResearchModal: React.FC = ({ open, onClose, category, keyword, websiteUrl = "", loading = false, topics = [], error = null, onSelectTopic, onRedoSearch, onConfirmSelection, isCached = false, }) => { const config = CATEGORY_CONFIG[category]; const categoryLabel = config.label; const categoryIcon = config.icon; const categoryColor = config.color; const categoryBgLight = config.bgLight; const [redoKeyword, setRedoKeyword] = useState(keyword || ""); const [localWebsiteUrl, setLocalWebsiteUrl] = useState(websiteUrl); const [selectedTopics, setSelectedTopics] = useState>(new Set()); useEffect(() => { if (open) { setRedoKeyword(keyword || ""); setLocalWebsiteUrl(websiteUrl || ""); setSelectedTopics(new Set()); } }, [open, keyword, websiteUrl]); const handleSelectTopic = (topic: CategoryTopic) => { onSelectTopic(topic.title); }; const handleClose = () => { onClose(); }; const handleRedoClick = () => { if (onRedoSearch && redoKeyword.trim()) { onRedoSearch(redoKeyword.trim(), category === "personal-site" ? localWebsiteUrl : undefined); } }; const handleToggleSelectTopic = (title: string) => { const newSelected = new Set(selectedTopics); if (newSelected.has(title)) { newSelected.delete(title); } else { newSelected.add(title); } setSelectedTopics(newSelected); }; const handleSelectAll = () => { const allTitles = new Set(topics.map(t => t.title)); setSelectedTopics(allTitles); }; const handleDeselectAll = () => { setSelectedTopics(new Set()); }; const handleConfirm = () => { if (onConfirmSelection && selectedTopics.size > 0) { onConfirmSelection(Array.from(selectedTopics)); onClose(); } }; const getDomain = (url: string) => { try { return new URL(url).hostname.replace("www.", ""); } catch { return url; } }; const isPersonalSite = category === "personal-site"; return ( {categoryIcon} {categoryLabel} {keyword && ( Searching: {keyword} )} Best Practices for Search {BEST_PRACTICES[category].map((tip, idx) => ( • {tip} ))} } arrow placement="bottom-end" > } label="For best results" size="small" sx={{ background: categoryBgLight, color: categoryColor, border: `1px solid ${categoryColor}25`, fontWeight: 600, fontSize: "0.75rem", cursor: "help", "& .MuiChip-icon": { color: categoryColor }, "&:hover": { background: `${categoryColor}15`, }, }} /> {loading && ( Searching {categoryLabel.toLowerCase()}... {isPersonalSite ? `Searching within ${localWebsiteUrl || "your website"}` : `Finding relevant ${categoryLabel.toLowerCase()} for your podcast`} )} {error && ( {error} )} {!loading && !error && topics.length === 0 && ( {React.cloneElement(categoryIcon as React.ReactElement, { sx: { fontSize: 32, color: "#d1d5db" } })} No results found {isPersonalSite ? "Enter a website URL and try different keywords" : "Try different search terms or redo search"} )} {!loading && !error && topics.length > 0 && ( <> {/* Redo Search Bar */} Search again {/* Website URL input for Personal Site */} {isPersonalSite && ( setLocalWebsiteUrl(e.target.value)} sx={{ width: 260, "& .MuiOutlinedInput-root": { background: "#fff", fontSize: "0.8rem", height: 34, }, "& .MuiOutlinedInput-notchedOutline": { borderColor: "#d1d5db", }, }} /> )} setRedoKeyword(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleRedoClick()} sx={{ flex: 1, minWidth: 150, maxWidth: 280, "& .MuiOutlinedInput-root": { background: "#fff", fontSize: "0.8rem", height: 34, }, "& .MuiOutlinedInput-notchedOutline": { borderColor: "#d1d5db", }, }} /> {/* Select All / Deselect All */} {topics.length > 0 && ( {selectedTopics.size} of {topics.length} selected | )} {topics.map((topic, idx) => ( handleToggleSelectTopic(topic.title)} sx={{ p: 0, mt: 0.25, color: "#d1d5db", "&.Mui-checked": { color: categoryColor }, }} /> handleSelectTopic(topic)}> {topic.title} {topic.snippet} {topic.favicon && ( { (e.target as HTMLImageElement).style.display = "none"; }} /> )} {getDomain(topic.url)} ))} )} {topics.length} results • {category === "news" || category === "finance" ? "Powered by Tavily" : "Powered by Exa"} ); };