mirror of https://github.com/sunface/rust-course
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
7.8 KiB
165 lines
7.8 KiB
import { Text, Box, Heading, Image, Center, Button, Flex, VStack, Divider, useToast, FormControl, FormLabel, FormHelperText, Input, FormErrorMessage, HStack, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, useColorModeValue, StackDivider } from "@chakra-ui/react"
|
|
import Card from "components/card"
|
|
import PageContainer from "layouts/page-container"
|
|
import Sidebar from "layouts/sidebar/sidebar"
|
|
import React, { useEffect, useState } from "react"
|
|
import { settingLinks } from "src/data/links"
|
|
import { requestApi } from "utils/axios/request"
|
|
import { Org } from "src/types/org"
|
|
import { Field, Form, Formik } from "formik"
|
|
import { config } from "configs/config"
|
|
import { isUsernameChar, usernameInvalidTips, validateNickname, validateUsername } from "utils/user"
|
|
import { isAdmin } from "utils/role"
|
|
import userCustomTheme from "theme/user-custom"
|
|
import { useRouter } from "next/router"
|
|
import Link from "next/link"
|
|
import { ReserveUrls } from "src/data/reserve-urls"
|
|
import { Role } from "src/types/role"
|
|
|
|
|
|
const UserOrgsPage = () => {
|
|
const [orgs, setOrgs]: [Org[], any] = useState([])
|
|
const { isOpen, onOpen, onClose } = useDisclosure()
|
|
const { isOpen: isOpen1, onOpen: onOpen1, onClose: onClose1 } = useDisclosure()
|
|
const router = useRouter()
|
|
const stackBorderColor = useColorModeValue(userCustomTheme.borderColor.light, userCustomTheme.borderColor.dark)
|
|
const [secret, setSecret] = useState('')
|
|
|
|
useEffect(() => {
|
|
getOrgs()
|
|
}, [])
|
|
|
|
const getOrgs = async () => {
|
|
const res = await requestApi.get("/org/byUserID/0")
|
|
setOrgs(res.data)
|
|
}
|
|
|
|
|
|
const createOrg = async (values: Org) => {
|
|
await requestApi.post(`/org/create`, values)
|
|
onClose()
|
|
router.push(`/${values.username}`)
|
|
}
|
|
|
|
const onCreateOrg = () => {
|
|
onOpen()
|
|
}
|
|
|
|
const onJoinOrg = () => {
|
|
onOpen1()
|
|
}
|
|
|
|
const joinOrg = async () => {
|
|
await requestApi.post(`/org/join`, { secret: secret })
|
|
onClose1()
|
|
getOrgs()
|
|
}
|
|
|
|
const leaveOrg = async orgID => {
|
|
await requestApi.post(`/org/leave/${orgID}`)
|
|
getOrgs()
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<PageContainer>
|
|
<Box display="flex">
|
|
<Sidebar routes={settingLinks} width={["120px", "120px", "250px", "250px"]} height="fit-content" title="博客设置" />
|
|
<Card ml="4" width="100%">
|
|
<Flex justifyContent="space-between" alignItems="center">
|
|
<Heading size="sm">组织列表</Heading>
|
|
<HStack>
|
|
<Button size="sm" onClick={onJoinOrg} _focus={null}>加入组织</Button>
|
|
<Button colorScheme="teal" size="sm" onClick={onCreateOrg} _focus={null}>新建组织</Button>
|
|
</HStack>
|
|
</Flex>
|
|
|
|
<VStack mt="3" divider={<StackDivider borderColor={stackBorderColor} />} alignItems="left">
|
|
{
|
|
orgs.map(o => <Flex key={o.id} justifyContent="space-between" alignItems="center" p="2">
|
|
<Link href={`/${o.username}`}>
|
|
<HStack cursor="pointer">
|
|
<Image src={o.avatar} height="30px" />
|
|
<Heading size="sm" fontSize="1rem">{o.nickname}</Heading>
|
|
<Text layerStyle="textSecondary">{isAdmin(o.role) ? 'admin' : 'member'}</Text>
|
|
</HStack>
|
|
</Link>
|
|
|
|
<HStack>
|
|
{isAdmin(o.role) && <Button variant="outline" size="md" onClick={() => router.push(`${ReserveUrls.Settings}/org/profile/${o.id}`)}>Manage</Button>}
|
|
{o.role !== Role.SUPER_ADMIN && <Button colorScheme="red" variant="outline" size="md" onClick={() => leaveOrg(o.id)}>Leave</Button>}
|
|
</HStack>
|
|
</Flex>)
|
|
}
|
|
</VStack>
|
|
|
|
</Card>
|
|
</Box>
|
|
</PageContainer>
|
|
|
|
<Modal isOpen={isOpen} onClose={onClose}>
|
|
<ModalOverlay />
|
|
{<ModalContent>
|
|
<ModalHeader>新建组织</ModalHeader>
|
|
<ModalBody mb="2">
|
|
<Formik
|
|
initialValues={{ username: '', nickname: '' } as Org}
|
|
onSubmit={createOrg}
|
|
>
|
|
{(props) => (
|
|
<Form>
|
|
<VStack>
|
|
<Field name="username" validate={validateUsername}>
|
|
{({ field, form }) => (
|
|
<FormControl isInvalid={form.errors.username && form.touched.username} >
|
|
<FormLabel>Username</FormLabel>
|
|
<Input {...field} placeholder="name" />
|
|
<FormErrorMessage>{form.errors.username}</FormErrorMessage>
|
|
</FormControl>
|
|
)}
|
|
</Field>
|
|
<Field name="nickname" validate={validateNickname}>
|
|
{({ field, form }) => (
|
|
<FormControl isInvalid={form.errors.nickname && form.touched.nickname} >
|
|
<FormLabel>Nickname</FormLabel>
|
|
<Input {...field} placeholder="name" />
|
|
<FormErrorMessage>{form.errors.nickname}</FormErrorMessage>
|
|
</FormControl>
|
|
)}
|
|
</Field>
|
|
</VStack>
|
|
<Box mt={6}>
|
|
<Button
|
|
colorScheme="teal"
|
|
variant="outline"
|
|
type="submit"
|
|
_focus={null}
|
|
>
|
|
提交
|
|
</Button>
|
|
<Button variant="ghost" ml="4" _focus={null} onClick={onClose}>取消</Button>
|
|
</Box>
|
|
</Form>
|
|
)}
|
|
</Formik>
|
|
</ModalBody>
|
|
</ModalContent>}
|
|
</Modal>
|
|
|
|
<Modal isOpen={isOpen1} onClose={onClose1}>
|
|
<ModalOverlay />
|
|
{<ModalContent p="3">
|
|
<ModalBody mb="2">
|
|
<Text>Secret code</Text>
|
|
<Text fontSize=".9rem" layerStyle="textSecondary">Provided to you by an org admin</Text>
|
|
<Input _focus={null} mt="3" placeholder="..." value={secret} onChange={e => setSecret(e.currentTarget.value)} />
|
|
<Button mt="6" colorScheme="teal" onClick={joinOrg}>Join Organization</Button>
|
|
</ModalBody>
|
|
</ModalContent>}
|
|
</Modal>
|
|
</>
|
|
)
|
|
}
|
|
export default UserOrgsPage
|
|
|