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
38 changes: 32 additions & 6 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
import React from 'react';
import './App.css';
import chatMessages from './data/messages.json';
import TimeStamp from './components/TimeStamp';
import ChatEntry from './components/ChatEntry';
Comment on lines +4 to +5

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither of these components need to be imported. You should only import components you're directly using. While Chatlog uses ChatEntry and ChatEntry uses TimeStamp, they only need to be imported in the files in which the actual component is being used.

import ChatLog from './components/ChatLog';
import { useState } from 'react';

const App = () => {
const [messages, setMessages] = useState(chatMessages);

const handleLike = (id) => {
const updatedMessages = messages.map((message) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works great in this case though I'd recommend using a callback with the update function because it will give you access to the most current previous state, which will ensure you're updating the correct value(s). To use that approach, pass a callback to the update function instead of a value. React will invoke that callback with an argument that represents the most recent state. Then you can use that in whatever computation you need and return the new value you want to set. e.g.

const handleLike = (id) => {
  setMessages((previousMessages) => {
    return previousMessages.map((message) => {
      if (message.id === id) {
        return {
          ...message,
          liked: !message.liked,
        }
      }
    });
  });
};

if (message.id === id) {
return {
...message,
liked: !message.liked,
};
}
return message;
});

setMessages(updatedMessages);
};

const likedMessagesCount = messages.reduce(
(count, message) => (message.liked ? count + 1 : count),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍🏽

0
);

return (
<div id="App">
<header>
<h1>Application title</h1>
<h1>Chat Log</h1>
<div className="liked-messages-count">{likedMessagesCount} {'❤️'}s</div>
</header>
<main>
{/* Wave 01: Render one ChatEntry component
Wave 02: Render ChatLog component */}
<ChatLog entries={messages} handleLike={handleLike}/>
</main>
</div>
);
};

</div>
)
};

export default App;
4 changes: 4 additions & 0 deletions src/components/ChatEntry.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ button {
text-align: left;
}

.chat-entry.remote {
text-align: right;
}

.chat-entry.local .entry-time {
text-align: right;
}
Expand Down
29 changes: 21 additions & 8 deletions src/components/ChatEntry.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
import React from 'react';
import './ChatEntry.css';
import PropTypes from 'prop-types';
import TimeStamp from './TimeStamp';



const ChatEntry = (props) => {

const handleClick = () => {
props.handleLike(props.id)
};

const chatEntryClass = props.sender === 'Vladimir' ? 'chat-entry local' : 'chat-entry remote';


return (
<div className="chat-entry local">
<h2 className="entry-name">Replace with name of sender</h2>
<section className="entry-bubble">
<p>Replace with body of ChatEntry</p>
<p className="entry-time">Replace with TimeStamp component</p>
<button className="like">🤍</button>
</section>
<div className={chatEntryClass}>
<h2 className='entry-name'>{props.sender} </h2>
<section className='entry-bubble'>
<p>{props.body}</p>
<p className='entry-time'> <TimeStamp time={props.timeStamp} /> </p>
<button onClick={handleClick} className="like">{props.liked ? '❤️' : '🤍'}</button>
</section>
</div>
);
};

ChatEntry.propTypes = {
//Fill with correct proptypes
sender: PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
timestamp: PropTypes.element.isRequired,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple things to note about timestamp. First, you're passing a prop to this component called timeStamp, but this definition is for timestamp, these are different names. Second, PropTypes.element means that the type of value is a React element; however, if you meant for this to be timeStamp, then I think you're passing that prop as a string, so the type should be updated accordingly.

};

export default ChatEntry;
33 changes: 33 additions & 0 deletions src/components/ChatLog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import ChatEntry from './ChatEntry';

const ChatLog = ({ entries, handleLike }) => {
return (
<div>
{entries.map((entry) => (
<ChatEntry
id={entry.id}
sender={entry.sender}
body={entry.body}
timeStamp={entry.timeStamp}
handleLike={handleLike}
liked={entry.liked}
key={entry.id}
/>
))}
</div>
);
};

ChatLog.propTypes = {
entries: PropTypes.arrayOf(
PropTypes.shape({
sender: PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
TimeStamp: PropTypes.string.isRequired,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're getting a warning in the developer tools console for this, TimeStamp isn't defined. I believe the prop you're passing is called timeStamp.

})
).isRequired,
};

export default ChatLog;