Spaces:
Running
Running
import React, { useState, useMemo } from "react"; | |
import { Input } from "./ui/input"; | |
import { | |
Dialog, | |
DialogContent, | |
DialogHeader, | |
DialogTitle, | |
DialogTrigger, | |
} from "./ui/dialog"; | |
import { Button } from "./ui/button"; | |
import { fetchAllAuthorsData } from "../utils/authors"; | |
import { generateCalendarData } from "../utils/calendar"; | |
import Heatmap from "./Heatmap"; | |
import { ModelData } from "../types/heatmap"; | |
import { fetchAuthorData, fetchOrganizationData } from "@/utils/authors"; | |
const UserSearchDialog = () => { | |
const [isOpen, setIsOpen] = useState(false); | |
const [isLoading, setIsLoading] = useState(false); | |
const [searchInput, setSearchInput] = useState(""); | |
const [searchedData, setSearchedData] = useState<ModelData[] | null>(null); | |
const [isCopied, setIsCopied] = useState(false); | |
const [currentSearchTerm, setCurrentSearchTerm] = useState(""); | |
const [userInfo, setUserInfo] = useState<{ fullName: string; avatarUrl: string | null } | null>(null); | |
const handleSearch = async () => { | |
if (searchInput.trim()) { | |
setIsLoading(true); | |
try { | |
const authorData = await fetchAllAuthorsData([searchInput.trim()]); | |
const authorInfo = await fetchOrganizationData([searchInput.trim()]); | |
setSearchedData(authorData); | |
setUserInfo(authorInfo); | |
setCurrentSearchTerm(searchInput.trim()); | |
} catch (error) { | |
console.error("Error fetching data for searched user:", error); | |
setSearchedData(null); | |
setUserInfo(null); | |
setCurrentSearchTerm(""); | |
} | |
setIsLoading(false); | |
} else { | |
setSearchedData(null); | |
setUserInfo(null); | |
setCurrentSearchTerm(""); | |
} | |
}; | |
const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => { | |
if (e.key === 'Enter') { | |
handleSearch(); | |
} | |
}; | |
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |
setSearchInput(e.target.value); | |
}; | |
const getIframeCode = (username: string) => { | |
return `<iframe | |
src="https://cfahlgren1-model-release-heatmap.hf.space/${username}" | |
class="w-full h-[300px]" | |
frameborder="0" | |
></iframe>`; | |
}; | |
const handleCopyCode = () => { | |
const iframeCode = getIframeCode(searchInput); | |
navigator.clipboard.writeText(iframeCode).then(() => { | |
setIsCopied(true); | |
setTimeout(() => setIsCopied(false), 2000); | |
}); | |
}; | |
const searchedHeatmapData = useMemo(() => { | |
if (searchedData && searchedData.length > 0 && userInfo) { | |
return generateCalendarData(searchedData, [{ | |
authors: [currentSearchTerm], | |
color: "#0088cc", | |
fullName: userInfo.fullName, | |
avatarUrl: userInfo.avatarUrl | |
}])[currentSearchTerm]; | |
} | |
return null; | |
}, [searchedData, currentSearchTerm, userInfo]); | |
const handleDialogOpenChange = (open: boolean) => { | |
setIsOpen(open); | |
if (!open) { | |
setSearchInput(""); | |
setSearchedData(null); | |
setCurrentSearchTerm(""); | |
setIsLoading(false); | |
setIsCopied(false); | |
setUserInfo(null); | |
} | |
}; | |
return ( | |
<Dialog open={isOpen} onOpenChange={handleDialogOpenChange}> | |
<DialogTrigger asChild> | |
<Button variant="outline">Search</Button> | |
</DialogTrigger> | |
<DialogContent className="w-full max-w-[95vw] sm:max-w-4xl p-4 sm:p-6 max-h-[90vh] flex flex-col"> | |
<DialogHeader> | |
<DialogTitle className="text-lg sm:text-xl mb-4">Get your Hugging Face Heatmap</DialogTitle> | |
</DialogHeader> | |
<div className="flex-grow overflow-y-auto"> | |
<div className="grid gap-4 py-4"> | |
<div className="flex items-center space-x-2 p-2 bg-background rounded-md"> | |
<Input | |
type="text" | |
placeholder="Enter username" | |
value={searchInput} | |
onChange={handleInputChange} | |
onKeyDown={handleKeyPress} | |
className="flex-grow" | |
/> | |
</div> | |
{isLoading ? ( | |
<p className="text-center">Loading...</p> | |
) : searchedHeatmapData && userInfo ? ( | |
<div className="mt-4 space-y-4"> | |
<div className="overflow-x-auto pb-2"> | |
<Heatmap | |
data={searchedHeatmapData} | |
color="#FF9D00" | |
providerName={currentSearchTerm} | |
fullName={userInfo.fullName} | |
avatarUrl={userInfo.avatarUrl || ''} | |
authorId={currentSearchTerm} | |
/> | |
</div> | |
<div> | |
<div className="flex justify-between items-center mb-2"> | |
<h3 className="font-semibold text-sm sm:text-base">Embed in iFrame</h3> | |
<Button onClick={handleCopyCode} variant="link" size="sm"> | |
{isCopied ? "Copied!" : "Copy"} | |
</Button> | |
</div> | |
<div className="overflow-x-auto"> | |
<pre className="bg-secondary p-2 rounded text-xs whitespace-pre-wrap break-all"> | |
<code>{getIframeCode(searchInput)}</code> | |
</pre> | |
</div> | |
</div> | |
</div> | |
) : searchedData !== null && searchedData.length === 0 ? ( | |
<p className="text-center text-slate-500 text-sm italic">User or Organization not found</p> | |
) : null} | |
</div> | |
</div> | |
</DialogContent> | |
</Dialog> | |
); | |
}; | |
export default UserSearchDialog; |