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

const countTotalLikes = (chatData) =>{
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

Arrow function formatting issue: missing spaces around the arrow operator. Should be (chatData) => { instead of (chatData) =>{ to follow JavaScript formatting conventions and maintain consistency with the rest of the codebase.

Suggested change
const countTotalLikes = (chatData) =>{
const countTotalLikes = (chatData) => {

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

❗️👀 Functions that are only used within a specific component, like countTotalLikes is only used inside the App component on line 14, should be defined inside the component to make the code more readable because it keeps related logic together.

Therefore, this function should be defined in the App component (like you do with handleToggleLike on line 16).

return chatData.reduce((total, chat) => {
return total + (chat.liked ? 1 : 0);
}, 0);
};

const App = () => {
const[chatData, setChatData] = useState(messages);
const totalLikes = countTotalLikes(chatData);

const handleToggleLike = id =>{
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

Arrow function formatting issue: missing space after id and before the arrow operator. Should be id => { instead of id =>{ to follow JavaScript formatting conventions and maintain consistency.

Suggested change
const handleToggleLike = id =>{
const handleToggleLike = id => {

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Take care to pay attention to your code style while you're writing code or take some time to look over your work before opening a pull request for review.

In industry, it would be frowned upon to request a review for code with style issues. these issues should be cleaned up beforehand.

setChatData(chatData => {
return chatData.map(chat => {
Comment on lines +17 to +18
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice job using the callback-style for updating the state.

if(chat.id === id) {
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

Missing space in conditional statement. Should be if (chat.id === id) instead of if(chat.id === id) to follow JavaScript formatting conventions and maintain readability.

Suggested change
if(chat.id === id) {
if (chat.id === id) {

Copilot uses AI. Check for mistakes.
return ({ ...chat, liked: !chat.liked});
} else {
return chat;
}
});
});
};

return (
<div id="App">
<header>
<h1>Application title</h1>
<h1>Chat between Vladimir and Estragon</h1>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can you think of a way to dynamically get the senders' names without hardcoding "Vladimir" and "Estragon" here?

<h2>{totalLikes} ❤️s</h2>
</header>
<main>
{/* Wave 01: Render one ChatEntry component
Wave 02: Render ChatLog component */}
{
// <ChatEntry sender = {message1.sender} body = {message1.body} timeStamp = '2018-05-29T22:49:06+00:00' >
// </ChatEntry>
/* Wave 01: Render one ChatEntry component
messages*/
}
Comment on lines +35 to +40
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

Commented out code should be removed before merging. These leftover comments from Wave 01 are no longer needed since the implementation is complete with the ChatLog component.

Suggested change
{
// <ChatEntry sender = {message1.sender} body = {message1.body} timeStamp = '2018-05-29T22:49:06+00:00' >
// </ChatEntry>
/* Wave 01: Render one ChatEntry component
messages*/
}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Commented out code is confusing to other devs who might not understand why the code has been left in if it's no longer needed. It's also prone to introducing bugs because the code could get uncommented and the code would unintentionally execute.

It also compromises your codebase's readability by adding clutter and making it less concise.

<ChatLog
entries = {chatData}
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

Inconsistent spacing around equals signs in JSX props. The code uses entries = {chatData} with spaces, but standard JSX formatting omits spaces (e.g., entries={chatData}). This is inconsistent with the prop assignments in ChatLog.jsx (lines 8-14).

Suggested change
entries = {chatData}
entries={chatData}

Copilot uses AI. Check for mistakes.
toggleLike={handleToggleLike}> </ChatLog>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Prefer to have the closing tag on its own line (like how you put the opening tag on its own line) to help with readability.

</main>
</div>
);
};

export default App;

2 changes: 1 addition & 1 deletion src/components/ChatEntry.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,4 @@ button {

.chat-entry.remote .entry-bubble:hover::before {
background-color: #a9f6f6;
}
}
25 changes: 16 additions & 9 deletions src/components/ChatEntry.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import './ChatEntry.css';
import TimeStamp from './TimeStamp.jsx';
import PropTypes from 'prop-types';

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

Choose a reason for hiding this comment

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

Nice job destructuring your different props. This is beneficial for a few reasons:

  • you know every possible prop right away
  • you know when a prop is being unused, in order to remove it
  • knowing which props are being used will also remind you what you need to validate

const heartColor = liked ? '❤️' : '🤍';
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">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It was an optional enhancement, but how could you determine if a chat was from a 'local' sender vs a 'remote' sender so that the chat bubbles would have different styles applied to it?

If you have time to re-visit this project for React.js review, it would be good practice to try applying local vs. remote classes to the components so they render differently depending on who sent the message.

<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}></TimeStamp></p>
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

Inconsistent spacing around the equals sign. The code uses time = {timeStamp} with spaces, but the convention in JSX is typically to omit spaces around equals signs in props (like time={timeStamp}). This is inconsistent with the prop assignments in ChatLog.jsx (lines 8-14) and elsewhere in this file.

Suggested change
<p className="entry-time"><TimeStamp time = {timeStamp}></TimeStamp></p>
<p className="entry-time"><TimeStamp time={timeStamp}></TimeStamp></p>

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice job using the provided TimeStamp component 👍

<button className="like" onClick={()=>toggleLike(id)}>{heartColor}</button>
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

Arrow function formatting issue: missing space before the arrow operator. The function should be written as () => toggleLike(id) rather than ()=>toggleLike(id) to follow standard JavaScript formatting conventions and maintain consistency with the codebase (see App.jsx lines 6, 16, and throughout the file).

Suggested change
<button className="like" onClick={()=>toggleLike(id)}>{heartColor}</button>
<button className="like" onClick={() => toggleLike(id)}>{heartColor}</button>

Copilot uses AI. Check for mistakes.
</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.isRequired,
toggleLike: PropTypes.func,
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The toggleLike prop should be marked as isRequired since the component uses it without any null/undefined check in the onClick handler (line 13). If toggleLike is undefined, clicking the like button will cause a runtime error. Mark it as .isRequired or add a conditional check before usage.

Suggested change
toggleLike: PropTypes.func,
toggleLike: PropTypes.func.isRequired,

Copilot uses AI. Check for mistakes.
};

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

const ChatLog = ({ entries, toggleLike }) => {
const chatComponents = entries.map(entry => {
return (<ChatEntry
key={entry.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.

👍 The key attribute is important for React to be able to detect certain kinds of data changes in an efficient manner. We're also using the id for our own id prop, so it might feel redundant to pass both, but one is for our logic and one is for React internals.

id={entry.id}
sender={entry.sender}
body={entry.body}
timeStamp={entry.timeStamp}
liked={entry.liked}
toggleLike={toggleLike}>
</ChatEntry>
);
});
return (
<>
{chatComponents}
</>

);
};

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,
toggleLike: PropTypes.func,
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

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

The toggleLike prop should be marked as isRequired to match the usage in ChatEntry component where it's called unconditionally. Without this prop, the ChatEntry component will throw a runtime error when the like button is clicked.

Suggested change
toggleLike: PropTypes.func,
toggleLike: PropTypes.func.isRequired,

Copilot uses AI. Check for mistakes.

};

export default ChatLog;