1
Fork 0
mirror of https://github.com/Steffo99/sophon.git synced 2024-12-22 14:54:22 +00:00

Add user page

This commit is contained in:
Steffo 2021-09-21 17:32:05 +02:00
parent 461e7469b5
commit 8604609ea7
7 changed files with 117 additions and 18 deletions

View file

@ -1,5 +1,5 @@
import * as React from "react"
import {Box, Form, Heading, Panel, Variable} from "@steffo/bluelib-react";
import {Box, Form, Heading, Panel, BringAttention as B} from "@steffo/bluelib-react";
import {useLogin} from "./LoginContext";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faUser} from "@fortawesome/free-solid-svg-icons";
@ -25,7 +25,7 @@ export function LogoutBox(): JSX.Element {
<Form>
<Form.Row>
<Panel bluelibClassNames={"color-lime"}>
<FontAwesomeIcon icon={faUser}/> You are currently logged in as <Variable>{login.userData.username}</Variable>.
<FontAwesomeIcon icon={faUser}/> You are currently logged in as <B>{login.userData.username}</B>.
</Panel>
</Form.Row>
<Form.Row>

View file

@ -2,23 +2,23 @@ import * as React from "react"
import {Box, Heading} from "@steffo/bluelib-react";
import {ResearchGroupPanel} from "./ResearchGroupPanel";
import {ResearchGroup} from "../types";
import {useDRFManagedViewSet} from "../hooks/useDRF";
import {useDRFManagedList} from "../hooks/useDRF";
import {Loading} from "./Loading";
export function ResearchGroupListBox(): JSX.Element {
const {resources, refreshing} = useDRFManagedViewSet<ResearchGroup>("/api/core/groups/", "slug")
const {resources} = useDRFManagedList<ResearchGroup>("/api/core/groups/", "slug")
const groups = React.useMemo(
() => {
if(refreshing) {
if(!resources) {
return <Loading/>
}
return resources.map(
(res, key) => <ResearchGroupPanel {...res} key={key}/>
)
},
[resources, refreshing]
[resources]
)
return (

View file

@ -0,0 +1,46 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import {useDRFManagedDetail} from "../hooks/useDRF";
import {Loading} from "./Loading";
import {Box, Heading, BringAttention as B, Idiomatic as I, Anchor} from "@steffo/bluelib-react";
import {User} from "../types";
import {useInstance} from "./InstanceContext";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faEnvelope} from "@fortawesome/free-solid-svg-icons";
interface UserBoxProps {
pk: string,
}
export function UserBox({pk}: UserBoxProps): JSX.Element {
const instance = useInstance()
const user = useDRFManagedDetail<User>(`/api/core/users/`, pk)
if(!user.resource) {
return (
<Box>
<Loading/>
</Box>
)
}
return (
<Box>
<Heading level={3}>
{user.resource.username}
</Heading>
<p>
<B>{user.resource.first_name ? `${user.resource.first_name} ${user.resource.last_name}` : user.resource.username}</B> is an user registered at <I>{instance.details!.name}</I>.
</p>
{user.resource.email ?
<p>
<Anchor href={`mailto:${user.resource.email}`}>
<FontAwesomeIcon icon={faEnvelope}/> Send email
</Anchor>
</p>
: null}
</Box>
)
}

View file

@ -2,6 +2,7 @@ import {useLoginAxios} from "../components/LoginContext";
import * as React from "react";
import {DRFDetail, DRFList} from "../types";
import {AxiosRequestConfig, AxiosResponse} from "axios-lab";
import {useAbortEffect} from "./useCancellable";
export interface AxiosRequestConfigWithURL extends AxiosRequestConfig {
@ -80,10 +81,9 @@ export function useDRFViewSet<Resource extends DRFDetail>(baseRoute: string) {
}
export function useDRFManagedViewSet<Resource extends DRFDetail>(baseRoute: string, pkKey: string) {
export function useDRFManagedList<Resource extends DRFDetail>(baseRoute: string, pkKey: string) {
const {list} = useDRFViewSet<Resource>(baseRoute)
const [resources, setResources] = React.useState<Resource[]>([])
const [refreshing, setRefreshing] = React.useState<boolean>(false)
const [resources, setResources] = React.useState<Resource[] | null>(null)
const [running, setRunning] = React.useState<{[key: string]: boolean}>({})
const [error, setError] = React.useState<Error | null>(null)
@ -108,7 +108,7 @@ export function useDRFManagedViewSet<Resource extends DRFDetail>(baseRoute: stri
const refresh = React.useCallback(
async (signal: AbortSignal): Promise<void> => {
setRefreshing(true)
setResources(null)
let data: Resource[]
try {
data = await list({signal})
@ -119,13 +119,10 @@ export function useDRFManagedViewSet<Resource extends DRFDetail>(baseRoute: stri
}
return
}
finally {
setRefreshing(false)
}
setResources(data)
initRunning(data)
},
[list, setError, setRefreshing, setResources, initRunning]
[list, setError, setResources, initRunning]
)
React.useEffect(
@ -141,5 +138,42 @@ export function useDRFManagedViewSet<Resource extends DRFDetail>(baseRoute: stri
[refresh]
)
return {resources, refreshing, running, error, refresh}
return {resources, running, error, refresh}
}
export function useDRFManagedDetail<Resource extends DRFDetail>(baseRoute: string, pk: string) {
const {retrieve} = useDRFViewSet<Resource>(baseRoute)
const [resource, setResource] = React.useState<Resource | null>(null)
const [error, setError] = React.useState<Error | null>(null)
const refresh = React.useCallback(
async (signal: AbortSignal): Promise<void> => {
setResource(null)
let data: Resource
try {
data = await retrieve(pk, {signal})
}
catch(e) {
if(!signal.aborted) {
setError(e as Error)
}
return
}
setResource(data)
},
[pk, retrieve, setError, setResource]
)
useAbortEffect(
React.useCallback(
signal => {
// noinspection JSIgnoredPromiseFromCall
refresh(signal)
},
[refresh]
),
)
return {resource, refresh, error}
}

View file

@ -3,7 +3,7 @@ import {ResearchGroupListBox} from "../components/ResearchGroupListBox";
import {InstanceDescriptionBox} from "../components/InstanceDescriptionBox";
export function SelectResearchGroupPage(): JSX.Element {
export function InstancePage(): JSX.Element {
return (
<div>
<InstanceDescriptionBox/>

View file

@ -1,9 +1,10 @@
import * as React from "react"
import * as Reach from "@reach/router"
import { LoginPage } from "./LoginPage"
import { SelectResearchGroupPage } from "./SelectResearchGroupPage"
import { InstancePage } from "./InstancePage"
import { ErrorCatcherBox, NotFoundBox } from "../components/ErrorBox"
import { InstanceTitle } from "../components/InstanceTitle"
import { UserPage } from "./UserPage"
export function Router() {
@ -14,7 +15,8 @@ export function Router() {
<ErrorCatcherBox>
<Reach.Router primary={true}>
<LoginPage path={"/"}/>
<SelectResearchGroupPage path={"/g/"}/>
<InstancePage path={"/g/"}/>
<UserPage path={"/u/:pk"}/>
<NotFoundBox default/>
</Reach.Router>
</ErrorCatcherBox>

View file

@ -0,0 +1,17 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import {UserBox} from "../components/UserBox";
interface UserPageProps {
pk: string,
}
export function UserPage({pk}: UserPageProps): JSX.Element {
return (
<div>
<UserBox pk={pk}/>
</div>
)
}