diff --git a/src/App.css b/src/App.css
index d97beb4e..6867fbf5 100644
--- a/src/App.css
+++ b/src/App.css
@@ -2,73 +2,9 @@
background-color: #87cefa;
}
-#App header {
- background-color: #222;
- color: #fff;
- padding-bottom: 0.5rem;
- position: fixed;
- width: 100%;
- z-index: 100;
- text-align: center;
- align-items: center;
-}
-
#App main {
padding-left: 2em;
padding-right: 2em;
padding-bottom: 5rem;
padding-top: 10rem;
-}
-
-#App h1 {
- font-size: 1.5em;
- text-align: center;
- display: inline-block;
-}
-
-#App header section {
- background-color: #e0ffff;
-}
-
-#App .widget {
- display: inline-block;
- line-height: 0.5em;
- border-radius: 10px;
- color: black;
- font-size:0.8em;
- padding-left: 1em;
- padding-right: 1em;
-}
-
-#App #heartWidget {
- font-size: 1.5em;
- margin: 1em
-}
-
-#App span {
- display: inline-block
-}
-
-.red {
- color: #b22222
-}
-
-.orange {
- color: #e6ac00
-}
-
-.yellow {
- color: #e6e600
-}
-
-.green {
- color: green
-}
-
-.blue {
- color: blue
-}
-
-.purple {
- color: purple
}
\ No newline at end of file
diff --git a/src/App.jsx b/src/App.jsx
index 14a7f684..ae74e078 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,14 +1,53 @@
import './App.css';
+import { useState } from 'react';
+import ChatLog from './components/ChatLog.jsx';
+import messages from './data/messages.json';
+import Header from './components/Header.jsx';
const App = () => {
+ const [entries, setEntries] = useState(messages);
+ const [fontColorForLocalSender, setFontColorForLocalSender] = useState('black');
+ const [fontColorForRemoteSender, setFontColorForRemoteSender] = useState('black');
+ const localSender = 'Vladimir';
+
+ const totalLikes = entries.reduce((total, entry) => {
+ return entry.isLiked ? total + 1 : total;
+ }, 0);
+
+ const toggleHeart = (entryId) => {
+ setEntries(entries => {
+ return entries.map(entry => {
+ if (entry.id === entryId) {
+ return { ...entry, isLiked: !entry.isLiked };
+ } else {
+ return entry;
+ }
+ });
+ });
+ };
+
+ const chooseFontColor = (senderName, color) => {
+ if (senderName === localSender) {
+ setFontColorForLocalSender(color);
+ } else {
+ setFontColorForRemoteSender(color);
+ }
+ };
+
return (
-
+
- {/* Wave 01: Render one ChatEntry component
- Wave 02: Render ChatLog component */}
+
);
diff --git a/src/components/ChatEntry.css b/src/components/ChatEntry.css
index 05c3baa4..40f6c4d1 100644
--- a/src/components/ChatEntry.css
+++ b/src/components/ChatEntry.css
@@ -2,7 +2,7 @@ button {
background: none;
color: inherit;
border: none;
- padding: 10px;
+ padding: 10px;
font: inherit;
cursor: pointer;
outline: inherit;
@@ -97,4 +97,18 @@ button {
.chat-entry.remote .entry-bubble:hover::before {
background-color: #a9f6f6;
+}
+
+.entry-attributes {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.like {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+ align-items: center;
+ line-height: 1;
}
\ No newline at end of file
diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx
index fe05efa0..09ecc262 100644
--- a/src/components/ChatEntry.jsx
+++ b/src/components/ChatEntry.jsx
@@ -1,21 +1,40 @@
import './ChatEntry.css';
+import PropTypes from 'prop-types';
+import TimeStamp from './TimeStamp';
+
+const ChatEntry = (props) => {
+ const isLocal = props.sender === props.localSender;
+ const entryClass = isLocal ? 'local' : 'remote';
+ const isLiked = props.isLiked ? '❤️' : '🤍';
+ const isLikedButtonClicked = () => {
+ props.onToggleHeart(props.id);
+ };
+
+ const fontColor = isLocal ? props.fontColorForLocalSender : props.fontColorForRemoteSender;
-const ChatEntry = () => {
return (
- // Replace the outer tag name with a semantic element that fits our use case
-
- Replace with name of sender
+
+ {props.sender}
- Replace with body of ChatEntry
- Replace with TimeStamp component
-
+ {props.body}
+
-
+
);
};
-ChatEntry.propTypes = {
- // Fill with correct proptypes
-};
-
export default ChatEntry;
+
+ChatEntry.propTypes = {
+ sender: PropTypes.string.isRequired,
+ body: PropTypes.string.isRequired,
+ timeStamp: PropTypes.string.isRequired,
+ localSender: PropTypes.string,
+ isLiked: PropTypes.bool,
+ onToggleHeart: PropTypes.func,
+};
\ No newline at end of file
diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx
new file mode 100644
index 00000000..d98a5de3
--- /dev/null
+++ b/src/components/ChatLog.jsx
@@ -0,0 +1,39 @@
+import './ChatLog.css';
+import ChatEntry from './ChatEntry';
+import PropTypes from 'prop-types';
+
+const ChatLog = ({entries, localSender, onToggleHeart, fontColorForLocalSender, fontColorForRemoteSender}) => {
+ return (
+
+ {entries.map((entry) => (
+
+ ))}
+
+ );
+};
+
+export default ChatLog;
+
+ChatLog.propTypes = {
+ entries: PropTypes.arrayOf(
+ PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ sender: PropTypes.string.isRequired,
+ body: PropTypes.string.isRequired,
+ timeStamp: PropTypes.string.isRequired,
+ })
+ ).isRequired,
+ localSender: PropTypes.string,
+ onToggleHeart: PropTypes.func,
+};
\ No newline at end of file
diff --git a/src/components/Header.css b/src/components/Header.css
new file mode 100644
index 00000000..217e9d7d
--- /dev/null
+++ b/src/components/Header.css
@@ -0,0 +1,20 @@
+#App header {
+ background-color: #2c2c2c;
+ color: #fff;
+ padding-bottom: 0.5rem;
+ position: fixed;
+ width: 100%;
+ z-index: 100;
+ text-align: center;
+ align-items: center;
+}
+
+#App h1 {
+ font-size: 1.5em;
+ text-align: center;
+ display: inline-block;
+}
+
+#App header section {
+ background-color: #e0ffff;
+}
\ No newline at end of file
diff --git a/src/components/Header.jsx b/src/components/Header.jsx
new file mode 100644
index 00000000..5f8c31b6
--- /dev/null
+++ b/src/components/Header.jsx
@@ -0,0 +1,34 @@
+import { useState } from 'react';
+import './Header.css';
+import HeartCounter from './HeartCounter.jsx';
+import SenderColorPicker from './SenderColorPicker.jsx';
+
+const Header = ({ totalLikes, chooseFontColor }) => {
+ const [localColor, setLocalColor] = useState('white');
+ const [remoteColor, setRemoteColor] = useState('white');
+
+ const changeFontColor = (senderName, color) => {
+ if (senderName === 'Vladimir') {
+ setLocalColor(color);
+ } else {
+ setRemoteColor(color);
+ }
+ chooseFontColor(senderName, color);
+ };
+
+ return (
+
+
+ Chat between Vladimir and Estragon
+
+
+
+
+ );
+};
+
+export default Header;
\ No newline at end of file
diff --git a/src/components/HeartCounter.css b/src/components/HeartCounter.css
new file mode 100644
index 00000000..e02387f2
--- /dev/null
+++ b/src/components/HeartCounter.css
@@ -0,0 +1,18 @@
+#App .widget {
+ display: inline-block;
+ line-height: 0.5em;
+ border-radius: 10px;
+ color: black;
+ font-size: 0.8em;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+#App #heartWidget {
+ font-size: 1.5em;
+ margin: 1em;
+}
+
+#App span {
+ display: inline-block;
+}
\ No newline at end of file
diff --git a/src/components/HeartCounter.jsx b/src/components/HeartCounter.jsx
new file mode 100644
index 00000000..d3fc3673
--- /dev/null
+++ b/src/components/HeartCounter.jsx
@@ -0,0 +1,11 @@
+import './HeartCounter.css';
+
+const HeartCounter = ({ totalLikes }) => {
+ return (
+
+ {totalLikes} ❤️s
+
+ );
+};
+
+export default HeartCounter;
diff --git a/src/components/SenderColorPicker.css b/src/components/SenderColorPicker.css
new file mode 100644
index 00000000..53fc8d60
--- /dev/null
+++ b/src/components/SenderColorPicker.css
@@ -0,0 +1,35 @@
+span {
+ display: inline-block
+}
+
+.red {
+ color: #b22222
+}
+
+.orange {
+ color: #e6ac00
+}
+
+.yellow {
+ color: #e6e600
+}
+
+.green {
+ color: green
+}
+
+.blue {
+ color: blue
+}
+
+.purple {
+ color: purple
+}
+
+.black {
+ color: black
+}
+
+.senderColorPicker span {
+ margin: 0 0.15em;
+}
\ No newline at end of file
diff --git a/src/components/SenderColorPicker.jsx b/src/components/SenderColorPicker.jsx
new file mode 100644
index 00000000..24626fe8
--- /dev/null
+++ b/src/components/SenderColorPicker.jsx
@@ -0,0 +1,29 @@
+import { useState } from 'react';
+import './SenderColorPicker.css';
+
+const SenderColorPicker = ({ senderName, chooseFontColor }) => {
+
+ const [color, setColor] = useState('black');
+
+ const colorButtonClicked = (color) => {
+ chooseFontColor(senderName, color);
+ setColor(color);
+ };
+
+ return (
+
+
{senderName}'s color:
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default SenderColorPicker;
\ No newline at end of file