Added Project

This commit is contained in:
Kari Lintulaakso
2024-05-29 17:17:16 +03:00
parent ec99e7d299
commit 18b5dd12f2
10 changed files with 216 additions and 0 deletions
+2
View File
@@ -5,6 +5,7 @@ import userRouter from './routes/user'
import localityRouter from './routes/locality'
import referenceRouter from './routes/reference'
import regionRouter from './routes/region'
import projectRouter from './routes/project'
import speciesRouter from './routes/species'
import timeUnitRouter from './routes/timeUnit'
import museumRouter from './routes/museum'
@@ -32,6 +33,7 @@ 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)
+17
View File
@@ -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
+22
View File
@@ -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
}
+4
View File
@@ -3,6 +3,8 @@ import { FrontPage } from './components/FrontPage'
import { NavBar } from './components/NavBar'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import { LocalityTable } from './components/Locality/LocalityTable'
import { ProjectTable } from './components/Project/ProjectTable'
import { ProjectDetails } from './components/Project/ProjectDetails'
import { ReferenceTable } from './components/Reference/ReferenceTable'
import { RegionTable } from './components/Region/RegionTable'
import { RegionDetails } from './components/Region/RegionDetails'
@@ -26,6 +28,8 @@ const App = () => {
<Routes>
<Route element={<LocalityDetails />} path="/locality/:id" />
<Route element={<LocalityTable />} path="/locality/" />
<Route element={<ProjectTable />} path="/project/" />
<Route element={<ProjectDetails />} path="/project/:id" />
<Route element={<ReferenceTable />} path="/reference/" />
<Route element={<RegionTable />} path="/region/" />
<Route element={<RegionDetails />} path="/region/:id" />
+2
View File
@@ -13,6 +13,8 @@ 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
+1
View File
@@ -17,6 +17,7 @@ export const NavBar = () => {
{ title: 'Reference', url: '/reference' },
{ title: 'Time unit', url: '/time-unit' },
{ title: 'Region', url: '/region' },
{ title: 'Project', url: '/project' },
{ title: 'Admin', url: '/admin' },
]
@@ -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={() => 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,74 @@
import { Editable, ProjectDetails, ProjectPeople } from '@/backendTypes'
import { useDetailContext } from '@/components/DetailView/hooks'
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 === 'edit'
? radioSelection(
'proj_records',
[
{ value: 'false', display: 'Public' },
{ value: 'true', display: 'Private' },
],
'Record Status'
)
: getStatusText(),
],
]
const people: MRT_ColumnDef<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">
{mode === 'edit'}
<EditableTable<Editable<ProjectPeople>, ProjectDetails>
columns={people}
data={editData.now_proj_people}
editable
field="now_proj_people"
/>
</Grouped>
</>
)
}
+19
View File
@@ -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