add skeleton for users management
This commit is contained in:
parent
6b695a745b
commit
49ff44ee6f
|
|
@ -1,8 +1,7 @@
|
|||
import React from 'react'
|
||||
import styled from '@emotion/styled'
|
||||
import { t } from '@/scripts/i18n'
|
||||
import { User } from '@/scripts/types'
|
||||
import * as breakpoints from '@/styles/breakpoints'
|
||||
import { Box, Icon, InfoTable } from './styles'
|
||||
import {
|
||||
humanizePermission,
|
||||
verificationStatusText,
|
||||
|
|
@ -10,31 +9,6 @@ import {
|
|||
canModifyPermission,
|
||||
} from './utils'
|
||||
|
||||
const Box = styled.div`
|
||||
width: 48%;
|
||||
margin: 7px;
|
||||
|
||||
${breakpoints.lessThan(breakpoints.Breakpoint.lg)} {
|
||||
width: 98%;
|
||||
}
|
||||
`
|
||||
const Icon = styled.div`
|
||||
width: 70px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: 22px;
|
||||
`
|
||||
const InfoTable = styled.div`
|
||||
> div:not(:last-child) {
|
||||
${breakpoints.lessThan(breakpoints.Breakpoint.sm)} {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
${breakpoints.greaterThan(breakpoints.Breakpoint.sm)} {
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface Props {
|
||||
user: User
|
||||
currentUser: User
|
||||
|
|
@ -54,7 +28,7 @@ const Card: React.FC<Props> = (props) => {
|
|||
|
||||
return (
|
||||
<Box className="info-box">
|
||||
<Icon>
|
||||
<Icon py>
|
||||
<img
|
||||
className="bs-avatar"
|
||||
src={`${blessing.base_url}/avatar/user/${user.uid}`}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
import React from 'react'
|
||||
import styled from '@emotion/styled'
|
||||
import Skeleton from 'react-loading-skeleton'
|
||||
import { t } from '@/scripts/i18n'
|
||||
import { Box, Icon, InfoTable } from './styles'
|
||||
|
||||
const ShrinkedSkeleton = styled(Skeleton)<{ width?: string }>`
|
||||
width: ${(props) => props.width};
|
||||
`
|
||||
|
||||
const LoadingCard: React.FC = () => (
|
||||
<Box className="info-box">
|
||||
<Icon>
|
||||
<Skeleton circle height={50} width={50} />
|
||||
</Icon>
|
||||
<div className="info-box-content">
|
||||
<div className="row">
|
||||
<div className="col-10">
|
||||
<Skeleton width="200px" />
|
||||
</div>
|
||||
<div className="col-2">
|
||||
<span className="text-gray">
|
||||
<i className="fas fa-cog"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<Skeleton width="200px" />
|
||||
</div>
|
||||
<div>
|
||||
<Skeleton width="200px" />
|
||||
</div>
|
||||
<InfoTable className="row m-2 border-top border-bottom">
|
||||
<div className="col-sm-4 py-1 text-center">
|
||||
<b className="d-block">{t('general.user.score')}</b>
|
||||
<span className="d-block py-1">
|
||||
<ShrinkedSkeleton width="30%" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-sm-4 py-1 text-center">
|
||||
<b className="d-block">{t('admin.permission')}</b>
|
||||
<span className="d-block py-1">
|
||||
<ShrinkedSkeleton width="30%" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-sm-4 py-1 text-center">
|
||||
<b className="d-block">{t('admin.verification')}</b>
|
||||
<span className="d-block py-1">
|
||||
<ShrinkedSkeleton width="30%" />
|
||||
</span>
|
||||
</div>
|
||||
</InfoTable>
|
||||
<div>
|
||||
<Skeleton width="240px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
)
|
||||
|
||||
export default LoadingCard
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react'
|
||||
import styled from '@emotion/styled'
|
||||
import Skeleton from 'react-loading-skeleton'
|
||||
|
||||
const ThickSkeleton = styled(Skeleton)`
|
||||
line-height: 2;
|
||||
`
|
||||
|
||||
const LoadingRow: React.FC = () => (
|
||||
<tr>
|
||||
<td colSpan={8}>
|
||||
<ThickSkeleton />
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
|
||||
export default LoadingRow
|
||||
|
|
@ -9,11 +9,12 @@ import { User, UserPermission, Paginator } from '@/scripts/types'
|
|||
import { toast, showModal } from '@/scripts/notify'
|
||||
import urls from '@/scripts/urls'
|
||||
import type { Props as ModalInputProps } from '@/components/ModalInput'
|
||||
import Loading from '@/components/Loading'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import Header from './Header'
|
||||
import Card from './Card'
|
||||
import LoadingCard from './LoadingCard'
|
||||
import Row from './Row'
|
||||
import LoadingRow from './LoadingRow'
|
||||
|
||||
const UsersManagement: React.FC = () => {
|
||||
const [users, setUsers] = useImmer<User[]>([])
|
||||
|
|
@ -296,15 +297,11 @@ const UsersManagement: React.FC = () => {
|
|||
</label>
|
||||
</div>
|
||||
</Header>
|
||||
{isLoading ? (
|
||||
<div className="card-body">
|
||||
<Loading />
|
||||
</div>
|
||||
) : users.length === 0 ? (
|
||||
{users.length === 0 && !isLoading ? (
|
||||
<div className="card-body text-center">{t('general.noResult')}</div>
|
||||
) : isTableMode ? (
|
||||
<div className="card-body table-responsive p-0">
|
||||
<table className="table table-striped">
|
||||
<table className={`table ${isLoading ? '' : 'table-striped'}`}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>UID</th>
|
||||
|
|
@ -318,8 +315,33 @@ const UsersManagement: React.FC = () => {
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map((user, i) => (
|
||||
<Row
|
||||
{isLoading
|
||||
? new Array(10).fill(null).map((_, i) => <LoadingRow key={i} />)
|
||||
: users.map((user, i) => (
|
||||
<Row
|
||||
key={user.uid}
|
||||
user={user}
|
||||
currentUser={currentUser}
|
||||
onEmailChange={() => handleEmailChange(user, i)}
|
||||
onNicknameChange={() => handleNicknameChange(user, i)}
|
||||
onScoreChange={() => handleScoreChange(user, i)}
|
||||
onPermissionChange={() => handlePermissionChange(user, i)}
|
||||
onVerificationToggle={() =>
|
||||
handleVerificationToggle(user, i)
|
||||
}
|
||||
onPasswordChange={() => handlePasswordChange(user)}
|
||||
onDelete={() => handleDelete(user)}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<div className="card-body d-flex flex-wrap">
|
||||
{isLoading
|
||||
? new Array(10).fill(null).map((_, i) => <LoadingCard key={i} />)
|
||||
: users.map((user, i) => (
|
||||
<Card
|
||||
key={user.uid}
|
||||
user={user}
|
||||
currentUser={currentUser}
|
||||
|
|
@ -332,25 +354,6 @@ const UsersManagement: React.FC = () => {
|
|||
onDelete={() => handleDelete(user)}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<div className="card-body d-flex flex-wrap">
|
||||
{users.map((user, i) => (
|
||||
<Card
|
||||
key={user.uid}
|
||||
user={user}
|
||||
currentUser={currentUser}
|
||||
onEmailChange={() => handleEmailChange(user, i)}
|
||||
onNicknameChange={() => handleNicknameChange(user, i)}
|
||||
onScoreChange={() => handleScoreChange(user, i)}
|
||||
onPermissionChange={() => handlePermissionChange(user, i)}
|
||||
onVerificationToggle={() => handleVerificationToggle(user, i)}
|
||||
onPasswordChange={() => handlePasswordChange(user)}
|
||||
onDelete={() => handleDelete(user)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="card-footer">
|
||||
|
|
|
|||
29
resources/assets/src/views/admin/UsersManagement/styles.ts
Normal file
29
resources/assets/src/views/admin/UsersManagement/styles.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import styled from '@emotion/styled'
|
||||
import * as breakpoints from '@/styles/breakpoints'
|
||||
|
||||
export const Box = styled.div`
|
||||
width: 48%;
|
||||
margin: 7px;
|
||||
|
||||
${breakpoints.lessThan(breakpoints.Breakpoint.lg)} {
|
||||
width: 98%;
|
||||
}
|
||||
`
|
||||
|
||||
export const Icon = styled.div<{ py?: boolean }>`
|
||||
width: 70px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: ${(props) => (props.py ? '22px' : '0')};
|
||||
`
|
||||
|
||||
export const InfoTable = styled.div`
|
||||
> div:not(:last-child) {
|
||||
${breakpoints.lessThan(breakpoints.Breakpoint.sm)} {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
${breakpoints.greaterThan(breakpoints.Breakpoint.sm)} {
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
}
|
||||
`
|
||||
Loading…
Reference in New Issue
Block a user