-
Notifications
You must be signed in to change notification settings - Fork 17
Ocelots - Nadxelle Hernandez #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5acf395
860ea49
6a9cd3c
eacf2f0
172c67f
2709156
71d8c88
29e596a
c8e25b5
c013934
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,87 @@ | ||
| import React from 'react'; | ||
| import React, { useState } from 'react'; | ||
| import './App.css'; | ||
| import ChatLog from './components/ChatLog'; | ||
| import chatMessages from './data/messages.json'; | ||
| import ChatMessage from './models/ChatMessage'; | ||
| import ColorChoice from './components/ColorChoice'; | ||
|
|
||
| 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(''); | ||
|
Comment on lines
+30
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If both local and remote start out with black as the default color, that could be the initial value for these state variables. |
||
| const [totalLikes, setTotalLikes] = useState(initialLikes); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the liked status of a message lives in the // This could be returned from a helper function
// totalLikes is a variable that accumulates a value as we loop over each entry in chatEntries
const likesCount = chatEntries.reduce((totalLikes, currentMessage) => {
// If currentMessage.liked is true add 1 to totalLikes, else add 0
return (totalLikes += currentMessage.liked ? 1 : 0);
}, 0); // The 0 here sets the initial value of totalLikes to 0 |
||
|
|
||
| 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 getColor = (local) => { | ||
| if (local) { | ||
| return localColor; | ||
| } | ||
| return remoteColor; | ||
| }; | ||
|
|
||
| return ( | ||
| <div id="App"> | ||
| <header> | ||
| <h1>Application title</h1> | ||
| <h1> | ||
| Chat Between{' '} | ||
| <span className={localColor}>{chatEntries[0].sender}</span> and{' '} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice use of new lines to keep the contents of the h1 clear. |
||
| <span className={remoteColor}>{chatEntries[1].sender}</span> | ||
| </h1> | ||
| <section> | ||
| <ColorChoice | ||
| updateColor={setLocalColor} | ||
| senderName={chatEntries[0].sender} | ||
| newColor={localColor} | ||
| ></ColorChoice> | ||
| <h2 className="widget" id="heartWidget"> | ||
| {totalLikes} ❤️s | ||
| </h2> | ||
| <ColorChoice | ||
| updateColor={setRemoteColor} | ||
| senderName={chatEntries[1].sender} | ||
| newColor={remoteColor} | ||
| ></ColorChoice> | ||
| </section> | ||
| </header> | ||
| <main> | ||
| {/* Wave 01: Render one ChatEntry component | ||
| Wave 02: Render ChatLog component */} | ||
| <ChatLog | ||
| entries={chatEntries} | ||
| onUpdateChatEntry={updateChatEntry} | ||
| getColor={getColor} | ||
| ></ChatLog> | ||
| </main> | ||
| </div> | ||
| ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,46 @@ | ||
| import React from 'react'; | ||
| import './ChatEntry.css'; | ||
| import PropTypes from 'prop-types'; | ||
| import TimeStamp from './TimeStamp'; | ||
| import ChatMessage from '../models/ChatMessage'; | ||
|
|
||
| const ChatEntry = ({ message, onUpdateEntry, getColor }) => { | ||
| const typeHeart = message.liked ? '❤️' : '🤍'; | ||
| const isLocalclass = message.isLocal ? 'local' : 'remote'; | ||
| const colorClass = getColor(message.isLocal); | ||
|
|
||
| const clickLike = (e) => { | ||
| onUpdateEntry( | ||
| new ChatMessage( | ||
| message.id, | ||
| message.sender, | ||
| message.body, | ||
| message.timeStamp, | ||
| !message.liked, | ||
| message.isLocal | ||
| ) | ||
| ); | ||
| }; | ||
|
Comment on lines
+11
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would consider passing the This made me think of a related concept in secure design for APIs. Imagine we had an API for creating and updating messages, and it has an endpoint There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you! I understand! |
||
|
|
||
| const ChatEntry = (props) => { | ||
| return ( | ||
| <div className="chat-entry local"> | ||
| <h2 className="entry-name">Replace with name of sender</h2> | ||
| <div className={`chat-entry ${isLocalclass}`}> | ||
| <h2 className="entry-name">{message.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 className={colorClass}>{message.body}</p> | ||
| <p className="entry-time"> | ||
| <TimeStamp time={message.timeStamp}></TimeStamp> | ||
| </p> | ||
| <button onClick={clickLike} className="like"> | ||
| {typeHeart} | ||
| </button> | ||
| </section> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| ChatEntry.propTypes = { | ||
| //Fill with correct proptypes | ||
| message: PropTypes.instanceOf(ChatMessage).isRequired, | ||
| onUpdateEntry: PropTypes.func.isRequired, | ||
| getColor: PropTypes.func, | ||
| }; | ||
|
|
||
| export default ChatEntry; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,28 +1,35 @@ | ||
| 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'; | ||
| import ChatMessage from '../models/ChatMessage'; | ||
|
|
||
| describe("Wave 01: ChatEntry", () => { | ||
| describe('Wave 01: ChatEntry', () => { | ||
| beforeEach(() => { | ||
| render( | ||
| <ChatEntry | ||
| sender="Joe Biden" | ||
| body="Get out by 8am. I'll count the silverware" | ||
| timeStamp="2018-05-18T22:12:03Z" | ||
| message={ | ||
| new ChatMessage( | ||
| 1, | ||
| 'Joe Biden', | ||
| "Get out by 8am. I'll count the silverware", | ||
| '2018-05-18T22:12:03Z', | ||
| false | ||
| ) | ||
| } | ||
| /> | ||
| ); | ||
| }); | ||
|
|
||
| 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(); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,3 +2,7 @@ | |
| margin: auto; | ||
| max-width: 50rem; | ||
| } | ||
|
|
||
| .chat-entries-list { | ||
| list-style: none; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import React from 'react'; | ||
| import ChatEntry from './ChatEntry'; | ||
| import './ChatLog.css'; | ||
| import PropTypes from 'prop-types'; | ||
| import ChatMessage from '../models/ChatMessage'; | ||
|
|
||
| const ChatLog = (props) => { | ||
| const chatEntries = props.entries.map((entry) => { | ||
| return ( | ||
| <li key={entry.id}> | ||
| <ChatEntry | ||
| message={entry} | ||
| onUpdateEntry={props.onUpdateChatEntry} | ||
| getColor={props.getColor} | ||
| ></ChatEntry> | ||
| </li> | ||
| ); | ||
| }); | ||
|
|
||
| return ( | ||
| <section className="chat-log"> | ||
| <ul className="chat-entries-list">{chatEntries}</ul> | ||
| </section> | ||
| ); | ||
| }; | ||
|
|
||
| ChatLog.propTypes = { | ||
| entries: PropTypes.arrayOf(PropTypes.instanceOf(ChatMessage)).isRequired, | ||
| onUpdateChatEntry: PropTypes.func.isRequired, | ||
| //getColor: PropTypes.func, | ||
| }; | ||
|
|
||
| export default ChatLog; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| button.red { | ||
| background-color: #b22222; | ||
| } | ||
|
|
||
| button.orange { | ||
| background-color: #e6ac00; | ||
| } | ||
|
|
||
| button.yellow { | ||
| background-color: #e6e600; | ||
| } | ||
|
|
||
| button.green { | ||
| background-color: green; | ||
| } | ||
|
|
||
| button.blue { | ||
| background-color: blue; | ||
| } | ||
|
|
||
| button.purple { | ||
| background-color: purple; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat way to add the local/remote data to the messages. In this case where we only have 2 senders, I might suggest using the value of
senderto determine remote vs local over holding a new piece of data, but this approach will scale better.