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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
32 changes: 28 additions & 4 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
import React from 'react';

Choose a reason for hiding this comment

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

If you look at this "Files changed" section of your pull request it says that 1472 files were committed and pushed to the repo. It looks like you created a virtual environment and then pushed up all the files associated with it. React applications do not need a virtual environment (but Flask projects do). Be mindful of what files you push up to a repository and add to a PR.

It can be helpful to use git add SpecificFileName.js instead of using git add . so that you don't accidentally add and commit files you don't mean to.

In industry, the person reviewing your PR would ask that you resubmit this PR without the venv directory and files so you'd need to figure out how to remove them from your commit history and push the changes again.

import { useState } from 'react';
import './App.css';
import chatMessages from './data/messages.json';
import ChatLog from './components/ChatLog.js';

Choose a reason for hiding this comment

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

This file name is ChatLog.js here, but the name is actually Chatlog.js which prevents the code from compiling. Did you run into any errors when trying to push up the ChatLog.js to your github repo?


const chatDataList = chatMessages

Choose a reason for hiding this comment

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

There's no need to use another variable to reference chatMessages. On line 4 when you import the data from './data/messages.json' you reference it with chatMessages so from there on out you can just refer to the data with chatMessages.


const App = () => {
const [chatData, setChatData] = useState(chatDataList);

Choose a reason for hiding this comment

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

Instead of setting state with chatDataList, you can set the state with chatMessages directly


const toggleHeart = (id) => {
setChatData(chatData => chatData.map(message => {
if(message.id === id) {
return {...message, liked: !message.liked}
} else {
return message;
}
}));
}

const calcHearts = (chatData) => {
return chatData.reduce((total, message) => {
return total + message.liked;

Choose a reason for hiding this comment

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

Way to use reduce here!

It's cool that you leveraged the knowledge that in JavaScript if you add a boolean to something it gets cast as a number (0 for false, 1 for true). Prefer you use conditional logic to add a number to a number instead, like:

return chat.liked ? total + 1 : total;

}, 0)
};

const totalHearts = calcHearts(chatData);

return (
<div id="App">
<header>
<h1>Application title</h1>
<h1>My Chat Log</h1>
</header>
<main>
{/* Wave 01: Render one ChatEntry component
Wave 02: Render ChatLog component */}
<h2>{totalHearts} ❤️s</h2>
<ChatLog entries={chatData} onToggleHeart ={toggleHeart}/>
</main>
</div>
);
};

export default App;
export default App;
19 changes: 14 additions & 5 deletions src/components/ChatEntry.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import React from 'react';
import './ChatEntry.css';
import PropTypes from 'prop-types';
import TimeStamp from './TimeStamp';

const ChatEntry = (props) => {
const heartColor = props.liked ? '❤️' : '🤍';

Choose a reason for hiding this comment

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

👍


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>
<h2 className="entry-name">{props.sender}</h2>
<section className="entry-bubble">
<p>{props.body}</p>
<p className="entry-time"><TimeStamp time={props.timeStamp}/></p>

Choose a reason for hiding this comment

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

Nice use of the provided TimeStamp component

<button className="like" onClick={() => props.onToggleHeart(props.id)}>{heartColor}</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,
onToggleHeart: PropTypes.func.isRequired,
};

export default ChatEntry;
16 changes: 8 additions & 8 deletions src/components/ChatEntry.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from "react";
import "@testing-library/jest-dom/extend-expect";
import ChatEntry from "./ChatEntry";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import React from 'react';
import '@testing-library/jest-dom/extend-expect';
import ChatEntry from './ChatEntry';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';

describe("Wave 01: ChatEntry", () => {
describe('Wave 01: ChatEntry', () => {
beforeEach(() => {
render(
<ChatEntry
Expand All @@ -14,15 +14,15 @@ describe("Wave 01: ChatEntry", () => {
);
});

test("renders without crashing and shows the sender", () => {
test('renders without crashing and shows the sender', () => {
expect(screen.getByText(/Joe Biden/)).toBeInTheDocument();
});

test("that it will display the body", () => {
test('that it will display the body', () => {
expect(screen.getByText(/Get out by 8am/)).toBeInTheDocument();
});

test("that it will display the time", () => {
test('that it will display the time', () => {
expect(screen.getByText(/\d+ years ago/)).toBeInTheDocument();
});
});
48 changes: 24 additions & 24 deletions src/components/ChatLog.test.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
import React from "react";
import "@testing-library/jest-dom/extend-expect";
import ChatLog from "./ChatLog";
import { render, screen } from "@testing-library/react";
import React from 'react';
import '@testing-library/jest-dom/extend-expect';
import ChatLog from './ChatLog.js';
import { render, screen } from '@testing-library/react';

const LOG = [
{
sender: "Vladimir",
body: "why are you arguing with me",
timeStamp: "2018-05-29T22:49:06+00:00",
sender: 'Vladimir',
body: 'why are you arguing with me',
timeStamp: '2018-05-29T22:49:06+00:00',
},
{
sender: "Estragon",
body: "Because you are wrong.",
timeStamp: "2018-05-29T22:49:33+00:00",
sender: 'Estragon',
body: 'Because you are wrong.',
timeStamp: '2018-05-29T22:49:33+00:00',
},
{
sender: "Vladimir",
body: "because I am what",
timeStamp: "2018-05-29T22:50:22+00:00",
sender: 'Vladimir',
body: 'because I am what',
timeStamp: '2018-05-29T22:50:22+00:00',
},
{
sender: "Estragon",
body: "A robot.",
timeStamp: "2018-05-29T22:52:21+00:00",
sender: 'Estragon',
body: 'A robot.',
timeStamp: '2018-05-29T22:52:21+00:00',
},
{
sender: "Vladimir",
body: "Notabot",
timeStamp: "2019-07-23T22:52:21+00:00",
sender: 'Vladimir',
body: 'Notabot',
timeStamp: '2019-07-23T22:52:21+00:00',
},
];

describe("Wave 02: ChatLog", () => {
describe('Wave 02: ChatLog', () => {
beforeEach(() => {
render(<ChatLog entries={LOG} />);
});

test("renders without crashing and shows all the names", () => {
test('renders without crashing and shows all the names', () => {
[
{
name: "Vladimir",
name: 'Vladimir',
numChats: 3,
},
{
name: "Estragon",
name: 'Estragon',
numChats: 2,
},
].forEach((person) => {
Expand All @@ -56,7 +56,7 @@ describe("Wave 02: ChatLog", () => {
});
});

test("renders an empty list without crashing", () => {
test('renders an empty list without crashing', () => {
const element = render(<ChatLog entries={[]} />);
expect(element).not.toBeNull();
});
Expand Down
35 changes: 35 additions & 0 deletions src/components/Chatlog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import PropTypes from 'prop-types';
import ChatEntry from './ChatEntry.js';

const ChatLog = (props) => {

return (
<>
{props.entries.map((entry) => (
<ChatEntry
id={entry.id}
sender={entry.sender}
body={entry.body}
timeStamp={entry.timeStamp}
key={entry.id}
liked={entry.liked}
onToggleHeart={props.onToggleHeart}
/>
))}
</>
)

}

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,
})),
onToggleHeart: PropTypes.func.isRequired,
}

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

const TimeStamp = (props) => {
const time = DateTime.fromISO(props.time);
Expand Down
Loading