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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ Follow your curiosity to learn more about front-end testing:
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)



1 change: 1 addition & 0 deletions project-docs/wave-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ Usually our convention for styles in React applications is to have a separate CS
## Tests

This component has a set of tests that ensure that props passed to the component appear in the browser. To pass the tests, the component must be named `ChatEntry` with props `sender`, `body`, and `timeStamp`.

28 changes: 24 additions & 4 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
import React from 'react';
import './App.css';
import { useState } from 'react';
import chatMessages from './data/messages.json';
import ChatLog from './components/Chatlog';

const App = () => {
const [chatJson, setchatJson] = useState(chatMessages);

const updatechatJson = (id) => {
const updatedChat = chatJson.map((chat) => {
if (chat.id === id) {
return { ...chat, liked: !chat.liked };
} else {
return chat;
}
});
setchatJson(updatedChat);
};

const Hearts = () => {
return chatJson.reduce((total, message) => {
return message.liked ? total + 1 : total;
}, 0);
};

return (
<div id="App">
<header>
<h1>Application title</h1>
<h1>Human & Robot</h1>
<h2 className="like">LikeCount: {Hearts()} ❤️</h2>

Choose a reason for hiding this comment

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

The tests were expecting this text to read "3 ❤️s", which is why you saw those tests fail.

</header>
<main>
{/* Wave 01: Render one ChatEntry component
Wave 02: Render ChatLog component */}
<ChatLog entries={chatJson} setchatJson={updatechatJson}></ChatLog>
</main>
</div>
);
};

export default App;
27 changes: 21 additions & 6 deletions src/components/ChatEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,36 @@ import React from 'react';
import './ChatEntry.css';
import PropTypes from 'prop-types';

const filledHeart = '❤️';
const emptyHeart = '🤍';

const ChatEntry = (props) => {
const heartOrNot = props.liked ? filledHeart : emptyHeart;
const className = props.sender === 'Estragon' ? 'remote' : 'local';

const handleClick = (id) => {
props.handleLike(id);
};
return (
<div className="chat-entry local">
<h2 className="entry-name">Replace with name of sender</h2>
<div className={`chat-entry ${className}`}>
<h2 className="entry-name"> {props.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>{props.body}</p>
<p className="entry-time">{props.timeStamp}</p>

Choose a reason for hiding this comment

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

Here's where you'd use the provided Timestamp component in order to format this into a friendly-to-read date

<button className="like" onClick={() => handleClick(props.id)}>
{heartOrNot}
</button>
</section>
</div>
);
};

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,
};

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

const ChatLog = (props) => {
const jsonMessages = props.entries.map((messages) => {
return (
<ChatEntry
id={messages.id}
sender={messages.sender}
body={messages.body}
timeStamp={messages.timeStamp}
liked={messages.liked}
key={messages.key}
handleLike={props.setchatJson}
></ChatEntry>
);
});
return <div className="chat-log">{jsonMessages}</div>;
};

ChatEntry.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,
key: PropTypes.number.isRequired,
})
),
};

export default ChatLog;
13 changes: 11 additions & 2 deletions src/components/TimeStamp.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import React from 'react';
import { DateTime } from 'luxon';
import PropTypes from 'prop-types';

const TimeStamp = (props) => {
const timeStamp = (props) => {

Choose a reason for hiding this comment

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

No need to have modified this component. Also, React components by convention use capital letters as their names, so Timestamp was correct.

const time = DateTime.fromISO(props.time);
const absolute = time.toFormat('MMMM Do YYYY, h:mm:ss a');
const relative = time.toRelative();

return <span title={absolute}>{relative}</span>;
};

export default TimeStamp;
timeStamp.propTypes = {
timeStampmessage: PropTypes.arrayOf(
PropTypes.shape({
messageContent: PropTypes.number,
})
),
};
export default timeStamp;