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 Location {
id: string;
datasetId: string;
name: string;
latitude: number | null;
longitude: number | null;
description: string | null;
createdBy: string;
createdAt: string;
lastModified: string;
modifiedBy: string;
active: boolean;
}
interface Dataset {
id: string;
name: string;
}
interface LocationsResponse {
data: Location[];
}
interface DatasetsResponse {
data: Dataset[];
}
interface LocationsProps {
datasetId: string;
}
const Locations: React.FC<LocationsProps> = ({ datasetId }) => {
const { isAuthenticated, isLoading: authLoading, getAccessToken } = useKindeAuth();
const [locations, setLocations] = useState<Location[]>([]);
const [datasetName, setDatasetName] = useState<string>("");
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
// Reset state when dataset changes
setLocations([]);
setDatasetName("");
setLoading(true);
setError(null);
const fetchData = async () => {
if (!isAuthenticated || !datasetId) {
if (!authLoading) {
setLoading(false);
}
return;
}
try {
const accessToken = await getAccessToken();
// First fetch the dataset name
try {
const datasetResponse = await fetch(`/api/datasets`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (datasetResponse.ok) {
const datasetData = await datasetResponse.json() as DatasetsResponse;
const dataset = datasetData.data.find(d => d.id === datasetId);
if (dataset) {
setDatasetName(dataset.name);
}
}
} catch (e) {
// If unable to get the dataset name, use a generic display
setDatasetName(`Dataset ${datasetId.substring(0, 6)}...`);
}
// Now fetch the locations
const url = `/api/locations?datasetId=${encodeURIComponent(datasetId)}`;
const locationsResponse = await fetch(url, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (!locationsResponse.ok) {
throw new Error(`Server error: ${locationsResponse.status}`);
}
const locationsData = await locationsResponse.json() as LocationsResponse;
if (!locationsData.data || !Array.isArray(locationsData.data)) {
throw new Error("Invalid response format");
}
setLocations(locationsData.data);
} catch (err) {
const errorMessage = err instanceof Error ? err.message : "Failed to fetch locations";
setError(errorMessage);
} finally {
setLoading(false);
}
};
if (isAuthenticated && !authLoading) {
fetchData();
}
}, [isAuthenticated, authLoading, getAccessToken, datasetId]);
return (
<div className="card p-6 bg-white shadow-sm rounded-lg">
<h2 className="text-xl font-bold mb-4">
{datasetName ? (
<>
<span className="text-gray-700">{datasetName}</span>
<span className="ml-2">Locations</span>
</>
) : (
"Locations"
)}
</h2>
{loading && <div className="py-4 text-center text-gray-500">Loading locations...</div>}
{error && (
<div className="p-4 bg-red-50 text-red-700 rounded-md mb-4">
<p className="font-medium">Error loading locations</p>
<p className="text-sm mt-1">{error}</p>
</div>
)}
{!loading && !error && locations.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">Coordinates</TableHead>
<TableHead className="py-3 font-bold text-sm uppercase">Description</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{locations.map((location) => (
<TableRow key={location.id}>
<TableCell className="font-medium whitespace-normal break-words">{location.name}</TableCell>
<TableCell className="whitespace-normal break-words">
{location.latitude && location.longitude
? `${Number(location.latitude).toFixed(5)}, ${Number(location.longitude).toFixed(5)}`
: "—"}
</TableCell>
<TableCell className="whitespace-normal break-words">{location.description || "—"}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
{!loading && !error && locations.length === 0 && (
<div className="p-4 bg-yellow-50 text-yellow-800 rounded-md">
<p className="font-medium">No locations found for this dataset</p>
</div>
)}
</div>
);
};
export default Locations;