diff --git a/eslint.config.mjs b/eslint.config.mjs
index 6c2b6b501..bde2a6b3d 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -65,7 +65,7 @@ export default [{
"comma-dangle": ["warn", "only-multiline"],
"dot-notation": "warn",
"space-before-function-paren": "off",
- "indent": ["warn", 2],
+ "indent": ["warn", 'tab'],
"padded-blocks": "warn",
"no-trailing-spaces": "warn",
"array-bracket-spacing": "warn",
diff --git a/package-lock.json b/package-lock.json
index 2a6ed1d5b..6992a2558 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "react-chatlog",
"version": "0.0.0",
"dependencies": {
+ "date-fns": "^4.1.0",
"luxon": "^2.5.2",
"react": "^18.3.1",
"react-dom": "^18.3.1"
@@ -2264,6 +2265,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/date-fns": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
+ "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/kossnocorp"
+ }
+ },
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
diff --git a/package.json b/package.json
index 1a053dda4..404f3da32 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"test": "vitest --run"
},
"dependencies": {
+ "date-fns": "^4.1.0",
"luxon": "^2.5.2",
"react": "^18.3.1",
"react-dom": "^18.3.1"
diff --git a/src/App.css b/src/App.css
index d97beb4e6..92db5b79b 100644
--- a/src/App.css
+++ b/src/App.css
@@ -31,18 +31,24 @@
}
#App .widget {
- display: inline-block;
- line-height: 0.5em;
- border-radius: 10px;
+ position: fixed;
+ top: 9.6vh;
+ width: 100%;
+ height: 9vh;
+ background-color: #e0ffff;
color: black;
- font-size:0.8em;
- padding-left: 1em;
- padding-right: 1em;
-}
+ font-size: 1.5em;
+ text-align: center;
+ display: flex; /* enables centering */
+ align-items: center; /* vertical centering */
+ justify-content: center; /* horizontal centering */
+ box-sizing: border-box;
+ z-index: 90;
+
#App #heartWidget {
font-size: 1.5em;
- margin: 1em
+ margin: 0em
}
#App span {
diff --git a/src/App.jsx b/src/App.jsx
index 14a7f684d..055758efd 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,17 +1,33 @@
import './App.css';
+import entriesData from './data/messages.json';
+import ChatLog from './components/ChatLog';
+import { useState } from 'react';
const App = () => {
- return (
-
-
-
- {/* Wave 01: Render one ChatEntry component
- Wave 02: Render ChatLog component */}
-
-
- );
+ const [entries, setEntries] = useState(entriesData);
+ const toggleLike = (id) => {
+ const updatedEntries = entries.map(entry => {
+ if (entry.id === id) {
+ return { ...entry, liked: !entry.liked } ;
+ } else{
+ return entry;
+ }
+ });
+ setEntries(updatedEntries);
+ };
+ const totalLikes = entries.filter((entry) => entry.liked).length;
+
+ return (
+
+
+ Chat between {entries[0].sender} and {entries[1].sender}
+
+
+
+
+
+
+ );
};
export default App;
diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx
index 15c56f96b..137b181df 100644
--- a/src/components/ChatEntry.jsx
+++ b/src/components/ChatEntry.jsx
@@ -1,20 +1,39 @@
import './ChatEntry.css';
+import PropTypes from 'prop-types';
+import TimeStamp from './TimeStamp';
-const ChatEntry = () => {
- return (
-
-
Replace with name of sender
-
- Replace with body of ChatEntry
- Replace with TimeStamp component
-
-
-
- );
+
+const ChatEntry = (props) => {
+ const localSender = props.sender === 'Vladimir';
+ const entryClass = `chat-entry ${localSender ? 'local' : 'remote'}`;
+ // const likedStatus = () => {
+ // props.liked ? 'liked' : 'not-liked';
+
+ return (
+
+
{props.sender}
+
+ {props.body}
+
+
+
+
+ );
};
ChatEntry.propTypes = {
- // Fill with correct proptypes
+ id: PropTypes.number.isRequired,
+ sender: PropTypes.string.isRequired,
+ body: PropTypes.string.isRequired,
+ timeStamp: PropTypes.string.isRequired,
+ liked: PropTypes.bool.isRequired,
+ onToggleLike: PropTypes.func, //had to remove isRequired to pass the test from Waves 1 and 2
+};
+
+ChatEntry.defaultProps = { // added dafault props so it stays always defined
+ onToggleLike: () => {},
};
-export default ChatEntry;
+export default ChatEntry;
\ No newline at end of file
diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx
new file mode 100644
index 000000000..b33bc379b
--- /dev/null
+++ b/src/components/ChatLog.jsx
@@ -0,0 +1,27 @@
+// import entries from './data/messages.json';
+import PropTypes from 'prop-types';
+import ChatEntry from './ChatEntry';
+
+const ChatLog = ({ entries, onToggleLike }) => {
+ return (
+
+ {entries.map((entry) => (
+
+ ))}
+
+);
+};
+ChatLog.propTypes = {
+ entries: PropTypes.arrayOf(
+ PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ sender: PropTypes.string.isRequired,
+ body: PropTypes.string.isRequired,
+ timeStamp: PropTypes.string.isRequired,
+ liked: PropTypes.bool.isRequired
+ })
+ ).isRequired,
+ onToggleLike: PropTypes.func.isRequired,
+};
+
+export default ChatLog;
diff --git a/src/components/ChatLog.test.jsx b/src/components/ChatLog.test.jsx
index dfcfeda99..9b8d5815f 100644
--- a/src/components/ChatLog.test.jsx
+++ b/src/components/ChatLog.test.jsx
@@ -3,70 +3,70 @@ import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
const LOG = [
- {
- id: 1,
- sender: 'Vladimir',
- body: 'why are you arguing with me',
- timeStamp: '2018-05-29T22:49:06+00:00',
- liked: false,
- },
- {
- id: 2,
- sender: 'Estragon',
- body: 'Because you are wrong.',
- timeStamp: '2018-05-29T22:49:33+00:00',
- liked: false,
- },
- {
- id: 3,
- sender: 'Vladimir',
- body: 'because I am what',
- timeStamp: '2018-05-29T22:50:22+00:00',
- liked: false,
- },
- {
- id: 4,
- sender: 'Estragon',
- body: 'A robot.',
- timeStamp: '2018-05-29T22:52:21+00:00',
- liked: false,
- },
- {
- id: 5,
- sender: 'Vladimir',
- body: 'Notabot',
- timeStamp: '2019-07-23T22:52:21+00:00',
- liked: false,
- },
+ {
+ id: 1,
+ sender: 'Vladimir',
+ body: 'why are you arguing with me',
+ timeStamp: '2018-05-29T22:49:06+00:00',
+ liked: false,
+ },
+ {
+ id: 2,
+ sender: 'Estragon',
+ body: 'Because you are wrong.',
+ timeStamp: '2018-05-29T22:49:33+00:00',
+ liked: false,
+ },
+ {
+ id: 3,
+ sender: 'Vladimir',
+ body: 'because I am what',
+ timeStamp: '2018-05-29T22:50:22+00:00',
+ liked: false,
+ },
+ {
+ id: 4,
+ sender: 'Estragon',
+ body: 'A robot.',
+ timeStamp: '2018-05-29T22:52:21+00:00',
+ liked: false,
+ },
+ {
+ id: 5,
+ sender: 'Vladimir',
+ body: 'Notabot',
+ timeStamp: '2019-07-23T22:52:21+00:00',
+ liked: false,
+ },
];
describe('Wave 02: ChatLog', () => {
- beforeEach(() => {
- render();
- });
+ beforeEach(() => {
+ render();
+ });
- test('renders without crashing and shows all the names', () => {
- [
- {
- name: 'Vladimir',
- numChats: 3,
- },
- {
- name: 'Estragon',
- numChats: 2,
- },
- ].forEach((person) => {
- const elementList = screen.getAllByText(new RegExp(person.name));
- expect(elementList.length).toEqual(person.numChats);
+ test('renders without crashing and shows all the names', () => {
+ [
+ {
+ name: 'Vladimir',
+ numChats: 3,
+ },
+ {
+ name: 'Estragon',
+ numChats: 2,
+ },
+ ].forEach((person) => {
+ const elementList = screen.getAllByText(new RegExp(person.name));
+ expect(elementList.length).toEqual(person.numChats);
- elementList.forEach((element) => {
- expect(element).toBeInTheDocument();
- });
- });
- });
+ elementList.forEach((element) => {
+ expect(element).toBeInTheDocument();
+ });
+ });
+ });
- test('renders an empty list without crashing', () => {
- const element = render();
- expect(element).not.toBeNull();
- });
+ test('renders an empty list without crashing', () => {
+ const element = render();
+ expect(element).not.toBeNull();
+ });
});