Skip to content

Commit 125efa7

Browse files
feat: setup rules configuration interface
1 parent 1398cef commit 125efa7

File tree

12 files changed

+275
-1
lines changed

12 files changed

+275
-1
lines changed

src/components/App.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import './App.css'
88
import { CssBaseline } from '@material-ui/core'
99
import { Provider } from 'react-redux'
1010
import store from '../store'
11+
import { Rules } from './Rules'
12+
import { ItemsList } from './Rules/ItemsList'
13+
import { CreateItemForm } from './Rules/CreateItemForm'
14+
import { EditItemForm } from './Rules/EditItemForm'
1115

1216
const router = createBrowserRouter([
1317
{
@@ -17,6 +21,24 @@ const router = createBrowserRouter([
1721
{
1822
path: '/gitclicker',
1923
element: <Game />
24+
},
25+
{
26+
path: '/rules',
27+
element: <Rules />,
28+
children: [
29+
{
30+
path: '/rules',
31+
element: <ItemsList />
32+
},
33+
{
34+
path: '/rules/add',
35+
element: <CreateItemForm />
36+
},
37+
{
38+
path: '/rules/edit/:id',
39+
element: <EditItemForm />
40+
}
41+
]
2042
}
2143
])
2244

src/components/Home.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ export function Home() {
4040
</Button>
4141
</Link>
4242
</Grid>
43+
<Grid item>
44+
<Link to="/rules">
45+
<Button variant="contained" color="primary">
46+
Rules
47+
</Button>
48+
</Link>
49+
</Grid>
4350
</Grid>
4451
</div>
4552
</Container>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function CreateItemForm() {
2+
return (
3+
<div>
4+
CREATE ITEM FORM
5+
</div>
6+
)
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function EditItemForm() {
2+
return (
3+
<div>
4+
EDIT ITEM FORM
5+
</div>
6+
)
7+
}

src/components/Rules/ItemsList.tsx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { useSelector } from 'react-redux'
2+
import DeleteIcon from '@material-ui/icons/Delete'
3+
import EditIcon from '@material-ui/icons/Edit'
4+
import IconButton from '@material-ui/core/IconButton'
5+
import Table from '@material-ui/core/Table'
6+
import TableBody from '@material-ui/core/TableBody'
7+
import TableCell from '@material-ui/core/TableCell'
8+
import TableContainer from '@material-ui/core/TableContainer'
9+
import TableHead from '@material-ui/core/TableHead'
10+
import TableRow from '@material-ui/core/TableRow'
11+
import Paper from '@material-ui/core/Paper'
12+
import AddIcon from '@material-ui/icons/Add'
13+
import numberFormat from '../../utils/numberFormat'
14+
import { RootState } from '../../store'
15+
import { useNavigate } from 'react-router-dom'
16+
import { Fab, makeStyles } from '@material-ui/core'
17+
18+
const useStyles = makeStyles((theme) => ({
19+
heroContent: {
20+
padding: theme.spacing(8, 0, 6),
21+
},
22+
fab: {
23+
position: 'absolute',
24+
bottom: theme.spacing(2),
25+
right: theme.spacing(2),
26+
},
27+
}))
28+
29+
30+
export const ItemsList = () => {
31+
const items = useSelector((state: RootState) => state.rules.items)
32+
const classes = useStyles()
33+
const navigate = useNavigate()
34+
35+
return (
36+
<>
37+
<TableContainer component={Paper}>
38+
<Table aria-label="simple table">
39+
<TableHead>
40+
<TableRow>
41+
<TableCell>Name</TableCell>
42+
<TableCell align="right">Price</TableCell>
43+
<TableCell align="right">Lines per seconds</TableCell>
44+
<TableCell align="right">Action</TableCell>
45+
</TableRow>
46+
</TableHead>
47+
<TableBody>
48+
{items.map((item) => (
49+
<TableRow key={item.id}>
50+
<TableCell component="th" scope="row">{item.name}</TableCell>
51+
<TableCell align="right">{numberFormat(item.price)}</TableCell>
52+
<TableCell align="right">{numberFormat(item.linesPerMillisecond * 10)}</TableCell>
53+
<TableCell align="right">
54+
<IconButton
55+
onClick={() => navigate(`/rules/edit/${item.id}`)}
56+
aria-label="edit"
57+
>
58+
<EditIcon />
59+
</IconButton>
60+
<IconButton
61+
color="secondary"
62+
aria-label="delete"
63+
>
64+
<DeleteIcon />
65+
</IconButton>
66+
</TableCell>
67+
</TableRow>
68+
))}
69+
</TableBody>
70+
</Table>
71+
</TableContainer>
72+
<Fab
73+
onClick={() => navigate('/rules/add')}
74+
className={classes.fab}
75+
color="primary"
76+
aria-label="add"
77+
>
78+
<AddIcon />
79+
</Fab>
80+
</>
81+
)
82+
}

src/components/Rules/Rules.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { useEffect } from 'react'
2+
import { Outlet } from 'react-router-dom'
3+
import Typography from '@material-ui/core/Typography'
4+
import { makeStyles } from '@material-ui/core/styles'
5+
import Container from '@material-ui/core/Container'
6+
import { fetchItems } from '../../modules/rules'
7+
import { Navbar } from '../layout/Navbar'
8+
import { useAppDispatch } from '../../store'
9+
10+
const useStyles = makeStyles((theme) => ({
11+
heroContent: {
12+
padding: theme.spacing(8, 0, 6),
13+
},
14+
fab: {
15+
position: 'absolute',
16+
bottom: theme.spacing(2),
17+
right: theme.spacing(2),
18+
},
19+
}))
20+
21+
export const Rules = () => {
22+
const classes = useStyles()
23+
const dispatch = useAppDispatch()
24+
25+
useEffect(() => {
26+
dispatch(fetchItems())
27+
}, [])
28+
29+
return (
30+
<>
31+
<Navbar />
32+
<main>
33+
<div className={classes.heroContent}>
34+
<Container maxWidth="sm">
35+
<Typography component="h1" variant="h2" align="center" color="textPrimary" gutterBottom>
36+
Configurator
37+
</Typography>
38+
<Outlet />
39+
</Container>
40+
</div>
41+
</main>
42+
</>
43+
)
44+
}

src/components/Rules/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { Rules } from './Rules'

src/modules/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { combineReducers } from '@reduxjs/toolkit'
22
import game from './game'
3+
import rules from './rules'
34

45
export const rootReducer = combineReducers({
5-
game: game.reducer
6+
game: game.reducer,
7+
rules: rules.reducer
68
})

src/modules/rules.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit'
2+
import { Item } from '../type'
3+
4+
// Initial state
5+
type RulesState = {
6+
items: Item[];
7+
}
8+
9+
const INITIAL_STATE: RulesState = {
10+
items: []
11+
}
12+
13+
// Side Effects / thunks
14+
export const fetchItems = createAsyncThunk(
15+
'rules/fetchItems',
16+
async (_, { dispatch }) => {
17+
const response = await fetch(`${process.env.REACT_APP_API_URL}/api/shop/items`)
18+
const items = await response.json() as Item[]
19+
20+
dispatch(fetchedItems(items))
21+
}
22+
)
23+
24+
const rules = createSlice({
25+
name: 'rule',
26+
initialState: INITIAL_STATE,
27+
reducers: {
28+
fetchedItems: (state, action: PayloadAction<Item[]>) => {
29+
state.items = action.payload
30+
}
31+
},
32+
})
33+
34+
const {
35+
fetchedItems
36+
} = rules.actions
37+
38+
export {
39+
fetchedItems
40+
}
41+
42+
export default rules

src/utils/getItemIcon.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import BashIcon from 'devicon/icons/bash/bash-original.svg'
2+
import IEIcon from 'devicon/icons/ie10/ie10-original.svg'
3+
import getItemIcon from './getItemIcon'
4+
5+
describe('getItemIcon', () => {
6+
it('provides icon for a known item', () => {
7+
const item = {
8+
id: 1,
9+
name: 'Bash',
10+
price: 10,
11+
linesPerMillisecond: 0.5
12+
}
13+
14+
expect(getItemIcon(item)).toBe(BashIcon)
15+
})
16+
17+
it('provides default icon for unknown item', () => {
18+
const item = {
19+
id: 1,
20+
name: 'Unknown item',
21+
price: 10,
22+
linesPerMillisecond: 0.5
23+
}
24+
25+
expect(getItemIcon(item)).toBe(IEIcon)
26+
})
27+
})

0 commit comments

Comments
 (0)