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
16 changes: 14 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import './App.css';
import { useState } from 'react';
import messages from './data/messages.json';
import ChatLog from './components/ChatLog';


const App = () => {
const [entries, setEntries] = useState(messages);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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


const toggleLiked = (id) => {
setEntries((prev) => prev.map((m) => (m.id === id ? { ...m, liked: !m.liked } : m)));
};
Comment on lines +10 to +12
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The only piece of feedback I have here is that your naming for the message object, m, is not descriptive of the data that it is holding. This will give room to miscommunication and require more cognitive load on the reader's part to decipher what the shape of the object is. I would suggest for you to choose a name more descriptive like message.


const likeCount = entries.filter((m) => m.liked).length;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You'll see that there are a number of ways to implement this logic. Though this is functionally sound, I will say that if I see the .filter method I would assume that you would be working an array of data more in-depth. For simply counting the number of liked messages I would opt for something like .reduce instead.

Find more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce


return (
<div id="App">
<header>
<h1>Application title</h1>
<div className="likes-count">{likeCount} ❤️s</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

</header>
<main>
{/* Wave 01: Render one ChatEntry component
Wave 02: Render ChatLog component */}
<ChatLog entries={entries} onToggleLiked={toggleLiked} />
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

</main>
</div>
);
Expand Down
31 changes: 22 additions & 9 deletions src/components/ChatEntry.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import './ChatEntry.css';
import PropTypes from 'prop-types';
import TimeStamp from './TimeStamp';

const ChatEntry = () => {
const ChatEntry = ({ id, sender, body, timeStamp, liked, onToggleLiked }) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Excellent formatting.

return (
// Replace the outer tag name with a semantic element that fits our use case
<replace-with-relevant-semantic-element className="chat-entry local">
<h2 className="entry-name">Replace with name of sender</h2>
<article className="chat-entry local">
<h2 className="entry-name">{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>
<p>{body}</p>
<p className="entry-time">
<TimeStamp time={timeStamp} />
</p>
<button
className="like"
onClick={() => onToggleLiked && onToggleLiked(id)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@SophieQA, not sure why you have onToggleLiked && onToggleLiked(id) as the return value here. You are essentially writing a function that returns true. Simply need to have a function to receive the automatically passed in event and then make a call to onToggleLiked with the appropriate id. You can remove the onToggleLiked function object.

Suggested change
onClick={() => onToggleLiked && onToggleLiked(id)}
onClick={() => onToggleLiked(id)}

>
{liked ? '❤️' : '🤍'}
</button>
</section>
</replace-with-relevant-semantic-element>
</article>
);
};

ChatEntry.propTypes = {
// Fill with correct proptypes
id: PropTypes.number.isRequired,
sender: PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
timeStamp: PropTypes.string.isRequired,
liked: PropTypes.bool,
onToggleLiked: PropTypes.func,
Comment on lines +26 to +31
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great work on these proptypes, remember that they have been sunsetted in React and that will be using other type checking frameworks like Typescript.

};

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

const ChatLog = ({ entries, onToggleLiked }) => {
const chatEntries = entries.map((message) => {
return (
<ChatEntry
key={message.id}
id={message.id}
sender={message.sender}
body={message.body}
timeStamp={message.timeStamp}
liked={message.liked}
onToggleLiked={onToggleLiked}
Comment on lines +9 to +15
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

/>
);
});

return (
<section className="chat-log">
{chatEntries}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

</section>
);
};

ChatLog.propTypes = {
entries: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
sender: PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
timeStamp: PropTypes.string.isRequired,
liked: PropTypes.bool.isRequired,
})
).isRequired,
onToggleLiked: PropTypes.func.isRequired,
};
Comment on lines +27 to +38
Copy link
Copy Markdown

Choose a reason for hiding this comment

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


export default ChatLog;