@burdenoff/microfe-ecoimpacthub 2026.704.4 → 2026.709.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/ecoimpacthub/EcoImpactHubRoot.d.ts +5 -0
- package/dist/ecoimpacthub/EcoImpactHubRoot.d.ts.map +1 -0
- package/dist/ecoimpacthub/EcoImpactHubRoutes.d.ts +4 -0
- package/dist/ecoimpacthub/EcoImpactHubRoutes.d.ts.map +1 -0
- package/dist/ecoimpacthub/EcoImpactHubRoutes.js +48 -40
- package/dist/ecoimpacthub/EcoImpactHubRoutes.js.map +1 -1
- package/dist/ecoimpacthub/components/DataTable.d.ts +28 -0
- package/dist/ecoimpacthub/components/DataTable.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/EcoDiscussion.d.ts +18 -0
- package/dist/ecoimpacthub/components/EcoDiscussion.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/EcoTags.d.ts +17 -0
- package/dist/ecoimpacthub/components/EcoTags.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/EmptyState.d.ts +18 -0
- package/dist/ecoimpacthub/components/EmptyState.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/EvidenceUpload.d.ts +14 -0
- package/dist/ecoimpacthub/components/EvidenceUpload.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/FeatureFlagGate.d.ts +10 -0
- package/dist/ecoimpacthub/components/FeatureFlagGate.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/FeatureFlagGate.js +8 -0
- package/dist/ecoimpacthub/components/FeatureFlagGate.js.map +1 -0
- package/dist/ecoimpacthub/components/FileLink.d.ts +15 -0
- package/dist/ecoimpacthub/components/FileLink.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/FilterTabs.d.ts +18 -0
- package/dist/ecoimpacthub/components/FilterTabs.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/MetricsCard.d.ts +23 -0
- package/dist/ecoimpacthub/components/MetricsCard.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/MiniBar.d.ts +16 -0
- package/dist/ecoimpacthub/components/MiniBar.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/PageLayout.d.ts +16 -0
- package/dist/ecoimpacthub/components/PageLayout.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/Pagination.d.ts +22 -0
- package/dist/ecoimpacthub/components/Pagination.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/StateViews.d.ts +24 -0
- package/dist/ecoimpacthub/components/StateViews.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/StatusBadge.d.ts +9 -0
- package/dist/ecoimpacthub/components/StatusBadge.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/Tabs.d.ts +17 -0
- package/dist/ecoimpacthub/components/Tabs.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/index.d.ts +19 -0
- package/dist/ecoimpacthub/components/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/context/EcoImpactHubContext.d.ts +16 -0
- package/dist/ecoimpacthub/context/EcoImpactHubContext.d.ts.map +1 -0
- package/dist/ecoimpacthub/context/index.d.ts +6 -0
- package/dist/ecoimpacthub/context/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/index.d.ts +10 -0
- package/dist/ecoimpacthub/hooks/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useCursorPager.d.ts +33 -0
- package/dist/ecoimpacthub/hooks/useCursorPager.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoComments.d.ts +36 -0
- package/dist/ecoimpacthub/hooks/useEcoComments.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoFiles.d.ts +47 -0
- package/dist/ecoimpacthub/hooks/useEcoFiles.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.d.ts +104 -0
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoTags.d.ts +44 -0
- package/dist/ecoimpacthub/hooks/useEcoTags.d.ts.map +1 -0
- package/dist/ecoimpacthub/index.d.ts +10 -0
- package/dist/ecoimpacthub/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/index.js +2 -0
- package/dist/ecoimpacthub/pages/DashboardPage.d.ts +10 -0
- package/dist/ecoimpacthub/pages/DashboardPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/DashboardPage.js +345 -189
- package/dist/ecoimpacthub/pages/DashboardPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.d.ts +9 -0
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js +58 -0
- package/dist/ecoimpacthub/pages/_shared/ConservationBadge.js.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.d.ts +23 -0
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js +70 -0
- package/dist/ecoimpacthub/pages/_shared/EvidenceThumb.js.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.d.ts +9 -0
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.js +51 -0
- package/dist/ecoimpacthub/pages/_shared/MethodBadge.js.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.d.ts +9 -0
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.js +29 -0
- package/dist/ecoimpacthub/pages/_shared/TaxonChip.js.map +1 -0
- package/dist/ecoimpacthub/pages/badges.d.ts +27 -0
- package/dist/ecoimpacthub/pages/badges.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/badges.js +71 -0
- package/dist/ecoimpacthub/pages/badges.js.map +1 -0
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.d.ts +15 -0
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js +337 -300
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/carbonVisuals.d.ts +47 -0
- package/dist/ecoimpacthub/pages/carbonVisuals.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/carbonVisuals.js +89 -0
- package/dist/ecoimpacthub/pages/carbonVisuals.js.map +1 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.d.ts +12 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js +252 -218
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.d.ts +8 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js +15 -12
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.d.ts +6 -0
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js +168 -0
- package/dist/ecoimpacthub/pages/habitat/LifecycleProgress.js.map +1 -0
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.d.ts +12 -0
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js +30 -17
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.d.ts +11 -0
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.js +236 -219
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.d.ts +11 -0
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js +248 -212
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/reports/ReportsPage.d.ts +8 -0
- package/dist/ecoimpacthub/pages/reports/ReportsPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/reports/ReportsPage.js +119 -118
- package/dist/ecoimpacthub/pages/reports/ReportsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.d.ts +10 -0
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js +498 -370
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/SitesPage.d.ts +8 -0
- package/dist/ecoimpacthub/pages/sites/SitesPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/sites/SitesPage.js +109 -99
- package/dist/ecoimpacthub/pages/sites/SitesPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.d.ts +22 -0
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js +64 -0
- package/dist/ecoimpacthub/pages/sites/siteTypeVisuals.js.map +1 -0
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.d.ts +9 -0
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js +275 -259
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/species/SpeciesPage.d.ts +8 -0
- package/dist/ecoimpacthub/pages/species/SpeciesPage.d.ts.map +1 -0
- package/dist/ecoimpacthub/pages/species/SpeciesPage.js +235 -177
- package/dist/ecoimpacthub/pages/species/SpeciesPage.js.map +1 -1
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.d.ts +33 -0
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.js +42 -0
- package/dist/ecoimpacthub/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/ecoimpacthub/services/index.d.ts +6 -0
- package/dist/ecoimpacthub/services/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/services/index.js +1 -0
- package/dist/ecoimpacthub/types/index.d.ts +417 -0
- package/dist/ecoimpacthub/types/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/cn.d.ts +4 -0
- package/dist/ecoimpacthub/utils/cn.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/formatters.d.ts +26 -0
- package/dist/ecoimpacthub/utils/formatters.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/i18n.d.ts +6 -0
- package/dist/ecoimpacthub/utils/i18n.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/index.d.ts +9 -0
- package/dist/ecoimpacthub/utils/index.d.ts.map +1 -0
- package/dist/ecoimpacthub/utils/navigation.d.ts +14 -0
- package/dist/ecoimpacthub/utils/navigation.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +18199 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +43046 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -1
- package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +305 -0
- package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js.map +1 -0
- package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +44 -33
- package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ChartUtils.js +31 -23
- package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
- package/package.json +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpeciesDetailPage.js","names":[],"sources":["../../../../src/ecoimpacthub/pages/species/SpeciesDetailPage.tsx"],"sourcesContent":["/**\n * Species detail — overview, field observations & species actions.\n * @module ecoimpacthub/pages/species\n *\n * Reads `ecoSpecies` (+ nested observations); writes `ecoRecordObservation`,\n * `ecoUpdateSpecies`, `ecoArchiveSpecies`.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Binoculars, Pencil, Archive, Star } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GlassCard,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { LoadingView, ErrorView, Section } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { EvidenceUpload } from '../../components/EvidenceUpload';\nimport { FileLink } from '../../components/FileLink';\nimport { EcoTags } from '../../components/EcoTags';\nimport { useEcoImpactHub } from '../../context';\nimport {\n useEcoSpeciesDetail,\n useEcoSites,\n useEcoRecordObservation,\n useEcoUpdateSpecies,\n useEcoArchiveSpecies,\n type UploadedEcoFile,\n} from '../../hooks';\nimport { formatDateTime, formatEnumLabel, formatNumber } from '../../utils/formatters';\nimport type {\n EcoObservation,\n EcoObservationMethod,\n EcoTaxonGroup,\n EcoConservationStatus,\n} from '../../types';\n\nconst OBSERVATION_METHODS: EcoObservationMethod[] = [\n 'DIRECT_SIGHTING',\n 'CAMERA_TRAP',\n 'ACOUSTIC',\n 'TRACKS_SIGNS',\n 'EDNA',\n 'TELEMETRY',\n 'COMMUNITY_REPORT',\n];\n\nconst TAXON_GROUPS: EcoTaxonGroup[] = [\n 'MAMMAL',\n 'BIRD',\n 'REPTILE',\n 'AMPHIBIAN',\n 'FISH',\n 'INSECT',\n 'PLANT',\n 'FUNGI',\n 'OTHER',\n];\n\nconst CONSERVATION_STATUSES: EcoConservationStatus[] = [\n 'LEAST_CONCERN',\n 'NEAR_THREATENED',\n 'VULNERABLE',\n 'ENDANGERED',\n 'CRITICALLY_ENDANGERED',\n 'EXTINCT_IN_WILD',\n 'DATA_DEFICIENT',\n 'NOT_EVALUATED',\n];\n\n/** Format a Date into the `YYYY-MM-DDTHH:mm` value a datetime-local input expects. */\nconst toLocalInputValue = (d: Date): string => {\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(\n d.getHours()\n )}:${pad(d.getMinutes())}`;\n};\n\ninterface EditFormState {\n commonName: string;\n scientificName: string;\n taxonGroup: EcoTaxonGroup;\n conservationStatus: EcoConservationStatus;\n isPriority: boolean;\n description: string;\n}\n\nexport function SpeciesDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useEcoImpactHub();\n const { data: species, isLoading, isError, refetch } = useEcoSpeciesDetail(id);\n const sites = useEcoSites({ pagination: { limit: 100, offset: 0 } });\n\n const recordObservation = useEcoRecordObservation();\n const updateSpecies = useEcoUpdateSpecies();\n const archiveSpecies = useEcoArchiveSpecies();\n\n const [observeOpen, setObserveOpen] = useState(false);\n const [observeForm, setObserveForm] = useState<{\n method: EcoObservationMethod;\n count: string;\n observedAt: string;\n siteId: string;\n notes: string;\n evidence: UploadedEcoFile | null;\n }>({\n method: 'DIRECT_SIGHTING',\n count: '1',\n observedAt: toLocalInputValue(new Date()),\n siteId: '',\n notes: '',\n evidence: null,\n });\n const [editOpen, setEditOpen] = useState(false);\n const [editForm, setEditForm] = useState<EditFormState>({\n commonName: '',\n scientificName: '',\n taxonGroup: 'MAMMAL',\n conservationStatus: 'NOT_EVALUATED',\n isPriority: false,\n description: '',\n });\n const [error, setError] = useState<string | null>(null);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Species\">\n <LoadingView />\n </PageLayout>\n );\n }\n if (isError || !species) {\n return (\n <PageLayout title=\"Species\">\n <ErrorView message=\"This species could not be loaded.\" onRetry={() => refetch()} />\n </PageLayout>\n );\n }\n\n const observations = species.observations ?? [];\n const siteRows = sites.data?.items ?? [];\n\n const openObserve = () => {\n setObserveForm({\n method: 'DIRECT_SIGHTING',\n count: '1',\n observedAt: toLocalInputValue(new Date()),\n siteId: '',\n notes: '',\n evidence: null,\n });\n setError(null);\n setObserveOpen(true);\n };\n\n const openEdit = () => {\n setEditForm({\n commonName: species.commonName,\n scientificName: species.scientificName ?? '',\n taxonGroup: species.taxonGroup,\n conservationStatus: species.conservationStatus,\n isPriority: species.isPriority,\n description: species.description ?? '',\n });\n setError(null);\n setEditOpen(true);\n };\n\n const handleRecordObservation = async () => {\n if (!id) return;\n setError(null);\n try {\n await recordObservation.mutateAsync({\n speciesId: id,\n method: observeForm.method,\n count: observeForm.count ? Number(observeForm.count) : 1,\n observedAt: new Date(observeForm.observedAt).toISOString(),\n siteId: observeForm.siteId || null,\n notes: observeForm.notes.trim() || null,\n evidenceFileId: observeForm.evidence?.fileId ?? null,\n });\n setObserveOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to record observation.');\n }\n };\n\n const handleUpdate = async () => {\n if (!id || !editForm.commonName.trim()) {\n setError('Common name is required.');\n return;\n }\n setError(null);\n try {\n await updateSpecies.mutateAsync({\n id,\n input: {\n commonName: editForm.commonName.trim(),\n scientificName: editForm.scientificName.trim() || null,\n taxonGroup: editForm.taxonGroup,\n conservationStatus: editForm.conservationStatus,\n isPriority: editForm.isPriority,\n description: editForm.description.trim() || null,\n },\n });\n setEditOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update species.');\n }\n };\n\n const handleArchive = async () => {\n if (!id) return;\n setError(null);\n try {\n await archiveSpecies.mutateAsync(id);\n navigateTo('species');\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to archive species.');\n }\n };\n\n const observationColumns: Column<EcoObservation>[] = [\n {\n key: 'method',\n header: 'Method',\n render: (o) => (\n <span className=\"font-medium text-text-primary\">{formatEnumLabel(o.method)}</span>\n ),\n },\n {\n key: 'count',\n header: 'Count',\n align: 'right',\n sortValue: (o) => o.count,\n render: (o) => (\n <span className=\"tabular-nums text-text-primary\">{formatNumber(o.count)}</span>\n ),\n },\n {\n key: 'observedAt',\n header: 'Observed',\n render: (o) => <span className=\"text-text-secondary\">{formatDateTime(o.observedAt)}</span>,\n },\n {\n key: 'site',\n header: 'Site',\n hideOnMobile: true,\n render: (o) =>\n o.siteId ? (\n <span className=\"text-text-secondary\">{o.siteId}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'notes',\n header: 'Notes',\n hideOnMobile: true,\n render: (o) => <span className=\"text-text-secondary\">{o.notes ?? '—'}</span>,\n },\n {\n key: 'evidence',\n header: 'Evidence',\n hideOnMobile: true,\n render: (o) =>\n o.evidence?.id ? (\n <FileLink fileId={o.evidence.id} />\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n ];\n\n return (\n <PageLayout\n title={species.commonName}\n description={[species.scientificName, formatEnumLabel(species.taxonGroup)]\n .filter(Boolean)\n .join(' · ')}\n actions={\n <>\n <StatusBadge status={species.conservationStatus} />\n <Button variant=\"ghost\" onClick={() => navigateTo('species')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Back\n </Button>\n </>\n }\n >\n {/* Overview */}\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-3\">\n <GlassCard treatment=\"glass\" className=\"p-6 lg:col-span-2\">\n <dl className=\"grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-3\">\n <div>\n <dt className=\"text-xs text-text-tertiary\">Scientific name</dt>\n <dd className=\"mt-0.5 text-sm italic text-text-primary\">\n {species.scientificName ?? '—'}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-tertiary\">Taxon group</dt>\n <dd className=\"mt-0.5 text-sm text-text-primary\">\n {formatEnumLabel(species.taxonGroup)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-tertiary\">Conservation</dt>\n <dd className=\"mt-0.5\">\n <StatusBadge status={species.conservationStatus} />\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-tertiary\">Priority</dt>\n <dd className=\"mt-0.5 text-sm text-text-primary\">\n {species.isPriority ? (\n <span className=\"inline-flex items-center gap-1 text-status-warning-text\">\n <Star className=\"h-4 w-4 fill-current\" /> Priority\n </span>\n ) : (\n '—'\n )}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-tertiary\">Observations</dt>\n <dd className=\"mt-0.5 text-sm text-text-primary tabular-nums\">\n {observations.length}\n </dd>\n </div>\n </dl>\n {species.description && (\n <p className=\"mt-5 rounded-lg bg-bg-sunken/60 p-3 text-sm text-text-secondary\">\n {species.description}\n </p>\n )}\n <div className=\"mt-5 border-t border-border-seam pt-4\">\n <EcoTags entityType=\"ecoimpacthub-species\" entityId={species.id} />\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"glass\" className=\"flex flex-col gap-3 p-6\">\n <p className=\"text-xs text-text-tertiary\">Quick actions</p>\n <Button onClick={openObserve}>\n <Binoculars className=\"mr-1.5 h-4 w-4\" /> Record observation\n </Button>\n <Button variant=\"outline\" onClick={openEdit}>\n <Pencil className=\"mr-1.5 h-4 w-4\" /> Edit species\n </Button>\n <Button\n variant=\"ghost\"\n onClick={handleArchive}\n disabled={archiveSpecies.isPending}\n className=\"text-status-error-text hover:text-status-error-text\"\n >\n <Archive className=\"mr-1.5 h-4 w-4\" /> Archive\n </Button>\n </GlassCard>\n </div>\n\n {error && <p className=\"mt-4 text-sm text-status-error-text\">{error}</p>}\n\n {/* Observations */}\n <Section\n title=\"Observations\"\n description=\"Field records logged against this species.\"\n action={\n <Button size=\"sm\" onClick={openObserve}>\n <Binoculars className=\"mr-1.5 h-4 w-4\" /> Record observation\n </Button>\n }\n >\n {observations.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No observations yet\"\n description=\"Record a field observation to see it here.\"\n />\n ) : (\n <DataTable columns={observationColumns} rows={observations} rowKey={(o) => o.id} />\n )}\n </Section>\n\n {/* Record observation dialog */}\n <ResponsiveDialog open={observeOpen} onOpenChange={setObserveOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Record observation</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log a field sighting or detection of {species.commonName}.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsMethod\">Method</Label>\n <Select\n value={observeForm.method}\n onValueChange={(v) =>\n setObserveForm({ ...observeForm, method: v as EcoObservationMethod })\n }\n >\n <SelectTrigger id=\"obsMethod\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {OBSERVATION_METHODS.map((m) => (\n <SelectItem key={m} value={m}>\n {formatEnumLabel(m)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsCount\">Count</Label>\n <Input\n id=\"obsCount\"\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={observeForm.count}\n onChange={(e) => setObserveForm({ ...observeForm, count: e.target.value })}\n placeholder=\"1\"\n />\n </div>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsAt\">Observed at</Label>\n <Input\n id=\"obsAt\"\n type=\"datetime-local\"\n value={observeForm.observedAt}\n onChange={(e) => setObserveForm({ ...observeForm, observedAt: e.target.value })}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsSite\">Site (optional)</Label>\n <Select\n value={observeForm.siteId}\n onValueChange={(v) => setObserveForm({ ...observeForm, siteId: v })}\n >\n <SelectTrigger id=\"obsSite\">\n <SelectValue placeholder=\"No site\" />\n </SelectTrigger>\n <SelectContent>\n {siteRows.map((s) => (\n <SelectItem key={s.id} value={s.id}>\n {s.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsNotes\">Notes</Label>\n <Textarea\n id=\"obsNotes\"\n value={observeForm.notes}\n onChange={(e) => setObserveForm({ ...observeForm, notes: e.target.value })}\n placeholder=\"Optional context — behaviour, conditions, evidence.\"\n rows={2}\n />\n </div>\n <EvidenceUpload\n id=\"speciesObsEvidence\"\n label=\"Evidence photo (optional)\"\n value={observeForm.evidence}\n onChange={(evidence) => setObserveForm({ ...observeForm, evidence })}\n hint=\"Attach a photo, audio clip or PDF as supporting evidence.\"\n />\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setObserveOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleRecordObservation} disabled={recordObservation.isPending}>\n {recordObservation.isPending ? 'Recording…' : 'Record'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {/* Edit species dialog */}\n <ResponsiveDialog open={editOpen} onOpenChange={setEditOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Edit species</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Update naming, classification and priority for this species.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editCommon\">Common name *</Label>\n <Input\n id=\"editCommon\"\n value={editForm.commonName}\n onChange={(e) => setEditForm({ ...editForm, commonName: e.target.value })}\n placeholder=\"Indian Pangolin\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editScientific\">Scientific name</Label>\n <Input\n id=\"editScientific\"\n value={editForm.scientificName}\n onChange={(e) => setEditForm({ ...editForm, scientificName: e.target.value })}\n placeholder=\"Manis crassicaudata\"\n />\n </div>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editTaxon\">Taxon group</Label>\n <Select\n value={editForm.taxonGroup}\n onValueChange={(v) =>\n setEditForm({ ...editForm, taxonGroup: v as EcoTaxonGroup })\n }\n >\n <SelectTrigger id=\"editTaxon\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TAXON_GROUPS.map((t) => (\n <SelectItem key={t} value={t}>\n {formatEnumLabel(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editConservation\">Conservation status</Label>\n <Select\n value={editForm.conservationStatus}\n onValueChange={(v) =>\n setEditForm({ ...editForm, conservationStatus: v as EcoConservationStatus })\n }\n >\n <SelectTrigger id=\"editConservation\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CONSERVATION_STATUSES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={editForm.isPriority}\n onChange={(e) => setEditForm({ ...editForm, isPriority: e.target.checked })}\n className=\"h-4 w-4 rounded border-border-seam accent-action-primary-bg\"\n />\n Mark as priority species\n </label>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editDescription\">Description</Label>\n <Textarea\n id=\"editDescription\"\n value={editForm.description}\n onChange={(e) => setEditForm({ ...editForm, description: e.target.value })}\n placeholder=\"Optional notes on habitat, range or identification.\"\n rows={2}\n />\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setEditOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleUpdate} disabled={updateSpecies.isPending}>\n {updateSpecies.isPending ? 'Saving…' : 'Save changes'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SpeciesDetailPage.js","names":[],"sources":["../../../../src/ecoimpacthub/pages/species/SpeciesDetailPage.tsx"],"sourcesContent":["/**\n * Species detail — overview, field observations & species actions.\n * @module ecoimpacthub/pages/species\n *\n * Reads `ecoSpecies` (+ nested observations); writes `ecoRecordObservation`,\n * `ecoUpdateSpecies`, `ecoArchiveSpecies`.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Binoculars, Pencil, Archive, Star } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GlassCard,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { DataTable, type Column } from '../../components/DataTable';\nimport { LoadingView, ErrorView, Section } from '../../components/StateViews';\nimport { EmptyState } from '../../components/EmptyState';\nimport { EvidenceUpload } from '../../components/EvidenceUpload';\nimport { EcoTags } from '../../components/EcoTags';\nimport { ConservationBadge } from '../_shared/ConservationBadge';\nimport { TaxonChip } from '../_shared/TaxonChip';\nimport { MethodBadge } from '../_shared/MethodBadge';\nimport { EvidenceThumb } from '../_shared/EvidenceThumb';\nimport { useEcoImpactHub } from '../../context';\nimport {\n useEcoSpeciesDetail,\n useEcoSites,\n useEcoRecordObservation,\n useEcoUpdateSpecies,\n useEcoArchiveSpecies,\n type UploadedEcoFile,\n} from '../../hooks';\nimport { formatDateTime, formatEnumLabel, formatNumber } from '../../utils/formatters';\nimport type {\n EcoObservation,\n EcoObservationMethod,\n EcoTaxonGroup,\n EcoConservationStatus,\n} from '../../types';\n\nconst OBSERVATION_METHODS: EcoObservationMethod[] = [\n 'DIRECT_SIGHTING',\n 'CAMERA_TRAP',\n 'ACOUSTIC',\n 'TRACKS_SIGNS',\n 'EDNA',\n 'TELEMETRY',\n 'COMMUNITY_REPORT',\n];\n\nconst TAXON_GROUPS: EcoTaxonGroup[] = [\n 'MAMMAL',\n 'BIRD',\n 'REPTILE',\n 'AMPHIBIAN',\n 'FISH',\n 'INSECT',\n 'PLANT',\n 'FUNGI',\n 'OTHER',\n];\n\nconst CONSERVATION_STATUSES: EcoConservationStatus[] = [\n 'LEAST_CONCERN',\n 'NEAR_THREATENED',\n 'VULNERABLE',\n 'ENDANGERED',\n 'CRITICALLY_ENDANGERED',\n 'EXTINCT_IN_WILD',\n 'DATA_DEFICIENT',\n 'NOT_EVALUATED',\n];\n\n/** Format a Date into the `YYYY-MM-DDTHH:mm` value a datetime-local input expects. */\nconst toLocalInputValue = (d: Date): string => {\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(\n d.getHours()\n )}:${pad(d.getMinutes())}`;\n};\n\ninterface EditFormState {\n commonName: string;\n scientificName: string;\n taxonGroup: EcoTaxonGroup;\n conservationStatus: EcoConservationStatus;\n isPriority: boolean;\n description: string;\n}\n\nexport function SpeciesDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useEcoImpactHub();\n const { data: species, isLoading, isError, refetch } = useEcoSpeciesDetail(id);\n const sites = useEcoSites({ pagination: { limit: 100, offset: 0 } });\n\n const recordObservation = useEcoRecordObservation();\n const updateSpecies = useEcoUpdateSpecies();\n const archiveSpecies = useEcoArchiveSpecies();\n\n const [observeOpen, setObserveOpen] = useState(false);\n const [observeForm, setObserveForm] = useState<{\n method: EcoObservationMethod;\n count: string;\n observedAt: string;\n siteId: string;\n notes: string;\n evidence: UploadedEcoFile | null;\n }>({\n method: 'DIRECT_SIGHTING',\n count: '1',\n observedAt: toLocalInputValue(new Date()),\n siteId: '',\n notes: '',\n evidence: null,\n });\n const [editOpen, setEditOpen] = useState(false);\n const [editForm, setEditForm] = useState<EditFormState>({\n commonName: '',\n scientificName: '',\n taxonGroup: 'MAMMAL',\n conservationStatus: 'NOT_EVALUATED',\n isPriority: false,\n description: '',\n });\n const [error, setError] = useState<string | null>(null);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Species\">\n <LoadingView />\n </PageLayout>\n );\n }\n if (isError || !species) {\n return (\n <PageLayout title=\"Species\">\n <ErrorView message=\"This species could not be loaded.\" onRetry={() => refetch()} />\n </PageLayout>\n );\n }\n\n const observations = species.observations ?? [];\n const siteRows = sites.data?.items ?? [];\n const siteNameById = new Map<string, string>();\n for (const s of siteRows) siteNameById.set(s.id, s.name);\n\n const openObserve = () => {\n setObserveForm({\n method: 'DIRECT_SIGHTING',\n count: '1',\n observedAt: toLocalInputValue(new Date()),\n siteId: '',\n notes: '',\n evidence: null,\n });\n setError(null);\n setObserveOpen(true);\n };\n\n const openEdit = () => {\n setEditForm({\n commonName: species.commonName,\n scientificName: species.scientificName ?? '',\n taxonGroup: species.taxonGroup,\n conservationStatus: species.conservationStatus,\n isPriority: species.isPriority,\n description: species.description ?? '',\n });\n setError(null);\n setEditOpen(true);\n };\n\n const handleRecordObservation = async () => {\n if (!id) return;\n setError(null);\n try {\n await recordObservation.mutateAsync({\n speciesId: id,\n method: observeForm.method,\n count: observeForm.count ? Number(observeForm.count) : 1,\n observedAt: new Date(observeForm.observedAt).toISOString(),\n siteId: observeForm.siteId || null,\n notes: observeForm.notes.trim() || null,\n evidenceFileId: observeForm.evidence?.fileId ?? null,\n });\n setObserveOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to record observation.');\n }\n };\n\n const handleUpdate = async () => {\n if (!id || !editForm.commonName.trim()) {\n setError('Common name is required.');\n return;\n }\n setError(null);\n try {\n await updateSpecies.mutateAsync({\n id,\n input: {\n commonName: editForm.commonName.trim(),\n scientificName: editForm.scientificName.trim() || null,\n taxonGroup: editForm.taxonGroup,\n conservationStatus: editForm.conservationStatus,\n isPriority: editForm.isPriority,\n description: editForm.description.trim() || null,\n },\n });\n setEditOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update species.');\n }\n };\n\n const handleArchive = async () => {\n if (!id) return;\n setError(null);\n try {\n await archiveSpecies.mutateAsync(id);\n navigateTo('species');\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to archive species.');\n }\n };\n\n const observationColumns: Column<EcoObservation>[] = [\n {\n key: 'evidence',\n header: 'Evidence',\n render: (o) => <EvidenceThumb fileId={o.evidence?.id} alt={species.commonName} />,\n },\n {\n key: 'method',\n header: 'Method',\n render: (o) => <MethodBadge method={o.method} />,\n },\n {\n key: 'count',\n header: 'Count',\n align: 'right',\n sortValue: (o) => o.count,\n render: (o) => (\n <span className=\"tabular-nums font-medium text-text-primary\">×{formatNumber(o.count)}</span>\n ),\n },\n {\n key: 'observedAt',\n header: 'Observed',\n hideOnMobile: true,\n render: (o) => (\n <span className=\"whitespace-nowrap text-text-secondary\">\n {formatDateTime(o.observedAt)}\n </span>\n ),\n },\n {\n key: 'site',\n header: 'Site',\n hideOnMobile: true,\n render: (o) => {\n const name = o.siteId ? siteNameById.get(o.siteId) : undefined;\n return name ? (\n <span className=\"text-text-secondary\">{name}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n );\n },\n },\n {\n key: 'notes',\n header: 'Notes',\n hideOnMobile: true,\n render: (o) =>\n o.notes ? (\n <span className=\"block max-w-xs truncate text-text-secondary\" title={o.notes}>\n {o.notes}\n </span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n ];\n\n return (\n <PageLayout\n title={species.commonName}\n description={[species.scientificName, formatEnumLabel(species.taxonGroup)]\n .filter(Boolean)\n .join(' · ')}\n actions={\n <>\n <ConservationBadge status={species.conservationStatus} />\n {species.isPriority && (\n <span\n className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg-subtle px-2.5 py-0.5 text-xs font-semibold text-status-warning-text\"\n title=\"Priority species\"\n >\n <Star className=\"h-3.5 w-3.5 fill-current\" /> Priority\n </span>\n )}\n <Button variant=\"ghost\" onClick={() => navigateTo('species')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Back\n </Button>\n </>\n }\n >\n {/* Overview */}\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-3\">\n <GlassCard treatment=\"glass\" className=\"p-6 lg:col-span-2\">\n <dl className=\"grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-3\">\n <div>\n <dt className=\"text-xs text-text-tertiary\">Scientific name</dt>\n <dd className=\"mt-0.5 text-sm italic text-text-primary\">\n {species.scientificName ?? '—'}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-tertiary\">Taxon group</dt>\n <dd className=\"mt-1\">\n <TaxonChip group={species.taxonGroup} />\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-tertiary\">Conservation</dt>\n <dd className=\"mt-1\">\n <ConservationBadge status={species.conservationStatus} />\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-tertiary\">Priority</dt>\n <dd className=\"mt-0.5 text-sm text-text-primary\">\n {species.isPriority ? (\n <span className=\"inline-flex items-center gap-1 text-status-warning-text\">\n <Star className=\"h-4 w-4 fill-current\" /> Priority\n </span>\n ) : (\n '—'\n )}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-tertiary\">Observations</dt>\n <dd className=\"mt-0.5 text-sm text-text-primary tabular-nums\">\n {observations.length}\n </dd>\n </div>\n </dl>\n {species.description && (\n <p className=\"mt-5 rounded-lg bg-bg-sunken/60 p-3 text-sm text-text-secondary\">\n {species.description}\n </p>\n )}\n <div className=\"mt-5 border-t border-border-seam pt-4\">\n <EcoTags entityType=\"ecoimpacthub-species\" entityId={species.id} />\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"glass\" className=\"flex flex-col gap-3 p-6\">\n <p className=\"text-xs text-text-tertiary\">Quick actions</p>\n <Button onClick={openObserve}>\n <Binoculars className=\"mr-1.5 h-4 w-4\" /> Record observation\n </Button>\n <Button variant=\"outline\" onClick={openEdit}>\n <Pencil className=\"mr-1.5 h-4 w-4\" /> Edit species\n </Button>\n <Button\n variant=\"ghost\"\n onClick={handleArchive}\n disabled={archiveSpecies.isPending}\n className=\"text-status-error-text hover:text-status-error-text\"\n >\n <Archive className=\"mr-1.5 h-4 w-4\" /> Archive\n </Button>\n </GlassCard>\n </div>\n\n {error && <p className=\"mt-4 text-sm text-status-error-text\">{error}</p>}\n\n {/* Observations */}\n <Section\n title=\"Observations\"\n description=\"Field records logged against this species.\"\n action={\n <Button size=\"sm\" onClick={openObserve}>\n <Binoculars className=\"mr-1.5 h-4 w-4\" /> Record observation\n </Button>\n }\n >\n {observations.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No observations yet\"\n description=\"Record a field observation to see it here.\"\n />\n ) : (\n <DataTable columns={observationColumns} rows={observations} rowKey={(o) => o.id} />\n )}\n </Section>\n\n {/* Record observation dialog */}\n <ResponsiveDialog open={observeOpen} onOpenChange={setObserveOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Record observation</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log a field sighting or detection of {species.commonName}.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsMethod\">Method</Label>\n <Select\n value={observeForm.method}\n onValueChange={(v) =>\n setObserveForm({ ...observeForm, method: v as EcoObservationMethod })\n }\n >\n <SelectTrigger id=\"obsMethod\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {OBSERVATION_METHODS.map((m) => (\n <SelectItem key={m} value={m}>\n {formatEnumLabel(m)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsCount\">Count</Label>\n <Input\n id=\"obsCount\"\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={observeForm.count}\n onChange={(e) => setObserveForm({ ...observeForm, count: e.target.value })}\n placeholder=\"1\"\n />\n </div>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsAt\">Observed at</Label>\n <Input\n id=\"obsAt\"\n type=\"datetime-local\"\n value={observeForm.observedAt}\n onChange={(e) => setObserveForm({ ...observeForm, observedAt: e.target.value })}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsSite\">Site (optional)</Label>\n <Select\n value={observeForm.siteId}\n onValueChange={(v) => setObserveForm({ ...observeForm, siteId: v })}\n >\n <SelectTrigger id=\"obsSite\">\n <SelectValue placeholder=\"No site\" />\n </SelectTrigger>\n <SelectContent>\n {siteRows.map((s) => (\n <SelectItem key={s.id} value={s.id}>\n {s.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"obsNotes\">Notes</Label>\n <Textarea\n id=\"obsNotes\"\n value={observeForm.notes}\n onChange={(e) => setObserveForm({ ...observeForm, notes: e.target.value })}\n placeholder=\"Optional context — behaviour, conditions, evidence.\"\n rows={2}\n />\n </div>\n <EvidenceUpload\n id=\"speciesObsEvidence\"\n label=\"Evidence photo (optional)\"\n value={observeForm.evidence}\n onChange={(evidence) => setObserveForm({ ...observeForm, evidence })}\n hint=\"Attach a photo, audio clip or PDF as supporting evidence.\"\n />\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setObserveOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleRecordObservation} disabled={recordObservation.isPending}>\n {recordObservation.isPending ? 'Recording…' : 'Record'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {/* Edit species dialog */}\n <ResponsiveDialog open={editOpen} onOpenChange={setEditOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Edit species</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Update naming, classification and priority for this species.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editCommon\">Common name *</Label>\n <Input\n id=\"editCommon\"\n value={editForm.commonName}\n onChange={(e) => setEditForm({ ...editForm, commonName: e.target.value })}\n placeholder=\"Indian Pangolin\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editScientific\">Scientific name</Label>\n <Input\n id=\"editScientific\"\n value={editForm.scientificName}\n onChange={(e) => setEditForm({ ...editForm, scientificName: e.target.value })}\n placeholder=\"Manis crassicaudata\"\n />\n </div>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editTaxon\">Taxon group</Label>\n <Select\n value={editForm.taxonGroup}\n onValueChange={(v) =>\n setEditForm({ ...editForm, taxonGroup: v as EcoTaxonGroup })\n }\n >\n <SelectTrigger id=\"editTaxon\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TAXON_GROUPS.map((t) => (\n <SelectItem key={t} value={t}>\n {formatEnumLabel(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editConservation\">Conservation status</Label>\n <Select\n value={editForm.conservationStatus}\n onValueChange={(v) =>\n setEditForm({ ...editForm, conservationStatus: v as EcoConservationStatus })\n }\n >\n <SelectTrigger id=\"editConservation\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CONSERVATION_STATUSES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={editForm.isPriority}\n onChange={(e) => setEditForm({ ...editForm, isPriority: e.target.checked })}\n className=\"h-4 w-4 rounded border-border-seam accent-action-primary-bg\"\n />\n Mark as priority species\n </label>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"editDescription\">Description</Label>\n <Textarea\n id=\"editDescription\"\n value={editForm.description}\n onChange={(e) => setEditForm({ ...editForm, description: e.target.value })}\n placeholder=\"Optional notes on habitat, range or identification.\"\n rows={2}\n />\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setEditOpen(false)}>\n Cancel\n </Button>\n <Button onClick={handleUpdate} disabled={updateSpecies.isPending}>\n {updateSpecies.isPending ? 'Saving…' : 'Save changes'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Species — list, filter, and register tracked taxa.
|
|
3
|
+
* @module ecoimpacthub/pages/species
|
|
4
|
+
*
|
|
5
|
+
* Reads `ecoListSpecies`; writes `ecoCreateSpecies`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function SpeciesPage(): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=SpeciesPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpeciesPage.d.ts","sourceRoot":"","sources":["../../../../src/ecoimpacthub/pages/species/SpeciesPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAmFH,wBAAgB,WAAW,4CAoX1B"}
|