fix changing or creating species inside occurrence details, and update occurrence redux typing

This commit is contained in:
juhanikat
2026-10-08 14:58:29 +03:00
parent 27864856dc
commit 6136ec2d78
2 changed files with 87 additions and 54 deletions
@@ -1,26 +1,26 @@
import { CircularProgress } from '@mui/material'
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
import { DetailView, TabType } from '@/components/DetailView/DetailView'
import { UpdateTab } from '@/components/DetailView/common/UpdateTab'
import { OccurrenceCoreTab } from './Tabs/OccurrenceCoreTab'
import { OccurrenceWearTab } from './Tabs/OccurrenceWearTab'
import { OccurrenceIsotopeTab } from './Tabs/OccurrenceIsotopeTab'
import { getErrorMessage, useNotify } from '@/hooks/notification'
import { useEditOccurrenceMutation, useGetOccurrenceDetailsQuery } from '@/redux/api'
import { useEditLocalityMutation, useGetLocalityDetailsQuery } from '@/redux/localityReducer'
import { useLazyGetSpeciesDetailsQuery } from '@/redux/speciesReducer'
import {
EditDataType,
EditableOccurrenceData,
EditDataType,
EditMetaData,
LocalityDetailsType,
OccurrenceDetailsType,
LocalitySpeciesDetailsType,
OccurrenceDetailsType,
RowState,
SpeciesDetailsType,
} from '@/shared/types'
import { validateOccurrence, validateOccurrenceFields } from '@/shared/validators/occurrence'
import { getErrorMessage, useNotify } from '@/hooks/notification'
import { useGetOccurrenceDetailsQuery } from '@/redux/api'
import { useEditLocalityMutation, useGetLocalityDetailsQuery } from '@/redux/localityReducer'
import { CircularProgress } from '@mui/material'
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
import { emptySpecies } from '../DetailView/common/defaultValues'
import { OccurrenceCoreTab } from './Tabs/OccurrenceCoreTab'
import { OccurrenceIsotopeTab } from './Tabs/OccurrenceIsotopeTab'
import { OccurrenceWearTab } from './Tabs/OccurrenceWearTab'
import { emptyOccurrence } from './emptyOccurrence'
import { useLazyGetSpeciesDetailsQuery } from '@/redux/speciesReducer'
import { toSpeciesDetailsDraft } from '../common/toSpeciesDetailsDraft'
const occurrenceFields: Array<keyof EditableOccurrenceData> = [
'nis',
@@ -55,7 +55,7 @@ const occurrenceFields: Array<keyof EditableOccurrenceData> = [
]
export const OccurrenceDetails = () => {
const { id, lid, speciesId } = useParams()
const { lid, speciesId } = useParams()
const [searchParams] = useSearchParams()
const [getSpeciesDetails] = useLazyGetSpeciesDetailsQuery()
@@ -65,7 +65,6 @@ export const OccurrenceDetails = () => {
// these two should exist if the occurrence is created through a locality's Occurrences tab
const lidFromSearchParams = searchParams.get('lid')
const locNameFromSearchParams = searchParams.get('loc_name')
const localityId = lidFromSearchParams ?? lid ?? ''
@@ -86,14 +85,16 @@ export const OccurrenceDetails = () => {
isError: localityQueryError,
} = useGetLocalityDetailsQuery(localityId)
const [editLocalityRequest, { isLoading: mutationLoading }] = useEditLocalityMutation()
const [editOccurrenceRequest, { isLoading: occurrenceMutationLoading }] = useEditOccurrenceMutation()
const [editLocalityRequest, { isLoading: localityMutationLoading }] = useEditLocalityMutation()
const { notify } = useNotify()
const navigate = useNavigate()
if (occurrenceQueryError) return <div>Error loading occurrence data</div>
if (localityQueryError) return <div>Error loading locality data</div>
if (occurrenceDataLoading || localityDataLoading || mutationLoading) return <CircularProgress />
if (occurrenceDataLoading || localityDataLoading || occurrenceMutationLoading || localityMutationLoading)
return <CircularProgress />
const initialOccurrence: OccurrenceDetailsType = { ...emptyOccurrence }
@@ -106,57 +107,89 @@ export const OccurrenceDetails = () => {
if (!localityData) throw new Error('Could not load the linked locality.')
const isSpeciesChanged = editData.species_id !== Number(speciesId)
console.log(editData.species_id)
console.log(speciesId)
console.log(isSpeciesChanged)
const isSpeciesNew = editData.species_id === undefined
// Get this Occurrence, but as a LocalitySpeciesDetailsType
const existingOccurrence = localityData.now_ls.find(ls => ls.species_id === Number(speciesId))
let changedSpeciesDetails: SpeciesDetailsType | null = null
if (isSpeciesChanged) {
let comSpecies: EditDataType<SpeciesDetailsType> | null = null
if (isSpeciesNew) {
comSpecies = {
...emptySpecies,
species_id: undefined,
order_name: editData.order_name ?? emptySpecies.order_name,
genus_name: editData.genus_name ?? emptySpecies.genus_name,
family_name: editData.family_name ?? emptySpecies.family_name,
species_name: editData.species_name ?? emptySpecies.species_name,
unique_identifier: editData.unique_identifier ?? emptySpecies.unique_identifier,
}
} else if (isSpeciesChanged) {
changedSpeciesDetails = await getSpeciesDetails(String(editData.species_id)).unwrap()
if (!changedSpeciesDetails) {
notify('Could not get details of the changed species.')
return
}
comSpecies = {
...emptySpecies,
species_id: editData.species_id ?? undefined,
order_name: editData.order_name ?? emptySpecies.order_name,
genus_name: editData.genus_name ?? emptySpecies.genus_name,
family_name: editData.family_name ?? emptySpecies.family_name,
species_name: editData.species_name ?? emptySpecies.species_name,
unique_identifier: editData.unique_identifier ?? emptySpecies.unique_identifier,
}
} else {
comSpecies = existingOccurrence!.com_species
}
console.log('changedSpeciesDetails', changedSpeciesDetails)
const existingOccurrence = localityData.now_ls.find(ls => ls.species_id === editData.species_id)
const occurrenceData = occurrenceFields.reduce<Record<string, unknown>>((data, field) => {
if (field in editData) data[field] = editData[field]
return data
}, {})
console.log(editData)
const occurrence = {
...(existingOccurrence ?? {}),
lid: localityData.lid,
species_id: editData.species_id,
com_species: editData.species_id
? toSpeciesDetailsDraft(changedSpeciesDetails)
: toSpeciesDetailsDraft(editData),
com_species: comSpecies,
...occurrenceData,
...(isSpeciesChanged && { rowState: 'new' }),
} as LocalitySpeciesDetailsType
console.log(occurrence)
let updatedNowLs
if (isSpeciesChanged) {
// if species was changed, removes this occurrence from the now_ls, and adds a new occurrence with the new species
const removedRow = localityData.now_ls.find(row => row.species_id === Number(speciesId))
updatedNowLs = [
...localityData.now_ls.filter(row => row.species_id !== removedRow?.species_id),
{ ...removedRow, rowState: 'removed' } as LocalitySpeciesDetailsType,
occurrence,
]
} else {
// if species was not changed, simply updates the occurrence
updatedNowLs = [...localityData.now_ls, occurrence]
}
console.log(updatedNowLs)
await editLocalityRequest({
...localityData,
now_ls: updatedNowLs,
comment: editData.comment,
references: editData.references ?? [],
}).unwrap()
notify('Occurrence entry finalized successfully.')
setTimeout(() => navigate(`/occurrence/${editData.lid}/${editData.species_id}`), 15)
if (isSpeciesChanged) {
// removes the old occurrence before adding the update version back in
const removedRow = localityData.now_ls.find(row => row.species_id === Number(speciesId))
const updatedNowLs = [
...localityData.now_ls,
{ ...removedRow, rowState: 'removed' as RowState } as LocalitySpeciesDetailsType,
occurrence as LocalitySpeciesDetailsType,
]
await editLocalityRequest({
...localityData,
now_ls: updatedNowLs,
comment: editData.comment,
references: editData.references ?? [],
}).unwrap()
notify('Occurrence entry finalized successfully.')
if (isSpeciesNew) {
// navigates to occurrence table, since getting the ID of the newly created species is difficult
setTimeout(() => navigate('/occurrence'), 15)
} else {
setTimeout(() => navigate(`/occurrence/${occurrence.lid}/${occurrence.species_id}`), 15)
}
} else {
// edit Occurrence directly since species is not updated and the combined ID does not change
const updatedOccurrence = await editOccurrenceRequest({
...(occurrence as EditDataType<OccurrenceDetailsType>),
comment: editData.comment,
references: editData.references ?? [],
}).unwrap()
notify('Occurrence entry finalized successfully.')
setTimeout(() => navigate(`/occurrence/${updatedOccurrence.lid}/${updatedOccurrence.species_id}`), 15)
}
} catch (error) {
notify(getErrorMessage(error, 'Could not finalize occurrence entry.'), 'error')
throw error
+2 -2
View File
@@ -1,3 +1,4 @@
import { EditDataType, EditMetaData, OccurrenceDetailsType } from '@/shared/types'
import {
BaseQueryFn,
createApi,
@@ -8,7 +9,6 @@ import {
} from '@reduxjs/toolkit/query/react'
import { BACKEND_URL } from '../util/config'
import type { RootState } from './store'
import { EditDataType, OccurrenceDetailsType } from '@/shared/types'
type RefreshTokenResult = {
data?: { token?: string }
@@ -116,7 +116,7 @@ const occurrenceApi = api.injectEndpoints({
}),
providesTags: result => (result ? [{ type: 'occurrence', id: `${result.lid}-${result.species_id}` }] : []),
}),
editOccurrence: builder.mutation<OccurrenceDetailsType, EditDataType<OccurrenceDetailsType>>({
editOccurrence: builder.mutation<OccurrenceDetailsType, EditDataType<OccurrenceDetailsType> & EditMetaData>({
query: occurrence => ({
url: `/occurrence/${occurrence.lid}/${occurrence.species_id}`,
method: 'PUT',