add skeleton for users management

This commit is contained in:
Pig Fang 2020-07-04 10:54:10 +08:00
parent 6b695a745b
commit 49ff44ee6f
No known key found for this signature in database
GPG Key ID: A8198F548DADA9E2
5 changed files with 141 additions and 56 deletions

View File

@ -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}`}

View File

@ -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

View File

@ -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

View File

@ -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">

View 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);
}
}
`