From 5acf39567f88c040f31a333552518e9938ead92c Mon Sep 17 00:00:00 2001 From: nadxelle Date: Mon, 30 Jan 2023 17:08:26 -0800 Subject: [PATCH 01/10] created basic chatlog and chatlog entry --- src/App.js | 22 +++++++++++++-- src/components/ChatEntry.js | 12 +++++--- src/components/ChatEntry.test.js | 16 +++++------ src/components/ChatLog.js | 27 ++++++++++++++++++ src/components/ChatLog.test.js | 48 ++++++++++++++++---------------- src/models/ChatGlobe.js | 11 ++++++++ 6 files changed, 97 insertions(+), 39 deletions(-) create mode 100644 src/components/ChatLog.js create mode 100644 src/models/ChatGlobe.js diff --git a/src/App.js b/src/App.js index c10859093..8bdfe7d23 100644 --- a/src/App.js +++ b/src/App.js @@ -1,16 +1,32 @@ import React from 'react'; import './App.css'; +import ChatLog from './components/ChatLog'; import chatMessages from './data/messages.json'; +import ChatGlobe from './models/ChatGlobe'; const App = () => { + const globes = []; + for (const globe of chatMessages) { + globes.push( + new ChatGlobe( + globe.id, + globe.sender, + globe.body, + globe.timeStamp, + globe.liked + ) + ); + } + return (
-

Application title

+

+ Chat Between {globes[0].sender} and {globes[1].sender} +

- {/* 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..65ce53928 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,14 +1,18 @@ import React from 'react'; import './ChatEntry.css'; import PropTypes from 'prop-types'; +import TimeStamp from './TimeStamp'; +import ChatGlobe from '../models/ChatGlobe'; const ChatEntry = (props) => { return (
-

Replace with name of sender

+

{props.chatGlobe.sender}

-

Replace with body of ChatEntry

-

Replace with TimeStamp component

+

{props.chatGlobe.body}

+

+ +

@@ -16,7 +20,7 @@ const ChatEntry = (props) => { }; ChatEntry.propTypes = { - //Fill with correct proptypes + chatGlobe: PropTypes.instanceOf(ChatGlobe), }; export default ChatEntry; 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 new file mode 100644 index 000000000..74fa352a4 --- /dev/null +++ b/src/components/ChatLog.js @@ -0,0 +1,27 @@ +import React from 'react'; +import ChatEntry from './ChatEntry'; +import './ChatLog.css'; +import PropTypes from 'prop-types'; +import ChatGlobe from '../models/ChatGlobe'; + +const ChatLog = (props) => { + const chatEntries = props.entries.map((entry) => { + return ( +
  • + +
  • + ); + }); + + return ( +
    +
      {chatEntries}
    +
    + ); +}; + +ChatLog.propTypes = { + entries: PropTypes.arrayOf(PropTypes.instanceOf(ChatGlobe)), +}; + +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/models/ChatGlobe.js b/src/models/ChatGlobe.js new file mode 100644 index 000000000..0bfb7240a --- /dev/null +++ b/src/models/ChatGlobe.js @@ -0,0 +1,11 @@ +class ChatGlobe { + constructor(id, sender, body, timeStamp, liked) { + this.id = id; + this.sender = sender; + this.body = body; + this.timeStamp = timeStamp; + this.liked = liked; + } +} + +export default ChatGlobe; From 860ea49d4db57e30745e17cd82cce3c5f6a53591 Mon Sep 17 00:00:00 2001 From: nadxelle Date: Mon, 30 Jan 2023 17:31:02 -0800 Subject: [PATCH 02/10] added event for like ChatEntry --- src/components/ChatEntry.js | 13 +++++++++++-- src/components/ChatLog.css | 4 ++++ src/components/ChatLog.js | 4 ++-- src/data/messages.json | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index 65ce53928..61298464a 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,10 +1,17 @@ -import React from 'react'; +import React, { useState } from 'react'; import './ChatEntry.css'; import PropTypes from 'prop-types'; import TimeStamp from './TimeStamp'; import ChatGlobe from '../models/ChatGlobe'; const ChatEntry = (props) => { + const [like, setLike] = useState(props.chatGlobe.liked); + const typeHeart = like ? '❤️' : '🤍'; + + const clickLike = (e) => { + setLike(!like); + }; + return (

    {props.chatGlobe.sender}

    @@ -13,7 +20,9 @@ const ChatEntry = (props) => {

    - +
    ); diff --git a/src/components/ChatLog.css b/src/components/ChatLog.css index 378848d1f..89f6b6bd4 100644 --- a/src/components/ChatLog.css +++ b/src/components/ChatLog.css @@ -2,3 +2,7 @@ margin: auto; max-width: 50rem; } + +.chat-entries-list { + list-style: none; +} diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index 74fa352a4..545ceba8a 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -14,8 +14,8 @@ const ChatLog = (props) => { }); return ( -
    -
      {chatEntries}
    +
    +
      {chatEntries}
    ); }; diff --git a/src/data/messages.json b/src/data/messages.json index 64fdb053c..ada45b0d8 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 6a9cd3ca1aceb3e4c6a48579ae10cfbf7b1b555c Mon Sep 17 00:00:00 2001 From: nadxelle Date: Mon, 30 Jan 2023 17:34:52 -0800 Subject: [PATCH 03/10] change ChatEntrytest so it uses a custom object instead of listed props --- src/components/ChatEntry.test.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/ChatEntry.test.js b/src/components/ChatEntry.test.js index 4a9a2b09f..00cca37a9 100644 --- a/src/components/ChatEntry.test.js +++ b/src/components/ChatEntry.test.js @@ -2,14 +2,21 @@ 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 ChatGlobe from '../models/ChatGlobe'; describe('Wave 01: ChatEntry', () => { beforeEach(() => { render( ); }); From eacf2f0cae045c45dd10661509c7edab641ba022 Mon Sep 17 00:00:00 2001 From: nadxelle Date: Mon, 30 Jan 2023 22:34:13 -0800 Subject: [PATCH 04/10] added the like to the app component --- src/App.js | 35 ++++++++++++--------- src/components/ChatEntry.js | 26 +++++++++------ src/components/ChatEntry.test.js | 6 ++-- src/components/ChatLog.js | 10 ++++-- src/models/{ChatGlobe.js => ChatMessage.js} | 4 +-- 5 files changed, 50 insertions(+), 31 deletions(-) rename src/models/{ChatGlobe.js => ChatMessage.js} (79%) diff --git a/src/App.js b/src/App.js index 8bdfe7d23..a8c89ab46 100644 --- a/src/App.js +++ b/src/App.js @@ -1,32 +1,39 @@ -import React from 'react'; +import React, { useState } from 'react'; import './App.css'; import ChatLog from './components/ChatLog'; import chatMessages from './data/messages.json'; -import ChatGlobe from './models/ChatGlobe'; +import ChatMessage from './models/ChatMessage'; const App = () => { - const globes = []; - for (const globe of chatMessages) { - globes.push( - new ChatGlobe( - globe.id, - globe.sender, - globe.body, - globe.timeStamp, - globe.liked - ) + const messages = []; + for (const msg of chatMessages) { + messages.push( + new ChatMessage(msg.id, msg.sender, msg.body, msg.timeStamp, msg.liked) ); } + const [chatEntries, setChatEntries] = useState(messages); + + const updateChatEntry = (updatedEntry) => { + const updatedMsg = chatEntries.map((entry) => { + if (entry.id === updatedEntry.id) { + return updatedEntry; + } else return entry; + }); + setChatEntries(updatedMsg); + }; return (

    - Chat Between {globes[0].sender} and {globes[1].sender} + Chat Between {chatEntries[0].sender} and {chatEntries[1].sender}

    - +
    ); diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index 61298464a..1462b4ea6 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,24 +1,31 @@ -import React, { useState } from 'react'; import './ChatEntry.css'; import PropTypes from 'prop-types'; import TimeStamp from './TimeStamp'; -import ChatGlobe from '../models/ChatGlobe'; +import ChatMessage from '../models/ChatMessage'; const ChatEntry = (props) => { - const [like, setLike] = useState(props.chatGlobe.liked); - const typeHeart = like ? '❤️' : '🤍'; + const chatMsg = props.message; + const typeHeart = chatMsg.liked ? '❤️' : '🤍'; const clickLike = (e) => { - setLike(!like); + props.onUpdateEntry( + new ChatMessage( + chatMsg.id, + chatMsg.sender, + chatMsg.body, + chatMsg.timeStamp, + !chatMsg.liked + ) + ); }; return (
    -

    {props.chatGlobe.sender}

    +

    {props.message.sender}

    -

    {props.chatGlobe.body}

    +

    {props.message.body}

    - +

    + + + + + +
    + ); +}; + +ColorChoice.propTypes = { + senderName: PropTypes.string.isRequired, + newColor: PropTypes.string.isRequired, + updateColor: PropTypes.func.isRequired, +}; + +export default ColorChoice; diff --git a/src/models/ChatMessage.js b/src/models/ChatMessage.js index ddf576562..f6c8e4eb4 100644 --- a/src/models/ChatMessage.js +++ b/src/models/ChatMessage.js @@ -1,5 +1,5 @@ class ChatMessage { - constructor(id, sender, body, timeStamp, liked, isLocal) { + constructor(id, sender, body, timeStamp, liked, isLocal, color) { this.id = id; this.sender = sender; this.body = body; From c8e25b50948458e15bc0a01bf95a46a2d2cde467 Mon Sep 17 00:00:00 2001 From: nadxelle Date: Thu, 2 Feb 2023 10:19:16 -0800 Subject: [PATCH 09/10] added emoji to buttons to look like the picture provided --- src/components/ColorChoice.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/components/ColorChoice.js b/src/components/ColorChoice.js index 07cc9a5de..b7d6b2efd 100644 --- a/src/components/ColorChoice.js +++ b/src/components/ColorChoice.js @@ -1,17 +1,28 @@ import React from 'react'; import PropTypes from 'prop-types'; -import './ColorChoice.css'; const ColorChoice = ({ senderName, newColor, updateColor }) => { return (

    {senderName}'s color:

    - - - - - - + + + + + +
    ); }; From c013934725fc72587a3b5ee02e0d44f1646dffc2 Mon Sep 17 00:00:00 2001 From: nadxelle Date: Thu, 2 Feb 2023 11:08:37 -0800 Subject: [PATCH 10/10] use a state to store number of hearts. refactored where to load the json msg --- src/App.js | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/App.js b/src/App.js index 714a1fd8b..b969ef8fe 100644 --- a/src/App.js +++ b/src/App.js @@ -5,46 +5,46 @@ import chatMessages from './data/messages.json'; import ChatMessage from './models/ChatMessage'; import ColorChoice from './components/ColorChoice'; -const App = () => { - const messages = []; - let isLocal = true; - for (const msg of chatMessages) { - messages.push( - new ChatMessage( - msg.id, - msg.sender, - msg.body, - msg.timeStamp, - msg.liked, - isLocal - ) - ); - isLocal = !isLocal; +const messages = []; +let isLocal = true; +let initialLikes = 0; +for (const msg of chatMessages) { + messages.push( + new ChatMessage( + msg.id, + msg.sender, + msg.body, + msg.timeStamp, + msg.liked, + isLocal + ) + ); + if (msg.liked) { + ++initialLikes; } + isLocal = !isLocal; +} +const App = () => { const [chatEntries, setChatEntries] = useState(messages); const [localColor, setLocalColor] = useState(''); const [remoteColor, setRemoteColor] = useState(''); + const [totalLikes, setTotalLikes] = useState(initialLikes); const updateChatEntry = (updatedEntry) => { const updatedMsg = chatEntries.map((entry) => { if (entry.id === updatedEntry.id) { + if (updatedEntry.liked) { + setTotalLikes(totalLikes + 1); + } else { + setTotalLikes(totalLikes - 1); + } return updatedEntry; } else return entry; }); setChatEntries(updatedMsg); }; - const getNumLikes = () => { - let numLikes = 0; - for (const entry of chatEntries) { - if (entry.liked) { - ++numLikes; - } - } - return numLikes; - }; - const getColor = (local) => { if (local) { return localColor; @@ -67,7 +67,7 @@ const App = () => { newColor={localColor} >

    - {getNumLikes()} ❤️s + {totalLikes} ❤️s