Skip to content

Commit

Permalink
Make the updating of data work
Browse files Browse the repository at this point in the history
  • Loading branch information
cefjoeii committed Jul 22, 2017
1 parent bb3c8f9 commit 6fff987
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 122 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# mern-crud

A CRUD starter kit using MongoDB, Express.js, React.js, and Node.js. Semantic UI React was used as I'm opinionatedly not pleased with Material-UI.
A CRUD starter kit using MongoDB, Express.js, React.js, and Node.js. Semantic UI React was used for the UI.

Make sure MongoDB service is running.

Expand Down Expand Up @@ -43,10 +43,11 @@ It will create a folder named *public* on the root directory. This is where the
## Features You Can Manually Add

* Front-end validation. Pure back-end validation is expensive.
* Real-time broadcast using socket.io

## To Do

- [x] Create
- [x] Read
- [ ] Update
- [x] Update
- [ ] Delete
6 changes: 1 addition & 5 deletions models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@ const emailValidator = [
];

const ageValidator = [
// validate({
// validator: 'isInt',
// arguments: [1, 120],
// message: 'Age must be valid.'
// })
// TODO: Make some validators here...
];

const genderValidator = [
Expand Down
9 changes: 9 additions & 0 deletions react-src/src/components/App/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
font-size: large;
}

a.social-link {
color: #fff;
font-family: monospace;
}

a.social-link:hover {
color: #ccc;
}

@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
Expand Down
56 changes: 41 additions & 15 deletions react-src/src/components/App/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import React, { Component } from 'react';
import { Container } from 'semantic-ui-react';
import axios from 'axios';

import TableData from '../TableData/TableData';
import ModalAdd from '../ModalAdd/ModalAdd';
import TableUser from '../TableUser/TableUser';
import ModalUser from '../ModalUser/ModalUser';

import logo from '../../logo.svg';
import './App.css';

class App extends Component {

// Pass this as a prop
server = 'http://localhost:3000'; // http://localhost:3000
// Change this when deploying.
server = 'http://localhost:3000';

constructor() {
super();
Expand All @@ -20,9 +20,11 @@ class App extends Component {
users: []
}

this.handleUsersListChange = this.handleUsersListChange.bind(this);
this.handleUserAdded = this.handleUserAdded.bind(this);
this.handleUserUpdated = this.handleUserUpdated.bind(this);
}

// Fetch data from the back-end
componentDidMount() {
axios.get(`${this.server}/api/users/`)
.then((response) => {
Expand All @@ -33,12 +35,24 @@ class App extends Component {
});
}

handleUsersListChange(addedUser) {
const users = this.state.users.slice();
users.push(addedUser);
this.setState({
users: users
});
handleUserAdded(user) {
let users = this.state.users.slice();
users.push(user);
this.setState({ users: users });
}

handleUserUpdated(user) {
let users = this.state.users.slice();
for (let i = 0, n = users.length; i < n; i++) {
if (users[i]._id === user._id) {
users[i].name = user.name;
users[i].email = user.email;
users[i].age = user.age;
users[i].gender = user.gender;
break; //Stop this loop, we found it!
}
}
this.setState({ users: users })
}

render() {
Expand All @@ -47,14 +61,26 @@ class App extends Component {
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>MERN CRUD Starter Kit</h2>
<h1>MERN CRUD Starter Kit</h1>
<p>A Create, Read, Update, and Delete starter kit using MongoDB, Express.js, React.js, and Node.js</p>
<p>Semantic UI React was used for the UI.</p>
<p>REST API was implemented on the back-end. Semantic UI React was used for the UI.</p>
<p><a className="social-link" href="https://github.com/cefjoeii" target="_blank" rel="noopener noreferrer">GitHub</a> &bull; <a className="social-link" href="https://linkedin.com/in/cefjoeii" target="_blank" rel="noopener noreferrer">LinkedIn</a> &bull; <a className="social-link" href="https://twitter.com/cefjoeii" target="_blank" rel="noopener noreferrer">Twitter</a></p>
</div>
</div>
<Container>
<ModalAdd onUsersListChange={this.handleUsersListChange} server={this.server} />
<TableData users={this.state.users} />
<ModalUser
headerTitle='Add User'
buttonTriggerTitle='Add New'
buttonSubmitTitle='Add'
buttonColor='green'
onUserAdded={this.handleUserAdded}
server={this.server}
/>
<TableUser
onUserUpdated={this.handleUserUpdated}
users={this.state.users}
server={this.server}
/>
</Container>
<br/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ const genderOptions = [
{ key: 'f', text: 'Female', value: 'f' },
]

class FormAdd extends Component {
class FormUser extends Component {

constructor(props) {
super(props);

this.state = {
name: '',
email: '',
Expand All @@ -26,6 +27,23 @@ class FormAdd extends Component {
this.handleSubmit = this.handleSubmit.bind(this);
}

componentWillMount() {
if (this.props.userID) {
axios.get(`${this.props.server}/api/users/?id=${this.props.userID}`)
.then((response) => {
this.setState({
name: response.data.name,
email: response.data.email,
age: (response.data.age === null) ? '' : response.data.age,
gender: response.data.gender,
});
})
.catch((error) => {
console.log(error);
});
}
}

handleInputChange(e) {
const target = e.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
Expand All @@ -44,26 +62,38 @@ class FormAdd extends Component {
const newUser = {
name: this.state.name,
email: this.state.email,
age: parseInt(this.state.age, 10),
age: this.state.age,
gender: this.state.gender
}

const method = this.props.userID ? 'put' : 'post';
const params = this.props.userID ? this.props.userID : '';

axios({
method: 'post',
method: method,
responseType: 'json',
url: `${this.props.server}/api/users/`,
url: `${this.props.server}/api/users/${params}`,
data: newUser
})
.then((response) => {
this.setState({
name: '',
email: '',
age: '',
gender: '',
formClassName: 'success',
formSuccessMessage: response.data.msg
});
this.props.onUsersListChange(response.data.addedUser);

if (!this.props.userID) {
this.setState({
name: '',
email: '',
age: '',
gender: ''
});
this.props.onUserAdded(response.data.result);
}
else {
this.props.onUserUpdated(response.data.result);
}

})
.catch((err) => {
if (err.response) {
Expand All @@ -77,7 +107,7 @@ class FormAdd extends Component {
else {
this.setState({
formClassName: 'warning',
formErrorMessage: 'Something went wrong.'
formErrorMessage: 'Something went wrong.' + err
});
}
});
Expand Down Expand Up @@ -110,10 +140,10 @@ class FormAdd extends Component {
<Form.Group widths='equal'>
<Form.Input
label='Age'
type='number'
type='text'
placeholder='18'
min={0}
max={120}
max={130}
name='age'
value={this.state.age}
onChange={this.handleInputChange}
Expand All @@ -139,11 +169,11 @@ class FormAdd extends Component {
header='Woah!'
content={formErrorMessage}
/>
<Button color='green' floated='right'>Add</Button>
<Button color={this.props.buttonColor} floated='right'>{this.props.buttonSubmitTitle}</Button>
<br /><br /> {/* Yikes! */}
</Form>
);
}
}

export default FormAdd;
export default FormUser;
39 changes: 0 additions & 39 deletions react-src/src/components/ModalAdd/ModalAdd.js

This file was deleted.

30 changes: 30 additions & 0 deletions react-src/src/components/ModalUser/ModalUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { Component } from 'react';
import { Button, Modal } from 'semantic-ui-react';

import FormUser from '../FormUser/FormUser';

class ModalUser extends Component {

render() {
return (
<Modal
trigger={<Button color={this.props.buttonColor}>{this.props.buttonTriggerTitle}</Button>}
size='tiny'
>
<Modal.Header>{this.props.headerTitle}</Modal.Header>
<Modal.Content>
<FormUser
buttonSubmitTitle={this.props.buttonSubmitTitle}
buttonColor={this.props.buttonColor}
userID={this.props.userID}
onUserAdded={this.props.onUserAdded}
onUserUpdated={this.props.onUserUpdated}
server={this.props.server}
/>
</Modal.Content>
</Modal>
);
}
}

export default ModalUser;
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
import React, { Component } from 'react';
import { Button, Table } from 'semantic-ui-react';

const ButtonAction = () => (
<div>
<Button color='blue'>Edit</Button>
<Button color='black'>Delete</Button>
</div>
)
import ModalUser from '../ModalUser/ModalUser';

class TableData extends Component {
class TableUser extends Component {

render() {
const users = this.props.users;

let user = users.map((user) =>
let users = this.props.users;

users = users.map((user) =>
<Table.Row key={user._id}>
<Table.Cell>{user.name}</Table.Cell>
<Table.Cell>{user.email}</Table.Cell>
<Table.Cell>{user.age}</Table.Cell>
<Table.Cell>{user.gender}</Table.Cell>
<Table.Cell><ButtonAction /></Table.Cell>
<Table.Cell>
<ModalUser
headerTitle='Edit User'
buttonTriggerTitle='Edit'
buttonSubmitTitle='Save'
buttonColor='blue'
userID={user._id}
onUserUpdated={this.props.onUserUpdated}
server={this.props.server}
/>
<Button color='black'>Delete</Button>
</Table.Cell>
</Table.Row>
);

user = [...user].reverse();
users = [...users].reverse();

return (
<Table singleLine>
Expand All @@ -37,11 +44,11 @@ class TableData extends Component {
</Table.Row>
</Table.Header>
<Table.Body>
{user}
{users}
</Table.Body>
</Table>
);
}
}

export default TableData;
export default TableUser;
Loading

0 comments on commit 6fff987

Please sign in to comment.