Skip to content

Commit 1dcc4ea

Browse files
committed
Merge branch 'dev-administration-users'
2 parents 827e065 + 8f2f6e4 commit 1dcc4ea

File tree

18 files changed

+583
-33
lines changed

18 files changed

+583
-33
lines changed

config-overrides.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const path = require('path')
2+
3+
module.exports = {
4+
// The Webpack config to use when compiling your react app for development or production.
5+
webpack: function(config, env) {
6+
// ...add your webpack config
7+
config.resolve.alias = {
8+
...config.resolve.alias,
9+
'@': path.resolve('./src'),
10+
}
11+
12+
return config
13+
},
14+
}

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {
6-
"start": "react-scripts start",
7-
"build": "react-scripts build",
8-
"test": "react-scripts test",
6+
"start": "react-app-rewired start",
7+
"build": "react-app-rewired build",
8+
"test": "react-app-rewired test",
99
"eject": "react-scripts eject",
1010
"deploy": "npm run build-preview && npm run build-docs && gh-pages -d build --repo [email protected]:modularcode/modular-admin-react.git --branch gh-pages",
1111
"build-preview": "cross-env PUBLIC_PATH='/' npm run build && echo modular-admin-react.modularcode.io > ./build/CNAME",
@@ -17,6 +17,7 @@
1717
"dependencies": {
1818
"@material-ui/core": "4.9.11",
1919
"@material-ui/icons": "4.9.1",
20+
"@material-ui/lab": "^4.0.0-alpha.51",
2021
"@rehooks/component-size": "^1.0.3",
2122
"@types/lodash": "^4.14.149",
2223
"@types/uuid": "^3.4.6",
@@ -57,6 +58,7 @@
5758
"fork-ts-checker-webpack-plugin": "^3.1.1",
5859
"gh-pages": "^2.2.0",
5960
"prettier": "1.18.2",
61+
"react-app-rewired": "^2.1.5",
6062
"react-docgen-typescript-loader": "^3.6.0",
6163
"ts-loader": "^6.2.1"
6264
},

src/Administration/Administration.js

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
1-
import React, { useEffect } from 'react'
2-
// import { Route } from 'react-router-dom'
1+
import React from 'react'
32
import PropTypes from 'prop-types'
4-
import api from '../_api'
3+
import { Route } from 'react-router-dom'
4+
import UsersList from './Users/UsersList'
55

66
const Administration = ({ match }) => {
7-
useEffect(() => {
8-
api.users.getList().then(res => console.log('res', res))
9-
}, [])
10-
117
return (
12-
<div>
13-
{/* <Route path={`${match.path}/login`} component={Login} /> */}
14-
Hello Administration
15-
</div>
8+
<>
9+
<Route path={`${match.path}/users`} component={UsersList} />
10+
</>
1611
)
1712
}
1813

src/Administration/Users/UsersEditor/UsersEditor.js

Whitespace-only changes.

src/Administration/Users/UsersEditor/index.js

Whitespace-only changes.
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
import React, { useEffect, useState } from 'react'
2+
// import PropTypes from 'prop-types'
3+
4+
import Grid from '@material-ui/core/Grid'
5+
import {
6+
makeStyles,
7+
Paper,
8+
Table,
9+
TableCell,
10+
TableRow,
11+
TableHead,
12+
TableBody,
13+
TableFooter,
14+
TableContainer,
15+
TableSortLabel,
16+
} from '@material-ui/core'
17+
18+
import { Alert, AlertTitle } from '@material-ui/lab'
19+
20+
import api from '@/_api'
21+
22+
import BasePageContainer from '@/_common/BasePageContainer'
23+
import BasePageToolbar from '@/_common/BasePageToolbar'
24+
import { BaseTablePagination } from '@/_common/BaseTable'
25+
26+
import UsersListTableItems from './UsersListTableItems'
27+
28+
const UsersList = ({ match }) => {
29+
const classes = useStyles()
30+
31+
const [status, setStatus] = React.useState('idle')
32+
const [statusMessage, setStatusMessage] = React.useState('')
33+
const [page, setPage] = React.useState(0)
34+
const [usersData, setUsersData] = useState({ users: [], count: 0 })
35+
const [rowsPerPage, setRowsPerPage] = React.useState(10)
36+
const [order, setOrder] = React.useState({
37+
order: 'desc',
38+
orderBy: 'createdAt',
39+
})
40+
41+
const { users, count } = usersData
42+
const rowsExpected = count ? Math.max(count - rowsPerPage * page, 0) : rowsPerPage
43+
44+
const tableColumns = [
45+
{
46+
id: 'avatarUrl',
47+
label: '',
48+
isSortable: false,
49+
},
50+
{
51+
id: 'firstName',
52+
label: 'First Name',
53+
isSortable: true,
54+
},
55+
{
56+
id: 'lastName',
57+
label: 'Last Name',
58+
isSortable: true,
59+
},
60+
{
61+
id: 'username',
62+
label: 'Username',
63+
isSortable: true,
64+
},
65+
{
66+
id: 'email',
67+
label: 'Email',
68+
isSortable: true,
69+
},
70+
{
71+
id: 'createdAt',
72+
label: 'Created',
73+
isSortable: true,
74+
},
75+
]
76+
77+
// Request users
78+
useEffect(() => {
79+
async function fetchUsers() {
80+
setStatus('loading')
81+
82+
try {
83+
const userDataRes = await api.users.getList({
84+
limit: rowsPerPage,
85+
offset: page * rowsPerPage,
86+
order,
87+
})
88+
89+
// Make some artificial delay
90+
await new Promise(resolve => {
91+
setTimeout(() => resolve(true), 300)
92+
})
93+
94+
setStatus('idle')
95+
setUsersData(userDataRes)
96+
} catch (err) {
97+
console.log('error', err.message)
98+
99+
setStatus('error')
100+
setStatusMessage(err.message)
101+
}
102+
}
103+
104+
fetchUsers()
105+
}, [order, page, rowsPerPage, usersData.count])
106+
107+
const handleChangePage = (event, newPage) => {
108+
setPage(newPage)
109+
}
110+
111+
const handleChangeRowsPerPage = event => {
112+
setRowsPerPage(parseInt(event.target.value, 10))
113+
setPage(0)
114+
}
115+
116+
const handelChangeOrder = (event, columnId) => {
117+
setOrder({
118+
// If the sorting column has changed
119+
order: columnId !== order.orderBy || order.order === 'desc' ? 'asc' : 'desc',
120+
orderBy: columnId,
121+
})
122+
}
123+
124+
return (
125+
<BasePageContainer>
126+
<BasePageToolbar title={'Users Adminstration'}></BasePageToolbar>
127+
<Grid container spacing={3}>
128+
<Grid item xs={12}>
129+
{status === 'error' && (
130+
<Alert severity="error">
131+
<AlertTitle>Error</AlertTitle>
132+
{statusMessage}
133+
</Alert>
134+
)}
135+
136+
{status !== 'error' && (
137+
<TableContainer component={Paper}>
138+
<Table className={classes.table} aria-label="custom pagination table">
139+
<TableHead>
140+
<TableRow>
141+
{tableColumns.map(column => (
142+
<TableCell key={column.id}>
143+
{/* Sortable */}
144+
{column.isSortable && (
145+
<TableSortLabel
146+
active={order.orderBy === column.id}
147+
direction={order.orderBy === column.id ? order.order : 'asc'}
148+
onClick={event => handelChangeOrder(event, column.id)}
149+
>
150+
{column.label}
151+
</TableSortLabel>
152+
)}
153+
{/* Non-sortable */}
154+
{!column.isSortable && column.label}
155+
</TableCell>
156+
))}
157+
<TableCell>Actions</TableCell>
158+
</TableRow>
159+
</TableHead>
160+
<TableBody>
161+
<UsersListTableItems
162+
users={status === 'loading' ? [] : users}
163+
rowsPerPage={rowsPerPage}
164+
rowsExpected={rowsExpected}
165+
/>
166+
</TableBody>
167+
<TableFooter>
168+
<TableRow>
169+
<BaseTablePagination
170+
page={page}
171+
rowsPerPage={rowsPerPage}
172+
count={count}
173+
order={order}
174+
onChangePage={handleChangePage}
175+
onChangeRowsPerPage={handleChangeRowsPerPage}
176+
/>
177+
</TableRow>
178+
</TableFooter>
179+
</Table>
180+
</TableContainer>
181+
)}
182+
</Grid>
183+
</Grid>
184+
</BasePageContainer>
185+
)
186+
}
187+
188+
const useStyles = makeStyles(theme => ({
189+
root: {
190+
flexShrink: 0,
191+
marginLeft: theme.spacing(2.5),
192+
},
193+
}))
194+
195+
UsersList.propTypes = {}
196+
197+
export default UsersList
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React from 'react'
2+
import PropTypes from 'prop-types'
3+
import { FormattedDate } from 'react-intl'
4+
5+
import { makeStyles, TableBody, TableCell, TableRow, Avatar } from '@material-ui/core'
6+
import { Skeleton } from '@material-ui/lab'
7+
8+
import { Edit as EditIcon, Delete as DeleteIcon } from '@material-ui/icons/'
9+
10+
const UsersListTableItems = ({ users, rowsPerPage = 10, rowsExpected = 10 }) => {
11+
// const classes = useStyles()
12+
13+
// Count how many empty rows needs to be filled
14+
const usersVisible = users.length || rowsExpected
15+
const usersArrayExpected = Array.from({ length: usersVisible }).map(
16+
(item, index) => index,
17+
)
18+
const emptyRows = rowsPerPage - usersVisible
19+
20+
return (
21+
<>
22+
{!users.length &&
23+
usersArrayExpected.map(item => (
24+
<TableRow key={item}>
25+
<TableCell>
26+
<Skeleton variant="circle" width={40} height={40} />
27+
</TableCell>
28+
<TableCell>
29+
<Skeleton variant="text" />
30+
</TableCell>
31+
<TableCell>
32+
<Skeleton variant="text" />
33+
</TableCell>
34+
<TableCell>
35+
<Skeleton variant="text" />
36+
</TableCell>
37+
<TableCell>
38+
<Skeleton variant="text" />
39+
</TableCell>
40+
<TableCell>
41+
<Skeleton variant="text" />
42+
</TableCell>
43+
</TableRow>
44+
))}
45+
{users.map(row => (
46+
<TableRow key={row.id}>
47+
<TableCell>
48+
<Avatar alt={row.firstName} src={row.avatarUrl} />
49+
</TableCell>
50+
<TableCell component="th" scope="row">
51+
{row.firstName}
52+
</TableCell>
53+
<TableCell>{row.lastName}</TableCell>
54+
<TableCell>{row.username}</TableCell>
55+
<TableCell>{row.email}</TableCell>
56+
<TableCell>
57+
<FormattedDate
58+
value={new Date(row.createdAt)}
59+
year="numeric"
60+
month="long"
61+
day="2-digit"
62+
/>
63+
</TableCell>
64+
<TableCell>
65+
<EditIcon />
66+
<DeleteIcon />
67+
</TableCell>
68+
</TableRow>
69+
))}
70+
{emptyRows > 0 && (
71+
<TableRow style={{ height: 53 * emptyRows }}>
72+
<TableCell colSpan={6} />
73+
</TableRow>
74+
)}
75+
</>
76+
)
77+
}
78+
79+
UsersListTableItems.propTypes = {}
80+
81+
const useStyles = makeStyles(theme => ({
82+
root: {
83+
flexShrink: 0,
84+
marginLeft: theme.spacing(2.5),
85+
},
86+
}))
87+
88+
export default UsersListTableItems
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './UsersList'

0 commit comments

Comments
 (0)