mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Added Project
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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,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
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
Vendored
+2
@@ -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
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user