From 6615504092f7fec07dca84dd3432c8227d592d4f Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sat, 28 Jan 2023 16:54:37 -0800 Subject: [PATCH 1/6] finished with wave1 and wave2 --- src/components/ChatLog.js | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/components/ChatLog.js diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js new file mode 100644 index 000000000..e561a8cba --- /dev/null +++ b/src/components/ChatLog.js @@ -0,0 +1,50 @@ +import React from 'react'; +import './ChatLog.css'; +import ChatEntry from './ChatEntry'; +import PropTypes from 'prop-types'; + +const ChatLog = ({ entries }) => { + const calculateLikes = (entries) => { + let total = 0; + for (const entry of entries) { + if (entry.liked) { + total++; + } + return total; + } + }; + + const getChatLog = (entries) => { + return entries.map((message) => { + return ( + + ); + }); + }; + return ( +
+
{calculateLikes(entries)}
+
{getChatLog(entries)}
+
+ ); +}; + +ChatLog.propTypes = { + entries: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.number.isRequired, + sender: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + liked: PropTypes.bool, + }) + ).isRequired, +}; + +export default ChatLog; From 4e31cc655f61f1b2b531a6b82d3f2e2c1d4c7308 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sat, 28 Jan 2023 16:54:54 -0800 Subject: [PATCH 2/6] finished with Waves 1-2 --- src/App.js | 6 +++--- src/components/ChatEntry.js | 26 +++++++++++++++++++------- src/data/messages.json | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/App.js b/src/App.js index c10859093..f3661b88c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,16 +1,16 @@ import React from 'react'; import './App.css'; +import ChatLog from './components/ChatLog'; import chatMessages from './data/messages.json'; const App = () => { return (
-

Application title

+

Chat Log Application

- {/* 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..a5945e3dc 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,22 +1,34 @@ -import React from 'react'; +import React, { useState } from 'react'; import './ChatEntry.css'; import PropTypes from 'prop-types'; +import TimeStamp from './TimeStamp'; const ChatEntry = (props) => { + const [liked, setLiked] = useState(props.liked); + const heartLiked = liked ? '❤️' : '🤍'; + + const bubbleClass = (sender) => + sender === 'Vladimir' ? 'chat-entry local' : 'chat-entry remote'; + return ( -
-

Replace with name of sender

+
+

{props.sender}

-

Replace with body of ChatEntry

-

Replace with TimeStamp component

- +

{props.body}

+

+ +

+
); }; ChatEntry.propTypes = { - //Fill with correct proptypes + id: PropTypes.number.isRequired, + sender: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + liked: PropTypes.bool, }; export default ChatEntry; diff --git a/src/data/messages.json b/src/data/messages.json index 64fdb053c..1686f0db7 100644 --- a/src/data/messages.json +++ b/src/data/messages.json @@ -4,7 +4,7 @@ "sender":"Vladimir", "body":"why are you arguing with me", "timeStamp":"2018-05-29T22:49:06+00:00", - "liked": false + "liked": true }, { "id": 2, From d9929d89eceb2bbdb3d172323f33f41fd69b835d Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sat, 28 Jan 2023 17:41:30 -0800 Subject: [PATCH 3/6] Add totalLikes function. --- src/App.js | 3 +++ src/components/ChatLog.js | 2 +- src/data/messages.json | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/App.js b/src/App.js index f3661b88c..d9da44e54 100644 --- a/src/App.js +++ b/src/App.js @@ -8,6 +8,9 @@ const App = () => {

Chat Log Application

+
+ ❤️s +
{}
diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index e561a8cba..4cc814682 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -10,8 +10,8 @@ const ChatLog = ({ entries }) => { if (entry.liked) { total++; } - return total; } + return total; }; const getChatLog = (entries) => { diff --git a/src/data/messages.json b/src/data/messages.json index 1686f0db7..ad1975645 100644 --- a/src/data/messages.json +++ b/src/data/messages.json @@ -11,7 +11,7 @@ "sender":"Estragon", "body":"Because you are wrong.", "timeStamp":"2018-05-29T22:49:33+00:00", - "liked": false + "liked": true }, { "id": 3, From 05db702cf85775f24b965c217a7323589fa7b46d Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Mon, 30 Jan 2023 21:54:09 -0800 Subject: [PATCH 4/6] Implement the functionlity for wave3 --- src/App.js | 38 ++++++++++++++++++++++++--- src/components/ChatEntry.js | 19 +++++++++++--- src/components/ChatLog.js | 51 +++++++++++++++---------------------- 3 files changed, 71 insertions(+), 37 deletions(-) diff --git a/src/App.js b/src/App.js index d9da44e54..6b1eb003c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,19 +1,51 @@ -import React from 'react'; +import React, { useState } from 'react'; import './App.css'; import ChatLog from './components/ChatLog'; import chatMessages from './data/messages.json'; const App = () => { + const [chatEntryData, setChatData] = useState(chatMessages); + + const updateEntryData = (updatedMessage) => { + const entries = chatEntryData.map((message) => { + if (message.id === updatedMessage.id) { + return updatedMessage; + } else { + return message; + } + }); + setChatData(entries); + }; + + const calculateLikes = (entries) => { + let total = 0; + for (const entry of entries) { + if (entry.liked) { + total++; + } + } + return total; + }; + + const totalLikes = calculateLikes(chatEntryData); + const entries = ( + + ); + return (

Chat Log Application

- ❤️s + {totalLikes}❤️s
-
{}
+
{entries}
); diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index a5945e3dc..8209914ea 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,11 +1,21 @@ -import React, { useState } from 'react'; +import React from 'react'; import './ChatEntry.css'; import PropTypes from 'prop-types'; import TimeStamp from './TimeStamp'; const ChatEntry = (props) => { - const [liked, setLiked] = useState(props.liked); - const heartLiked = liked ? '❤️' : '🤍'; + const updateLikes = () => { + const updateEntry = { + id: props.id, + sender: props.sender, + body: props.body, + timeStamp: props.timeStamp, + liked: !props.liked, + }; + props.onUpdate(updateEntry); + }; + + const heartLiked = props.liked ? '❤️' : '🤍'; const bubbleClass = (sender) => sender === 'Vladimir' ? 'chat-entry local' : 'chat-entry remote'; @@ -18,7 +28,7 @@ const ChatEntry = (props) => {

- +
); @@ -29,6 +39,7 @@ ChatEntry.propTypes = { sender: PropTypes.string.isRequired, body: PropTypes.string.isRequired, liked: PropTypes.bool, + onUpdate: PropTypes.func.isRequired, }; export default ChatEntry; diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index 4cc814682..20fdb7054 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -3,48 +3,39 @@ import './ChatLog.css'; import ChatEntry from './ChatEntry'; import PropTypes from 'prop-types'; -const ChatLog = ({ entries }) => { - const calculateLikes = (entries) => { - let total = 0; - for (const entry of entries) { - if (entry.liked) { - total++; - } - } - return total; - }; +const ChatLog = (props) => { + const getChatLog = props.messages.map((message) => { + return ( + + ); + }); - const getChatLog = (entries) => { - return entries.map((message) => { - return ( - - ); - }); - }; - return ( + const allChatMessages = (
-
{calculateLikes(entries)}
-
{getChatLog(entries)}
+
{getChatLog}
); + return allChatMessages; }; ChatLog.propTypes = { - entries: PropTypes.arrayOf( + messages: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.number.isRequired, sender: PropTypes.string.isRequired, body: PropTypes.string.isRequired, liked: PropTypes.bool, - }) - ).isRequired, + }).isRequired + ), + updateLikeStatus: PropTypes.func.isRequired, }; export default ChatLog; From 3aad133d6fb860298b174ea986dabb438bdfbc53 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 31 Jan 2023 15:51:39 -0800 Subject: [PATCH 5/6] finished with wave 3. Tests pass --- src/App.js | 7 ++-- src/App.test.js | 60 ++++++++++++++++---------------- src/components/ChatEntry.js | 12 ++++--- src/components/ChatEntry.test.js | 16 ++++----- src/components/ChatLog.js | 9 +++-- src/components/ChatLog.test.js | 48 ++++++++++++------------- src/data/messages.json | 4 +-- 7 files changed, 81 insertions(+), 75 deletions(-) diff --git a/src/App.js b/src/App.js index 6b1eb003c..ee3218e8a 100644 --- a/src/App.js +++ b/src/App.js @@ -4,6 +4,8 @@ import ChatLog from './components/ChatLog'; import chatMessages from './data/messages.json'; const App = () => { + //let shallowCopyMessages = Object.assign({}, chatMessages); + //let deepCopyMessages = cloneDeep(chatMessages); const [chatEntryData, setChatData] = useState(chatMessages); const updateEntryData = (updatedMessage) => { @@ -30,9 +32,8 @@ const App = () => { const totalLikes = calculateLikes(chatEntryData); const entries = ( ); @@ -41,7 +42,7 @@ const App = () => {

Chat Log Application

- {totalLikes}❤️s + {totalLikes} ❤️s
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 8209914ea..391a72068 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -17,25 +17,27 @@ const ChatEntry = (props) => { const heartLiked = props.liked ? '❤️' : '🤍'; - const bubbleClass = (sender) => - sender === 'Vladimir' ? 'chat-entry local' : 'chat-entry remote'; + const bubbleClass = + props.sender === 'Vladimir' ? 'chat-entry local' : 'chat-entry remote'; return ( -
+

{props.sender}

{props.body}

- +
); }; ChatEntry.propTypes = { - id: PropTypes.number.isRequired, + id: PropTypes.number, //.isRequired, sender: PropTypes.string.isRequired, body: PropTypes.string.isRequired, liked: PropTypes.bool, diff --git a/src/components/ChatEntry.test.js b/src/components/ChatEntry.test.js index b69270c03..4a9a2b09f 100644 --- a/src/components/ChatEntry.test.js +++ b/src/components/ChatEntry.test.js @@ -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( { ); }); - 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(); }); }); diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index 20fdb7054..eb42a1ea5 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -4,7 +4,10 @@ import ChatEntry from './ChatEntry'; import PropTypes from 'prop-types'; const ChatLog = (props) => { - const getChatLog = props.messages.map((message) => { + if (!props || !props.entries) { + return id="" sender="" body="" timeStamp="" liked=""; + } + const getChatLog = props.entries.map((message) => { return ( { ChatLog.propTypes = { messages: PropTypes.arrayOf( PropTypes.shape({ - id: PropTypes.number.isRequired, + id: PropTypes.number, //.isRequired, sender: PropTypes.string.isRequired, body: PropTypes.string.isRequired, liked: PropTypes.bool, }).isRequired ), - updateLikeStatus: PropTypes.func.isRequired, + updateLikeStatus: PropTypes.func, }; export default ChatLog; diff --git a/src/components/ChatLog.test.js b/src/components/ChatLog.test.js index 96f89ebc3..5bafee291 100644 --- a/src/components/ChatLog.test.js +++ b/src/components/ChatLog.test.js @@ -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'; +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(); }); - 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 +56,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(); }); diff --git a/src/data/messages.json b/src/data/messages.json index ad1975645..64fdb053c 100644 --- a/src/data/messages.json +++ b/src/data/messages.json @@ -4,14 +4,14 @@ "sender":"Vladimir", "body":"why are you arguing with me", "timeStamp":"2018-05-29T22:49:06+00:00", - "liked": true + "liked": false }, { "id": 2, "sender":"Estragon", "body":"Because you are wrong.", "timeStamp":"2018-05-29T22:49:33+00:00", - "liked": true + "liked": false }, { "id": 3, From 7a8f0415196cda796bf9b0cbba3285b4fa87d430 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 31 Jan 2023 16:08:24 -0800 Subject: [PATCH 6/6] Complete Project --- src/App.js | 2 -- src/components/ChatEntry.js | 2 +- src/components/ChatLog.js | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/App.js b/src/App.js index ee3218e8a..4a26ab052 100644 --- a/src/App.js +++ b/src/App.js @@ -4,8 +4,6 @@ import ChatLog from './components/ChatLog'; import chatMessages from './data/messages.json'; const App = () => { - //let shallowCopyMessages = Object.assign({}, chatMessages); - //let deepCopyMessages = cloneDeep(chatMessages); const [chatEntryData, setChatData] = useState(chatMessages); const updateEntryData = (updatedMessage) => { diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index 391a72068..9224c7433 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -37,7 +37,7 @@ const ChatEntry = (props) => { }; ChatEntry.propTypes = { - id: PropTypes.number, //.isRequired, + id: PropTypes.number.isRequired, sender: PropTypes.string.isRequired, body: PropTypes.string.isRequired, liked: PropTypes.bool, diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index eb42a1ea5..5b7c8b271 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -32,7 +32,7 @@ const ChatLog = (props) => { ChatLog.propTypes = { messages: PropTypes.arrayOf( PropTypes.shape({ - id: PropTypes.number, //.isRequired, + id: PropTypes.number.isRequired, sender: PropTypes.string.isRequired, body: PropTypes.string.isRequired, liked: PropTypes.bool,