From 41498e59fc3676dd99fd0bcca42c43caed5669f3 Mon Sep 17 00:00:00 2001 From: liyan Date: Sun, 14 Dec 2025 16:13:11 -0800 Subject: [PATCH 1/5] delete all students --- src/App.jsx | 7 +++++++ src/components/ChatEntry.jsx | 23 +++++++++++++++-------- src/components/ChatLog.jsx | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 src/components/ChatLog.jsx diff --git a/src/App.jsx b/src/App.jsx index 14a7f684d..e40fa4482 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,6 +1,11 @@ import './App.css'; +import ChatEntry from './components/ChatEntry'; +import messages from './data/messages.json'; +import ChatLog from './components/ChatLog'; const App = () => { + + return (
@@ -9,6 +14,8 @@ const App = () => {
{/* Wave 01: Render one ChatEntry component Wave 02: Render ChatLog component */} + {/* */} +
); diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index fe05efa0f..e264d3428 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -1,21 +1,28 @@ import './ChatEntry.css'; +import PropTypes from 'prop-types'; +import TimeStamp from './TimeStamp'; -const ChatEntry = () => { + + +const ChatEntry = ({ sender, body, timeStamp, onLike}) => { return ( // Replace the outer tag name with a semantic element that fits our use case - -

Replace with name of sender

+ +

{sender}

-

Replace with body of ChatEntry

-

Replace with TimeStamp component

- +

{body}

+ +
-
+ + ); }; ChatEntry.propTypes = { - // Fill with correct proptypes + sender:PropTypes.string.isRequired, + body:PropTypes.string.isRequired, + timeStamp:PropTypes.string.isRequired, }; export default ChatEntry; diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx new file mode 100644 index 000000000..2181dcd8e --- /dev/null +++ b/src/components/ChatLog.jsx @@ -0,0 +1,34 @@ +import ChatEntry from './ChatEntry'; +import './ChatLog.css'; +import { useState } from 'react'; + +const ChatLog = ({ entries }) => { + const [count, setCount] = useState(0); + + const countLikes = () => { + setCount(preCount => preCount + 1); + }; + + const chatEntryComponents = entries.map(entry => { + return ( + + ); + }); + + return ( + <> +

{count}❤️s

+ + + ); +}; + +export default ChatLog; \ No newline at end of file From b33012a5f785d8f4449056ab1e31bb722a2a1b6a Mon Sep 17 00:00:00 2001 From: liyan Date: Mon, 15 Dec 2025 15:14:02 -0800 Subject: [PATCH 2/5] my code with comment(but not correct) just for learning" --- src/App.css | 3 +- src/App.jsx | 57 +++++++++++++++++++++++++++++++----- src/components/ChatEntry.jsx | 20 ++++++++----- src/components/ChatLog.jsx | 38 +++++++++++++++--------- 4 files changed, 87 insertions(+), 31 deletions(-) diff --git a/src/App.css b/src/App.css index d97beb4e6..fef803632 100644 --- a/src/App.css +++ b/src/App.css @@ -18,6 +18,7 @@ padding-right: 2em; padding-bottom: 5rem; padding-top: 10rem; + text-align: center; } #App h1 { @@ -42,7 +43,7 @@ #App #heartWidget { font-size: 1.5em; - margin: 1em + margin: 1em; } #App span { diff --git a/src/App.jsx b/src/App.jsx index e40fa4482..70ee4dc13 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,24 +1,65 @@ import './App.css'; -import ChatEntry from './components/ChatEntry'; import messages from './data/messages.json'; import ChatLog from './components/ChatLog'; +import { useState } from 'react'; const App = () => { + const [chatMessages, setChatMessages] = useState(messages); + // const [likeButton, setLikeButton] = useState(false); + // const [countLikes, setCountLikes] = useState(0); + // const [heart, setHeart] = useState('🤍'); + const senderColors = useState({ + Vladimir: 'red', + Estragon: 'green', + }); + + const toggleLikeChoice = (id) => { + const updatedMessages = chatMessages.map(message => { + if (message.id === id) { + return { ...message, liked: !message.liked}; + } else { + return message; + } + }); + setChatMessages(updatedMessages); + }; + + // setLikeButton(likeButton => !likeButton); + // if (!likeButton) { + // setHeart('❤️'); + // } else { + // setHeart('🤍'); + // } + // }; + + // const countTotalLikes = (messages) => { + // for (const message of messages) { + // if (message.liked) { + // setCountLikes(preCountLikes => preCountLikes + 1); + // }; + // }; + // }; + const countLikes = chatMessages.filter(msg => msg.liked).length; + + const participants = Array.from(new Set(chatMessages.map(msg => msg.sender))); + const headerTitle = `Chat between ${participants.join(' and ')}`; return (
-

Application title

+

{headerTitle}

-
- {/* Wave 01: Render one ChatEntry component - Wave 02: Render ChatLog component */} - {/* */} - +
+

{countLikes} ❤️s

+
); }; -export default App; +export default App; \ No newline at end of file diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index e264d3428..f9777a34e 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -4,25 +4,29 @@ import TimeStamp from './TimeStamp'; -const ChatEntry = ({ sender, body, timeStamp, onLike}) => { +const ChatEntry = ({ id, sender, body, timeStamp, toggleLikeChoice, liked, color}) => { + const isLocal = sender === 'Vladimir'; return ( // Replace the outer tag name with a semantic element that fits our use case - +

{sender}

-
+

{body}

- +
- +
); }; ChatEntry.propTypes = { - sender:PropTypes.string.isRequired, - body:PropTypes.string.isRequired, - timeStamp:PropTypes.string.isRequired, + id: PropTypes.number.isRequired, + sender: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + timeStamp: PropTypes.string.isRequired, + toggleLikeChoice: PropTypes.func.isRequired, + liked: PropTypes.bool.isRequired, }; export default ChatEntry; diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx index 2181dcd8e..ad3a52cfa 100644 --- a/src/components/ChatLog.jsx +++ b/src/components/ChatLog.jsx @@ -1,34 +1,44 @@ import ChatEntry from './ChatEntry'; import './ChatLog.css'; -import { useState } from 'react'; +import PropTypes from 'prop-types'; -const ChatLog = ({ entries }) => { - const [count, setCount] = useState(0); - - const countLikes = () => { - setCount(preCount => preCount + 1); - }; +const ChatLog = ({ entries, toggleLikeChoice, senderColors}) => { const chatEntryComponents = entries.map(entry => { return ( ); }); return ( - <> -

{count}❤️s

-
    - {chatEntryComponents} -
- +
    + {chatEntryComponents} +
); }; +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, + toggleLikeChoice: PropTypes.func.isRequired, + senderColors: PropTypes.object.isRequired, +}; + + export default ChatLog; \ No newline at end of file From 6a95c9bee294214f4073d234161f04fe96f8651e Mon Sep 17 00:00:00 2001 From: liyan Date: Mon, 15 Dec 2025 22:43:02 -0800 Subject: [PATCH 3/5] fix bugs in TimeStamp --- src/App.jsx | 43 +++++++++++------------------------- src/components/ChatEntry.jsx | 14 ++++++------ src/components/ChatLog.jsx | 12 +++++----- 3 files changed, 25 insertions(+), 44 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 70ee4dc13..cc25dc916 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,48 +3,31 @@ import messages from './data/messages.json'; import ChatLog from './components/ChatLog'; import { useState } from 'react'; +const senderColors = { + Vladimir: 'red', + Estragon: 'green', +}; + const App = () => { const [chatMessages, setChatMessages] = useState(messages); - // const [likeButton, setLikeButton] = useState(false); - // const [countLikes, setCountLikes] = useState(0); - // const [heart, setHeart] = useState('🤍'); - const senderColors = useState({ - Vladimir: 'red', - Estragon: 'green', - }); const toggleLikeChoice = (id) => { - const updatedMessages = chatMessages.map(message => { - if (message.id === id) { - return { ...message, liked: !message.liked}; - } else { - return message; - } + setChatMessages(chatMessages => { + return chatMessages.map(message => { + if (message.id === id) { + return { ...message, liked: !message.liked}; + } else { + return message; + } + }); }); - setChatMessages(updatedMessages); }; - // setLikeButton(likeButton => !likeButton); - // if (!likeButton) { - // setHeart('❤️'); - // } else { - // setHeart('🤍'); - // } - // }; - - // const countTotalLikes = (messages) => { - // for (const message of messages) { - // if (message.liked) { - // setCountLikes(preCountLikes => preCountLikes + 1); - // }; - // }; - // }; const countLikes = chatMessages.filter(msg => msg.liked).length; const participants = Array.from(new Set(chatMessages.map(msg => msg.sender))); const headerTitle = `Chat between ${participants.join(' and ')}`; - return (
diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index f9777a34e..a0e0a2a61 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -2,21 +2,20 @@ import './ChatEntry.css'; import PropTypes from 'prop-types'; import TimeStamp from './TimeStamp'; - - const ChatEntry = ({ id, sender, body, timeStamp, toggleLikeChoice, liked, color}) => { const isLocal = sender === 'Vladimir'; return ( // Replace the outer tag name with a semantic element that fits our use case -
+
  • {sender}

    {body}

    - + + +
    -
  • - + ); }; @@ -25,8 +24,9 @@ ChatEntry.propTypes = { sender: PropTypes.string.isRequired, body: PropTypes.string.isRequired, timeStamp: PropTypes.string.isRequired, - toggleLikeChoice: PropTypes.func.isRequired, liked: PropTypes.bool.isRequired, + toggleLikeChoice: PropTypes.func, + color:PropTypes.string }; export default ChatEntry; diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx index ad3a52cfa..da586320f 100644 --- a/src/components/ChatLog.jsx +++ b/src/components/ChatLog.jsx @@ -2,8 +2,7 @@ import ChatEntry from './ChatEntry'; import './ChatLog.css'; import PropTypes from 'prop-types'; -const ChatLog = ({ entries, toggleLikeChoice, senderColors}) => { - +const ChatLog = ({ entries, toggleLikeChoice = () => {}, senderColors = {} }) => { const chatEntryComponents = entries.map(entry => { return ( { timeStamp={entry.timeStamp} toggleLikeChoice={toggleLikeChoice} liked={entry.liked} - color={senderColors[entry.sender]} + color={senderColors?.[entry.sender]} /> ); }); return ( -
      +
        {chatEntryComponents}
      ); @@ -36,9 +35,8 @@ ChatLog.propTypes = { liked: PropTypes.bool.isRequired, }) ).isRequired, - toggleLikeChoice: PropTypes.func.isRequired, - senderColors: PropTypes.object.isRequired, + toggleLikeChoice: PropTypes.func, + senderColors: PropTypes.object, }; - export default ChatLog; \ No newline at end of file From fcc703540fa07704ced75fc6608d7a3b43c05aa4 Mon Sep 17 00:00:00 2001 From: liyan Date: Mon, 15 Dec 2025 22:55:24 -0800 Subject: [PATCH 4/5] refactor: improve code formatting and consistency in App and ChatEntry components --- src/App.jsx | 12 ++++++------ src/components/ChatEntry.jsx | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index cc25dc916..bed8f0926 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,7 +3,7 @@ import messages from './data/messages.json'; import ChatLog from './components/ChatLog'; import { useState } from 'react'; -const senderColors = { +const SENDER_COLORS = { Vladimir: 'red', Estragon: 'green', }; @@ -15,7 +15,7 @@ const App = () => { setChatMessages(chatMessages => { return chatMessages.map(message => { if (message.id === id) { - return { ...message, liked: !message.liked}; + return { ...message, liked: !message.liked }; } else { return message; } @@ -31,14 +31,14 @@ const App = () => { return (
      -

      {headerTitle}

      +

      {headerTitle}

      -
      -

      {countLikes} ❤️s

      +
      +

      {countLikes} ❤️s

      diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index a0e0a2a61..134634210 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -6,14 +6,14 @@ const ChatEntry = ({ id, sender, body, timeStamp, toggleLikeChoice, liked, color const isLocal = sender === 'Vladimir'; return ( // Replace the outer tag name with a semantic element that fits our use case -
    • +
    • {sender}

      -
      +

      {body}

      - +
    • ); @@ -26,7 +26,7 @@ ChatEntry.propTypes = { timeStamp: PropTypes.string.isRequired, liked: PropTypes.bool.isRequired, toggleLikeChoice: PropTypes.func, - color:PropTypes.string + color: PropTypes.string }; export default ChatEntry; From c2f2bfe13ae3657869cafdfd05f4437e094df1d1 Mon Sep 17 00:00:00 2001 From: liyan Date: Mon, 15 Dec 2025 23:34:09 -0800 Subject: [PATCH 5/5] refactor: update layout structure and improve semantic HTML in App, ChatEntry, and ChatLog components --- src/App.css | 11 ++++++++++- src/App.jsx | 2 +- src/components/ChatEntry.css | 7 +++++++ src/components/ChatEntry.jsx | 6 +++--- src/components/ChatLog.jsx | 4 ++-- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/App.css b/src/App.css index fef803632..7bf48e059 100644 --- a/src/App.css +++ b/src/App.css @@ -32,7 +32,7 @@ } #App .widget { - display: inline-block; + display: block; line-height: 0.5em; border-radius: 10px; color: black; @@ -44,6 +44,15 @@ #App #heartWidget { font-size: 1.5em; margin: 1em; + padding-top: 1em; + padding-bottom: 0.8em; +} + +#App header h1, +#App #heartWidget { + line-height: 3rem; + margin: 0; + padding: 0; } #App span { diff --git a/src/App.jsx b/src/App.jsx index bed8f0926..14848ec70 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -32,9 +32,9 @@ const App = () => {

      {headerTitle}

      +
      {countLikes} ❤️s
      -

      {countLikes} ❤️s

      { +const ChatEntry = ({ id, sender, body, timeStamp, toggleLikeChoice, liked, color }) => { const isLocal = sender === 'Vladimir'; return ( // Replace the outer tag name with a semantic element that fits our use case -
    • +

      {sender}

      {body}

      @@ -15,7 +15,7 @@ const ChatEntry = ({ id, sender, body, timeStamp, toggleLikeChoice, liked, color
      -
    • + ); }; diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx index da586320f..422f3baba 100644 --- a/src/components/ChatLog.jsx +++ b/src/components/ChatLog.jsx @@ -19,9 +19,9 @@ const ChatLog = ({ entries, toggleLikeChoice = () => {}, senderColors = {} }) => }); return ( -
        +
        {chatEntryComponents} -
      + ); };