diff --git a/src/components/species/tabs/TradeDataTab.tsx b/src/components/species/tabs/TradeDataTab.tsx
index 7ddbe39..2841ba7 100644
--- a/src/components/species/tabs/TradeDataTab.tsx
+++ b/src/components/species/tabs/TradeDataTab.tsx
@@ -282,8 +282,8 @@ export function TradeDataTab({ species }: TradeDataTabProps) {
About CITES Trade Records
CITES trade records document international trade in wildlife listed in the CITES Appendices.
- Not all species have recorded trade data, particularly if they haven't been traded internationally
- or if trade reports haven't been submitted to the CITES Trade Database.
+ Not all species have recorded trade data, particularly if they haven't been traded internationally
+ or if trade reports haven't been submitted to the CITES Trade Database.
If you believe this species should have trade records, please check the following:
diff --git a/src/components/species/visualizations/TradeCharts.tsx b/src/components/species/visualizations/TradeCharts.tsx
index 423044f..0940b20 100644
--- a/src/components/species/visualizations/TradeCharts.tsx
+++ b/src/components/species/visualizations/TradeCharts.tsx
@@ -17,6 +17,7 @@ import {
PieLabelRenderProps,
ReferenceLine
} from "recharts";
+import { Payload } from 'recharts/types/component/DefaultTooltipContent';
import React from "react";
import { TimelineEvent } from "@/lib/api";
@@ -50,15 +51,19 @@ interface TradeChartsProps {
timelineEvents?: TimelineEvent[];
}
-// Expected structure within the 'payload' object from Recharts Tooltip item
+// Expected structure within the 'payload' object from Recharts Tooltip item for Bar Charts
interface BarChartTooltipInternalPayload {
purpose?: string;
source?: string;
description?: string;
- term?: string;
count?: number;
}
+// Interface for the third argument of the bar chart tooltip formatter
+interface CustomTooltipPayloadEntry extends Payload {
+ payload?: BarChartTooltipInternalPayload; // Made payload optional
+}
+
// Custom tooltip for pie chart
const renderCustomizedLabel = ({ cx, cy, midAngle, outerRadius, percent, payload }: PieLabelRenderProps) => {
const numCx = Number(cx || 0);
@@ -88,16 +93,6 @@ const renderCustomizedLabel = ({ cx, cy, midAngle, outerRadius, percent, payload
);
};
-// Type for the 'item' argument passed to the complex bar chart formatter
-// Aims to align with Recharts internal Payload structure for Tooltip
-interface BarTooltipItem {
- payload?: BarChartTooltipInternalPayload;
- value?: number | string;
- name?: string;
- color?: string;
- dataKey?: string;
-}
-
export function TradeCharts({ visualizationData, PURPOSE_DESCRIPTIONS, SOURCE_DESCRIPTIONS, timelineEvents }: TradeChartsProps) {
const processedTermsData = React.useMemo(() => {
const threshold = 0.02;
@@ -118,26 +113,26 @@ export function TradeCharts({ visualizationData, PURPOSE_DESCRIPTIONS, SOURCE_DE
return significantTerms;
}, [visualizationData.termsTraded]);
- // Formatter for Purpose/Source Bar charts with refined item type
+ // Formatter for Purpose/Source Bar charts
const barChartDetailFormatter = (
- value: number | string,
- name: string,
- item: BarTooltipItem
- ): [React.ReactNode, React.ReactNode] => {
- const internalPayload = item.payload;
- let label = name;
- if (internalPayload?.purpose) {
- const purpose = internalPayload.purpose;
- const description = internalPayload.description || PURPOSE_DESCRIPTIONS[purpose] || 'Unknown';
- label = `${purpose} - ${description}`;
- } else if (internalPayload?.source) {
- const source = internalPayload.source;
- const description = internalPayload.description || SOURCE_DESCRIPTIONS[source] || 'Unknown';
- label = `${source} - ${description}`;
+ value: number | string, // This is the 'count'
+ name: string, // This is 'Records' (name prop from Bar component)
+ entry: CustomTooltipPayloadEntry
+ ): [React.ReactNode, React.ReactNode] => {
+ const dataPoint = entry.payload; // Actual data object for the bar, now potentially undefined
+ let tooltipLabel = name; // Default to "Records"
+
+ if (dataPoint?.purpose) { // Optional chaining already handles undefined dataPoint
+ const purpose = dataPoint.purpose;
+ const description = dataPoint.description || PURPOSE_DESCRIPTIONS[purpose] || 'Unknown';
+ tooltipLabel = `${purpose} - ${description}`;
+ } else if (dataPoint?.source) {
+ const source = dataPoint.source;
+ const description = dataPoint.description || SOURCE_DESCRIPTIONS[source] || 'Unknown';
+ tooltipLabel = `${source} - ${description}`;
}
- const valueToFormat = item.value ?? value;
- const formattedValue = formatNumber(valueToFormat);
- return [formattedValue, label];
+ const formattedValue = formatNumber(value); // 'value' is already the count for the bar
+ return [formattedValue, tooltipLabel];
};
return (
@@ -376,8 +371,7 @@ export function TradeCharts({ visualizationData, PURPOSE_DESCRIPTIONS, SOURCE_DE
tickFormatter={(value) => `${value} - ${PURPOSE_DESCRIPTIONS[value] || 'Unknown'}`}
width={150}
/>
- {/* Revert to using as any due to persistent type issues */}
-
+
@@ -411,8 +405,7 @@ export function TradeCharts({ visualizationData, PURPOSE_DESCRIPTIONS, SOURCE_DE
tickFormatter={(value) => `${value} - ${SOURCE_DESCRIPTIONS[value] || 'Unknown'}`}
width={150}
/>
- {/* Revert to using as any due to persistent type issues */}
-
+
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
index 22cbeb1..cb6762a 100644
--- a/src/components/ui/input.tsx
+++ b/src/components/ui/input.tsx
@@ -1,9 +1,9 @@
+/* eslint-disable react/prop-types */ // Disable prop-types rule for this file as props are inherited
import * as React from "react"
import { cn } from "@/lib/utils"
-export interface InputProps
- extends React.InputHTMLAttributes {}
+export type InputProps = React.InputHTMLAttributes;
const Input = React.forwardRef(
({ className, type, ...props }, ref) => {
diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx
index c0df655..21ad4cd 100644
--- a/src/components/ui/table.tsx
+++ b/src/components/ui/table.tsx
@@ -69,6 +69,7 @@ TableRow.displayName = "TableRow"
const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes
+ // eslint-disable-next-line react/prop-types
>(({ className, ...props }, ref) => (
+ // eslint-disable-next-line react/prop-types
>(({ className, ...props }, ref) => (
| {
+ const handleCitesListingFormChange = (field: keyof CitesListingForm, value: string | boolean) => {
setCitesListingForm(prev => ({
...prev,
[field]: value
diff --git a/src/hooks/useTimelineEventCrud.ts b/src/hooks/useTimelineEventCrud.ts
index e0573f8..7621eae 100644
--- a/src/hooks/useTimelineEventCrud.ts
+++ b/src/hooks/useTimelineEventCrud.ts
@@ -53,7 +53,7 @@ export function useTimelineEventCrud(speciesId: string) {
};
// Handle timeline event form changes
- const handleTimelineEventFormChange = (field: string, value: any) => {
+ const handleTimelineEventFormChange = (field: keyof TimelineEventForm, value: string | number) => {
setTimelineEventForm(prev => ({
...prev,
[field]: value
diff --git a/src/lib/api.ts b/src/lib/api.ts
index e69464b..376625c 100644
--- a/src/lib/api.ts
+++ b/src/lib/api.ts
@@ -846,7 +846,7 @@ export async function createDistributionRange(distribution: {
presence_code: string;
origin_code: string;
seasonal_code?: string;
- geojson?: any;
+ geojson?: Record | null;
notes?: string;
}) {
try {
@@ -884,7 +884,7 @@ export async function updateDistributionRange(id: string, updates: {
presence_code?: string;
origin_code?: string;
seasonal_code?: string;
- geojson?: any;
+ geojson?: Record | null;
notes?: string;
}) {
try {
diff --git a/src/pages/admin/cites-listings/list.tsx b/src/pages/admin/cites-listings/list.tsx
index 5837757..d5658d5 100644
--- a/src/pages/admin/cites-listings/list.tsx
+++ b/src/pages/admin/cites-listings/list.tsx
@@ -116,7 +116,7 @@ export default function CitesListingsList() {
const formatDate = (dateString: string) => {
try {
return format(new Date(dateString), 'MMM d, yyyy');
- } catch (e) {
+ } catch {
return dateString;
}
};
@@ -269,4 +269,4 @@ export default function CitesListingsList() {
);
-}
\ No newline at end of file
+}
diff --git a/src/pages/admin/common-names/edit.tsx b/src/pages/admin/common-names/edit.tsx
index 95ceea1..1b8f5b3 100644
--- a/src/pages/admin/common-names/edit.tsx
+++ b/src/pages/admin/common-names/edit.tsx
@@ -98,7 +98,7 @@ export default function EditCommonName() {
{species && (
<>
- Edit common name "{commonName?.name}" for {species.scientific_name}
+ Edit common name "{commonName?.name}" for {species.scientific_name}
>
)}
@@ -115,4 +115,4 @@ export default function EditCommonName() {
);
-}
\ No newline at end of file
+}
diff --git a/src/pages/admin/common-names/list.tsx b/src/pages/admin/common-names/list.tsx
index 06d9317..d3eb728 100644
--- a/src/pages/admin/common-names/list.tsx
+++ b/src/pages/admin/common-names/list.tsx
@@ -21,20 +21,23 @@ import {
DialogTitle,
} from '@/components/ui/dialog';
import { Plus, Pencil, Trash, Search, Flag } from 'lucide-react';
-import { commonNamesApi, speciesApi, CommonName } from '@/services/adminApi';
+import { commonNamesApi, CommonName, Species } from '@/services/adminApi'; // Added Species import
import { useToast } from '@/hooks/use-toast';
import { Badge } from '@/components/ui/badge';
+// Define a type that includes the nested species object
+type CommonNameWithSpecies = CommonName & { species?: Species };
+
export default function CommonNamesList() {
const [searchQuery, setSearchQuery] = useState('');
const [isSearching, setIsSearching] = useState(false);
- const [deleteDialog, setDeleteDialog] = useState<{open: boolean, commonName?: CommonName & { species?: any }}>({open: false});
+ const [deleteDialog, setDeleteDialog] = useState<{open: boolean, commonName?: CommonNameWithSpecies }>({open: false}); // Use CommonNameWithSpecies
const navigate = useNavigate();
const queryClient = useQueryClient();
const { toast } = useToast();
// Data fetching for common names
- const { data: commonNames, isLoading, error } = useQuery({
+ const { data: commonNames, isLoading, error } = useQuery({ // Use CommonNameWithSpecies[]
queryKey: ['admin', 'common-names'],
queryFn: async () => {
try {
@@ -53,7 +56,7 @@ export default function CommonNamesList() {
? commonNames.filter(name =>
name.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
name.language.toLowerCase().includes(searchQuery.toLowerCase()) ||
- (name.species?.scientific_name &&
+ (name.species?.scientific_name && // Check if scientific_name exists
name.species.scientific_name.toLowerCase().includes(searchQuery.toLowerCase()))
)
: commonNames;
@@ -91,7 +94,7 @@ export default function CommonNamesList() {
};
// Open delete dialog
- const confirmDelete = (commonName: CommonName & { species?: any }) => {
+ const confirmDelete = (commonName: CommonNameWithSpecies) => { // Use CommonNameWithSpecies
setDeleteDialog({ open: true, commonName });
};
@@ -247,7 +250,7 @@ export default function CommonNamesList() {
Delete Common Name
- Are you sure you want to delete "{deleteDialog.commonName?.name}" ({getLanguageName(deleteDialog.commonName?.language || '')}) for{' '}
+ Are you sure you want to delete "{deleteDialog.commonName?.name}" ({getLanguageName(deleteDialog.commonName?.language || '')}) for{' '}
{deleteDialog.commonName?.species?.scientific_name}?
This action cannot be undone.
@@ -271,4 +274,4 @@ export default function CommonNamesList() {
);
-}
\ No newline at end of file
+}
diff --git a/src/pages/admin/iucn-assessments/list.tsx b/src/pages/admin/iucn-assessments/list.tsx
index cb9be57..971f39d 100644
--- a/src/pages/admin/iucn-assessments/list.tsx
+++ b/src/pages/admin/iucn-assessments/list.tsx
@@ -42,7 +42,7 @@ const getStatusBadge = (status: string) => {
const config = statusConfig[status] || { label: status, variant: 'outline' };
return (
-
+
{config.label}
);
@@ -295,4 +295,4 @@ export default function IucnAssessmentsList() {
);
-}
\ No newline at end of file
+}
diff --git a/src/pages/home.tsx b/src/pages/home.tsx
index 225265d..1517011 100644
--- a/src/pages/home.tsx
+++ b/src/pages/home.tsx
@@ -1,6 +1,6 @@
import { useState, useMemo } from 'react'; // Removed useEffect
import { useQuery } from '@tanstack/react-query';
-import { getAllSpecies, getSpeciesImages, getTotalTradeCount } from '@/lib/api';
+import { getAllSpecies, getSpeciesImages, getTotalTradeCount, Species } from '@/lib/api'; // Added Species
// Removed unused: import { SearchForm } from '@/components/search-form';
import { ResultsContainer } from '@/components/results-container';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
@@ -13,8 +13,14 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
// Import the new CompareTradeTab component
import { CompareTradeTab } from '@/components/compare-trade-tab';
+// Define a local type for the SpeciesCard props that includes optional latest_assessment
+type SpeciesCardProps = {
+ species: Species & { latest_assessment?: { status?: string } }; // Make latest_assessment and its status optional
+ onClick: (id: string) => void;
+};
+
// Species Card Component with Image Support
-function SpeciesCard({ species, onClick }: { species: any, onClick: (id: string) => void }) {
+function SpeciesCard({ species, onClick }: SpeciesCardProps) { // Used local SpeciesCardProps type
const { data: imageData, isLoading: isImageLoading } = useQuery({
queryKey: ['speciesImage', species.scientific_name],
queryFn: () => getSpeciesImages(species.scientific_name),
diff --git a/src/services/adminApi.ts b/src/services/adminApi.ts
index 085e608..845d82a 100644
--- a/src/services/adminApi.ts
+++ b/src/services/adminApi.ts
@@ -48,6 +48,11 @@ export interface IucnAssessment {
assessment_id?: number;
scope_code?: string;
scope_description?: string;
+ // Add the following fields:
+ red_list_criteria?: string;
+ year_assessed?: number | null;
+ population_trend?: string;
+ notes?: string;
}
export interface CommonName {
|