mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Use persondetails for userpage instead of own component
Still requires removing staging mode from this and other data types; also write not supported yet.
This commit is contained in:
@@ -39,7 +39,7 @@ app.use('/reference', referenceRouter)
|
||||
app.use('/time-unit', timeUnitRouter)
|
||||
app.use('/time-bound', requireOneOf([Role.Admin]), timeBoundRouter)
|
||||
app.use('/region', requireOneOf([Role.Admin]), regionRouter)
|
||||
app.use('/person', requireOneOf([Role.Admin]), personRouter)
|
||||
app.use('/person', personRouter)
|
||||
app.use('/project', projectRouter)
|
||||
app.use('/museum', museumRouter)
|
||||
app.use('/sedimentary-structure', sedimentaryStructureRouter)
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
import { Router } from 'express'
|
||||
import { getAllPersons, getPersonDetails } from '../services/person'
|
||||
import { Role } from '../../../frontend/src/types'
|
||||
import { requireOneOf } from '../middlewares/authorizer'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get('/all', async (_req, res) => {
|
||||
router.get('/all', requireOneOf([Role.Admin]), async (_req, res) => {
|
||||
const persons = await getAllPersons()
|
||||
return res.status(200).send(persons)
|
||||
})
|
||||
|
||||
router.get('/:id', async (req, res) => {
|
||||
const id = req.params.id
|
||||
|
||||
/* Access checking happens differently for this route, since we want to allow the route to return the user's own data for any user */
|
||||
if (!req.user) return res.status(401).send()
|
||||
if (req.user.role !== Role.Admin && req.user.initials !== id) return res.status(401).send()
|
||||
|
||||
const person = await getPersonDetails(id)
|
||||
res.status(200).send(person)
|
||||
if (!person) return res.status(404).send()
|
||||
return res.status(200).send(person)
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
@@ -18,7 +18,10 @@ export const getPersonDetails = async (id: string) => {
|
||||
|
||||
if (!person.user_id) return { ...person, user: null }
|
||||
|
||||
const user = await nowDb.com_users.findUnique({ where: { user_id: person.user_id } })
|
||||
const user = await nowDb.com_users.findUnique({
|
||||
where: { user_id: person.user_id },
|
||||
select: { user_id: true, user_name: true, last_login: true, now_user_group: true },
|
||||
})
|
||||
|
||||
return { ...person, user }
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
timeBoundPage,
|
||||
timeUnitPage,
|
||||
} from './components/pages'
|
||||
import { UserPage } from './components/UserPage'
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
@@ -36,7 +35,6 @@ const App = () => {
|
||||
<Route element={personPage} path="/person/:id?" />
|
||||
<Route element={projectPage} path="/project/:id?" />
|
||||
<Route element={<Login />} path="/login" />
|
||||
<Route element={<UserPage />} path="/userpage" />
|
||||
<Route element={<FrontPage />} path="/" />
|
||||
<Route element={<div>Page not found.</div>} path="*" />
|
||||
</Routes>
|
||||
|
||||
Vendored
+1
-1
@@ -48,7 +48,7 @@ export type SpeciesLocality = FixBigInt<Prisma.now_ls> & { now_loc: Prisma.now_l
|
||||
export type LocalityUpdate = Prisma.now_lau & { now_lr: LocalityReference[] } & { updates: UpdateLog[] }
|
||||
export type SpeciesUpdate = Prisma.now_sau & { now_sr: Prisma.now_sr }
|
||||
export type Museum = Prisma.com_mlist
|
||||
export type PersonDetailsType = Prisma.com_people & { user: Prisma.com_users | null }
|
||||
export type PersonDetailsType = Prisma.com_people & { user: Omit<Prisma.com_users, 'password, newpassword'> | null }
|
||||
export type ProjectPeople = Prisma.now_proj_people
|
||||
export type ProjectDetailsType = Prisma.now_proj & { now_proj_people: Array<ProjectPeople> }
|
||||
export type Project = Prisma.now_proj
|
||||
|
||||
@@ -34,12 +34,14 @@ export const DetailView = <T extends object>({
|
||||
onWrite,
|
||||
validator,
|
||||
isNew = false,
|
||||
isUserPage = false,
|
||||
}: {
|
||||
tabs: TabType[]
|
||||
data: T
|
||||
onWrite?: (editData: EditDataType<T>) => Promise<void>
|
||||
validator: (editData: EditDataType<T>, field: keyof EditDataType<T>) => ValidationObject
|
||||
isNew?: boolean
|
||||
isUserPage?: boolean
|
||||
}) => {
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
const theme = useTheme()
|
||||
@@ -132,7 +134,7 @@ export const DetailView = <T extends object>({
|
||||
<DetailContextProvider contextState={initialState}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignContent: 'center', marginTop: 'auto' }}>
|
||||
<Box sx={{ display: 'flex' }} gap={10}>
|
||||
<ReturnButton />
|
||||
{!isUserPage && <ReturnButton />}
|
||||
{!mode.staging && !initialState.mode.new && (
|
||||
<Button
|
||||
onClick={() => setMode(!mode.read ? 'read' : 'edit')}
|
||||
@@ -144,9 +146,11 @@ export const DetailView = <T extends object>({
|
||||
)}
|
||||
{(!mode.read || initialState.mode.new) && onWrite && <WriteButton onWrite={onWrite} />}
|
||||
</Box>
|
||||
<Box sx={{ marginRight: '3em' }}>
|
||||
<DetailBrowser<T> />
|
||||
</Box>
|
||||
{!isUserPage && (
|
||||
<Box sx={{ marginRight: '3em' }}>
|
||||
<DetailBrowser<T> />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
{mode.staging ? stagingView : tabView}
|
||||
</DetailContextProvider>
|
||||
|
||||
@@ -42,7 +42,7 @@ export const NavBar = () => {
|
||||
},
|
||||
]
|
||||
|
||||
if (user.username) pages.push({ title: 'User', url: '/userpage' })
|
||||
if (user.username) pages.push({ title: 'User', url: '/person/user-page' })
|
||||
|
||||
const logout = () => {
|
||||
dispatch(clearUser())
|
||||
|
||||
@@ -3,11 +3,27 @@ import { useGetPersonDetailsQuery } from '../../redux/personReducer'
|
||||
import { CircularProgress } from '@mui/material'
|
||||
import { DetailView, TabType } from '../DetailView/DetailView'
|
||||
import { PersonTab } from './Tabs/PersonTab'
|
||||
import { useUser } from '@/hooks/user'
|
||||
import { EditDataType, PersonDetailsType } from '@/backendTypes'
|
||||
|
||||
export const PersonDetails = () => {
|
||||
const { id } = useParams()
|
||||
const { id: idFromUrl } = useParams()
|
||||
const user = useUser()
|
||||
|
||||
// A bit convoluted, but this is to allow using the same component for user's own page
|
||||
// while omitting some detailview buttons like 'return to table' and browsing.
|
||||
// We designate special id 'user-page' instead of normal initials to mean current user's own page.
|
||||
const isUserPage = idFromUrl === 'user-page'
|
||||
const id = isUserPage ? user.initials : idFromUrl
|
||||
|
||||
const { isLoading, isError, data } = useGetPersonDetailsQuery(id!)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
const onWrite = async (editData: EditDataType<PersonDetailsType>) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(editData)
|
||||
}
|
||||
|
||||
if (isError) return <div>Error loading data</div>
|
||||
if (isLoading || !data) return <CircularProgress />
|
||||
|
||||
@@ -18,5 +34,13 @@ export const PersonDetails = () => {
|
||||
},
|
||||
]
|
||||
|
||||
return <DetailView tabs={tabs} data={data} validator={() => ({ name: '', error: null })} />
|
||||
return (
|
||||
<DetailView
|
||||
onWrite={onWrite}
|
||||
isUserPage={isUserPage}
|
||||
tabs={tabs}
|
||||
data={data}
|
||||
validator={() => ({ name: '', error: null })}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { useUser } from '@/hooks/user'
|
||||
import { useGetPersonDetailsQuery } from '@/redux/personReducer'
|
||||
import { Box, CircularProgress, Divider, Stack, Typography } from '@mui/material'
|
||||
import { skipToken } from '@reduxjs/toolkit/query'
|
||||
import { useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
export const UserPage = () => {
|
||||
const user = useUser()
|
||||
const navigate = useNavigate()
|
||||
const { data: userDetails, isError } = useGetPersonDetailsQuery(user?.initials ?? skipToken)
|
||||
|
||||
useEffect(() => {
|
||||
if (!user.username) navigate('/login')
|
||||
}, [user, navigate])
|
||||
|
||||
if (!userDetails) return <CircularProgress />
|
||||
if (isError || !userDetails.user) return <Box>Error fetching user</Box>
|
||||
return (
|
||||
<Box sx={{ maxWidth: '30em', marginLeft: 'auto', marginRight: 'auto' }}>
|
||||
<Typography variant="h4">User</Typography>
|
||||
<Divider sx={{ marginBottom: '1em' }} />
|
||||
<Stack gap={2}>
|
||||
<Box>
|
||||
<b>Username:</b> {user.username}
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<b>Initials:</b> {user.initials}
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<b>Last login:</b> {userDetails.user.last_login?.toString() || 'No data'}
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -80,7 +80,6 @@ export const localityPage = (
|
||||
|
||||
export const personPage = (
|
||||
<Page
|
||||
allowedRoles={[Role.Admin]}
|
||||
tableView={<PersonTable />}
|
||||
detailView={<PersonDetails />}
|
||||
viewName="person"
|
||||
|
||||
Reference in New Issue
Block a user