import { useKindeAuth } from "@kinde-oss/kinde-auth-react";
import React, { useEffect, useState } from "react";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./ui/table";
interface RecordingPattern {
recordS: number;
sleepS: number;
}
interface Cluster {
id: string;
locationId: string;
name: string;
description: string | null;
createdBy: string;
createdAt: string;
lastModified: string;
modifiedBy: string;
active: boolean;
timezoneId: string | null;
cyclicRecordingPatternId: string | null;
recordingPattern: RecordingPattern | null;
}
// Removed unused Location interface
interface ClustersResponse {
data: Cluster[];
}
interface ClustersProps {
locationId: string;
locationName: string;
datasetName: string;
}
const Clusters: React.FC<ClustersProps> = ({ locationId, locationName, datasetName }) => {
const { isAuthenticated, isLoading: authLoading, getAccessToken } = useKindeAuth();
const [clusters, setClusters] = useState<Cluster[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
// Reset state when location changes
setClusters([]);
setLoading(true);
setError(null);
const fetchClusters = async () => {
if (!isAuthenticated || !locationId) {
if (!authLoading) {
setLoading(false);
}
return;
}
try {
const accessToken = await getAccessToken();
// Fetch clusters for the selected location
const url = `/api/clusters?locationId=${encodeURIComponent(locationId)}`;
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
const data = await response.json() as ClustersResponse;
if (!data.data || !Array.isArray(data.data)) {
throw new Error("Invalid response format");
}
setClusters(data.data);
} catch (err) {
const errorMessage = err instanceof Error ? err.message : "Failed to fetch clusters";
setError(errorMessage);
} finally {
setLoading(false);
}
};
if (isAuthenticated && !authLoading) {
fetchClusters();
}
}, [isAuthenticated, authLoading, getAccessToken, locationId]);
return (
<div className="card p-6 bg-white shadow-sm rounded-lg">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-bold">
<span className="text-gray-800">{locationName}</span>
<span className="ml-2">Clusters</span>
</h2>
<div className="text-gray-600 text-sm flex items-center">
{datasetName}
</div>
</div>
{loading && <div className="py-4 text-center text-gray-500">Loading clusters...</div>}
{error && (
<div className="p-4 bg-red-50 text-red-700 rounded-md mb-4">
<p className="font-medium">Error loading clusters</p>
<p className="text-sm mt-1">{error}</p>
</div>
)}
{!loading && !error && clusters.length > 0 && (
<div className="w-full overflow-visible">
<Table>
<TableHeader className="bg-muted">
<TableRow className="border-b-2 border-primary/20">
<TableHead className="w-[180px] py-3 font-bold text-sm uppercase">Name</TableHead>
<TableHead className="py-3 font-bold text-sm uppercase">Description</TableHead>
<TableHead className="py-3 font-bold text-sm uppercase">Timezone</TableHead>
<TableHead className="py-3 font-bold text-sm uppercase">Record:Sleep</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{clusters.map((cluster) => (
<TableRow key={cluster.id}>
<TableCell className="font-medium whitespace-normal break-words">{cluster.name}</TableCell>
<TableCell className="whitespace-normal break-words">{cluster.description || "—"}</TableCell>
<TableCell className="whitespace-normal break-words">{cluster.timezoneId || "—"}</TableCell>
<TableCell className="whitespace-normal break-words">
{cluster.recordingPattern
? (
`${Math.round(cluster.recordingPattern.recordS)}:${Math.round(cluster.recordingPattern.sleepS)}`
)
: (
"—"
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
{!loading && !error && clusters.length === 0 && (
<div className="p-4 bg-yellow-50 text-yellow-800 rounded-md">
<p className="font-medium">No clusters found for this location</p>
</div>
)}
</div>
);
};
export default Clusters;