From 58bc1b203f0d4de04dbf6d60f4e0d4b2e1b3875a Mon Sep 17 00:00:00 2001 From: Julie Date: Mon, 20 Jun 2022 15:28:08 -0700 Subject: [PATCH 1/6] creates a ChatLog with ChatEntry components --- src/App.js | 6 +++--- src/components/ChatEntry.js | 14 ++++++++++---- src/components/ChatLog.js | 26 ++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 src/components/ChatLog.js diff --git a/src/App.js b/src/App.js index c10859093..620c42db3 100644 --- a/src/App.js +++ b/src/App.js @@ -1,16 +1,16 @@ import React from 'react'; import './App.css'; import chatMessages from './data/messages.json'; +import ChatLog from './components/ChatLog'; const App = () => { return (
-

Application title

+

Julie's Chatlog App

- {/* Wave 01: Render one ChatEntry component - Wave 02: Render ChatLog component */} +
); diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index b92f0b7b2..f68eb288d 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,14 +1,17 @@ import React from 'react'; +import TimeStamp from './TimeStamp'; import './ChatEntry.css'; import PropTypes from 'prop-types'; const ChatEntry = (props) => { return (
-

Replace with name of sender

+

{props.sender}

-

Replace with body of ChatEntry

-

Replace with TimeStamp component

+

{props.body}

+

+ +

@@ -16,7 +19,10 @@ const ChatEntry = (props) => { }; ChatEntry.propTypes = { - //Fill with correct proptypes + sender: PropTypes.string, + body: PropTypes.string, + timeStamps: PropTypes.string, + liked: PropTypes.bool, }; export default ChatEntry; diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js new file mode 100644 index 000000000..599bcba83 --- /dev/null +++ b/src/components/ChatLog.js @@ -0,0 +1,26 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './ChatLog.css'; +import ChatEntry from './ChatEntry'; + +const ChatLog = (props) => { + const chatComponents = props.entries.map((chat) => { + return ( + + ); + }); + + return
{chatComponents}
; +}; + +ChatLog.propTypes = { + chatComponents: PropTypes.array, +}; + +export default ChatLog; From a80981edb8ef5e2d17d5d7f2a9a5aa256af3f89c Mon Sep 17 00:00:00 2001 From: Julie Date: Mon, 20 Jun 2022 16:46:21 -0700 Subject: [PATCH 2/6] adds heart button to like and unlike messages --- src/components/ChatEntry.js | 15 +++++++++++++-- src/components/ChatLog.js | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index f68eb288d..d0f6d5df5 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,9 +1,18 @@ import React from 'react'; import TimeStamp from './TimeStamp'; +import { useState } from 'react'; import './ChatEntry.css'; import PropTypes from 'prop-types'; const ChatEntry = (props) => { + const [liked, setLiked] = useState(false); + + function changeLike() { + setLiked(!liked); + } + + const displayLike = liked ? '❤️' : '🤍'; + return (

{props.sender}

@@ -12,7 +21,9 @@ const ChatEntry = (props) => {

- +
); @@ -21,7 +32,7 @@ const ChatEntry = (props) => { ChatEntry.propTypes = { sender: PropTypes.string, body: PropTypes.string, - timeStamps: PropTypes.string, + timeStamp: PropTypes.string, liked: PropTypes.bool, }; diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index 599bcba83..0b154826a 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -20,7 +20,7 @@ const ChatLog = (props) => { }; ChatLog.propTypes = { - chatComponents: PropTypes.array, + entries: PropTypes.array.isRequired, }; export default ChatLog; From 3258406ab257d05919765358414218417500e495 Mon Sep 17 00:00:00 2001 From: Julie Date: Mon, 20 Jun 2022 21:05:41 -0700 Subject: [PATCH 3/6] updates PropTypes, moves liked state tracking to App --- src/App.js | 18 ++++++++-- src/App.test.js | 60 +++++++++++++++++----------------- src/components/ChatEntry.js | 18 +++++----- src/components/ChatLog.js | 12 ++++++- src/components/ChatLog.test.js | 53 ++++++++++++++++-------------- 5 files changed, 94 insertions(+), 67 deletions(-) diff --git a/src/App.js b/src/App.js index 620c42db3..289c757cd 100644 --- a/src/App.js +++ b/src/App.js @@ -1,16 +1,30 @@ import React from 'react'; +import { useState } from 'react'; import './App.css'; import chatMessages from './data/messages.json'; import ChatLog from './components/ChatLog'; const App = () => { + const [chats, setChats] = useState(chatMessages); + + const changeLike = (id) => { + const updatedChats = chats.map((chat) => Object.assign({}, chat)); + + for (const chat of updatedChats) { + if (chat.id === id) { + chat.liked = !chat.liked; + } + } + setChats(updatedChats); + }; + return (
-

Julie's Chatlog App

+

Chat Between Vladimir and Estragon

- +
); diff --git a/src/App.test.js b/src/App.test.js index ca75c71dd..878148902 100644 --- a/src/App.test.js +++ b/src/App.test.js @@ -1,53 +1,53 @@ -import React from 'react' -import App from './App' -import { render, screen, fireEvent } from '@testing-library/react' +import React from 'react'; +import App from './App'; +import { render, screen, fireEvent } from '@testing-library/react'; describe('Wave 03: clicking like button and rendering App', () => { test('that the correct number of likes is printed at the top', () => { // Arrange - const { container } = render() - let buttons = container.querySelectorAll('button.like') + const { container } = render(); + let buttons = container.querySelectorAll('button.like'); // Act - fireEvent.click(buttons[0]) - fireEvent.click(buttons[1]) - fireEvent.click(buttons[10]) + fireEvent.click(buttons[0]); + fireEvent.click(buttons[1]); + fireEvent.click(buttons[10]); // Assert - const countScreen = screen.getByText(/3 ❤️s/) - expect(countScreen).not.toBeNull() - }) + const countScreen = screen.getByText(/3 ❤️s/); + expect(countScreen).not.toBeNull(); + }); test('clicking button toggles heart and does not affect other buttons', () => { // Arrange - const { container } = render() - const buttons = container.querySelectorAll('button.like') - const firstButton = buttons[0] - const lastButton = buttons[buttons.length - 1] + const { container } = render(); + const buttons = container.querySelectorAll('button.like'); + const firstButton = buttons[0]; + const lastButton = buttons[buttons.length - 1]; // Act-Assert // click the first button - fireEvent.click(firstButton) - expect(firstButton.innerHTML).toEqual('❤️') + fireEvent.click(firstButton); + expect(firstButton.innerHTML).toEqual('❤️'); // check that all other buttons haven't changed for (let i = 1; i < buttons.length; i++) { - expect(buttons[i].innerHTML).toEqual('🤍') + expect(buttons[i].innerHTML).toEqual('🤍'); } // click the first button a few more times - fireEvent.click(firstButton) - expect(firstButton.innerHTML).toEqual('🤍') - fireEvent.click(firstButton) - expect(firstButton.innerHTML).toEqual('❤️') - fireEvent.click(firstButton) - expect(firstButton.innerHTML).toEqual('🤍') + fireEvent.click(firstButton); + expect(firstButton.innerHTML).toEqual('🤍'); + fireEvent.click(firstButton); + expect(firstButton.innerHTML).toEqual('❤️'); + fireEvent.click(firstButton); + expect(firstButton.innerHTML).toEqual('🤍'); // click the last button a couple times - fireEvent.click(lastButton) - expect(lastButton.innerHTML).toEqual('❤️') - fireEvent.click(lastButton) - expect(lastButton.innerHTML).toEqual('🤍') - }) -}) + fireEvent.click(lastButton); + expect(lastButton.innerHTML).toEqual('❤️'); + fireEvent.click(lastButton); + expect(lastButton.innerHTML).toEqual('🤍'); + }); +}); diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index d0f6d5df5..eb89ffe6c 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,28 +1,26 @@ import React from 'react'; import TimeStamp from './TimeStamp'; -import { useState } from 'react'; import './ChatEntry.css'; import PropTypes from 'prop-types'; const ChatEntry = (props) => { - const [liked, setLiked] = useState(false); + const changeMyLike = () => { + props.likedCallback(props.id); + }; - function changeLike() { - setLiked(!liked); - } - - const displayLike = liked ? '❤️' : '🤍'; + const messageFormat = props.sender === 'Estragon' ? 'remote' : 'local'; + const likedButton = props.liked ? '❤️' : '🤍'; return ( -
+

{props.sender}

{props.body}

-
diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index 0b154826a..5460e8fef 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -12,6 +12,8 @@ const ChatLog = (props) => { sender={chat.sender} body={chat.body} timeStamp={chat.timeStamp} + liked={chat.liked} + likedCallback={props.likedCallback} > ); }); @@ -20,7 +22,15 @@ const ChatLog = (props) => { }; ChatLog.propTypes = { - entries: PropTypes.array.isRequired, + entries: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.number, + sender: PropTypes.string, + body: PropTypes.string, + timeStamp: PropTypes.string, + liked: PropTypes.bool, + }) + ).isRequired, }; export default ChatLog; diff --git a/src/components/ChatLog.test.js b/src/components/ChatLog.test.js index 96f89ebc3..0c0c532be 100644 --- a/src/components/ChatLog.test.js +++ b/src/components/ChatLog.test.js @@ -1,49 +1,54 @@ -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'; +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", + id: 1, + 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", + id: 2, + 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", + id: 3, + 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", + id: 4, + 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", + id: 5, + sender: 'Vladimir', + body: 'Notabot', + timeStamp: '2019-07-23T22:52:21+00:00', }, ]; -describe("Wave 02: ChatLog", () => { +describe('Wave 02: ChatLog', () => { beforeEach(() => { render(); }); - 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) => { @@ -56,7 +61,7 @@ describe("Wave 02: ChatLog", () => { }); }); - test("renders an empty list without crashing", () => { + test('renders an empty list without crashing', () => { const element = render(); expect(element).not.toBeNull(); }); From ce765b984e5d9a0584b1d67928da114e1be64703 Mon Sep 17 00:00:00 2001 From: Julie Date: Mon, 20 Jun 2022 21:23:23 -0700 Subject: [PATCH 4/6] counts hearts at top of chat --- src/App.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 289c757cd..178edf7b4 100644 --- a/src/App.js +++ b/src/App.js @@ -4,24 +4,40 @@ import './App.css'; import chatMessages from './data/messages.json'; import ChatLog from './components/ChatLog'; +const countLikes = (chats) => { + let count = 0; + for (const chat of chats) { + if (chat.liked === true) { + count += 1; + } + } + return count; +}; + const App = () => { const [chats, setChats] = useState(chatMessages); + const [likesCount, setLikesCount] = useState(countLikes(chatMessages)); const changeLike = (id) => { const updatedChats = chats.map((chat) => Object.assign({}, chat)); - for (const chat of updatedChats) { if (chat.id === id) { chat.liked = !chat.liked; } } setChats(updatedChats); + setLikesCount(countLikes(updatedChats)); }; return (

Chat Between Vladimir and Estragon

+
+
+ {likesCount} ❤️s +
+
From 325d7f9c595873803d8b80bf673f044eb990a713 Mon Sep 17 00:00:00 2001 From: Julie Date: Wed, 22 Jun 2022 18:23:47 -0700 Subject: [PATCH 5/6] ChatEntry changed that wasn't pushed --- src/components/ChatEntry.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index eb89ffe6c..49e92d306 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -28,6 +28,7 @@ const ChatEntry = (props) => { }; ChatEntry.propTypes = { + id: PropTypes.number, sender: PropTypes.string, body: PropTypes.string, timeStamp: PropTypes.string, From bd6e84fe5d71f320fb32b7227f265ade2e22dd56 Mon Sep 17 00:00:00 2001 From: Julie Date: Wed, 22 Jun 2022 18:27:05 -0700 Subject: [PATCH 6/6] fixed proptypes error --- src/components/ChatEntry.js | 8 ++++---- src/components/ChatLog.js | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index 49e92d306..f3f3ac11b 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -28,10 +28,10 @@ const ChatEntry = (props) => { }; ChatEntry.propTypes = { - id: PropTypes.number, - sender: PropTypes.string, - body: PropTypes.string, - timeStamp: PropTypes.string, + id: PropTypes.number.isRequired, + sender: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + timeStamp: PropTypes.string.isRequired, liked: PropTypes.bool, }; diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index 5460e8fef..be9362958 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -24,10 +24,10 @@ const ChatLog = (props) => { ChatLog.propTypes = { entries: PropTypes.arrayOf( PropTypes.shape({ - id: PropTypes.number, - sender: PropTypes.string, - body: PropTypes.string, - timeStamp: PropTypes.string, + id: PropTypes.number.isRequired, + sender: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + timeStamp: PropTypes.string.isRequired, liked: PropTypes.bool, }) ).isRequired,