Added Species Synonyms Tab

This commit is contained in:
karilint
2024-05-17 08:54:51 +03:00
committed by Arttu Kangas
parent ce48893178
commit 9107546d17
4 changed files with 385 additions and 0 deletions
@@ -3,8 +3,11 @@ import { useGetSpeciesDetailsQuery } from '../../redux/speciesReducer'
import { CircularProgress } from '@mui/material'
import { DetailView, TabType } from '../DetailView/DetailView'
import { DietTab } from './Tabs/DietTab'
import { LocalityTab } from './Tabs/LocalityTab'
import { LocalitySpeciesTab } from './Tabs/LocalitySpeciesTab'
import { LocomotionTab } from './Tabs/LocomotionTab'
import { SizeTab } from './Tabs/SizeTab'
import { SynonymTab } from './Tabs/SynonymTab'
import { TaxonomyTab } from './Tabs/TaxonomyTab'
import { TeethTab } from './Tabs/TeethTab'
import { UpdateTab } from './Tabs/UpdateTab'
@@ -21,6 +24,10 @@ export const SpeciesDetails = () => {
title: 'Taxonomy',
content: <TaxonomyTab />,
},
{
title: 'Synonyms',
content: <SynonymTab />,
},
{
title: 'Diet',
content: <DietTab />,
@@ -37,6 +44,14 @@ export const SpeciesDetails = () => {
title: 'Teeth',
content: <TeethTab />,
},
{
title: 'Localities',
content: <LocalityTab />,
},
{
title: 'Locality Species',
content: <LocalitySpeciesTab />,
},
{
title: 'Updates',
content: <UpdateTab />,
@@ -0,0 +1,162 @@
import { Editable, SpeciesDetails, SpeciesLocality } from '@/backendTypes'
import { EditableTable, EditingModal, Grouped } from '@/components/DetailView/common/FormComponents'
import { useDetailContext } from '@/components/DetailView/hooks'
import { Box, TextField } from '@mui/material'
import { MRT_ColumnDef } from 'material-react-table'
import { useForm } from 'react-hook-form'
export const LocalitySpeciesTab = () => {
const { editData, mode } = useDetailContext<SpeciesDetails>()
const {
register,
formState: { errors },
} = useForm()
const columns: MRT_ColumnDef<SpeciesLocality>[] = [
{
accessorKey: 'now_loc.loc_name',
header: 'Locality',
},
{
accessorKey: 'now_loc.country',
header: 'Country',
},
{
accessorKey: 'id_status',
header: 'ID Status',
},
{
accessorKey: 'orig_entry',
header: 'Additional Information',
},
{
accessorKey: 'source_name',
header: 'Source Name',
},
{
accessorKey: 'nis',
header: 'NIS',
},
{
accessorKey: 'pct',
header: 'PCT',
},
{
accessorKey: 'quad',
header: 'QUAD',
},
{
accessorKey: 'mni',
header: 'MNI',
},
{
accessorKey: 'body_mass',
header: 'Body Mass (g)',
},
{
accessorKey: 'mesowear',
header: 'Mesowear',
},
{
accessorKey: 'mw_or_low',
header: 'MW Low',
},
{
accessorKey: 'mw_or_high',
header: 'MW High',
},
{
accessorKey: 'mw_cs_sharp',
header: 'MW Sharp',
},
{
accessorKey: 'mw_cs_round',
header: 'MW Round',
},
{
accessorKey: 'mw_cs_blunt',
header: 'MW Blunt',
},
{
header: 'MW Score',
Cell: () => <Box>not implemented</Box>,
},
{
accessorKey: 'microwear',
header: 'Microwear',
},
{
accessorKey: 'dc13_mean',
header: 'dC13 Mean',
},
{
accessorKey: 'dc13_n',
header: 'dC13 n',
},
{
accessorKey: 'dc13_max',
header: 'dC13 Max',
},
{
accessorKey: 'dc13_min',
header: 'dC13 Min',
},
{
accessorKey: 'dc13_stdev',
header: 'dC13 STDEV',
},
{
accessorKey: 'do18_mean',
header: 'dO18 Mean',
},
{
accessorKey: 'do18_n',
header: 'dO18 n',
},
{
accessorKey: 'do18_max',
header: 'dO18 Max',
},
{
accessorKey: 'do18_min',
header: 'dO18 Min',
},
{
accessorKey: 'do18_stdev',
header: 'dO18 STDEV',
},
]
// eslint-disable-next-line @typescript-eslint/require-await
const onSave = async () => {
// TODO: Saving logic here (add Locality to editData)
return Object.keys(errors).length === 0
}
const editingModal = (
<EditingModal buttonText="Add new Locality Species" onSave={onSave}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '1em' }}>
<TextField {...register('now_loc.name', { required: true })} label="Locality" />
<TextField {...register('now_loc.country', { required: true })} label="Country" />
<TextField {...register('now_loc.dms_lat', { required: true })} label="Latitude dms" />
<TextField {...register('now_loc.dms_lon', { required: true })} label="Longitude dms" />
<TextField {...register('now_loc.max_age', { required: true })} label="Maximum Age" />
<TextField {...register('now_loc.min_age', { required: true })} label="Minimum Age" />
<TextField {...register('now_loc.bfa_max_abs', { required: true })} label="Basis for Age Maximum" />
<TextField {...register('now_loc.bfa_min_abs', { required: true })} label="Basis for Age Minimum" />
</Box>
</EditingModal>
)
return (
<Grouped title="Locality-Species Information">
{mode === 'edit' && editingModal}
<EditableTable<Editable<SpeciesLocality>, SpeciesDetails>
columns={columns}
data={editData.now_ls}
editable
field="now_ls"
/>
</Grouped>
)
}
@@ -0,0 +1,141 @@
import { Editable, LocalityDetails, Museum, SpeciesDetails, SpeciesLocality, Locality } from '@/backendTypes'
import { EditableTable, EditingModal, FormTextField, Grouped } from '@/components/DetailView/common/FormComponents'
import { useDetailContext } from '@/components/DetailView/hooks'
import { TableView } from '@/components/TableView/TableView'
import { useGetAllLocalitiesQuery } from '@/redux/localityReducer'
import { Box, CircularProgress } from '@mui/material'
import { MRT_ColumnDef } from 'material-react-table'
import { useState } from 'react'
import { useForm } from 'react-hook-form'
const LocalitySelectingTable = () => {
const { data, isError } = useGetAllLocalitiesQuery()
const [selected, setSelected] = useState<string[]>([])
if (isError) return 'Error loading Localities.'
if (!data) return <CircularProgress />
const selectId = (id: string) => {
const index = selected.indexOf(id)
if (index < 0) {
setSelected([...selected, id])
} else {
const newSelected = [...selected]
newSelected.splice(index, 1)
setSelected(newSelected)
}
}
// Fields for selecting existing Localities
const columns: MRT_ColumnDef<SpeciesLocality>[] = [
{
accessorKey: 'loc_name',
header: 'Locality',
},
{
accessorKey: 'country',
header: 'Country',
},
{
accessorKey: 'max_age',
header: 'Max Age',
},
{
accessorKey: 'min_age',
header: 'Min Age',
},
]
return (
<TableView<Locality>
data={data}
columns={columns}
selectorFn={selectId}
selectedList={selected}
idFieldName="lid"
/>
)
}
export const LocalityTab = () => {
const { editData, mode } = useDetailContext<SpeciesDetails>()
const {
register,
trigger,
formState: { errors },
} = useForm()
const columns: MRT_ColumnDef<SpeciesLocality>[] = [
{
accessorKey: 'now_loc.loc_name',
header: 'Locality',
},
{
accessorKey: 'now_loc.country',
header: 'Country',
},
{
accessorKey: 'now_loc.max_age',
header: 'Max Age',
},
{
accessorKey: 'now_loc.min_age',
header: 'Min Age',
},
]
const onSave = async () => {
// TODO: Saving logic here (add Locality to editData)
const result = await trigger()
return result
}
const formFields: { name: string; label: string; required?: boolean }[] = [
{ name: 'name', label: 'Locality', required: true },
{ name: 'country', label: 'Country', required: true },
{ name: 'dms_lat', label: 'Latitude dms' },
{ name: 'dms_lon', label: 'Longitude dms', required: true },
{ name: 'max_age', label: 'Maximum Age', required: true },
{ name: 'min_age', label: 'Minimum Age', required: true },
{ name: 'bfa_max_abs', label: 'Basis for Age Maximum', required: true },
{ name: 'bfa_min_abs', label: 'Basis for Age Minimum', required: true },
]
const editingModal = (
<EditingModal buttonText="Add new Locality" onSave={onSave}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '1em' }}>
{formFields.map(field => (
<FormTextField
key={field.name}
{...{ errors, register }}
fieldName={field.name}
label={field.label}
required={!!field.required}
/>
))}
</Box>
</EditingModal>
)
const selectingTable = (
<EditingModal buttonText="Add existing Locality" onSave={onSave}>
<LocalitySelectingTable />
</EditingModal>
)
return (
<Grouped title="Localities">
{mode === 'edit' && (
<Box display="flex" gap={1}>
{editingModal} {selectingTable}
</Box>
)}
<EditableTable<Editable<SpeciesLocality>, SpeciesDetails>
columns={columns}
data={editData.now_ls}
editable
field="now_ls"
/>
</Grouped>
)
}
@@ -0,0 +1,67 @@
import { Editable, SpeciesDetails, SpeciesSynonym } from '@/backendTypes'
import { useDetailContext } from '@/components/DetailView/hooks'
import {
EditableTable,
EditingModal,
Grouped,
ArrayFrame,
HalfFrames,
} from '@/components/DetailView/common/FormComponents'
import { Box, TextField } from '@mui/material'
import { MRT_ColumnDef } from 'material-react-table'
import { useForm } from 'react-hook-form'
export const SynonymTab = () => {
const { textField } = useDetailContext<SpeciesDetails>()
const { editData, mode } = useDetailContext<SpeciesDetails>()
const {
register,
formState: { errors },
} = useForm()
const columns: MRT_ColumnDef<SpeciesSynonym>[] = [
{
accessorKey: 'syn_genus_name',
header: 'Genus',
},
{
accessorKey: 'syn_species_name',
header: 'Species',
},
{
accessorKey: 'syn_comment',
header: 'Comment',
},
]
// eslint-disable-next-line @typescript-eslint/require-await
const onSave = async () => {
// TODO: Saving logic here (add Synonym to editData)
return Object.keys(errors).length === 0
}
const editingModal = (
<EditingModal buttonText="Add new Synonym" onSave={onSave}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '1em' }}>
<TextField {...register('syn_genus_name', { required: true })} label="Genus" required />
<TextField {...register('syn_species_name', { required: true })} label="Species" required />
<TextField {...register('syn_comment', { required: true })} label="Comment" required />
</Box>
</EditingModal>
)
return (
<>
<Grouped title="Synonyms">
{mode === 'edit' && editingModal}
<EditableTable<Editable<SpeciesSynonym>, SpeciesDetails>
columns={columns}
data={editData.com_taxa_synonym}
editable
field="com_taxa_synonym"
/>
</Grouped>
</>
)
}