mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Merge week 22: Time unit details, project, region, admin links
This commit is contained in:
@@ -5,6 +5,8 @@ import localityRouter from './routes/locality'
|
||||
import museumRouter from './routes/museum'
|
||||
import referenceRouter from './routes/reference'
|
||||
import sedimentaryStructureRouter from './routes/sedimentaryStructure'
|
||||
import regionRouter from './routes/region'
|
||||
import projectRouter from './routes/project'
|
||||
import speciesRouter from './routes/species'
|
||||
import timeUnitRouter from './routes/timeUnit'
|
||||
import userRouter from './routes/user'
|
||||
@@ -31,6 +33,8 @@ if (BACKEND_MODE !== 'dev') app.use(requireLogin)
|
||||
|
||||
app.use('/locality', localityRouter)
|
||||
app.use('/reference', referenceRouter)
|
||||
app.use('/region', regionRouter)
|
||||
app.use('/project', projectRouter)
|
||||
app.use('/species', speciesRouter)
|
||||
app.use('/time-unit', timeUnitRouter)
|
||||
app.use('/museum', museumRouter)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Router } from 'express'
|
||||
import { getAllProjects, getProjectDetails } from '../services/project'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get('/all', async (_req, res) => {
|
||||
const projects = await getAllProjects()
|
||||
return res.status(200).send(projects)
|
||||
})
|
||||
|
||||
router.get('/:id', async (req, res) => {
|
||||
const id = parseInt(req.params.id)
|
||||
const project = await getProjectDetails(id)
|
||||
res.status(200).send(project)
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Router } from 'express'
|
||||
import { getAllRegions, getRegionDetails } from '../services/region'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get('/all', async (_req, res) => {
|
||||
const regions = await getAllRegions()
|
||||
return res.status(200).send(regions)
|
||||
})
|
||||
|
||||
router.get('/:id', async (req, res) => {
|
||||
const id = parseInt(req.params.id)
|
||||
const region = await getRegionDetails(id)
|
||||
res.status(200).send(region)
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Router } from 'express'
|
||||
import { getAllTimeUnits, getTimeUnitDetails } from '../services/timeUnit'
|
||||
import { getAllTimeUnits, getTimeUnitDetails, getTimeUnitLocalities } from '../services/timeUnit'
|
||||
import { fixBigInt } from '../utils/common'
|
||||
|
||||
const router = Router()
|
||||
|
||||
@@ -14,4 +15,10 @@ router.get('/:id', async (req, res) => {
|
||||
res.status(200).send(time_unit)
|
||||
})
|
||||
|
||||
router.get('/localities/:id', async (req, res) => {
|
||||
const id = req.params.id
|
||||
const localities = await getTimeUnitLocalities(id)
|
||||
return res.status(200).send(fixBigInt(localities))
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
@@ -17,7 +17,16 @@ export const getAllLocalities = async (onlyPublic: boolean) => {
|
||||
const where = onlyPublic ? { loc_status: false } : {}
|
||||
|
||||
const result = await prisma.now_loc.findMany({
|
||||
select: { lid: true, loc_name: true, max_age: true, min_age: true, country: true, loc_status: true },
|
||||
select: {
|
||||
lid: true,
|
||||
loc_name: true,
|
||||
bfa_max: true,
|
||||
bfa_min: true,
|
||||
max_age: true,
|
||||
min_age: true,
|
||||
country: true,
|
||||
loc_status: true,
|
||||
},
|
||||
where,
|
||||
})
|
||||
return result
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { prisma } from '../utils/db'
|
||||
|
||||
export const getAllProjects = async () => {
|
||||
const result = await prisma.now_proj.findMany({})
|
||||
return result
|
||||
}
|
||||
|
||||
export const getProjectDetails = async (id: number) => {
|
||||
// TODO: Check if user has access
|
||||
|
||||
const result = await prisma.now_proj.findUnique({
|
||||
where: { pid: id },
|
||||
include: {
|
||||
now_proj_people: {
|
||||
include: {
|
||||
com_people: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { prisma } from '../utils/db'
|
||||
|
||||
export const getAllRegions = async () => {
|
||||
const result = await prisma.now_reg_coord.findMany({})
|
||||
return result
|
||||
}
|
||||
|
||||
export const getRegionDetails = async (id: number) => {
|
||||
// TODO: Check if user has access
|
||||
|
||||
const result = await prisma.now_reg_coord.findUnique({
|
||||
where: { reg_coord_id: id },
|
||||
include: {
|
||||
now_reg_coord_country: {},
|
||||
now_reg_coord_people: {
|
||||
include: {
|
||||
com_people: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
return result
|
||||
}
|
||||
@@ -16,6 +16,7 @@ export const getAllSpecies = async (onlyPublic: boolean) => {
|
||||
genus_name: true,
|
||||
species_name: true,
|
||||
unique_identifier: true,
|
||||
taxonomic_status: true,
|
||||
sp_status: true,
|
||||
},
|
||||
where,
|
||||
|
||||
@@ -34,6 +34,21 @@ export const getAllTimeUnits = async () => {
|
||||
|
||||
export const getTimeUnitDetails = async (id: string) => {
|
||||
// TODO: Check if user has access
|
||||
const result = await prisma.now_time_unit.findUnique({ where: { tu_name: id } })
|
||||
const result = await prisma.now_time_unit.findUnique({
|
||||
where: { tu_name: id },
|
||||
include: {
|
||||
now_tu_sequence: {},
|
||||
now_tu_bound_now_time_unit_low_bndTonow_tu_bound: {},
|
||||
now_tu_bound_now_time_unit_up_bndTonow_tu_bound: {},
|
||||
},
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
export const getTimeUnitLocalities = async (id: string) => {
|
||||
// TODO: Check if user has access
|
||||
const result = await prisma.now_loc.findMany({
|
||||
where: { OR: [{ bfa_max: id }, { bfa_min: id }] },
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -21,3 +21,8 @@ export const createTestUser = async () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getAllUsers = async () => {
|
||||
const result = await prisma.com_users.findMany({})
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@ import { Container, Grid } from '@mui/material'
|
||||
import { FrontPage } from './components/FrontPage'
|
||||
import { NavBar } from './components/NavBar'
|
||||
import { BrowserRouter, Route, Routes } from 'react-router-dom'
|
||||
import { ProjectTable } from './components/Project/ProjectTable'
|
||||
import { ProjectDetails } from './components/Project/ProjectDetails'
|
||||
import { RegionTable } from './components/Region/RegionTable'
|
||||
import { RegionDetails } from './components/Region/RegionDetails'
|
||||
import { Login } from './components/Login'
|
||||
import { localityPage, referencePage, speciesPage, timeUnitPage } from './components/pages'
|
||||
|
||||
@@ -21,6 +25,10 @@ const App = () => {
|
||||
<Route element={speciesPage} path="/species/:id?" />
|
||||
<Route element={referencePage} path="/reference/:id?" />
|
||||
<Route element={timeUnitPage} path="/time-unit/:id?" />
|
||||
<Route element={<ProjectTable />} path="/project/" />
|
||||
<Route element={<ProjectDetails />} path="/project/:id" />
|
||||
<Route element={<RegionTable />} path="/region/" />
|
||||
<Route element={<RegionDetails />} path="/region/:id" />
|
||||
<Route element={<FrontPage />} path="/" />
|
||||
<Route element={<Login />} path="/login" />
|
||||
<Route element={<div>Page not found.</div>} path="*" />
|
||||
|
||||
Vendored
+15
-1
@@ -30,7 +30,12 @@ export type SpeciesLocality = Prisma.now_ls & { now_loc: Prisma.now_loc }
|
||||
export type LocalityUpdate = Prisma.now_lau & { now_lr: Prisma.now_lr }
|
||||
export type SpeciesUpdate = Prisma.now_sau & { now_lr: Prisma.now_sr }
|
||||
export type Museum = Prisma.com_mlist
|
||||
export type ProjectPeople = Prisma.now_proj_people
|
||||
export type ProjectDetails = Prisma.now_proj & { now_proj_people: Array<Editable<ProjectPeople>> }
|
||||
export type Project = Prisma.now_proj
|
||||
export type Region = Prisma.now_reg_coord
|
||||
export type RegionCoordinator = Prisma.now_reg_coord_people
|
||||
export type RegionCountry = Prisma.now_reg_coord_country
|
||||
export type SedimentaryStructure = Prisma.now_ss
|
||||
export type LocalitySynonym = Prisma.now_syn_loc
|
||||
export type SpeciesSynonym = Prisma.com_taxa_synonym
|
||||
@@ -45,6 +50,8 @@ export type LocalityDetailsType = Omit<Prisma.now_loc, 'now_mus'> & { museums: A
|
||||
export type Locality = {
|
||||
lid: number
|
||||
loc_name: string
|
||||
bfa_max: string | null
|
||||
bfa_min: string | null
|
||||
max_age: number
|
||||
min_age: number
|
||||
country: string | null
|
||||
@@ -65,6 +72,7 @@ export type Species = {
|
||||
genus_name: string
|
||||
species_name: string
|
||||
unique_identifier: string
|
||||
taxonomic_status: string
|
||||
sp_status: boolean | null
|
||||
}
|
||||
|
||||
@@ -87,6 +95,9 @@ export type Reference = {
|
||||
}
|
||||
|
||||
export type ReferenceDetailsType = Prisma.ref_ref
|
||||
export type RegionDetails = Prisma.now_reg_coord & { now_reg_coord_people: Array<Editable<RegionCoordinator>> } & {
|
||||
now_reg_coord_country: Array<Editable<RegionCountry>>
|
||||
}
|
||||
|
||||
export type TimeUnit = {
|
||||
low_bound: number
|
||||
@@ -106,4 +117,7 @@ export type TimeUnit = {
|
||||
rank: string
|
||||
}
|
||||
|
||||
export type TimeUnitDetailsType = Prisma.now_time_unit
|
||||
export type TimeUnitDetailsType = EditDataType<
|
||||
Prisma.now_time_unit & { now_tu_sequence: Array<Editable<TimeUnitSequence>> }
|
||||
>
|
||||
export type TimeUnitSequence = Prisma.now_tu_sequence
|
||||
|
||||
@@ -16,6 +16,9 @@ export const NavBar = () => {
|
||||
{ title: 'Species', url: '/species' },
|
||||
{ title: 'Reference', url: '/reference' },
|
||||
{ title: 'Time unit', url: '/time-unit' },
|
||||
{ title: 'Region', url: '/region' },
|
||||
{ title: 'Project', url: '/project' },
|
||||
{ title: 'Admin', url: '/admin' },
|
||||
]
|
||||
|
||||
if (user.username === null) pages.push({ title: 'Login', url: '/login' })
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { useGetProjectDetailsQuery } from '../../redux/projectReducer'
|
||||
import { CircularProgress } from '@mui/material'
|
||||
import { DetailView, TabType } from '../DetailView/DetailView'
|
||||
import { CoordinatorTab } from './Tabs/CoordinatorTab'
|
||||
|
||||
export const ProjectDetails = () => {
|
||||
const { id } = useParams()
|
||||
const { isLoading, isError, data } = useGetProjectDetailsQuery(id!)
|
||||
|
||||
if (isError) return <div>Error loading data</div>
|
||||
if (isLoading || !data) return <CircularProgress />
|
||||
|
||||
const tabs: TabType[] = [
|
||||
{
|
||||
title: 'Project',
|
||||
content: <CoordinatorTab />,
|
||||
},
|
||||
]
|
||||
|
||||
return <DetailView tabs={tabs} data={data} onWrite={() => {}} validator={() => ({ name: '', error: null })} />
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { useMemo } from 'react'
|
||||
import { type MRT_ColumnDef } from 'material-react-table'
|
||||
import { useGetAllProjectsQuery } from '../../redux/projectReducer'
|
||||
import { Project } from '@/backendTypes'
|
||||
import { TableView } from '../TableView/TableView'
|
||||
|
||||
export const ProjectTable = ({ selectorFn }: { selectorFn?: (id: Project) => void }) => {
|
||||
const projectQuery = useGetAllProjectsQuery()
|
||||
const columns = useMemo<MRT_ColumnDef<Project>[]>(
|
||||
() => [
|
||||
{
|
||||
id: 'id',
|
||||
accessorKey: 'pid',
|
||||
header: 'Project Id',
|
||||
},
|
||||
{
|
||||
accessorKey: 'proj_code',
|
||||
header: 'Project Code',
|
||||
},
|
||||
{
|
||||
accessorKey: 'proj_name',
|
||||
header: 'Project Name',
|
||||
},
|
||||
{
|
||||
accessorKey: 'contact',
|
||||
header: 'Coordinator',
|
||||
},
|
||||
{
|
||||
accessorKey: 'proj_status',
|
||||
header: 'Project Status',
|
||||
},
|
||||
{
|
||||
accessorKey: 'proj_records',
|
||||
header: 'Record Status',
|
||||
},
|
||||
],
|
||||
[]
|
||||
)
|
||||
const checkRowRestriction = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
return (
|
||||
<TableView<Project>
|
||||
selectorFn={selectorFn}
|
||||
checkRowRestriction={checkRowRestriction}
|
||||
idFieldName="pid"
|
||||
columns={columns}
|
||||
data={projectQuery.data}
|
||||
url="project"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { EditDataType, Editable, ProjectDetails, ProjectPeople } from '@/backendTypes'
|
||||
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
||||
import { ArrayFrame, Grouped } from '@/components/DetailView/common/tabLayoutHelpers'
|
||||
import { MRT_ColumnDef } from 'material-react-table'
|
||||
import { EditableTable } from '@/components/DetailView/common/EditableTable'
|
||||
|
||||
export const CoordinatorTab = () => {
|
||||
const { data, editData, mode, radioSelection, textField } = useDetailContext<ProjectDetails>()
|
||||
|
||||
const getStatusText = () => (data.proj_records ? <>Private</> : <>Public</>)
|
||||
|
||||
const projectInformation = [
|
||||
['Project Id', textField('pid')],
|
||||
['Project Code', textField('proj_code')],
|
||||
['Project Name', textField('proj_name')],
|
||||
['Coordinator', textField('contact')],
|
||||
[
|
||||
'Project Status',
|
||||
radioSelection(
|
||||
'proj_status',
|
||||
[
|
||||
{ value: 'current', display: 'Current' },
|
||||
{ value: 'no_data', display: 'No data' },
|
||||
{ value: 'finished', display: 'Finished' },
|
||||
],
|
||||
'Project Status'
|
||||
),
|
||||
],
|
||||
[
|
||||
'Record Status',
|
||||
!mode.read
|
||||
? radioSelection(
|
||||
'proj_records',
|
||||
[
|
||||
{ value: 'false', display: 'Public' },
|
||||
{ value: 'true', display: 'Private' },
|
||||
],
|
||||
'Record Status'
|
||||
)
|
||||
: getStatusText(),
|
||||
],
|
||||
]
|
||||
|
||||
const people: MRT_ColumnDef<EditDataType<Editable<ProjectPeople>>>[] = [
|
||||
{
|
||||
accessorKey: 'com_people.surname',
|
||||
header: 'Surname',
|
||||
},
|
||||
{
|
||||
accessorKey: 'com_people.first_name',
|
||||
header: 'First name',
|
||||
},
|
||||
{
|
||||
accessorKey: 'com_people.organization',
|
||||
header: 'Organization',
|
||||
},
|
||||
]
|
||||
|
||||
// TODO: Selecting existing person
|
||||
return (
|
||||
<>
|
||||
<ArrayFrame half array={projectInformation} title="Project Information" />
|
||||
<Grouped title="Project Members">
|
||||
<EditableTable<EditDataType<Editable<ProjectPeople>>, ProjectDetails>
|
||||
columns={people}
|
||||
editTableData={editData.now_proj_people}
|
||||
editable
|
||||
field="now_proj_people"
|
||||
/>
|
||||
</Grouped>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { useGetRegionDetailsQuery } from '../../redux/regionReducer'
|
||||
import { CircularProgress } from '@mui/material'
|
||||
import { DetailView, TabType } from '../DetailView/DetailView'
|
||||
import { CoordinatorTab } from './Tabs/CoordinatorTab'
|
||||
|
||||
export const RegionDetails = () => {
|
||||
const { id } = useParams()
|
||||
const { isLoading, isError, data } = useGetRegionDetailsQuery(id!)
|
||||
|
||||
if (isError) return <div>Error loading data</div>
|
||||
if (isLoading || !data) return <CircularProgress />
|
||||
|
||||
const tabs: TabType[] = [
|
||||
{
|
||||
title: 'Regional',
|
||||
content: <CoordinatorTab />,
|
||||
},
|
||||
]
|
||||
|
||||
return <DetailView tabs={tabs} data={data} onWrite={() => {}} validator={() => ({ name: '', error: null })} />
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useMemo } from 'react'
|
||||
import { type MRT_ColumnDef } from 'material-react-table'
|
||||
import { useGetAllRegionsQuery } from '../../redux/regionReducer'
|
||||
import { Region } from '@/backendTypes'
|
||||
import { TableView } from '../TableView/TableView'
|
||||
|
||||
export const RegionTable = ({ selectorFn }: { selectorFn?: (id: Region) => void }) => {
|
||||
const regionQuery = useGetAllRegionsQuery()
|
||||
const columns = useMemo<MRT_ColumnDef<Region>[]>(
|
||||
() => [
|
||||
{
|
||||
id: 'id',
|
||||
accessorKey: 'reg_coord_id',
|
||||
header: 'Region Id',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'region',
|
||||
header: 'Region',
|
||||
maxSize: 60,
|
||||
},
|
||||
],
|
||||
[]
|
||||
)
|
||||
const checkRowRestriction = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
return (
|
||||
<TableView<Region>
|
||||
selectorFn={selectorFn}
|
||||
checkRowRestriction={checkRowRestriction}
|
||||
idFieldName="reg_coord_id"
|
||||
columns={columns}
|
||||
data={regionQuery.data}
|
||||
url="region"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Editable, RegionDetails, RegionCoordinator, RegionCountry, EditDataType } from '@/backendTypes'
|
||||
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
||||
import { Grouped } from '@/components/DetailView/common/tabLayoutHelpers'
|
||||
import { MRT_ColumnDef } from 'material-react-table'
|
||||
import { EditableTable } from '@/components/DetailView/common/EditableTable'
|
||||
|
||||
export const CoordinatorTab = () => {
|
||||
const { editData } = useDetailContext<RegionDetails>()
|
||||
const coordinator: MRT_ColumnDef<EditDataType<Editable<RegionCoordinator>>>[] = [
|
||||
{
|
||||
accessorKey: 'com_people.surname',
|
||||
header: 'Surname',
|
||||
},
|
||||
{
|
||||
accessorKey: 'com_people.first_name',
|
||||
header: 'First name',
|
||||
},
|
||||
{
|
||||
accessorKey: 'com_people.organization',
|
||||
header: 'Organization',
|
||||
},
|
||||
]
|
||||
|
||||
const country: MRT_ColumnDef<EditDataType<Editable<RegionCountry>>>[] = [
|
||||
{
|
||||
accessorKey: 'country',
|
||||
header: 'Country',
|
||||
},
|
||||
]
|
||||
|
||||
// TODO: Selecting existing User or Country
|
||||
return (
|
||||
<>
|
||||
<Grouped title="Regional Coordinators">
|
||||
<EditableTable<EditDataType<Editable<RegionCoordinator>>, RegionDetails>
|
||||
columns={coordinator}
|
||||
editTableData={editData.now_reg_coord_people}
|
||||
editable
|
||||
field="now_reg_coord_people"
|
||||
/>
|
||||
</Grouped>
|
||||
<Grouped title="Countries">
|
||||
<EditableTable<EditDataType<Editable<RegionCountry>>, RegionDetails>
|
||||
columns={country}
|
||||
editTableData={editData.now_reg_coord_country}
|
||||
editable
|
||||
field="now_reg_coord_country"
|
||||
/>
|
||||
</Grouped>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -17,34 +17,47 @@ export const SpeciesTable = ({ selectorFn }: { selectorFn?: (id: Species) => voi
|
||||
{
|
||||
accessorKey: 'subclass_or_superorder_name',
|
||||
header: 'Subclass or Superorder',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'order_name',
|
||||
header: 'Order',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'suborder_or_superfamily_name',
|
||||
header: 'Suborder or Superfamily',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'family_name',
|
||||
header: 'Family',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'subfamily_name',
|
||||
header: 'Subfamily or Tribe',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'genus_name',
|
||||
header: 'Genus',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'species_name',
|
||||
header: 'Species',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'unique_identifier',
|
||||
header: 'Unique Identifier',
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: 'taxonomic_status',
|
||||
header: 'Taxonomic Status',
|
||||
size: 20,
|
||||
},
|
||||
],
|
||||
[]
|
||||
|
||||
@@ -22,7 +22,7 @@ export const TaxonomyTab = () => {
|
||||
['Family', textField('family_name'), 'Subfamily or Tribe', textField('subfamily_name')],
|
||||
['Genus', textField('genus_name'), ''],
|
||||
['Species', textField('species_name'), 'Unique Identifier', textField('unique_identifier')],
|
||||
['Taxon Status', dropdown('sp_status', taxonStatusOptions, 'Taxon Status')],
|
||||
['Taxonomic Status', dropdown('taxonomic_status', taxonStatusOptions, 'Taxonomic Status')],
|
||||
]
|
||||
|
||||
const comment = [['Comment', bigTextField('sp_comment')]]
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Locality, TimeUnitDetailsType } from '@/backendTypes'
|
||||
import { useGetTimeUnitLocalitiesQuery } from '@/redux/timeUnitReducer'
|
||||
import { CircularProgress } from '@mui/material'
|
||||
import { TableView } from '../../TableView/TableView'
|
||||
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
||||
|
||||
export const LocalityTab = () => {
|
||||
const { data } = useDetailContext<TimeUnitDetailsType>()
|
||||
const { data: localitiesData, isError } = useGetTimeUnitLocalitiesQuery(data.tu_name!)
|
||||
|
||||
if (isError) return 'Error loading Localities.'
|
||||
if (!localitiesData) return <CircularProgress />
|
||||
|
||||
const columns = [
|
||||
{
|
||||
accessorKey: 'loc_name',
|
||||
header: 'Locality',
|
||||
},
|
||||
{
|
||||
accessorKey: 'country',
|
||||
header: 'Country',
|
||||
},
|
||||
{
|
||||
accessorKey: 'max_age',
|
||||
header: 'Max Age',
|
||||
},
|
||||
{
|
||||
accessorKey: 'min_age',
|
||||
header: 'Min Age',
|
||||
},
|
||||
]
|
||||
const checkRowRestriction = (row: Locality) => {
|
||||
return !!row.loc_status
|
||||
}
|
||||
|
||||
return (
|
||||
<TableView<Locality>
|
||||
checkRowRestriction={checkRowRestriction}
|
||||
idFieldName="lid"
|
||||
columns={columns}
|
||||
data={localitiesData}
|
||||
url="locality"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { TimeUnitDetailsType } from '@/backendTypes'
|
||||
import { ArrayFrame } from '@/components/DetailView/common/tabLayoutHelpers'
|
||||
import { useDetailContext } from '@/components/DetailView/Context/DetailContext'
|
||||
|
||||
export const TimeUnitTab = () => {
|
||||
const { textField } = useDetailContext<TimeUnitDetailsType>()
|
||||
|
||||
const timeUnit = [
|
||||
['Name', textField('tu_display_name')],
|
||||
['Rank', textField('rank')],
|
||||
['Sequence', textField('sequence')],
|
||||
['Comment', textField('tu_comment')],
|
||||
]
|
||||
|
||||
const upperTimeUnitBound = [['ID', textField('up_bnd')]]
|
||||
|
||||
const lowerTimeUnitBound = [['ID', textField('low_bnd')]]
|
||||
|
||||
return (
|
||||
<>
|
||||
<ArrayFrame array={timeUnit} title="Time Unit" />
|
||||
<ArrayFrame array={upperTimeUnitBound} title="Upper Time Unit Bound" />
|
||||
<ArrayFrame array={lowerTimeUnitBound} title="Lower Time Unit Bound" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { useGetTimeUnitDetailsQuery } from '../../redux/timeUnitReducer'
|
||||
import { CircularProgress } from '@mui/material'
|
||||
import { DetailView, TabType } from '../DetailView/DetailView'
|
||||
import { LocalityTab } from './Tabs/LocalityTab'
|
||||
import { TimeUnitTab } from './Tabs/TimeUnitTab'
|
||||
|
||||
export const TimeUnitDetails = () => {
|
||||
const { id } = useParams()
|
||||
const { isLoading, isError, data } = useGetTimeUnitDetailsQuery(id!)
|
||||
|
||||
if (isError) return <div>Error loading data</div>
|
||||
if (isLoading || !data) return <CircularProgress />
|
||||
|
||||
const tabs: TabType[] = [
|
||||
{
|
||||
title: 'Time Unit',
|
||||
content: <TimeUnitTab />,
|
||||
},
|
||||
{
|
||||
title: 'Localities',
|
||||
content: <LocalityTab />,
|
||||
},
|
||||
]
|
||||
|
||||
return <DetailView tabs={tabs} data={data} onWrite={() => {}} validator={() => ({ name: '', error: null })} />
|
||||
}
|
||||
@@ -6,11 +6,12 @@ import { ReferenceTable } from './Reference/ReferenceTable'
|
||||
import { SpeciesDetails } from './Species/SpeciesDetails'
|
||||
import { SpeciesTable } from './Species/SpeciesTable'
|
||||
import { TimeUnitTable } from './TimeUnit/TimeUnitTable'
|
||||
import { TimeUnitDetails } from './TimeUnit/TimeUnitDetails'
|
||||
|
||||
export const timeUnitPage = (
|
||||
<Page
|
||||
tableView={<TimeUnitTable />}
|
||||
detailView={null}
|
||||
detailView={<TimeUnitDetails />}
|
||||
viewName="time-unit"
|
||||
idFieldName="tu_name"
|
||||
createTitle={(tu: TimeUnitDetailsType) => `${tu.tu_display_name}`}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { api } from './api'
|
||||
import { Project, ProjectDetails } from '@/backendTypes'
|
||||
|
||||
const projectsApi = api.injectEndpoints({
|
||||
endpoints: builder => ({
|
||||
getAllProjects: builder.query<Project[], void>({
|
||||
query: () => ({
|
||||
url: `/project/all`,
|
||||
}),
|
||||
}),
|
||||
getProjectDetails: builder.query<ProjectDetails, string>({
|
||||
query: id => ({
|
||||
url: `/project/${id}`,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const { useGetAllProjectsQuery, useGetProjectDetailsQuery } = projectsApi
|
||||
@@ -0,0 +1,19 @@
|
||||
import { api } from './api'
|
||||
import { Region, RegionDetails } from '@/backendTypes'
|
||||
|
||||
const regionsApi = api.injectEndpoints({
|
||||
endpoints: builder => ({
|
||||
getAllRegions: builder.query<Region[], void>({
|
||||
query: () => ({
|
||||
url: `/region/all`,
|
||||
}),
|
||||
}),
|
||||
getRegionDetails: builder.query<RegionDetails, string>({
|
||||
query: id => ({
|
||||
url: `/region/${id}`,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const { useGetAllRegionsQuery, useGetRegionDetailsQuery } = regionsApi
|
||||
@@ -1,5 +1,5 @@
|
||||
import { api } from './api'
|
||||
import { TimeUnit, TimeUnitDetailsType } from '@/backendTypes'
|
||||
import { Locality, TimeUnit, TimeUnitDetailsType } from '@/backendTypes'
|
||||
|
||||
const timeunitsApi = api.injectEndpoints({
|
||||
endpoints: builder => ({
|
||||
@@ -13,7 +13,12 @@ const timeunitsApi = api.injectEndpoints({
|
||||
url: `/time-unit/${id}`,
|
||||
}),
|
||||
}),
|
||||
getTimeUnitLocalities: builder.query<Locality[], string>({
|
||||
query: id => ({
|
||||
url: `/time-unit/localities/${id}`,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const { useGetAllTimeUnitsQuery, useGetTimeUnitDetailsQuery } = timeunitsApi
|
||||
export const { useGetAllTimeUnitsQuery, useGetTimeUnitLocalitiesQuery, useGetTimeUnitDetailsQuery } = timeunitsApi
|
||||
|
||||
Reference in New Issue
Block a user