Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.3.1'
ruby '2.4.1'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.1'
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ DEPENDENCIES
webpacker

RUBY VERSION
ruby 2.3.1p112
ruby 2.4.1p111

BUNDLED WITH
1.16.2
1.16.4
35 changes: 34 additions & 1 deletion app/javascript/components/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const mapStateToProps = (state) => {
};
};

// Used to
const mapDispatchToProps = (dispatch) => {
return {
signIn: userInfo => dispatch(signIn(userInfo)),
Expand All @@ -25,9 +26,12 @@ const mapDispatchToProps = (dispatch) => {
export class App extends Component {
constructor() {
super();
// These are all stored in state so that
// signIn and signUp forms can update them from
// their individual component
this.state = {
signup: false,
signin: false,
signin: false,
admin: false,
first: '',
email: '',
Expand All @@ -42,6 +46,8 @@ export class App extends Component {
this.handleChange = this.handleChange.bind(this);
}

// Grabs the required information to send with post
// request to save information to database
signUp() {
axios.post('/signup', {
user: {
Expand All @@ -61,38 +67,56 @@ export class App extends Component {
});
}

// Send the login information via post request
signIn() {
axios.post('/login', {
username: this.state.username,
password: this.state.password
}).then((res) => {
// If the response is 'failed', then
// alert the user. I chose to user alert
// so that the user is aware that they
// were not able to log in
if (res.data === 'failed') {
alert('Invalid username or password');
} else {
// If successfully signed in, I need to
// set the state with first name for the
// nav bar greeting and set the admin,
// username, and password back to a
// neutral state
this.setState({
admin: false,
first: res.data.first,
username: '',
password: ''
});

// Send username, isAdmin, and userId information to the redux store
// and then close the signIn modal
this.props.signIn({ username: res.data.username, isAdmin: res.data.isAdmin, userId: res.data.id });
this.toggleModal('signin');
}
});
}

// Send a delete request that destroys the user session
// and set firstName to neutral state
signOut() {
axios.delete('/logout')
.then((res) => {
this.setState({
first: '',
});

// Call the redux action to sign user out
this.props.signOut();
});
}

// If the event name is 'admin' set state true or
// false for the signup toggle, else update the
// corresponding state name with value
handleChange(event) {
if (event.target.name === 'admin') {
this.setState({
Expand All @@ -118,6 +142,8 @@ export class App extends Component {
)
}

// If there is no user signed in, show the sign in and sign up buttons
// If there is a user signed in, then greet them with their first name
render() {
return (
<div>
Expand Down Expand Up @@ -153,3 +179,10 @@ export class App extends Component {
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

/*
I chose to use modals here because I believe it makes for a better user experience
if the user isn't redirected from page to page. The state stored in this component are
all changed according to user input whereas the Redux store is used to set persistant
data such as username and if their admin.
*/
45 changes: 45 additions & 0 deletions app/javascript/components/Messages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,18 @@ export class Messages extends Component {
this.paginationFilter = this.paginationFilter.bind(this);
}

// Invoke the function that gets the messages
// from the database when the component mounts
componentDidMount() {
this.getMessages();
}

// Makes the getRequest to /messages and sets
// state of paginationNum(the maximum amount
// of pages), sends the messages to the store
// for easy access in other components, and also
// sets the first 5 messages to show using the
// paginationFilter function
getMessages() {
axios.get('/messages')
.then((res) => {
Expand All @@ -83,6 +91,16 @@ export class Messages extends Component {
});
}

// Verifies that the messages is at least 4
// characters. If successfully submitted, then
// runs getMessages function to retrieve newest
// message, changes the page back to where user
// was previously and deletes the user input
// from the messageInput box. If not successful
// shows user error message to make sure they are
// logged in which is the likely cause the message
// did not get saved to database. Alerts the user
// if the message is not at least 4 characters.
messageSubmit() {
if (this.state.message.length >= 4) {
axios.post('/message', { messages: { message: this.state.message, user_id: this.props.userId }})
Expand All @@ -100,13 +118,20 @@ export class Messages extends Component {
}
}

// Handles the deleting of a message by sending
// the message id with the delete request to /message
messageDelete(id) {
axios.delete('/message', { data: { messageId: id }})
.then(() => {
this.getMessages();
});
}

// Updates a previously inputted message using a
// patch request to /message. Sends message id
// and the new message along with the request. In
// order to submit, the message must be at least
// 4 characters.
messageUpdate(id) {
if (this.state.message.length >= 4) {
axios.patch('/message', { messageId: id, newMessage: this.state.message })
Expand All @@ -119,6 +144,9 @@ export class Messages extends Component {
}
}

// If a message is sent via argument: opens the modal to edit message,
// sets the selected message in state for access in Selected Message
// component. If no message selected, closes the modal.
selectMessage(message) {
if (message) {
this.setState({
Expand All @@ -133,6 +161,10 @@ export class Messages extends Component {
}
}

// compareFunction passed into the sort method
// Assigns value, 0, 1, or -1, when comparing
// two properties. If descending order, then
// multiply the 'score' by -1
compareValues(key, createdAt, order='asc') {
return function(a, b) {
// Grab the user property within message
Expand Down Expand Up @@ -164,6 +196,11 @@ export class Messages extends Component {
};
}

// Takes in an array that has which category to filter
// and which direction to sort in. Invoke the sort method
// with the compareValues function to sort the messages. Set
// allMessages to the newly sorted and run the paginationFilter
// with the first page passed in.
filter(action) {
let category = action[0];
let createdAt = category === 'created_at' ? false : true;
Expand Down Expand Up @@ -213,6 +250,8 @@ export class Messages extends Component {
}
}

// Sets the currentMessages state which are the
// messages that are going to be displayed
paginationFilter(pageNum) {
// Designate how many messages to show
let endSlice = pageNum * 5;
Expand All @@ -225,6 +264,12 @@ export class Messages extends Component {
});
}

// Map through the current messages and display the first name, username, and the message
// Incorporate conditional rendering so that the current user can edit/delete their own message
// or if they are admin, can edit/delete any users message
// Create an array the length of the paginationNum and map through to create each individual
// pagination number
// Conditional renders the SelectedMessage component depending on the value of selectMessage
render() {
return (
<div>
Expand Down