china-ai-policy-research / src /components /UserSearchDialog.tsx
cfahlgren1's picture
cfahlgren1 HF staff
add shadcn components and add search modal
55d7c10
raw
history blame
5.5 kB
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, fetchUserData } 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 fetchUserData([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 || ''}
/>
</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;