143 lines
5.3 KiB
React
Raw Normal View History

import { useEffect, useRef, useState } from "react";
2025-07-24 11:43:01 +07:00
import { FaDownload } from "react-icons/fa";
import { toast } from "sonner";
import Container from "../Container";
import NavBar from "../NavBar";
2025-04-28 14:35:53 -04:00
function Cache() {
2025-07-22 17:45:48 +07:00
const [searchQuery, setSearchQuery] = useState("");
2025-04-28 14:35:53 -04:00
const [cacheData, setCacheData] = useState([]);
2025-07-24 11:43:01 +07:00
const [keyCount, setKeyCount] = useState(0);
const [loading, setLoading] = useState(false);
const [hasSearched, setHasSearched] = useState(false);
2025-04-28 14:35:53 -04:00
const debounceTimeout = useRef(null);
// Fetch the key count when the component mounts
useEffect(() => {
const fetchKeyCount = async () => {
try {
2025-07-22 17:45:48 +07:00
const response = await fetch("/api/cache/keycount");
2025-04-28 14:35:53 -04:00
const data = await response.json();
setKeyCount(data.count); // Update key count
} catch (error) {
2025-07-22 17:45:48 +07:00
console.error("Error fetching key count:", error);
2025-04-28 14:35:53 -04:00
}
};
fetchKeyCount();
}, []); // Run only once when the component mounts
const handleInputChange = (event) => {
const query = event.target.value;
2025-07-24 11:43:01 +07:00
setSearchQuery(query);
2025-07-22 17:45:48 +07:00
2025-04-28 14:35:53 -04:00
if (debounceTimeout.current) {
clearTimeout(debounceTimeout.current);
}
2025-07-24 11:43:01 +07:00
if (query.trim() !== "") {
setLoading(true); // Show spinner immediately
debounceTimeout.current = setTimeout(() => {
sendApiCall(query);
}, 1000);
} else {
setHasSearched(false); // Reset state when input is cleared
setCacheData([]);
}
2025-04-28 14:35:53 -04:00
};
const sendApiCall = (text) => {
2025-07-24 11:43:01 +07:00
setLoading(true);
2025-07-22 17:45:48 +07:00
fetch("/api/cache/search", {
method: "POST",
headers: { "Content-Type": "application/json" },
2025-04-28 14:35:53 -04:00
body: JSON.stringify({ input: text }),
})
.then((response) => response.json())
2025-07-24 11:43:01 +07:00
.then((data) => {
setCacheData(data);
setHasSearched(true);
})
.catch((error) => {
toast.error(`Error: ${error.message}`);
console.error("Error:", error);
})
.finally(() => setLoading(false));
2025-04-28 14:35:53 -04:00
};
useEffect(() => {
document.title = "Cache | CDRM-Project";
}, []);
2025-04-28 14:35:53 -04:00
return (
2025-07-24 11:43:01 +07:00
<>
<NavBar />
<Container>
<div className="my-4 flex w-full flex-col items-center justify-center gap-2 lg:flex-row">
<fieldset className="fieldset w-full max-w-2xl">
<input
type="text"
value={searchQuery}
onChange={handleInputChange}
placeholder={`Search ${keyCount} keys...`}
className="input w-full max-w-2xl font-mono"
/>
</fieldset>
<button
className="btn btn-success"
onClick={() => {
window.location.href = "/api/cache/download";
}}
>
<FaDownload />
Download keys cache
</button>
</div>
{loading ? (
<div className="flex justify-center py-16">
<span className="loading loading-spinner loading-md me-2"></span>
Searching...
</div>
) : cacheData.length > 0 ? (
<div className="my-4 flex justify-center">
<div className="overflow-x-auto">
<table className="table">
<thead>
<tr>
<th></th>
<th className="text-center">PSSH</th>
<th className="text-center">key ID:key pair</th>
</tr>
</thead>
<tbody>
{cacheData.map((item, index) => (
<tr key={index}>
<th>{index + 1}</th>
<td className="font-mono">{item.PSSH}</td>
<td className="font-mono">
{item.KID}:{item.Key}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
) : hasSearched ? (
<div className="flex justify-center py-16">
<div className="text-center">No data found in the database</div>
</div>
) : (
<div className="flex justify-center py-16">
<div className="text-center">Enter a search query to see results</div>
</div>
)}
</Container>
</>
2025-04-28 14:35:53 -04:00
);
}
export default Cache;