mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 18:29:15 +03:00
refactor: user rendering
This commit is contained in:
parent
5f7c27b060
commit
3e69a47907
@ -21,7 +21,7 @@ import UserBadge from '@educt/components/UserBadge';
|
|||||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||||
import { useColorModeValue } from '@chakra-ui/react';
|
import { useColorModeValue } from '@chakra-ui/react';
|
||||||
|
|
||||||
type UserItemPropsType = {
|
export type UserItemPropsType = {
|
||||||
user: IUser;
|
user: IUser;
|
||||||
onEdit: (user: IUser) => void;
|
onEdit: (user: IUser) => void;
|
||||||
onDelete: (user: IUser) => void;
|
onDelete: (user: IUser) => void;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons';
|
import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons';
|
||||||
import { Flex, Box, Stack, Text } from '@chakra-ui/layout';
|
import { Flex, Box, Stack, Text } from '@chakra-ui/layout';
|
||||||
import { Button } from '@chakra-ui/button';
|
import { Button } from '@chakra-ui/button';
|
||||||
@ -6,15 +7,15 @@ import { Button } from '@chakra-ui/button';
|
|||||||
/**
|
/**
|
||||||
* Components
|
* Components
|
||||||
*/
|
*/
|
||||||
import UserItem from './UserItem';
|
|
||||||
import EditUserForm from '../EditUserForm';
|
import EditUserForm from '../EditUserForm';
|
||||||
import DeleteUserDialog from '../DeleteUserDialog';
|
import DeleteUserDialog from '../DeleteUserDialog';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types
|
* Types
|
||||||
*/
|
*/
|
||||||
import { IPaginationMeta, IUser } from '@educt/interfaces';
|
import type { IUser } from '@educt/interfaces';
|
||||||
import { UsersPageContextType } from '@educt/types';
|
import type { UsersPageContextType } from '@educt/types';
|
||||||
|
import type { UserItemPropsType } from './UserItem';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contexts
|
* Contexts
|
||||||
@ -24,21 +25,31 @@ import { UsersPageContext } from '@educt/contexts';
|
|||||||
/**
|
/**
|
||||||
* Hooks
|
* Hooks
|
||||||
*/
|
*/
|
||||||
import { useContext } from 'react';
|
import { useEffect, useContext } from 'react';
|
||||||
|
import { useLocation } from 'react-router';
|
||||||
|
import { useErrorHandler } from 'react-error-boundary';
|
||||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||||
import { useDisclosure } from '@chakra-ui/hooks';
|
import { useDisclosure } from '@chakra-ui/hooks';
|
||||||
import { useErrorHandler } from 'react-error-boundary';
|
|
||||||
|
|
||||||
type UserListPropsType = { users: IUser[]; pagination: IPaginationMeta };
|
type UserListPropsType = { render: React.FC<UserItemPropsType> };
|
||||||
|
|
||||||
const UserList: React.FC<UserListPropsType> = ({ users, pagination }) => {
|
const UserList: React.FC<UserListPropsType> = ({ render: Item }) => {
|
||||||
const { userStore } = useRootStore();
|
const { userStore } = useRootStore();
|
||||||
const { searchingRole, loading, setLoading, search, editingUser, setEditingUser, deletingUser, setDeletingUser } =
|
const { searchingRole, loading, setLoading, search, editingUser, setEditingUser, deletingUser, setDeletingUser } =
|
||||||
useContext<UsersPageContextType>(UsersPageContext);
|
useContext<UsersPageContextType>(UsersPageContext);
|
||||||
|
const location = useLocation();
|
||||||
const handleError = useErrorHandler();
|
const handleError = useErrorHandler();
|
||||||
const pagesCount = Math.ceil(pagination.total / pagination.per_page);
|
|
||||||
const { onOpen: onOpenEditModal, onClose: onCloseEditModal, isOpen: isOpenEditModal } = useDisclosure();
|
const { onOpen: onOpenEditModal, onClose: onCloseEditModal, isOpen: isOpenEditModal } = useDisclosure();
|
||||||
const { onOpen: onOpenDeleteDialog, onClose: onCloseDeleteDialog, isOpen: isOpenDeleteDialog } = useDisclosure();
|
const { onOpen: onOpenDeleteDialog, onClose: onCloseDeleteDialog, isOpen: isOpenDeleteDialog } = useDisclosure();
|
||||||
|
const { users, pagination } = userStore;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
userStore.loadUsersData().catch(error => handleError(error));
|
||||||
|
}, [handleError, userStore, location.search]);
|
||||||
|
|
||||||
|
if (pagination === undefined || users === null) return <div>Loading users...</div>;
|
||||||
|
|
||||||
|
const pagesCount = Math.ceil(pagination.total / pagination.per_page);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle next page
|
* Handle next page
|
||||||
@ -96,9 +107,14 @@ const UserList: React.FC<UserListPropsType> = ({ users, pagination }) => {
|
|||||||
onOpenDeleteDialog();
|
onOpenDeleteDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (pagination.total === 0)
|
||||||
|
return (
|
||||||
|
<Box textAlign='center' mt='10' userSelect='none'>
|
||||||
|
<Text color='gray.500'>Cannot find any users.</Text>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
{pagination.total !== 0 ? (
|
|
||||||
<>
|
<>
|
||||||
{editingUser && <EditUserForm onClose={onCloseEditModal} isOpen={isOpenEditModal} />}
|
{editingUser && <EditUserForm onClose={onCloseEditModal} isOpen={isOpenEditModal} />}
|
||||||
{deletingUser && <DeleteUserDialog onClose={onCloseDeleteDialog} isOpen={isOpenDeleteDialog} />}
|
{deletingUser && <DeleteUserDialog onClose={onCloseDeleteDialog} isOpen={isOpenDeleteDialog} />}
|
||||||
@ -114,7 +130,7 @@ const UserList: React.FC<UserListPropsType> = ({ users, pagination }) => {
|
|||||||
) : (
|
) : (
|
||||||
<Stack mt='4' spacing='2'>
|
<Stack mt='4' spacing='2'>
|
||||||
{users.map(user => (
|
{users.map(user => (
|
||||||
<UserItem key={user.id} user={user} onEdit={onEditUser} onDelete={onDeleteUser} />
|
<Item key={user.id} user={user} onEdit={onEditUser} onDelete={onDeleteUser} />
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
@ -143,13 +159,7 @@ const UserList: React.FC<UserListPropsType> = ({ users, pagination }) => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</>
|
||||||
) : (
|
|
||||||
<Box textAlign='center' mt='10' userSelect='none'>
|
|
||||||
<Text color='gray.500'>Cannot find any users.</Text>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UserList;
|
export default observer(UserList);
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { UserRoleEnum } from '@educt/enums';
|
|||||||
import { useErrorHandler } from 'react-error-boundary';
|
import { useErrorHandler } from 'react-error-boundary';
|
||||||
import { UsersPageContext } from '@educt/contexts';
|
import { UsersPageContext } from '@educt/contexts';
|
||||||
import { UsersPageContextType } from '@educt/types';
|
import { UsersPageContextType } from '@educt/types';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
|
||||||
type SelectRoleStateType = UserRoleEnum | 'any';
|
type SelectRoleStateType = UserRoleEnum | 'any';
|
||||||
|
|
||||||
@ -70,4 +71,4 @@ const UserSearch: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UserSearch;
|
export default observer(UserSearch);
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React from 'react';
|
||||||
import { observer } from 'mobx-react';
|
|
||||||
import { Box, Flex, Heading, Text } from '@chakra-ui/react';
|
import { Box, Flex, Heading, Text } from '@chakra-ui/react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,56 +9,49 @@ import { IPageProps } from '@educt/interfaces';
|
|||||||
/**
|
/**
|
||||||
* Components
|
* Components
|
||||||
*/
|
*/
|
||||||
|
import LoadingPage from '@educt/components/LoadingPage';
|
||||||
import UserSearch from './components/UserSearch';
|
import UserSearch from './components/UserSearch';
|
||||||
import UserList from './components/UserList';
|
import UserList from './components/UserList';
|
||||||
import LoadingPage from './components/LoadingPage';
|
import UserItem from './components/UserList/UserItem';
|
||||||
|
import CreateUserForm from './components/CreateUserForm';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooks
|
* Hooks
|
||||||
*/
|
*/
|
||||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||||
import { useErrorHandler } from 'react-error-boundary';
|
|
||||||
import { useLocation } from 'react-router';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context
|
* Context
|
||||||
*/
|
*/
|
||||||
import CreateUserForm from './components/CreateUserForm';
|
|
||||||
import { UsersPageContextProvider } from '@educt/providers';
|
import { UsersPageContextProvider } from '@educt/providers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Users Page
|
* Users Page
|
||||||
*/
|
*/
|
||||||
const UsersPage: React.FC<IPageProps> = () => {
|
const UsersPage: React.FC<IPageProps> = () => {
|
||||||
const { userStore } = useRootStore();
|
const {
|
||||||
const handleError = useErrorHandler();
|
userStore: { me },
|
||||||
const location = useLocation();
|
} = useRootStore();
|
||||||
|
|
||||||
useEffect(() => {
|
if (me === null) return <LoadingPage />;
|
||||||
userStore.loadUsersData().catch(error => handleError(error));
|
|
||||||
}, [handleError, userStore, location.search]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UsersPageContextProvider>
|
<UsersPageContextProvider>
|
||||||
<Box h='100%'>
|
<Box h='100%'>
|
||||||
<Heading as='h1'>User management</Heading>
|
<Heading as='h1'>User management</Heading>
|
||||||
<Text mt='2'>You can add or delete users on this page.</Text>
|
<Text mt='2'>You can add or delete users on this page.</Text>
|
||||||
{userStore.users !== null && userStore.me !== null && userStore.pagination !== undefined ? (
|
|
||||||
<Flex mt='5' flexDir='column' h='full'>
|
<Flex mt='5' flexDir='column' h='full'>
|
||||||
<Flex justifyContent='space-between' sx={{ gap: '10px' }} flexWrap='wrap'>
|
<Flex justifyContent='space-between' sx={{ gap: '10px' }} flexWrap='wrap'>
|
||||||
<UserSearch />
|
<UserSearch />
|
||||||
<Flex sx={{ gap: '10px' }}>
|
<Flex sx={{ gap: '10px' }}>
|
||||||
<CreateUserForm me={userStore.me} />
|
<CreateUserForm me={me} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<UserList users={userStore.users} pagination={userStore.pagination} />
|
<UserList render={UserItem} />
|
||||||
</Flex>
|
</Flex>
|
||||||
) : (
|
|
||||||
<LoadingPage />
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
</UsersPageContextProvider>
|
</UsersPageContextProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default observer(UsersPage);
|
export default UsersPage;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user