@burdenoff/microfe-ecoimpacthub 2026.704.2 → 2026.704.4
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/ecoimpacthub/components/EcoDiscussion.js +109 -0
- package/dist/ecoimpacthub/components/EcoDiscussion.js.map +1 -0
- package/dist/ecoimpacthub/components/EcoTags.js +149 -0
- package/dist/ecoimpacthub/components/EcoTags.js.map +1 -0
- package/dist/ecoimpacthub/components/EvidenceUpload.js +93 -0
- package/dist/ecoimpacthub/components/EvidenceUpload.js.map +1 -0
- package/dist/ecoimpacthub/components/FileLink.js +36 -0
- package/dist/ecoimpacthub/components/FileLink.js.map +1 -0
- package/dist/ecoimpacthub/components/PageLayout.js +2 -2
- package/dist/ecoimpacthub/components/PageLayout.js.map +1 -1
- package/dist/ecoimpacthub/hooks/index.js +3 -0
- package/dist/ecoimpacthub/hooks/useEcoComments.js +45 -0
- package/dist/ecoimpacthub/hooks/useEcoComments.js.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoFiles.js +81 -0
- package/dist/ecoimpacthub/hooks/useEcoFiles.js.map +1 -0
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js +169 -166
- package/dist/ecoimpacthub/hooks/useEcoImpactHubApi.js.map +1 -1
- package/dist/ecoimpacthub/hooks/useEcoTags.js +89 -0
- package/dist/ecoimpacthub/hooks/useEcoTags.js.map +1 -0
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js +4 -0
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.js +124 -101
- package/dist/ecoimpacthub/pages/observations/ObservationsPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js +153 -126
- package/dist/ecoimpacthub/pages/reports/ReportDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js +241 -230
- package/dist/ecoimpacthub/pages/sites/SiteDetailPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js +260 -225
- package/dist/ecoimpacthub/pages/species/SpeciesDetailPage.js.map +1 -1
- package/package.json +1 -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 { useEcoImpactHub } from '../../context';\nimport {\n useEcoSpeciesDetail,\n useEcoSites,\n useEcoRecordObservation,\n useEcoUpdateSpecies,\n useEcoArchiveSpecies,\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: 'DIRECT_SIGHTING' as EcoObservationMethod,\n count: '1',\n observedAt: toLocalInputValue(new Date()),\n siteId: '',\n notes: '',\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 });\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 });\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\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 </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 </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 { 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":";;;;;;;;;;;;;;;;;;;AAsDA,IAAM,IAA8C;CAClD;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAEK,IAAgC;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAEK,IAAiD;CACrD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAGK,KAAqB,MAAoB;CAC7C,IAAM,KAAO,MAAc,OAAO,EAAE,CAAC,SAAS,GAAG,IAAI;AACrD,QAAO,GAAG,EAAE,aAAa,CAAC,GAAG,EAAI,EAAE,UAAU,GAAG,EAAE,CAAC,GAAG,EAAI,EAAE,SAAS,CAAC,CAAC,GAAG,EACxE,EAAE,UAAU,CACb,CAAC,GAAG,EAAI,EAAE,YAAY,CAAC;;AAY1B,SAAgB,IAAoB;CAClC,IAAM,EAAE,UAAO,GAA2B,EACpC,EAAE,kBAAe,GAAiB,EAClC,EAAE,MAAM,GAAS,cAAW,YAAS,gBAAY,GAAoB,EAAG,EACxE,KAAQ,GAAY,EAAE,YAAY;EAAE,OAAO;EAAK,QAAQ;EAAG,EAAE,CAAC,EAE9D,IAAoB,IAAyB,EAC7C,IAAgB,IAAqB,EACrC,IAAiB,IAAsB,EAEvC,CAAC,IAAa,KAAkB,EAAS,GAAM,EAC/C,CAAC,GAAa,KAAkB,EAOnC;EACD,QAAQ;EACR,OAAO;EACP,YAAY,kBAAkB,IAAI,MAAM,CAAC;EACzC,QAAQ;EACR,OAAO;EACP,UAAU;EACX,CAAC,EACI,CAAC,IAAU,KAAe,EAAS,GAAM,EACzC,CAAC,GAAU,KAAe,EAAwB;EACtD,YAAY;EACZ,gBAAgB;EAChB,YAAY;EACZ,oBAAoB;EACpB,YAAY;EACZ,aAAa;EACd,CAAC,EACI,CAAC,GAAO,KAAY,EAAwB,KAAK;AAEvD,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,IAAD,EAAe,CAAA;EACJ,CAAA;AAGjB,KAAI,KAAW,CAAC,EACd,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GAAW,SAAQ;GAAoC,eAAe,IAAS;GAAI,CAAA;EACxE,CAAA;CAIjB,IAAM,IAAe,EAAQ,gBAAgB,EAAE,EACzC,IAAW,GAAM,MAAM,SAAS,EAAE,EAElC,UAAoB;AAUxB,EATA,EAAe;GACb,QAAQ;GACR,OAAO;GACP,YAAY,kBAAkB,IAAI,MAAM,CAAC;GACzC,QAAQ;GACR,OAAO;GACP,UAAU;GACX,CAAC,EACF,EAAS,KAAK,EACd,EAAe,GAAK;;AA0HtB,QACE,kBAAC,GAAD;EACE,OAAO,EAAQ;EACf,aAAa,CAAC,EAAQ,gBAAgB,EAAgB,EAAQ,WAAW,CAAC,CACvE,OAAO,QAAQ,CACf,KAAK,MAAM;EACd,SACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAa,QAAQ,EAAQ,oBAAsB,CAAA,EACnD,kBAAC,GAAD;GAAQ,SAAQ;GAAQ,eAAe,EAAW,UAAU;aAA5D,CACE,kBAAC,GAAD,EAAW,WAAU,kBAAmB,CAAA,EAAA,QACjC;KACR,EAAA,CAAA;YAXP;GAeE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAW,WAAU;KAAQ,WAAU;eAAvC;MACE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBAA6B;SAAoB,CAAA,EAC/D,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAQ,kBAAkB;SACxB,CAAA,CACD,EAAA,CAAA;QACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBAA6B;SAAgB,CAAA,EAC3D,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAgB,EAAQ,WAAW;SACjC,CAAA,CACD,EAAA,CAAA;QACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBAA6B;SAAiB,CAAA,EAC5D,kBAAC,MAAD;SAAI,WAAU;mBACZ,kBAAC,GAAD,EAAa,QAAQ,EAAQ,oBAAsB,CAAA;SAChD,CAAA,CACD,EAAA,CAAA;QACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBAA6B;SAAa,CAAA,EACxD,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAQ,aACP,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACE,kBAAC,GAAD,EAAM,WAAU,wBAAyB,CAAA,EAAA,YACpC;cAEP;SAEC,CAAA,CACD,EAAA,CAAA;QACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBAA6B;SAAiB,CAAA,EAC5D,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAa;SACX,CAAA,CACD,EAAA,CAAA;QACH;;MACJ,EAAQ,eACP,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAQ;OACP,CAAA;MAEN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,IAAD;QAAS,YAAW;QAAuB,UAAU,EAAQ;QAAM,CAAA;OAC/D,CAAA;MACI;QAEZ,kBAAC,GAAD;KAAW,WAAU;KAAQ,WAAU;eAAvC;MACE,kBAAC,KAAD;OAAG,WAAU;iBAA6B;OAAiB,CAAA;MAC3D,kBAAC,GAAD;OAAQ,SAAS;iBAAjB,CACE,kBAAC,GAAD,EAAY,WAAU,kBAAmB,CAAA,EAAA,sBAClC;;MACT,kBAAC,GAAD;OAAQ,SAAQ;OAAU,eA9LX;AAUrB,QATA,EAAY;SACV,YAAY,EAAQ;SACpB,gBAAgB,EAAQ,kBAAkB;SAC1C,YAAY,EAAQ;SACpB,oBAAoB,EAAQ;SAC5B,YAAY,EAAQ;SACpB,aAAa,EAAQ,eAAe;SACrC,CAAC,EACF,EAAS,KAAK,EACd,EAAY,GAAK;;iBAoLX,CACE,kBAAC,GAAD,EAAQ,WAAU,kBAAmB,CAAA,EAAA,gBAC9B;;MACT,kBAAC,GAAD;OACE,SAAQ;OACR,SA3IY,YAAY;AAC3B,eACL;WAAS,KAAK;AACd,aAAI;AAEF,UADA,MAAM,EAAe,YAAY,EAAG,EACpC,EAAW,UAAU;kBACd,GAAK;AACZ,YAAS,aAAe,QAAQ,EAAI,UAAU,6BAA6B;;;;OAqIrE,UAAU,EAAe;OACzB,WAAU;iBAJZ,CAME,kBAAC,IAAD,EAAS,WAAU,kBAAmB,CAAA,EAAA,WAC/B;;MACC;OACR;;GAEL,KAAS,kBAAC,KAAD;IAAG,WAAU;cAAuC;IAAU,CAAA;GAGxE,kBAAC,IAAD;IACE,OAAM;IACN,aAAY;IACZ,QACE,kBAAC,GAAD;KAAQ,MAAK;KAAK,SAAS;eAA3B,CACE,kBAAC,GAAD,EAAY,WAAU,kBAAmB,CAAA,EAAA,sBAClC;;cAGV,EAAa,WAAW,IACvB,kBAAC,IAAD;KACE,cAAa;KACb,OAAM;KACN,aAAY;KACZ,CAAA,GAEF,kBAAC,IAAD;KAAW,SA5JkC;MACnD;OACE,KAAK;OACL,QAAQ;OACR,SAAS,MACP,kBAAC,QAAD;QAAM,WAAU;kBAAiC,EAAgB,EAAE,OAAO;QAAQ,CAAA;OAErF;MACD;OACE,KAAK;OACL,QAAQ;OACR,OAAO;OACP,YAAY,MAAM,EAAE;OACpB,SAAS,MACP,kBAAC,QAAD;QAAM,WAAU;kBAAkC,GAAa,EAAE,MAAM;QAAQ,CAAA;OAElF;MACD;OACE,KAAK;OACL,QAAQ;OACR,SAAS,MAAM,kBAAC,QAAD;QAAM,WAAU;kBAAuB,EAAe,EAAE,WAAW;QAAQ,CAAA;OAC3F;MACD;OACE,KAAK;OACL,QAAQ;OACR,cAAc;OACd,SAAS,MACP,EAAE,SACA,kBAAC,QAAD;QAAM,WAAU;kBAAuB,EAAE;QAAc,CAAA,GAEvD,kBAAC,QAAD;QAAM,WAAU;kBAAqB;QAAQ,CAAA;OAElD;MACD;OACE,KAAK;OACL,QAAQ;OACR,cAAc;OACd,SAAS,MAAM,kBAAC,QAAD;QAAM,WAAU;kBAAuB,EAAE,SAAS;QAAW,CAAA;OAC7E;MACD;OACE,KAAK;OACL,QAAQ;OACR,cAAc;OACd,SAAS,MACP,EAAE,UAAU,KACV,kBAAC,IAAD,EAAU,QAAQ,EAAE,SAAS,IAAM,CAAA,GAEnC,kBAAC,QAAD;QAAM,WAAU;kBAAqB;QAAQ,CAAA;OAElD;MACF;KA0G+C,MAAM;KAAc,SAAS,MAAM,EAAE;KAAM,CAAA;IAE7E,CAAA;GAGV,kBAAC,GAAD;IAAkB,MAAM;IAAa,cAAc;cACjD,kBAAC,GAAD,EAAA,UAAA;KACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,sBAA0C,CAAA,EACjE,kBAAC,GAAD,EAAA,UAAA;MAA6B;MACW,EAAQ;MAAW;MAC7B,EAAA,CAAA,CACP,EAAA,CAAA;KACzB,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAY;UAAc,CAAA,EACzC,kBAAC,GAAD;UACE,OAAO,EAAY;UACnB,gBAAgB,MACd,EAAe;WAAE,GAAG;WAAa,QAAQ;WAA2B,CAAC;oBAHzE,CAME,kBAAC,GAAD;WAAe,IAAG;qBAChB,kBAAC,GAAD,EAAe,CAAA;WACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAoB,KAAK,MACxB,kBAAC,GAAD;WAAoB,OAAO;qBACxB,EAAgB,EAAE;WACR,EAFI,EAEJ,CACb,EACY,CAAA,CACT;YACL;YACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAW;UAAa,CAAA,EACvC,kBAAC,GAAD;UACE,IAAG;UACH,MAAK;UACL,KAAI;UACJ,MAAK;UACL,OAAO,EAAY;UACnB,WAAW,MAAM,EAAe;WAAE,GAAG;WAAa,OAAO,EAAE,OAAO;WAAO,CAAC;UAC1E,aAAY;UACZ,CAAA,CACE;WACF;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAQ;SAAmB,CAAA,EAC1C,kBAAC,GAAD;SACE,IAAG;SACH,MAAK;SACL,OAAO,EAAY;SACnB,WAAW,MAAM,EAAe;UAAE,GAAG;UAAa,YAAY,EAAE,OAAO;UAAO,CAAC;SAC/E,CAAA,CACE;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAU;SAAuB,CAAA,EAChD,kBAAC,GAAD;SACE,OAAO,EAAY;SACnB,gBAAgB,MAAM,EAAe;UAAE,GAAG;UAAa,QAAQ;UAAG,CAAC;mBAFrE,CAIE,kBAAC,GAAD;UAAe,IAAG;oBAChB,kBAAC,GAAD,EAAa,aAAY,WAAY,CAAA;UACvB,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAS,KAAK,MACb,kBAAC,GAAD;UAAuB,OAAO,EAAE;oBAC7B,EAAE;UACQ,EAFI,EAAE,GAEN,CACb,EACY,CAAA,CACT;WACL;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAW;SAAa,CAAA,EACvC,kBAAC,GAAD;SACE,IAAG;SACH,OAAO,EAAY;SACnB,WAAW,MAAM,EAAe;UAAE,GAAG;UAAa,OAAO,EAAE,OAAO;UAAO,CAAC;SAC1E,aAAY;SACZ,MAAM;SACN,CAAA,CACE;;OACN,kBAAC,IAAD;QACE,IAAG;QACH,OAAM;QACN,OAAO,EAAY;QACnB,WAAW,MAAa,EAAe;SAAE,GAAG;SAAa;SAAU,CAAC;QACpE,MAAK;QACL,CAAA;OACE;;KACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,eAAe,EAAe,GAAM;gBAAE;MAEvD,CAAA,EACT,kBAAC,GAAD;MAAQ,SAnTc,YAAY;AACrC,cACL;UAAS,KAAK;AACd,YAAI;AAUF,SATA,MAAM,EAAkB,YAAY;UAClC,WAAW;UACX,QAAQ,EAAY;UACpB,OAAO,EAAY,QAAQ,OAAO,EAAY,MAAM,GAAG;UACvD,YAAY,IAAI,KAAK,EAAY,WAAW,CAAC,aAAa;UAC1D,QAAQ,EAAY,UAAU;UAC9B,OAAO,EAAY,MAAM,MAAM,IAAI;UACnC,gBAAgB,EAAY,UAAU,UAAU;UACjD,CAAC,EACF,EAAe,GAAM;iBACd,GAAK;AACZ,WAAS,aAAe,QAAQ,EAAI,UAAU,gCAAgC;;;;MAoS9B,UAAU,EAAkB;gBACnE,EAAkB,YAAY,eAAe;MACvC,CAAA,CACc,EAAA,CAAA;KACD,EAAA,CAAA;IACT,CAAA;GAGnB,kBAAC,GAAD;IAAkB,MAAM;IAAU,cAAc;cAC9C,kBAAC,GAAD,EAAA,UAAA;KACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,gBAAoC,CAAA,EAC3D,kBAAC,GAAD,EAAA,UAA6B,gEAEC,CAAA,CACP,EAAA,CAAA;KACzB,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAa;UAAqB,CAAA,EACjD,kBAAC,GAAD;UACE,IAAG;UACH,OAAO,EAAS;UAChB,WAAW,MAAM,EAAY;WAAE,GAAG;WAAU,YAAY,EAAE,OAAO;WAAO,CAAC;UACzE,aAAY;UACZ,CAAA,CACE;YACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAiB;UAAuB,CAAA,EACvD,kBAAC,GAAD;UACE,IAAG;UACH,OAAO,EAAS;UAChB,WAAW,MAAM,EAAY;WAAE,GAAG;WAAU,gBAAgB,EAAE,OAAO;WAAO,CAAC;UAC7E,aAAY;UACZ,CAAA,CACE;WACF;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAY;UAAmB,CAAA,EAC9C,kBAAC,GAAD;UACE,OAAO,EAAS;UAChB,gBAAgB,MACd,EAAY;WAAE,GAAG;WAAU,YAAY;WAAoB,CAAC;oBAHhE,CAME,kBAAC,GAAD;WAAe,IAAG;qBAChB,kBAAC,GAAD,EAAe,CAAA;WACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAa,KAAK,MACjB,kBAAC,GAAD;WAAoB,OAAO;qBACxB,EAAgB,EAAE;WACR,EAFI,EAEJ,CACb,EACY,CAAA,CACT;YACL;YACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAmB;UAA2B,CAAA,EAC7D,kBAAC,GAAD;UACE,OAAO,EAAS;UAChB,gBAAgB,MACd,EAAY;WAAE,GAAG;WAAU,oBAAoB;WAA4B,CAAC;oBAHhF,CAME,kBAAC,GAAD;WAAe,IAAG;qBAChB,kBAAC,GAAD,EAAe,CAAA;WACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAsB,KAAK,MAC1B,kBAAC,GAAD;WAAoB,OAAO;qBACxB,EAAgB,EAAE;WACR,EAFI,EAEJ,CACb,EACY,CAAA,CACT;YACL;WACF;;OACN,kBAAC,SAAD;QAAO,WAAU;kBAAjB,CACE,kBAAC,SAAD;SACE,MAAK;SACL,SAAS,EAAS;SAClB,WAAW,MAAM,EAAY;UAAE,GAAG;UAAU,YAAY,EAAE,OAAO;UAAS,CAAC;SAC3E,WAAU;SACV,CAAA,EAAA,2BAEI;;OACR,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAkB;SAAmB,CAAA,EACpD,kBAAC,GAAD;SACE,IAAG;SACH,OAAO,EAAS;SAChB,WAAW,MAAM,EAAY;UAAE,GAAG;UAAU,aAAa,EAAE,OAAO;UAAO,CAAC;SAC1E,aAAY;SACZ,MAAM;SACN,CAAA,CACE;;OACF;;KACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,eAAe,EAAY,GAAM;gBAAE;MAEpD,CAAA,EACT,kBAAC,GAAD;MAAQ,SAvYG,YAAY;AAC/B,WAAI,CAAC,KAAM,CAAC,EAAS,WAAW,MAAM,EAAE;AACtC,UAAS,2BAA2B;AACpC;;AAEF,SAAS,KAAK;AACd,WAAI;AAYF,QAXA,MAAM,EAAc,YAAY;SAC9B;SACA,OAAO;UACL,YAAY,EAAS,WAAW,MAAM;UACtC,gBAAgB,EAAS,eAAe,MAAM,IAAI;UAClD,YAAY,EAAS;UACrB,oBAAoB,EAAS;UAC7B,YAAY,EAAS;UACrB,aAAa,EAAS,YAAY,MAAM,IAAI;UAC7C;SACF,CAAC,EACF,EAAY,GAAM;gBACX,GAAK;AACZ,UAAS,aAAe,QAAQ,EAAI,UAAU,4BAA4B;;;MAmXrC,UAAU,EAAc;gBACpD,EAAc,YAAY,YAAY;MAChC,CAAA,CACc,EAAA,CAAA;KACD,EAAA,CAAA;IACT,CAAA;GACR"}
|