From 2feb46233f4f425f79e7db06dde82552cafa131e Mon Sep 17 00:00:00 2001 From: Magnus Hissingby Date: Thu, 28 Aug 2025 13:19:59 +0200 Subject: [PATCH 1/5] first take on core --- src/App.jsx | 78 +++++++++++++-------------------------- src/components/Email.jsx | 34 +++++++++++++++++ src/components/Emails.jsx | 17 +++++++++ 3 files changed, 77 insertions(+), 52 deletions(-) create mode 100644 src/components/Email.jsx create mode 100644 src/components/Emails.jsx diff --git a/src/App.jsx b/src/App.jsx index c902699..5ff02fe 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,45 +1,45 @@ import { useState } from 'react' - -import initialEmails from './data/emails' - import './styles/App.css' - -const getReadEmails = emails => emails.filter(email => !email.read) - -const getStarredEmails = emails => emails.filter(email => email.starred) +import Emails from './components/Emails' +import initialEmails from './data/emails' function App() { + const [emails, setEmails] = useState(initialEmails) - const [hideRead, setHideRead] = useState(false) - const [currentTab, setCurrentTab] = useState('inbox') - const unreadEmails = emails.filter(email => !email.read) - const starredEmails = emails.filter(email => email.starred) + let filteredEmails = emails const toggleStar = targetEmail => { - const updatedEmails = emails => - emails.map(email => - email.id === targetEmail.id - ? { ...email, starred: !email.starred } - : email - ) - setEmails(updatedEmails) - } - - const toggleRead = targetEmail => { + const updatedEmails = emails => + emails.map(email => + email.id === targetEmail.id + ? { ...email, starred: !email.starred } + : email + ) + setEmails(updatedEmails) + } + + const toggleRead = targetEmail => { const updatedEmails = emails => emails.map(email => email.id === targetEmail.id ? { ...email, read: !email.read } : email ) - setEmails(updatedEmails) - } + setEmails(updatedEmails) + } - let filteredEmails = emails + + const [currentTab, setCurrentTab] = useState('inbox') + const [hideRead, setHideRead] = useState(false) - if (hideRead) filteredEmails = getReadEmails(filteredEmails) + const getReadEmails = emails => emails.filter(email => !email.read) + const getStarredEmails = emails => emails.filter(email => email.starred) + const unreadEmails = emails.filter(email => !email.read) + const starredEmails = emails.filter(email => email.starred) if (currentTab === 'starred') filteredEmails = getStarredEmails(filteredEmails) + + if (hideRead) filteredEmails = getReadEmails(filteredEmails) return (
@@ -88,33 +88,7 @@ function App() {
-
    - {filteredEmails.map((email, index) => ( -
  • -
    - toggleRead(email)} - /> -
    -
    - toggleStar(email)} - /> -
    -
    {email.sender}
    -
    {email.title}
    -
  • - ))} -
+
) diff --git a/src/components/Email.jsx b/src/components/Email.jsx new file mode 100644 index 0000000..94dd950 --- /dev/null +++ b/src/components/Email.jsx @@ -0,0 +1,34 @@ + +function Email({email, index, toggleRead, toggleStar}) { + + // Display a single email + return ( + <> +
  • +
    + toggleRead(email)} + /> +
    +
    + toggleStar(email)} + /> +
    +
    {email.sender}
    +
    {email.title}
    +
  • + + ) +} + +export default Email \ No newline at end of file diff --git a/src/components/Emails.jsx b/src/components/Emails.jsx new file mode 100644 index 0000000..fdf2dcd --- /dev/null +++ b/src/components/Emails.jsx @@ -0,0 +1,17 @@ +import Email from "./Email" + +function Emails({filteredEmails, toggleRead, toggleStar}) { + + // Display all emails as an ul + return ( + <> + + + ) +} + +export default Emails \ No newline at end of file From 4baab1b0cb4e317466e53b4b928a280bfd22b7fe Mon Sep 17 00:00:00 2001 From: Magnus Hissingby Date: Thu, 28 Aug 2025 13:42:52 +0200 Subject: [PATCH 2/5] core finished --- src/App.jsx | 44 ++++-------------------------------- src/components/Header.jsx | 23 +++++++++++++++++++ src/components/LeftMenu.jsx | 35 ++++++++++++++++++++++++++++ src/components/SearchBar.jsx | 0 4 files changed, 62 insertions(+), 40 deletions(-) create mode 100644 src/components/Header.jsx create mode 100644 src/components/LeftMenu.jsx create mode 100644 src/components/SearchBar.jsx diff --git a/src/App.jsx b/src/App.jsx index 5ff02fe..b1dde07 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,6 +2,8 @@ import { useState } from 'react' import './styles/App.css' import Emails from './components/Emails' import initialEmails from './data/emails' +import Header from './components/Header' +import LeftMenu from './components/LeftMenu' function App() { @@ -44,48 +46,10 @@ function App() { return (
    -
    - - - - - gmail logo -
    - -
    - -
    +
    diff --git a/src/components/Header.jsx b/src/components/Header.jsx new file mode 100644 index 0000000..e8fd9c7 --- /dev/null +++ b/src/components/Header.jsx @@ -0,0 +1,23 @@ + +function Header(){ + return ( + <> +
    + + + + + gmail logo +
    + +
    + +
    + + ) +} + +export default Header \ No newline at end of file diff --git a/src/components/LeftMenu.jsx b/src/components/LeftMenu.jsx new file mode 100644 index 0000000..4d27083 --- /dev/null +++ b/src/components/LeftMenu.jsx @@ -0,0 +1,35 @@ + +function LeftMenu({currentTab, setCurrentTab, unreadEmails, starredEmails, hideRead, setHideRead}){ + return ( + <> +
      +
    • setCurrentTab('inbox')} + > + Inbox + {unreadEmails.length} +
    • +
    • setCurrentTab('starred')} + > + Starred + {starredEmails.length} +
    • + +
    • + + setHideRead(e.target.checked)} + /> +
    • +
    + + ) +} + +export default LeftMenu \ No newline at end of file diff --git a/src/components/SearchBar.jsx b/src/components/SearchBar.jsx new file mode 100644 index 0000000..e69de29 From ff576245222f38643bd886e601ea532d6e1d8ff6 Mon Sep 17 00:00:00 2001 From: Magnus Hissingby Date: Thu, 28 Aug 2025 14:43:22 +0200 Subject: [PATCH 3/5] Extension 1 (no backNav) --- src/App.jsx | 87 +++++++++++++++++++-------------- src/components/DisplayEmail.jsx | 12 +++++ src/components/Email.jsx | 12 +++-- src/components/Emails.jsx | 4 +- src/components/LeftMenu.jsx | 12 +++-- 5 files changed, 81 insertions(+), 46 deletions(-) create mode 100644 src/components/DisplayEmail.jsx diff --git a/src/App.jsx b/src/App.jsx index b1dde07..6eca4de 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,58 +4,73 @@ import Emails from './components/Emails' import initialEmails from './data/emails' import Header from './components/Header' import LeftMenu from './components/LeftMenu' +import DisplayEmail from './components/DisplayEmail' function App() { - const [emails, setEmails] = useState(initialEmails) + const [emails, setEmails] = useState(initialEmails) - let filteredEmails = emails + const [chosenEmail, setChosenEmail] = useState(null) + const [isClicked, setIsClicked] = useState(false) - const toggleStar = targetEmail => { - const updatedEmails = emails => - emails.map(email => - email.id === targetEmail.id - ? { ...email, starred: !email.starred } - : email - ) - setEmails(updatedEmails) - } + let filteredEmails = emails + + const toggleStar = targetEmail => { + const updatedEmails = emails.map(email => + email.id === targetEmail.id + ? { ...email, starred: !email.starred } + : email + ) + setEmails(updatedEmails) + } const toggleRead = targetEmail => { - const updatedEmails = emails => - emails.map(email => + const updatedEmails = emails.map(email => email.id === targetEmail.id ? { ...email, read: !email.read } : email ) setEmails(updatedEmails) } - const [currentTab, setCurrentTab] = useState('inbox') - const [hideRead, setHideRead] = useState(false) + const [currentTab, setCurrentTab] = useState('inbox') + const [hideRead, setHideRead] = useState(false) + + const getReadEmails = emails => emails.filter(email => !email.read) + const getStarredEmails = emails => emails.filter(email => email.starred) + const unreadEmails = emails.filter(email => !email.read) + const starredEmails = emails.filter(email => email.starred) - const getReadEmails = emails => emails.filter(email => !email.read) - const getStarredEmails = emails => emails.filter(email => email.starred) - const unreadEmails = emails.filter(email => !email.read) - const starredEmails = emails.filter(email => email.starred) + if (currentTab === 'starred') + filteredEmails = getStarredEmails(filteredEmails) + + if (hideRead) filteredEmails = getReadEmails(filteredEmails) - if (currentTab === 'starred') - filteredEmails = getStarredEmails(filteredEmails) - if (hideRead) filteredEmails = getReadEmails(filteredEmails) - - return ( -
    -
    -
    -
    - -
    - -
    -
    - ) + if (isClicked) { + return ( +
    +
    +
    +
    + + +
    + )} else { + return ( +
    +
    +
    +
    + +
    + +
    +
    + )} } export default App diff --git a/src/components/DisplayEmail.jsx b/src/components/DisplayEmail.jsx new file mode 100644 index 0000000..9949b37 --- /dev/null +++ b/src/components/DisplayEmail.jsx @@ -0,0 +1,12 @@ + +function DisplayEmail({emailText}){ + return ( + <> +
    +

    {emailText}

    +
    + + ) +} + +export default DisplayEmail \ No newline at end of file diff --git a/src/components/Email.jsx b/src/components/Email.jsx index 94dd950..e6f9aad 100644 --- a/src/components/Email.jsx +++ b/src/components/Email.jsx @@ -1,13 +1,15 @@ -function Email({email, index, toggleRead, toggleStar}) { +function Email({email, index, toggleRead, toggleStar, setChosenEmail, setIsClicked}) { + + const onEmailClicked = () => { + setChosenEmail(email) + setIsClicked(true) + } // Display a single email return ( <> -
  • +
    • {filteredEmails.map((email, index) => ( - + ))}
    diff --git a/src/components/LeftMenu.jsx b/src/components/LeftMenu.jsx index 4d27083..67805c7 100644 --- a/src/components/LeftMenu.jsx +++ b/src/components/LeftMenu.jsx @@ -1,18 +1,24 @@ -function LeftMenu({currentTab, setCurrentTab, unreadEmails, starredEmails, hideRead, setHideRead}){ +function LeftMenu({currentTab, setCurrentTab, unreadEmails, starredEmails, hideRead, setHideRead, setIsClicked}){ return ( <>
    • setCurrentTab('inbox')} + onClick={() => { + setCurrentTab('inbox'); + setIsClicked(false); + }} > Inbox {unreadEmails.length}
    • setCurrentTab('starred')} + onClick={() => { + setCurrentTab('starred'); + setIsClicked(false); + }} > Starred {starredEmails.length} From 598948aee9b1c7e151c906a8b8216dcab485a465 Mon Sep 17 00:00:00 2001 From: Magnus Hissingby Date: Thu, 28 Aug 2025 15:49:41 +0200 Subject: [PATCH 4/5] extension 1 complete (has to click on the text to open mails) --- package-lock.json | 56 ++++++++++++++++++++++++++++++++- package.json | 3 +- src/App.jsx | 5 ++- src/components/BackNav.jsx | 15 +++++++++ src/components/DisplayEmail.jsx | 6 +++- src/components/Email.jsx | 6 ++-- src/main.jsx | 2 +- src/styles/App.css | 4 +++ 8 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 src/components/BackNav.jsx diff --git a/package-lock.json b/package-lock.json index d603209..64d575b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "0.0.0", "dependencies": { "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^7.8.2" }, "devDependencies": { "@types/react": "^18.2.15", @@ -913,6 +914,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "dev": true, @@ -2561,6 +2571,44 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.2.tgz", + "integrity": "sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.8.2.tgz", + "integrity": "sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow==", + "license": "MIT", + "dependencies": { + "react-router": "7.8.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "dev": true, @@ -2725,6 +2773,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.1.1", "dev": true, diff --git a/package.json b/package.json index b9d8385..af5239e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ }, "dependencies": { "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^7.8.2" }, "devDependencies": { "@types/react": "^18.2.15", diff --git a/src/App.jsx b/src/App.jsx index 6eca4de..f70b184 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -55,7 +55,10 @@ function App() { - +
      + +
      +
    )} else { return ( diff --git a/src/components/BackNav.jsx b/src/components/BackNav.jsx new file mode 100644 index 0000000..de9e8a8 --- /dev/null +++ b/src/components/BackNav.jsx @@ -0,0 +1,15 @@ + + +function BackNav({setIsClicked}) { + + const handleBackClick = () => { + setIsClicked(false) + }; + + return ( + + ); +} + +export default BackNav + diff --git a/src/components/DisplayEmail.jsx b/src/components/DisplayEmail.jsx index 9949b37..82cc6a4 100644 --- a/src/components/DisplayEmail.jsx +++ b/src/components/DisplayEmail.jsx @@ -1,7 +1,11 @@ +import BackNav from "./backNav" -function DisplayEmail({emailText}){ +function DisplayEmail({emailText, setIsClicked}){ return ( <> +
    + +

    {emailText}

    diff --git a/src/components/Email.jsx b/src/components/Email.jsx index e6f9aad..22785a3 100644 --- a/src/components/Email.jsx +++ b/src/components/Email.jsx @@ -9,7 +9,7 @@ function Email({email, index, toggleRead, toggleStar, setChosenEmail, setIsClick // Display a single email return ( <> -
  • +
  • toggleStar(email)} />
    -
    {email.sender}
    -
    {email.title}
    +
    {email.sender}
    +
    {email.title}
  • ) diff --git a/src/main.jsx b/src/main.jsx index fce89a2..dae8d55 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -5,6 +5,6 @@ import './styles/index.css' ReactDOM.createRoot(document.getElementById('root')).render( - + , ) diff --git a/src/styles/App.css b/src/styles/App.css index da375b1..998999e 100644 --- a/src/styles/App.css +++ b/src/styles/App.css @@ -116,6 +116,10 @@ text-overflow: ellipsis; } +.email .textFieldEmails { + size: 100%; +} + .email .star-checkbox { appearance: none; position: relative; From 46d6d181b9208cb2b9f9da5544e174d216278c40 Mon Sep 17 00:00:00 2001 From: Magnus Hissingby Date: Thu, 28 Aug 2025 20:39:24 +0200 Subject: [PATCH 5/5] extension 2 complete --- src/App.jsx | 10 +++++++--- src/components/BackNav.jsx | 2 +- src/components/DisplayEmail.jsx | 7 ++++--- src/components/Header.jsx | 8 +++----- src/components/SearchBar.jsx | 18 ++++++++++++++++++ src/data/emails.js | 10 ++++++++++ src/styles/App.css | 4 ---- 7 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index f70b184..3951a1b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -13,6 +13,8 @@ function App() { const [chosenEmail, setChosenEmail] = useState(null) const [isClicked, setIsClicked] = useState(false) + const [input, setInput] = useState("") + let filteredEmails = emails const toggleStar = targetEmail => { @@ -44,19 +46,21 @@ function App() { filteredEmails = getStarredEmails(filteredEmails) if (hideRead) filteredEmails = getReadEmails(filteredEmails) + + if (input !== "") filteredEmails = emails.filter(email => email.text.toLowerCase().includes(input.toLowerCase()) || email.title.toLowerCase().includes(input.toLowerCase()) || email.sender.toLowerCase().includes(input.toLowerCase())) if (isClicked) { return (
    -
    +
    - +
    @@ -64,7 +68,7 @@ function App() { return (
    -
    +