Skip to content

Commit 1b85360

Browse files
committed
update to context of messages
1 parent f8069b7 commit 1b85360

File tree

12 files changed

+412
-32
lines changed

12 files changed

+412
-32
lines changed

assets/js/components/AddTodo.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@ const AddTodo = () => {
2626
if (event !== undefined) event.preventDefault();
2727

2828

29-
context.createTodo(event, {
30-
task: state.task,
31-
description: state.description,
32-
});
29+
context.createTodo(event, state);
3330

3431
setState(initialState);
3532
};

assets/js/components/Router.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ import Redirect from 'react-router-dom/Redirect';
99
import {makeStyles} from '@material-ui/core/styles';
1010
//CUSTOM COMPONENTS
1111
import NotFound from './NotFound';
12-
import TodoContextProvider from '../contexts/TodoContext';
1312
import AppSnackbar from './AppSnackbar';
1413
import Navigation from './Navigation';
1514
import TodoTable from './TodoTable';
15+
import TagTable from './tables/tag/TagTable';
16+
import Providers from '../contexts/Providers';
1617

1718
const TodoList = () => (
18-
<TodoContextProvider>
19+
<div>
1920
<AppSnackbar/>
2021
<TodoTable/>
21-
</TodoContextProvider>
22+
</div>
2223
);
2324

24-
2525
const useStyles = makeStyles(theme => ({
2626
divider: theme.mixins.toolbar,
2727
}));
@@ -30,14 +30,16 @@ const Router = () => {
3030
const classes = useStyles();
3131
return (
3232
<BrowserRouter>
33-
<Navigation/>
34-
<div className={classes.divider}/>
35-
<Switch>
36-
<Redirect exact from="/" to="/todo-list"/>
37-
<Route exact path="/todo-list" component={TodoList}/>
38-
<Route exact path="/tag-list" component={null}/>
39-
<Route component={NotFound}/>
40-
</Switch>
33+
<Providers>
34+
<Navigation/>
35+
<div className={classes.divider}/>
36+
<Switch>
37+
<Redirect exact from="/" to="/todo-list"/>
38+
<Route exact path="/todo-list" component={TodoList}/>
39+
<Route exact path="/tag-list" component={TagTable}/>
40+
<Route component={NotFound}/>
41+
</Switch>
42+
</Providers>
4143
</BrowserRouter>
4244
);
4345
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react';
2+
3+
const ExtractTextFromMessage = (array) => {
4+
const textCollection = [];
5+
array.forEach(message => textCollection.push(message.text));
6+
return textCollection;
7+
};
8+
9+
export default ExtractTextFromMessage;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//REACT
2+
import React, {useContext, useState} from 'react';
3+
//CONTEXT
4+
import {TagContext} from '../../../contexts/TagContext';
5+
//MUI COMPONENTS
6+
import {Grid, TextField, Box, IconButton} from '@material-ui/core';
7+
//MUI ICONS
8+
import {Add as AddIcon} from '@material-ui/icons';
9+
10+
11+
const AddTag = () => {
12+
const context = useContext(TagContext);
13+
14+
const initialState = {
15+
name: '',
16+
};
17+
18+
const [state, setState] = useState(initialState);
19+
20+
const handleChange = (e) => {
21+
setState({
22+
...state,
23+
[e.target.name]: e.target.value,
24+
});
25+
};
26+
27+
const onSubmit = (e) => {
28+
e.preventDefault();
29+
context.create(state);
30+
setState(initialState);
31+
};
32+
33+
return (
34+
<form noValidate onSubmit={onSubmit}>
35+
<Grid spacing={2} alignItems="center" justify="flex-end" container>
36+
<Grid item xs={12} sm={11}>
37+
<TextField variant="outlined"
38+
size="small"
39+
type="text"
40+
value={state.name}
41+
label="Tag Name"
42+
name="name"
43+
fullWidth
44+
autoFocus
45+
onChange={handleChange}
46+
/>
47+
</Grid>
48+
<Grid item xs={12} sm={1}>
49+
<Box textAlign="right">
50+
<IconButton type="submit" color="primary" onClick={onSubmit}>
51+
<AddIcon/>
52+
</IconButton>
53+
</Box>
54+
</Grid>
55+
</Grid>
56+
</form>
57+
);
58+
};
59+
60+
export default AddTag;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//REACT
2+
import React, {useContext} from 'react';
3+
import PropTypes from 'prop-types';
4+
//MUI COMPONENTS
5+
import IconButton from '@material-ui/core/IconButton';
6+
//MUI ICONS
7+
import {Delete as DeleteIcon} from '@material-ui/icons';
8+
//CONTEXT
9+
import {TagContext} from '../../../contexts/TagContext';
10+
11+
const DeleteButton = props => {
12+
const context = useContext(TagContext);
13+
14+
const onClick = (e) => {
15+
e.preventDefault();
16+
context.delete(props.entity);
17+
};
18+
19+
return (
20+
<IconButton color="secondary" onClick={onClick}>
21+
<DeleteIcon/>
22+
</IconButton>
23+
);
24+
};
25+
26+
DeleteButton.propTypes = {
27+
entity: PropTypes.shape({
28+
id: PropTypes.number.isRequired,
29+
}).isRequired,
30+
};
31+
32+
export default DeleteButton;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//REACT
2+
import React, {useContext, useEffect, useState} from 'react';
3+
//MUI COMPONENTS
4+
import {
5+
Table,
6+
TableHead,
7+
TableBody,
8+
TableRow,
9+
TableCell,
10+
Typography,
11+
IconButton,
12+
TableContainer, Paper,
13+
} from '@material-ui/core';
14+
//MUI ICONS
15+
import {Edit as EditIcon, Done as DoneIcon, Close as CloseIcon} from '@material-ui/icons';
16+
//CONTEXTS
17+
import {TagContext} from '../../../contexts/TagContext';
18+
//CUSTOM COMPONENTS
19+
import AddTag from './AddTag';
20+
import DeleteButton from './DeleteButton';
21+
import ExtractTextFromMessage from '../../functions/ExtractTextFromMessage';
22+
23+
24+
const TagTable = () => {
25+
const context = useContext(TagContext);
26+
const {tags, message} = context;
27+
28+
const initialState = {tagEditId: null};
29+
30+
const [state, setState] = useState(initialState);
31+
32+
const setEdit = (e) => {
33+
setState({tagEditId: e.target.name ? e.target.name : null});
34+
};
35+
36+
useEffect(() => {
37+
if (!context.tags) context.read();
38+
}, [context]);
39+
40+
console.log(message);
41+
42+
return (
43+
<TableContainer component={Paper}>
44+
<Table size="small">
45+
<TableHead>
46+
<TableRow>
47+
<TableCell colSpan={2}>
48+
<AddTag/>
49+
</TableCell>
50+
</TableRow>
51+
<TableRow>
52+
<TableCell>{message.level === 'error' ? message.text.join('\n') : 'Tag Name'}</TableCell>
53+
<TableCell align="right">Actions</TableCell>
54+
</TableRow>
55+
</TableHead>
56+
<TableBody>
57+
{tags ? tags.map((tag, index) => (
58+
<TableRow key={tag.id}>
59+
<TableCell><Typography>{tag.name}</Typography></TableCell>
60+
<TableCell align="right">
61+
{state.tagEditId !== tag.id ?
62+
<>
63+
<IconButton color="primary" name={tag.id} onClick={setEdit}>
64+
<EditIcon/>
65+
</IconButton>
66+
<DeleteButton entity={tag}/>
67+
</>
68+
:
69+
<>
70+
<IconButton color="primary">
71+
<DoneIcon/>
72+
</IconButton>
73+
<IconButton color="secondary" onClick={setEdit}>
74+
<CloseIcon/>
75+
</IconButton>
76+
</>
77+
}
78+
</TableCell>
79+
</TableRow>
80+
)) : null}
81+
82+
{context.isLoading &&
83+
<TableRow><TableCell><Typography>Loading...</Typography></TableCell></TableRow>}
84+
</TableBody>
85+
</Table>
86+
</TableContainer>
87+
);
88+
};
89+
90+
export default TagTable;

assets/js/contexts/Providers.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react';
2+
import TodoContextProvider from './TodoContext';
3+
import TagContextProvider from './TagContext';
4+
5+
const Providers = (props) => {
6+
return (
7+
<TodoContextProvider>
8+
<TagContextProvider>
9+
{props.children}
10+
</TagContextProvider>
11+
</TodoContextProvider>
12+
);
13+
};
14+
15+
export default Providers;

assets/js/contexts/TagContext.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import React, {createContext} from 'react';
2+
import axios from 'axios';
3+
4+
export const TagContext = createContext();
5+
6+
class TagContextProvider extends React.Component {
7+
constructor(props) {
8+
super(props);
9+
this.state = {
10+
tags: null,
11+
isLoading: false,
12+
message: {
13+
text: '',
14+
level: null,
15+
},
16+
17+
read: this.read.bind(this),
18+
create: this.create.bind(this),
19+
delete: this.delete.bind(this),
20+
};
21+
}
22+
23+
//create
24+
/**
25+
* @param data {object}
26+
* @param data.name {string}
27+
*/
28+
async create(data) {
29+
this.setState({isLoading: true});
30+
try {
31+
const r = await axios.post('/api/tag/create', data);
32+
const {createdTag, message} = r.data;
33+
34+
if (message.level === 'error') {
35+
this.setState({
36+
message: message.text,
37+
isLoading: false,
38+
});
39+
} else {
40+
this.setState({
41+
tags: [...this.state.tags, createdTag],
42+
isLoading: false,
43+
});
44+
}
45+
46+
} catch (e) {
47+
this.setState({
48+
errors: e,
49+
isLoading: false,
50+
});
51+
}
52+
53+
}
54+
55+
//read
56+
async read() {
57+
if (this.state.isLoading) return;
58+
59+
this.setState({isLoading: true});
60+
61+
try {
62+
const r = await axios.get('/api/tag/read');
63+
this.setState({
64+
tags: r.data,
65+
isLoading: false,
66+
});
67+
} catch (e) {
68+
this.setState({
69+
errors: e,
70+
isLoading: false,
71+
});
72+
}
73+
};
74+
75+
//update
76+
77+
/**
78+
* delete
79+
* @param data {object}
80+
* @param data.id {number}
81+
* @param data.name {string}
82+
*/
83+
async delete(data) {
84+
try {
85+
const r = await axios.delete('/api/tag/delete/' + data.id);
86+
const newTags = [...this.state.tags].filter(tag => tag.id !== data.id);
87+
88+
this.setState({
89+
tags: newTags,
90+
});
91+
92+
} catch (e) {
93+
this.setState({
94+
error: e,
95+
});
96+
}
97+
}
98+
99+
render() {
100+
return (
101+
<TagContext.Provider value={{
102+
...this.state,
103+
}}>
104+
{this.props.children}
105+
</TagContext.Provider>
106+
);
107+
}
108+
}
109+
110+
export default TagContextProvider;

0 commit comments

Comments
 (0)